<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * Licensed under the MIT license (see LICENSE).
 */
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <algorithm>
#include "log.h"
#include "../fnv.h"

namespace fnordmetric {
namespace database {

LogReader::LogReader(
    std::shared_ptr<PageManager> page_manager,
    const PageManager::Page& first_log_page,
    LogSnapshot* destination) :
    page_manager_(std::move(page_manager)),
    current_page_(first_log_page),
    destination_(destination) {}

void LogReader::import() {
  bool running = true;

  destination_->last_used_byte = current_page_.offset + current_page_.size;

  while (running) {
    auto mmapped_offset = current_page_.offset;
    auto mmapped = page_manager_->getPage(current_page_);
    size_t offset = 0;

    destination_->current_log_page = current_page_;
    destination_->current_log_page_offset = offset;

    while (current_page_.offset == mmapped_offset) {
      running = importNextEntry(mmapped.get(), current_page_.size, &offset);

      if (running) {
        destination_->current_log_page_offset = offset;
      } else {
        break;
      }
    }
  }

  for (auto& stream : destination_->streams) {
    if (stream.pages_.size() > 0) {
      countPageUsedBytes(stream.pages_.back());
    }
  }
}

bool LogReader::importNextEntry(
    const PageManager::PageRef* mmapped,
    size_t mmaped_size,
    size_t* offset) {
  size_t header_size = sizeof(Log::EntryHeader);

  if (*offset + header_size >= mmaped_size) {
    return false;
  }

  auto entry_header = mmapped->structAt<Log::EntryHeader>(*offset);
  size_t entry_size = header_size + entry_header->size;

  if (entry_header->size == 0 || *offset + entry_size >= mmaped_size) {
    return false;
  }

  if (entry_header->checksum != entry_header->computeChecksum()) {
    fprintf(stderr, "warning: invalid checksum for log entry 0x%" PRIx64 "\n",
        mmapped->page_.offset + *offset);
    return false;
  }

  *offset += entry_size;
  importLogEntry(entry_header);
  return true;
}

void LogReader::importLogEntry(const Log::EntryHeader* entry) {
  switch (entry->type) {

    case Log::PAGE_ALLOC_ENTRY: {
      auto alloc_entry = (Log::PageAllocEntry *) entry;
      auto iter = streams_.find(alloc_entry->stream_id);
      LogSnapshot::StreamState* stream_state;

      if (iter == streams_.end()) {
        destination_->streams.emplace_back(alloc_entry->stream_id);
        stream_state = &destination_->streams.back();
        streams_[alloc_entry->stream_id] = stream_state;

        size_t key_len = alloc_entry->hdr.size -
            (sizeof(Log::PageAllocEntry) - sizeof(Log::EntryHeader));
        stream_state->stream_key_.insert(0, alloc_entry->stream_key, key_len);

        if (alloc_entry->stream_id > destination_->max_stream_id) {
          destination_->max_stream_id = alloc_entry->stream_id;
        }
      } else {
        stream_state = iter->second;
      }

      PageManager::Page page;
      page.offset = alloc_entry->page_offset;
      page.size = alloc_entry->page_size;

      auto alloc = new PageAlloc(page, alloc_entry->page_first_row_time);
      stream_state->pages_.push_back(std::shared_ptr<PageAlloc>(alloc));
      setLastUsedByte(page.offset + page.size);
      break;
    }

    case Log::PAGE_FINISH_ENTRY: {
      auto finish_entry = (Log::PageFinishEntry *) entry;
      auto iter = streams_.find(finish_entry->stream_id);

      if (iter != streams_.end()) {
        auto stream_state = iter->second;
        if (stream_state->pages_.back()->page_.offset ==
            finish_entry->page_offset) {
          stream_state->pages_.back()->used_ = finish_entry->page_used;
          break;
        }
      }

      fprintf(stderr, "warning: unexpected PAGE_FINISH log entry\n");
      break;
    }

    case Log::NEXT_PAGE_ENTRY: {
      auto next_entry = (Log::NextPageEntry *) entry;
      current_page_.offset = next_entry->page_offset;
      current_page_.size = next_entry->page_size;
      setLastUsedByte(current_page_.offset + current_page_.size);
      break;
    }

    default:
      fprintf(stderr, "warning: invalid log entry type %i\n", entry->type);

  };
}

void LogReader::countPageUsedBytes(std::shared_ptr<PageAlloc> page) {
  size_t offset = 0;
  size_t max = page->page_.size - sizeof(Log::EntryHeader) - 1;
  auto mmapped = page_manager_->getPage(page->page_);

  while (offset < max) {
    auto row = mmapped->structAt<RowHeader>(offset);
    auto row_size = sizeof(RowHeader) + row->size;

    if (row->size == 0 || row->time == 0) {
      return;
    }

    if (offset + row_size >= page->page_.size) {
      return;
    }

    if (row->checksum != row->computeChecksum()) {
      return;
    }

    offset += row_size;
    page->used_ = offset;
  }
}

void LogReader::setLastUsedByte(uint64_t index) {
  if (index > destination_->last_used_byte) {
    destination_->last_used_byte = index;
  }
}

const uint64_t Log::kMinLogPageSize = 512;

Log::Log(
    const LogSnapshot& snapshot,
    std::shared_ptr<PageManager> page_manager) :
    page_manager_(page_manager),
    current_page_(snapshot.current_log_page),
    current_page_offset_(snapshot.current_log_page_offset) {}

Log::Log(
    const PageManager::Page& first_log_page,
    std::shared_ptr<PageManager> page_manager) :
    page_manager_(page_manager),
    current_page_(first_log_page),
    current_page_offset_(0) {}

void Log::appendEntry(Log::PageAllocEntry entry) {
  entry.hdr.size = sizeof(PageAllocEntry) - sizeof(EntryHeader);
  entry.hdr.type = PAGE_ALLOC_ENTRY;
  appendEntry((uint8_t *) &entry, sizeof(PageAllocEntry));
}

void Log::appendEntry(Log::PageAllocEntry entry, const std::string& stream_key) {
  assert(stream_key.size() < 0xffff);
  entry.hdr.size = sizeof(PageAllocEntry) - sizeof(EntryHeader);
  entry.hdr.size += stream_key.size();
  entry.hdr.type = PAGE_ALLOC_ENTRY;
  size_t tmp_len = sizeof(PageAllocEntry) + stream_key.size();
  uint8_t* tmp = (uint8_t *) malloc(tmp_len);
  assert(tmp);
  memcpy(tmp, &entry, sizeof(PageAllocEntry));
  memcpy(tmp + sizeof(PageAllocEntry), stream_key.c_str(), stream_key.size());
  appendEntry(tmp, tmp_len);
  free(tmp);
}

void Log::appendEntry(Log::PageFinishEntry entry) {
  entry.hdr.size = sizeof(PageFinishEntry) - sizeof(EntryHeader);
  entry.hdr.type = PAGE_FINISH_ENTRY;
  appendEntry((uint8_t *) &entry, sizeof(PageFinishEntry));
}

void Log::appendEntry(Log::PageFreeEntry entry) {
  entry.hdr.size = sizeof(PageFreeEntry) - sizeof(EntryHeader);
  entry.hdr.type = PAGE_FREE_ENTRY;
  appendEntry((uint8_t *) &entry, sizeof(PageFreeEntry));
}

// FIXPAUL lock!
void Log::appendEntry(uint8_t* data, size_t length) {
  uint64_t reserved_length = length + sizeof(Log::NextPageEntry);

  /* allocate a new page if the current one is full */
  if (current_page_offset_ + reserved_length >= current_page_.size) {
    assert(current_page_offset_ + sizeof(Log::NextPageEntry) <=
        current_page_.size);

    auto next_page_size = std::max(kMinLogPageSize, reserved_length);
    auto next_page = page_manager_->allocPage(next_page_size);

    Log::NextPageEntry log_entry;
    log_entry.page_offset = next_page.offset;
    log_entry.page_size = next_page.size;
    log_entry.hdr.size = sizeof(Log::NextPageEntry) - sizeof(Log::EntryHeader);
    log_entry.hdr.type = NEXT_PAGE_ENTRY;
    log_entry.hdr.checksum = log_entry.hdr.computeChecksum();

    auto mmaped = page_manager_->getPage(current_page_);
    auto dst = mmaped->structAt<char>(current_page_offset_);
    memcpy(dst, (char *) &log_entry, sizeof(Log::NextPageEntry));
    current_page_offset_ += sizeof(Log::NextPageEntry);

    current_page_ = next_page;
    current_page_offset_ = 0;
  }

  /* memcpy the entry into the current page */
  auto entry = (Log::EntryHeader*) data;
  entry->checksum = entry->computeChecksum();
  auto mmaped = page_manager_->getPage(current_page_);
  auto dst = mmaped->structAt<char>(current_page_offset_);
  memcpy(dst, data, length);
  current_page_offset_ += length;

  // FIXPAUL msync
}

uint32_t Log::EntryHeader::computeChecksum() {
  FNV<uint32_t> fnv;

  return fnv.hash(
      (uint8_t *) (((char* ) this) + sizeof(checksum)),
      size + sizeof(EntryHeader) - sizeof(checksum));
}

LogSnapshot::LogSnapshot() : max_stream_id(0) {}

LogSnapshot::StreamState::StreamState(uint32_t stream_id) :
  stream_id_(stream_id) {}

}
}
<commit_msg>fix includes...<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * Licensed under the MIT license (see LICENSE).
 */
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#include <algorithm>
#include "log.h"
#include "../fnv.h"

namespace fnordmetric {
namespace database {

LogReader::LogReader(
    std::shared_ptr<PageManager> page_manager,
    const PageManager::Page& first_log_page,
    LogSnapshot* destination) :
    page_manager_(std::move(page_manager)),
    current_page_(first_log_page),
    destination_(destination) {}

void LogReader::import() {
  bool running = true;

  destination_->last_used_byte = current_page_.offset + current_page_.size;

  while (running) {
    auto mmapped_offset = current_page_.offset;
    auto mmapped = page_manager_->getPage(current_page_);
    size_t offset = 0;

    destination_->current_log_page = current_page_;
    destination_->current_log_page_offset = offset;

    while (current_page_.offset == mmapped_offset) {
      running = importNextEntry(mmapped.get(), current_page_.size, &offset);

      if (running) {
        destination_->current_log_page_offset = offset;
      } else {
        break;
      }
    }
  }

  for (auto& stream : destination_->streams) {
    if (stream.pages_.size() > 0) {
      countPageUsedBytes(stream.pages_.back());
    }
  }
}

bool LogReader::importNextEntry(
    const PageManager::PageRef* mmapped,
    size_t mmaped_size,
    size_t* offset) {
  size_t header_size = sizeof(Log::EntryHeader);

  if (*offset + header_size >= mmaped_size) {
    return false;
  }

  auto entry_header = mmapped->structAt<Log::EntryHeader>(*offset);
  size_t entry_size = header_size + entry_header->size;

  if (entry_header->size == 0 || *offset + entry_size >= mmaped_size) {
    return false;
  }

  if (entry_header->checksum != entry_header->computeChecksum()) {
    fprintf(stderr, "warning: invalid checksum for log entry 0x%" PRIx64 "\n",
        mmapped->page_.offset + *offset);
    return false;
  }

  *offset += entry_size;
  importLogEntry(entry_header);
  return true;
}

void LogReader::importLogEntry(const Log::EntryHeader* entry) {
  switch (entry->type) {

    case Log::PAGE_ALLOC_ENTRY: {
      auto alloc_entry = (Log::PageAllocEntry *) entry;
      auto iter = streams_.find(alloc_entry->stream_id);
      LogSnapshot::StreamState* stream_state;

      if (iter == streams_.end()) {
        destination_->streams.emplace_back(alloc_entry->stream_id);
        stream_state = &destination_->streams.back();
        streams_[alloc_entry->stream_id] = stream_state;

        size_t key_len = alloc_entry->hdr.size -
            (sizeof(Log::PageAllocEntry) - sizeof(Log::EntryHeader));
        stream_state->stream_key_.insert(0, alloc_entry->stream_key, key_len);

        if (alloc_entry->stream_id > destination_->max_stream_id) {
          destination_->max_stream_id = alloc_entry->stream_id;
        }
      } else {
        stream_state = iter->second;
      }

      PageManager::Page page;
      page.offset = alloc_entry->page_offset;
      page.size = alloc_entry->page_size;

      auto alloc = new PageAlloc(page, alloc_entry->page_first_row_time);
      stream_state->pages_.push_back(std::shared_ptr<PageAlloc>(alloc));
      setLastUsedByte(page.offset + page.size);
      break;
    }

    case Log::PAGE_FINISH_ENTRY: {
      auto finish_entry = (Log::PageFinishEntry *) entry;
      auto iter = streams_.find(finish_entry->stream_id);

      if (iter != streams_.end()) {
        auto stream_state = iter->second;
        if (stream_state->pages_.back()->page_.offset ==
            finish_entry->page_offset) {
          stream_state->pages_.back()->used_ = finish_entry->page_used;
          break;
        }
      }

      fprintf(stderr, "warning: unexpected PAGE_FINISH log entry\n");
      break;
    }

    case Log::NEXT_PAGE_ENTRY: {
      auto next_entry = (Log::NextPageEntry *) entry;
      current_page_.offset = next_entry->page_offset;
      current_page_.size = next_entry->page_size;
      setLastUsedByte(current_page_.offset + current_page_.size);
      break;
    }

    default:
      fprintf(stderr, "warning: invalid log entry type %i\n", entry->type);

  };
}

void LogReader::countPageUsedBytes(std::shared_ptr<PageAlloc> page) {
  size_t offset = 0;
  size_t max = page->page_.size - sizeof(Log::EntryHeader) - 1;
  auto mmapped = page_manager_->getPage(page->page_);

  while (offset < max) {
    auto row = mmapped->structAt<RowHeader>(offset);
    auto row_size = sizeof(RowHeader) + row->size;

    if (row->size == 0 || row->time == 0) {
      return;
    }

    if (offset + row_size >= page->page_.size) {
      return;
    }

    if (row->checksum != row->computeChecksum()) {
      return;
    }

    offset += row_size;
    page->used_ = offset;
  }
}

void LogReader::setLastUsedByte(uint64_t index) {
  if (index > destination_->last_used_byte) {
    destination_->last_used_byte = index;
  }
}

const uint64_t Log::kMinLogPageSize = 512;

Log::Log(
    const LogSnapshot& snapshot,
    std::shared_ptr<PageManager> page_manager) :
    page_manager_(page_manager),
    current_page_(snapshot.current_log_page),
    current_page_offset_(snapshot.current_log_page_offset) {}

Log::Log(
    const PageManager::Page& first_log_page,
    std::shared_ptr<PageManager> page_manager) :
    page_manager_(page_manager),
    current_page_(first_log_page),
    current_page_offset_(0) {}

void Log::appendEntry(Log::PageAllocEntry entry) {
  entry.hdr.size = sizeof(PageAllocEntry) - sizeof(EntryHeader);
  entry.hdr.type = PAGE_ALLOC_ENTRY;
  appendEntry((uint8_t *) &entry, sizeof(PageAllocEntry));
}

void Log::appendEntry(Log::PageAllocEntry entry, const std::string& stream_key) {
  assert(stream_key.size() < 0xffff);
  entry.hdr.size = sizeof(PageAllocEntry) - sizeof(EntryHeader);
  entry.hdr.size += stream_key.size();
  entry.hdr.type = PAGE_ALLOC_ENTRY;
  size_t tmp_len = sizeof(PageAllocEntry) + stream_key.size();
  uint8_t* tmp = (uint8_t *) malloc(tmp_len);
  assert(tmp);
  memcpy(tmp, &entry, sizeof(PageAllocEntry));
  memcpy(tmp + sizeof(PageAllocEntry), stream_key.c_str(), stream_key.size());
  appendEntry(tmp, tmp_len);
  free(tmp);
}

void Log::appendEntry(Log::PageFinishEntry entry) {
  entry.hdr.size = sizeof(PageFinishEntry) - sizeof(EntryHeader);
  entry.hdr.type = PAGE_FINISH_ENTRY;
  appendEntry((uint8_t *) &entry, sizeof(PageFinishEntry));
}

void Log::appendEntry(Log::PageFreeEntry entry) {
  entry.hdr.size = sizeof(PageFreeEntry) - sizeof(EntryHeader);
  entry.hdr.type = PAGE_FREE_ENTRY;
  appendEntry((uint8_t *) &entry, sizeof(PageFreeEntry));
}

// FIXPAUL lock!
void Log::appendEntry(uint8_t* data, size_t length) {
  uint64_t reserved_length = length + sizeof(Log::NextPageEntry);

  /* allocate a new page if the current one is full */
  if (current_page_offset_ + reserved_length >= current_page_.size) {
    assert(current_page_offset_ + sizeof(Log::NextPageEntry) <=
        current_page_.size);

    auto next_page_size = std::max(kMinLogPageSize, reserved_length);
    auto next_page = page_manager_->allocPage(next_page_size);

    Log::NextPageEntry log_entry;
    log_entry.page_offset = next_page.offset;
    log_entry.page_size = next_page.size;
    log_entry.hdr.size = sizeof(Log::NextPageEntry) - sizeof(Log::EntryHeader);
    log_entry.hdr.type = NEXT_PAGE_ENTRY;
    log_entry.hdr.checksum = log_entry.hdr.computeChecksum();

    auto mmaped = page_manager_->getPage(current_page_);
    auto dst = mmaped->structAt<char>(current_page_offset_);
    memcpy(dst, (char *) &log_entry, sizeof(Log::NextPageEntry));
    current_page_offset_ += sizeof(Log::NextPageEntry);

    current_page_ = next_page;
    current_page_offset_ = 0;
  }

  /* memcpy the entry into the current page */
  auto entry = (Log::EntryHeader*) data;
  entry->checksum = entry->computeChecksum();
  auto mmaped = page_manager_->getPage(current_page_);
  auto dst = mmaped->structAt<char>(current_page_offset_);
  memcpy(dst, data, length);
  current_page_offset_ += length;

  // FIXPAUL msync
}

uint32_t Log::EntryHeader::computeChecksum() {
  FNV<uint32_t> fnv;

  return fnv.hash(
      (uint8_t *) (((char* ) this) + sizeof(checksum)),
      size + sizeof(EntryHeader) - sizeof(checksum));
}

LogSnapshot::LogSnapshot() : max_stream_id(0) {}

LogSnapshot::StreamState::StreamState(uint32_t stream_id) :
  stream_id_(stream_id) {}

}
}
<|endoftext|>


<commit_before>//
//  main.cpp
//  NetworksProject
//
//  Created by Patrick Dang-Ho on 2017-03-12.
//  Copyright © 2017 Patrick Dang-Ho. All rights reserved.
//

#include <iostream>

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    return 0;
}
<commit_msg>delete original main.cpp from task 4 folder<commit_after><|endoftext|>


<commit_before>#include "scope.h"
#include <yuni/core/noncopyable.h>
#include "details/utils/check-for-valid-identifier-name.h"
#include "details/grammar/nany.h"
#include "details/ast/ast.h"

using namespace Yuni;

namespace ny {
namespace ir {
namespace Producer {

namespace {

struct AttributeContext final {
	AttributeContext(AST::Node& node)
		: storage{std::make_unique<Attributes>(node)}
		, attributes(*storage)
	{}
	ShortString32 name;
	ShortString32 value;
	std::unique_ptr<Attributes> storage;
	Attributes& attributes;
};

} // namespace

bool Scope::fetchAttributes(AST::Node& node) {
	assert(node.rule == AST::rgAttributes);
	AttributeContext ctx{node};
	for (auto& child : node.children) {
		// checking for node type
		if (unlikely(child.rule != AST::rgAttributesParameter))
			return unexpectedNode(child, "invalid node, not attribute parameter");
		AST::Node* nodevalue;
		switch (child.children.size()) {
			case 1:
				nodevalue = nullptr;
				break;
			case 2:
				nodevalue = &(child.children[1]);
				break;
			default:
				return unexpectedNode(child, "invalid attribute parameter node");
		}
		AST::Node& nodekey = child.children[0];
		if (unlikely(nodekey.rule != AST::rgEntity))
			return unexpectedNode(child, "invalid attribute parameter name type");
		if (nodevalue) {
			if (unlikely(nodevalue->rule != AST::rgEntity))
				return (error(child) << "unsupported expression for attribute ctx.value");
		}
		ctx.name.clear();
		ctx.value.clear();
		if (not AST::appendEntityAsString(ctx.name, nodekey))
			return unexpectedNode(child, "invalid entity");
		switch (ctx.name[0]) {
			case 'n': {
				if (ctx.name == "nodiscard") {
					if (unlikely(nodevalue))
						return (error(child) << "no ctx.value expected for attribute '" << ctx.name << '\'');
					break;
				}
			}
			// [[fallthru]]
			case 'p': {
				if (ctx.name == "per") {
					if (unlikely(!nodevalue))
						return (error(child) << "ctx.value expected for attribute '" << ctx.name << '\'');
					AST::appendEntityAsString(ctx.value, *nodevalue);
					if (ctx.value == "thread")
						warning(child) << "ignored attribute 'per: thread'";
					else if (ctx.value == "process")
						warning(child) << "ignored attribute 'per: process'";
					else
						return (error(child) << "invalid 'per' ctx.value");
					break;
				}
			}
			// [[fallthru]]
			case 's': {
				if (ctx.name == "nosuggest") {
					ctx.attributes.flags += Attributes::Flag::doNotSuggest;
					if (unlikely(nodevalue))
						return (error(child) << "the attribute '" << ctx.name << "' does not accept ctx.values");
					break;
				}
			}
			// [[fallthru]]
			case 't': {
				if (ctx.name == "threadproc") {
					ctx.attributes.flags += Attributes::Flag::threadproc;
					if (unlikely(nodevalue))
						return (error(child) << "the attribute '" << ctx.name << "' does not accept ctx.values");
					break;
				}
			}
			// [[fallthru]]
			case '_': {
				if (ctx.name == "__nanyc_builtinalias") {
					if (unlikely(!nodevalue))
						return (error(child) << "ctx.value expected for attribute '" << ctx.name << '\'');
					ctx.attributes.builtinAlias = nodevalue;
					ctx.attributes.flags += Attributes::Flag::builtinAlias;
					break;
				}
				if (ctx.name == "__nanyc_shortcircuit") {
					if (unlikely(!nodevalue))
						return (error(child) << "ctx.value expected for attribute '" << ctx.name << '\'');
					AST::appendEntityAsString(ctx.value, *nodevalue);
					bool isTrue = (ctx.value == "__true");
					if (not isTrue and (ctx.value.empty() or ctx.value != "__false")) {
						error(child.children[1]) << "invalid shortcircuit ctx.value, expected '__false' or '__true', got '"
												 << ctx.value << "'";
						return false;
					}
					if (isTrue)
						ctx.attributes.flags += Attributes::Flag::shortcircuit;
					break;
				}
				if (ctx.name == "__nanyc_synthetic") {
					ctx.attributes.flags += Attributes::Flag::pushSynthetic;
					if (unlikely(nodevalue))
						return (error(child) << "the attribute '" << ctx.name << "' does not accept ctx.values");
					break;
				}
				// [FALLBACK]
				// ignore vendor specific attributes (starting by '__')
				if (ctx.name.size() > 2 and ctx.name[1] == '_') {
					// emit a warning for the unsupported specific nany attributes
					if (unlikely(ctx.name.startsWith("__nanyc_")))
						warning(child) << "unknown nanyc attribute '" << ctx.name << "'";
					break;
				}
			}
			// [[fallthru]]
			default: {
				error(child) << "unknown attribute '" << ctx.name << '\'';
				return false;
			}
		}
	}
	attributes = std::move(ctx.storage);
	return true;
}

} // namespace Producer
} // namespace ir
} // namespace ny
<commit_msg>ast2ir: attributes: use exception for unexpected nodes<commit_after>#include "scope.h"
#include <yuni/core/noncopyable.h>
#include "details/utils/check-for-valid-identifier-name.h"
#include "details/grammar/nany.h"
#include "details/ast/ast.h"
#include "exception.h"

using namespace Yuni;

namespace ny {
namespace ir {
namespace Producer {

namespace {

struct AttributeContext final {
	AttributeContext(AST::Node& node)
		: storage{std::make_unique<Attributes>(node)}
		, attributes(*storage)
	{}
	ShortString32 name;
	ShortString32 value;
	std::unique_ptr<Attributes> storage;
	Attributes& attributes;
};

} // namespace

bool Scope::fetchAttributes(AST::Node& node) {
	assert(node.rule == AST::rgAttributes);
	try {
		AttributeContext ctx{node};
		for (auto& child : node.children) {
			// checking for node type
			if (unlikely(child.rule != AST::rgAttributesParameter))
				throw UnexpectedNode(child, "invalid node, not attribute parameter");
			AST::Node* nodevalue;
			switch (child.children.size()) {
				case 1:
					nodevalue = nullptr;
					break;
				case 2:
					nodevalue = &(child.children[1]);
					break;
				default:
					throw UnexpectedNode(child, "invalid attribute parameter node");
			}
			AST::Node& nodekey = child.children[0];
			if (unlikely(nodekey.rule != AST::rgEntity))
				throw UnexpectedNode(child, "invalid attribute parameter name type");
			if (nodevalue) {
				if (unlikely(nodevalue->rule != AST::rgEntity))
					return (error(child) << "unsupported expression for attribute ctx.value");
			}
			ctx.name.clear();
			ctx.value.clear();
			if (not AST::appendEntityAsString(ctx.name, nodekey))
				throw UnexpectedNode(child, "invalid entity");
			switch (ctx.name[0]) {
				case 'n': {
					if (ctx.name == "nodiscard") {
						if (unlikely(nodevalue))
							return (error(child) << "no ctx.value expected for attribute '" << ctx.name << '\'');
						break;
					}
				}
				// [[fallthru]]
				case 'p': {
					if (ctx.name == "per") {
						if (unlikely(!nodevalue))
							return (error(child) << "ctx.value expected for attribute '" << ctx.name << '\'');
						AST::appendEntityAsString(ctx.value, *nodevalue);
						if (ctx.value == "thread")
							warning(child) << "ignored attribute 'per: thread'";
						else if (ctx.value == "process")
							warning(child) << "ignored attribute 'per: process'";
						else
							return (error(child) << "invalid 'per' ctx.value");
						break;
					}
				}
				// [[fallthru]]
				case 's': {
					if (ctx.name == "nosuggest") {
						ctx.attributes.flags += Attributes::Flag::doNotSuggest;
						if (unlikely(nodevalue))
							return (error(child) << "the attribute '" << ctx.name << "' does not accept ctx.values");
						break;
					}
				}
				// [[fallthru]]
				case 't': {
					if (ctx.name == "threadproc") {
						ctx.attributes.flags += Attributes::Flag::threadproc;
						if (unlikely(nodevalue))
							return (error(child) << "the attribute '" << ctx.name << "' does not accept ctx.values");
						break;
					}
				}
				// [[fallthru]]
				case '_': {
					if (ctx.name == "__nanyc_builtinalias") {
						if (unlikely(!nodevalue))
							return (error(child) << "ctx.value expected for attribute '" << ctx.name << '\'');
						ctx.attributes.builtinAlias = nodevalue;
						ctx.attributes.flags += Attributes::Flag::builtinAlias;
						break;
					}
					if (ctx.name == "__nanyc_shortcircuit") {
						if (unlikely(!nodevalue))
							return (error(child) << "ctx.value expected for attribute '" << ctx.name << '\'');
						AST::appendEntityAsString(ctx.value, *nodevalue);
						bool isTrue = (ctx.value == "__true");
						if (not isTrue and (ctx.value.empty() or ctx.value != "__false")) {
							error(child.children[1]) << "invalid shortcircuit ctx.value, expected '__false' or '__true', got '"
													 << ctx.value << "'";
							return false;
						}
						if (isTrue)
							ctx.attributes.flags += Attributes::Flag::shortcircuit;
						break;
					}
					if (ctx.name == "__nanyc_synthetic") {
						ctx.attributes.flags += Attributes::Flag::pushSynthetic;
						if (unlikely(nodevalue))
							return (error(child) << "the attribute '" << ctx.name << "' does not accept ctx.values");
						break;
					}
					// [FALLBACK]
					// ignore vendor specific attributes (starting by '__')
					if (ctx.name.size() > 2 and ctx.name[1] == '_') {
						// emit a warning for the unsupported specific nany attributes
						if (unlikely(ctx.name.startsWith("__nanyc_")))
							warning(child) << "unknown nanyc attribute '" << ctx.name << "'";
						break;
					}
				}
				// [[fallthru]]
				default: {
					error(child) << "unknown attribute '" << ctx.name << '\'';
					return false;
				}
			}
		}
		attributes = std::move(ctx.storage);
		return true;
	}
	catch (const UnexpectedNode& e) {
		unexpectedNode(e.node, e.message);
	}
	return false;
}

} // namespace Producer
} // namespace ir
} // namespace ny
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Alexandru-Eugen Ichim
 *                      Willow Garage, Inc
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef PCL_FEATURES_IMPL_PPF_H_
#define PCL_FEATURES_IMPL_PPF_H_

#include "pcl/features/ppf.h"
#include <pcl/features/pfh.h>

template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  /// initialize output container
  output.clear ();
  output.resize (input_->points.size () * input_->points.size ());
  PCL_INFO ("PPFEstimation input size: %u\nOutput PPF size: %u\n",
           input_->points.size (), output.size ());

  /// compute point pair features for every pair of points in the cloud
  for (size_t i = 0; i < input_->points.size (); ++i)
    for (size_t j = 0 ; j < input_->points.size (); ++j)
    {
      PointOutT p;
      if (i != j)
      {
        if (pcl::computePairFeatures (input_->points[i].getVector4fMap (),
                                      normals_->points[i].getNormalVector4fMap (),
                                      input_->points[j].getVector4fMap (),
                                      normals_->points[j].getNormalVector4fMap (),
                                      p.f1, p.f2, p.f3, p.f4))
        {
          /// calculate alpha_m angle
          Eigen::Vector3f model_reference_point = input_->points[i].getVector3fMap (),
              model_reference_normal = normals_->points[i].getNormalVector3fMap (),
              model_point = input_->points[j].getVector3fMap ();
          Eigen::AngleAxisf rotation_mg (acos (model_reference_normal.dot (Eigen::Vector3f::UnitX ())),
                                         model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ());
          Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg;
          p.alpha_m = acos (Eigen::Vector3f::UnitY ().dot ((transform_mg * model_point).normalized ()));
        }
        else
        {
          PCL_ERROR ("Computing pair feature vector between points %zu and %zu went wrong.\n", i, j);
          p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;
        }
      }
      /// do not calculate the feature for identity pairs (i, i) as they are not used
      /// in the following computations
      else
        p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;

      output.points[i*input_->points.size () + j] = p;
    }
}

#define PCL_INSTANTIATE_PPFEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFEstimation<T,NT,OutT>;

#endif // PCL_FEATURES_IMPL_PPF_H_
<commit_msg>removed info message<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Alexandru-Eugen Ichim
 *                      Willow Garage, Inc
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef PCL_FEATURES_IMPL_PPF_H_
#define PCL_FEATURES_IMPL_PPF_H_

#include "pcl/features/ppf.h"
#include <pcl/features/pfh.h>

template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  /// initialize output container
  output.clear ();
  output.resize (input_->points.size () * input_->points.size ());

  /// compute point pair features for every pair of points in the cloud
  for (size_t i = 0; i < input_->points.size (); ++i)
    for (size_t j = 0 ; j < input_->points.size (); ++j)
    {
      PointOutT p;
      if (i != j)
      {
        if (pcl::computePairFeatures (input_->points[i].getVector4fMap (),
                                      normals_->points[i].getNormalVector4fMap (),
                                      input_->points[j].getVector4fMap (),
                                      normals_->points[j].getNormalVector4fMap (),
                                      p.f1, p.f2, p.f3, p.f4))
        {
          /// calculate alpha_m angle
          Eigen::Vector3f model_reference_point = input_->points[i].getVector3fMap (),
              model_reference_normal = normals_->points[i].getNormalVector3fMap (),
              model_point = input_->points[j].getVector3fMap ();
          Eigen::AngleAxisf rotation_mg (acos (model_reference_normal.dot (Eigen::Vector3f::UnitX ())),
                                         model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ());
          Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg;
          p.alpha_m = acos (Eigen::Vector3f::UnitY ().dot ((transform_mg * model_point).normalized ()));
        }
        else
        {
          PCL_ERROR ("Computing pair feature vector between points %zu and %zu went wrong.\n", i, j);
          p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;
        }
      }
      /// do not calculate the feature for identity pairs (i, i) as they are not used
      /// in the following computations
      else
        p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;

      output.points[i*input_->points.size () + j] = p;
    }
}

#define PCL_INSTANTIATE_PPFEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFEstimation<T,NT,OutT>;

#endif // PCL_FEATURES_IMPL_PPF_H_
<|endoftext|>


<commit_before>//
//  BackCurl.cpp
//  Created by Taymindis Woon on 23/5/17.
//  Copyright © 2017 Taymindis Woon. All rights reserved.
//

#include "BackCurl.h"

namespace bcl {

/** If you activate mainLoopCallBack, please make sure bcl::LoopBackFire on the loop thread, for e.g. UI thread **/
void init() {
    curl_global_init(CURL_GLOBAL_ALL);
}

void LoopBackFire() {
    while (!internal::_mainLoopTasks.empty()) {
        auto task(std::move(internal::_mainLoopTasks.front()));
        internal::_mainLoopTasks.pop_front();

        // lock during the task?
        internal::_tasks_mutex.lock();
        task();
        internal::_tasks_mutex.unlock();
    }
}

bool isReady(FutureResponse const& f) {
    return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}

/*
 You should call curl_global_cleanup once for each call you make to curl_global_init, after you are done using libcurl.

 This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running.
 This doesn't just mean no other thread that is using libcurl. Because curl_global_cleanup calls functions of other libraries
 that are similarly thread unsafe, it could conflict with any other thread that uses these other libraries.
 */
void cleanUp() {
    curl_global_cleanup();
}

// For image purpose
size_t
writeByteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    MemoryByte *memBlock = (MemoryByte *)userp;
    memBlock->append((unsigned char*)contents, realsize);

    return realsize;
}

// For Content
size_t
writeContentCallback(void *contents, size_t size, size_t nmemb, void *contentWrapper) {
    size_t realsize = size * nmemb;
    std::string *memBlock = (std::string *)contentWrapper;
    memBlock->append((char*)contents, realsize);

    return realsize;
}

namespace internal {
std::deque<std::function<void()>> _mainLoopTasks;
std::mutex _tasks_mutex;
bool _hasMainLoopCallBack = false;

void BackCurlLoopCallBackChecker(bcl::Response &s) {
    _hasMainLoopCallBack = true;
}

void wrapResponse(bcl::Request &r, bcl::Response &resp) {
    curl_easy_getinfo(r.curl, CURLINFO_RESPONSE_CODE, &resp.code);

    curl_easy_getinfo(r.curl, CURLINFO_TOTAL_TIME, &resp.totalTime);

    char *url = NULL;
    curl_easy_getinfo(r.curl, CURLINFO_EFFECTIVE_URL, &url);
    if (url)
        resp.effectiveUrl = std::string(url);

    char *ct = NULL;
    curl_easy_getinfo(r.curl, CURLINFO_CONTENT_TYPE, &ct);
    if (ct)
        resp.contentType = std::string(ct);

    resp.__body = r.dataPtr;

    resp.curl = r.curl;
}

/*** comment this pattern for that you can return bahavior right this  **/
//    template <typename DataType>
//    auto __execute__(std::function<void(bcl::Request &req)> optsFilter, std::function<void(bcl::Response)> respFilter, CALL_TYPE,
//                     DataType &chunk) -> Response<decltype(chunk)>
void __execute__(std::function<void(bcl::Request &req)> optsFilter, std::function<void(bcl::Response &resp)> responseCallback,
                 internal::CALL_TYPE callType, Request &request, Response &response) {

    CURLcode curlCode;
    curl_slist *headersList = NULL;
    // curl_global_init(CURL_GLOBAL_ALL);

    // Response response;
    response.__streamRef = new int;
    (*response.__streamRef)++;

    /* init the curl session */
    request.curl = curl_easy_init();

    try {
        /***ROOT CAUSE MESSAGE***/
        if ((curlCode = curl_easy_setopt(request.curl, CURLOPT_ERRORBUFFER, request.errorBuffer)) != CURLE_OK) {
            fprintf(stderr, "Failed to set error buffer [%d]\n", curlCode);
            throw request.errorBuffer;
        }

        optsFilter(request);

        bcl::Headers &headers = request.headers;

        if (headers.size() > 0) {
            for (size_t i = 0; i < headers.size(); ++i)
                headersList = curl_slist_append(headersList, (headers.at(i).first + ": " + headers.at(i).second).c_str());

            if (curl_easy_setopt(request.curl, CURLOPT_HTTPHEADER, headersList) != CURLE_OK) {
                fprintf(stderr, "Failed to set headers params [%s]\n", request.errorBuffer);
                throw request.errorBuffer;
            }
        }

        /* get it! and check for errors*/
        if (curl_easy_perform(request.curl) != CURLE_OK) {
            throw request.errorBuffer;
        }
    } catch (char const* err) {
        response.error = std::string(err);

    } catch (std::exception& e) {

    }

    bcl::internal::wrapResponse(request, response);

    if (callType == internal::ASYNC_CALL) {
        (*response.__streamRef) += 2; // Expected will destruct 2 more time
        responseCallback(response);
        //                response.close(); temporary close as Response bundle will close smartly
    } else if (callType == internal::MAIN_LOOP_CALLBACK) {
        (*response.__streamRef) += 2; // Expected will destruct 2 more time
        std::function<void()> task(std::bind(responseCallback, response));
        {
            std::lock_guard<std::mutex> lock(_tasks_mutex);
            _mainLoopTasks.push_back(std::move(task));
        }
    } else {
        responseCallback(response);
        //                response.close(); temporary close
    }

    if (headersList) {
        curl_slist_free_all(headersList);
    }

    /* cleanup curl stuff */
    // curl_easy_cleanup(request.curl); // Resp will clean up

    // Not needed, all will be free when out of scope
    //            SDL_free(chunk.memory);
    //        chunk.erase(chunk.begin());

    /* we're done with libcurl, so clean it up */
    // curl_global_cleanup(); // TODO should we free every time??
}
}

// ** Response Bundle ** /
bcl::Response::Response() {
    curl = NULL;
    __streamRef = NULL;
    __body = NULL;

}

void bcl::Response::close() {
    // delete static_cast<std::remove_pointer<decltype(body)*>::type>(body); //best solution so far
    streamClose(__body);
    delete __streamRef;
    //        printf("address of CURL is %p\n", curl);
    curl_easy_cleanup(curl); // TODO please implement clean up curl later by using valgrind got error or not
    __streamRef = NULL;
    __body = NULL;
}

Response& bcl::Response::operator = (const Response& r)
{
    // Assignment operator
    if (this != &r) // Avoid self assignment
    {
        // Decrement the old reference count
        // if reference become zero delete the old data¢
        if (__streamRef != NULL && --(*__streamRef) == 0)
        {
            close();
        }

        // Copy the data and reference pointer
        // and increment the reference count
        __body = r.__body;
        __streamRef = r.__streamRef;
        curl = r.curl;
        (*__streamRef)++;
    }
    return *this;
}

std::function<void(void*)>& bcl::Response::attachStreamClose()  {
    return streamClose;
}

bcl::Response::~Response () {
    if (__streamRef != NULL && --(*__streamRef) == 0) {
        close();
    }
}

}

// Test Scope ------------------------------------------------------------------

// void simpleGetOption(bcl::Request &req) {
//     bcl::setOpts(req, CURLOPT_URL , "http://www.google.com",
//                  CURLOPT_FOLLOWLOCATION, 1L,
//                  CURLOPT_WRITEFUNCTION, &bcl::writeContentCallback,
//                  CURLOPT_WRITEDATA, req.dataPtr,
//                  CURLOPT_USERAGENT, "libcurl-agent/1.0",
//                  CURLOPT_RANGE, "0-200000"
//                 );
// }

// void doSync() {
//     bcl::execute<std::string>(simpleGetOption, [&](bcl::Response & resp) {
//         std::string ret =  std::string(resp.getBody<std::string>()->c_str());
//         printf("Sync === %s\n", ret.c_str());
//         //    return ret;
//         // std::this_thread::sleep_for(std::chrono::milliseconds(500));
//         return resp;
//     });

// }

// void doFuture() {
//     bcl::FutureResponse frp;

//     frp = bcl::execFuture<std::string>(simpleGetOption);
//     while(bcl::hasRequestedButNotReady(frp)) {
//         printf("Future Sync ==%s\n", "Drawing Graphiccccc");
//     }

//     bcl::Response r = frp.get();
//     printf("The data content is = %s\n", r.getBody<std::string>()->c_str());
//     printf("Got Http Status code = %ld\n", r.code);
//     printf("Got Error = %s\n", r.error.c_str());

//     if(!bcl::isProcessing(frp)) printf("no data process now, no more coming data\n\n" );

// }

// int countUI = 0;
// void doGuiWork() {
//     printf("%s", "Drawing thousand Pieces of Color ");
//     countUI++;

// }

// void doUpdate() {
//     bcl::LoopBackFire();
// }

// void doRunOnUI () {
//     bool gui_running = true;
//     std::cout << "Game is running thread: ";

//     bcl::executeOnUI<std::string>([](bcl::Request & req) -> void {
//         bcl::setOpts(req, CURLOPT_URL , "http://www.google.com",
//         CURLOPT_FOLLOWLOCATION, 1L,
//         CURLOPT_WRITEFUNCTION, &bcl::writeContentCallback,
//         CURLOPT_WRITEDATA, req.dataPtr,
//         CURLOPT_USERAGENT, "libcurl-agent/1.0",
//         CURLOPT_RANGE, "0-200000"
//                     );
//     }, [&](bcl::Response & resp) {
//         printf("On UI === %s\n", resp.getBody<std::string>()->c_str());
//         printf("Done , stop gui running with count ui %d\n", countUI );
//         std::this_thread::sleep_for(std::chrono::milliseconds(500));
//         gui_running = false;
//     });

//     while (gui_running) {
//         doGuiWork();
//         doUpdate();
//         std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 16));
//     }
// }

// int main()
// {
//     bcl::init();

//     doSync();

//     // doRunOnUI();

//     bcl::cleanUp();

//     return 1;
// }

<commit_msg>Fixed the uninitialized value<commit_after>//
//  BackCurl.cpp
//  Created by Taymindis Woon on 23/5/17.
//  Copyright © 2017 Taymindis Woon. All rights reserved.
//

#include "BackCurl.h"

namespace bcl {

/** If you activate mainLoopCallBack, please make sure bcl::LoopBackFire on the loop thread, for e.g. UI thread **/
void init() {
    curl_global_init(CURL_GLOBAL_ALL);
}

void LoopBackFire() {
    while (!internal::_mainLoopTasks.empty()) {
        auto task(std::move(internal::_mainLoopTasks.front()));
        internal::_mainLoopTasks.pop_front();

        // lock during the task?
        internal::_tasks_mutex.lock();
        task();
        internal::_tasks_mutex.unlock();
    }
}

bool isReady(FutureResponse const& f) {
    return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}

/*
 You should call curl_global_cleanup once for each call you make to curl_global_init, after you are done using libcurl.

 This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running.
 This doesn't just mean no other thread that is using libcurl. Because curl_global_cleanup calls functions of other libraries
 that are similarly thread unsafe, it could conflict with any other thread that uses these other libraries.
 */
void cleanUp() {
    curl_global_cleanup();
}

// For image purpose
size_t
writeByteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    MemoryByte *memBlock = (MemoryByte *)userp;
    memBlock->append((unsigned char*)contents, realsize);

    return realsize;
}

// For Content
size_t
writeContentCallback(void *contents, size_t size, size_t nmemb, void *contentWrapper) {
    size_t realsize = size * nmemb;
    std::string *memBlock = (std::string *)contentWrapper;
    memBlock->append((char*)contents, realsize);

    return realsize;
}

namespace internal {
std::deque<std::function<void()>> _mainLoopTasks;
std::mutex _tasks_mutex;
bool _hasMainLoopCallBack = false;

void BackCurlLoopCallBackChecker(bcl::Response &s) {
    _hasMainLoopCallBack = true;
}

void wrapResponse(bcl::Request &r, bcl::Response &resp) {
    curl_easy_getinfo(r.curl, CURLINFO_RESPONSE_CODE, &resp.code);

    curl_easy_getinfo(r.curl, CURLINFO_TOTAL_TIME, &resp.totalTime);

    char *url = NULL;
    curl_easy_getinfo(r.curl, CURLINFO_EFFECTIVE_URL, &url);
    if (url)
        resp.effectiveUrl = std::string(url);

    char *ct = NULL;
    curl_easy_getinfo(r.curl, CURLINFO_CONTENT_TYPE, &ct);
    if (ct)
        resp.contentType = std::string(ct);

    resp.__body = r.dataPtr;

    resp.curl = r.curl;
}

/*** comment this pattern for that you can return bahavior right this  **/
//    template <typename DataType>
//    auto __execute__(std::function<void(bcl::Request &req)> optsFilter, std::function<void(bcl::Response)> respFilter, CALL_TYPE,
//                     DataType &chunk) -> Response<decltype(chunk)>
void __execute__(std::function<void(bcl::Request &req)> optsFilter, std::function<void(bcl::Response &resp)> responseCallback,
                 internal::CALL_TYPE callType, Request &request, Response &response) {

    CURLcode curlCode;
    curl_slist *headersList = NULL;
    // curl_global_init(CURL_GLOBAL_ALL);

    /* init the curl session */
    request.curl = curl_easy_init();

    try {
        /***ROOT CAUSE MESSAGE***/
        if ((curlCode = curl_easy_setopt(request.curl, CURLOPT_ERRORBUFFER, request.errorBuffer)) != CURLE_OK) {
            fprintf(stderr, "Failed to set error buffer [%d]\n", curlCode);
            throw request.errorBuffer;
        }

        optsFilter(request);

        bcl::Headers &headers = request.headers;

        if (headers.size() > 0) {
            for (size_t i = 0; i < headers.size(); ++i)
                headersList = curl_slist_append(headersList, (headers.at(i).first + ": " + headers.at(i).second).c_str());

            if (curl_easy_setopt(request.curl, CURLOPT_HTTPHEADER, headersList) != CURLE_OK) {
                fprintf(stderr, "Failed to set headers params [%s]\n", request.errorBuffer);
                throw request.errorBuffer;
            }
        }

        /* get it! and check for errors*/
        if (curl_easy_perform(request.curl) != CURLE_OK) {
            throw request.errorBuffer;
        }
    } catch (char const* err) {
        response.error = std::string(err);

    } catch (std::exception& e) {

    }

    bcl::internal::wrapResponse(request, response);

    if (callType == internal::ASYNC_CALL) {
        (*response.__streamRef) += 2; // Expected will destruct 2 more time
        responseCallback(response);
        //                response.close(); temporary close as Response bundle will close smartly
    } else if (callType == internal::MAIN_LOOP_CALLBACK) {
        (*response.__streamRef) += 2; // Expected will destruct 2 more time
        std::function<void()> task(std::bind(responseCallback, response));
        {
            std::lock_guard<std::mutex> lock(_tasks_mutex);
            _mainLoopTasks.push_back(std::move(task));
        }
    } else {
        responseCallback(response);
        //                response.close(); temporary close
    }

    if (headersList) {
        curl_slist_free_all(headersList);
    }

    /* cleanup curl stuff */
    // curl_easy_cleanup(request.curl); // Resp will clean up

    // Not needed, all will be free when out of scope
    //            SDL_free(chunk.memory);
    //        chunk.erase(chunk.begin());

    /* we're done with libcurl, so clean it up */
    // curl_global_cleanup(); // TODO should we free every time??
}
}

// ** Response Bundle ** /
bcl::Response::Response() {
    curl = NULL;
    __streamRef = new int(1);
    __body = NULL;

}

void bcl::Response::close() {
    // delete static_cast<std::remove_pointer<decltype(body)*>::type>(body); //best solution so far
    if (__body)
        streamClose(__body);

    delete __streamRef;
    //        printf("address of CURL is %p\n", curl);
    if (curl)
        curl_easy_cleanup(curl); // TODO please implement clean up curl later by using valgrind got error or not
    __streamRef = NULL;
    __body = NULL;
}

Response& bcl::Response::operator = (const Response& r)
{
    // Assignment operator
    if (this != &r) // Avoid self assignment
    {
        // Decrement the old reference count
        // if reference become zero delete the old data¢
        if (__streamRef != NULL && --(*__streamRef) == 0)
        {
            close();
        }

        // Copy the data and reference pointer
        // and increment the reference count
        __body = r.__body;
        __streamRef = r.__streamRef;
        curl = r.curl;
        (*__streamRef)++;
    }
    return *this;
}

std::function<void(void*)>& bcl::Response::attachStreamClose()  {
    return streamClose;
}

bcl::Response::~Response () {
    if (__streamRef != NULL && --(*__streamRef) == 0) {
        close();
    }
}

}<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                              SOFA :: Framework                              *
*                                                                             *
* Authors: The SOFA Team (see Authors.txt)                                    *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_HELPER_KDTREE_INL
#define SOFA_HELPER_KDTREE_INL

#include "kdTree.h"

#include <map>
#include <limits>
#include <set>
#include <iterator>

namespace sofa
{
namespace helper
{

template<class Coord>
void kdTree<Coord>::build(const VecCoord& positions)
{
    unsigned int nbp=positions.size();
    UIlist list;   for(unsigned int i=0; i<nbp; i++) list.push_back(i);
    tree.resize(nbp);
    firstNode=build(list,(unsigned char)0, positions);
}

template<class Coord>
void kdTree<Coord>::build(const VecCoord& positions, const vector<unsigned int> &ROI)
{
    unsigned int nbp=ROI.size();
    UIlist list;   for(unsigned int i=0; i<nbp; i++) list.push_back(ROI[i]);
    tree.resize(nbp);
    firstNode=build(list,(unsigned char)0, positions);
}

template<class Coord>
void kdTree<Coord>::print(const unsigned int index)
{
    std::cout<<index<<"["<<(int)tree[index].splitdir<<"] "<<tree[index].left<<" "<<tree[index].right<<std::endl;
    if(tree[index].left!=index) print(tree[index].left);
    if(tree[index].right!=index) print(tree[index].right);
}

template<class Coord>
unsigned int kdTree<Coord>::build(UIlist &list, unsigned char direction, const VecCoord& positions)
{
    // detect leaf
    if(list.size()==(unsigned int)1)
    {
        unsigned int index=list.front(); list.pop_front();
        tree[index].left=tree[index].right=index;
        tree[index].splitdir=direction;
        return index;
    }
    // ordered list of 1D coord
    distanceSet q;
    UIlist::iterator it;
    for(it=list.begin(); it!=list.end(); it++) q.insert( distanceToPoint(positions[*it][direction],*it));
    it=list.begin();    for(distanceSetIt sit=q.begin(); sit!=q.end(); sit++) {*it=sit->second; it++;}
    // split list in 2
    it=list.begin(); advance (it,list.size()/2);
    UIlist newlist;
    newlist.splice(newlist.begin(),list,list.begin(),it);
    // add node
    unsigned int index=list.front(); list.pop_front();
    tree[index].splitdir=direction;
    tree[index].left=tree[index].right=index;
    // split children recursively
    unsigned char newdirection=direction+1; if(newdirection==dim) newdirection=0;
    if(newlist.size()!=0) tree[index].left=build(newlist,newdirection,positions);
    if(list.size()!=0) tree[index].right=build(list,newdirection,positions);
    // return child index to parent
    return index;
}

template<class Coord>
void kdTree<Coord>::closest(distanceSet &cl,const Coord &x, const unsigned int &currentnode, const VecCoord& positions)
// [zhang94] algorithm
{
    Real Dmax;
    distanceSetIt it=cl.end();
    if(cl.size()==N) { it--; Dmax=it->first; } else Dmax=std::numeric_limits<Real>::max();
    unsigned int splitdir=tree[currentnode].splitdir;
    Coord pos=positions[currentnode];
    Real c1=x[splitdir],c2=pos[splitdir];
    if(abs(c1-c2)<=Dmax)
    {
        Real d=(x-pos).norm();
        if(d<Dmax)
        {
            Dmax=d;
            cl.insert(distanceToPoint(d,currentnode));
            if(cl.size()>N) {it=cl.end(); it--; cl.erase(it);}
        }
    }
    if(tree[currentnode].left!=currentnode)     if(c1-Dmax<c2)  closest(cl,x,tree[currentnode].left,positions);
    if(tree[currentnode].right!=currentnode)    if(c2-Dmax<c1)  closest(cl,x,tree[currentnode].right,positions);
}

// slightly improved version of the above, for one point
template<class Coord>
void kdTree<Coord>::closest(distanceToPoint &cl,const Coord &x, const unsigned int &currentnode, const VecCoord& positions)
{
    Real Dmax=cl.first;
    unsigned int splitdir=tree[currentnode].splitdir;
    Coord pos=positions[currentnode];
    Real c1=x[splitdir],c2=pos[splitdir];
    if(fabs(c1-c2)<=Dmax)
    {
        Real d=(x-pos).norm();
        if(d<Dmax)
        {
            Dmax=d;
            cl.first=d;
            cl.second=currentnode;
        }
    }
    if(tree[currentnode].left!=currentnode)     if(c1-Dmax<c2)  closest(cl,x,tree[currentnode].left,positions);
    if(tree[currentnode].right!=currentnode)    if(c2-Dmax<c1)  closest(cl,x,tree[currentnode].right,positions);
}

template<class Coord>
void kdTree<Coord>::getNClosest(distanceSet &cl, const Coord &x, const VecCoord& positions, const unsigned int n)
{
    N=n;
    cl.clear();
    closest(cl,x,firstNode,positions);
}

template<class Coord>
unsigned int kdTree<Coord>::getClosest(const Coord &x, const VecCoord& positions)
{
    distanceToPoint cl(std::numeric_limits<Real>::max(),firstNode);
    closest(cl,x,firstNode,positions);
    return cl.second;
}

template<class Coord>
void kdTree<Coord>::getNClosestCached(distanceSet &cl,  distanceToPoint &cacheThresh_max, distanceToPoint &cacheThresh_min, Coord &previous_x, const Coord &x, const VecCoord& positions, const unsigned int n)
{
    Real dx=(previous_x-x).norm();
    if(dx>=cacheThresh_max.first || cl.size()<2)
    {
        getNClosest(cl,x,positions,n);
        distanceSetIt it0=cl.begin(), it1=it0; it1++;
        typename distanceSet::reverse_iterator itn=cl.rbegin();
        cacheThresh_max.first=((itn->first)-(it0->first))*(Real)0.5; // half distance between first and last closest points
        cacheThresh_max.second=itn->second;
        cacheThresh_min.first=((it1->first)-(it0->first))*(Real)0.5; // half distance between first and second closest points
        cacheThresh_min.second=it0->second;
        previous_x=x;
//        std::cout<<"not in cache"<<std::endl;
    }
    else if(dx>=cacheThresh_min.first) // in the cache -> update N-1 distances
    {
        distanceSet newset;
        for(distanceSetIt it=cl.begin(); it!=cl.end(); it++)
            if(it->second!=cacheThresh_max.second)
                newset.insert(distanceToPoint((positions[it->second]-x).norm(),it->second));
            else
                newset.insert(distanceToPoint(std::numeric_limits<Real>::max(),it->second));
        cl.swap(newset);
//        std::cout<<"in cache:"<<std::endl;
    }
    else // still the same closest point
    {
        distanceSet newset;
        for(distanceSetIt it=cl.begin(); it!=cl.end(); it++)
            if(it->second==cacheThresh_min.second)
                newset.insert(distanceToPoint((positions[it->second]-x).norm(),it->second));
            else
                newset.insert(distanceToPoint(std::numeric_limits<Real>::max(),it->second));
        cl.swap(newset);
//        std::cout<<"same"<<std::endl;
    }
}

}
}

#endif
<commit_msg>fix bug in kdtree build using roi<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                              SOFA :: Framework                              *
*                                                                             *
* Authors: The SOFA Team (see Authors.txt)                                    *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_HELPER_KDTREE_INL
#define SOFA_HELPER_KDTREE_INL

#include "kdTree.h"

#include <map>
#include <limits>
#include <set>
#include <iterator>

namespace sofa
{
namespace helper
{

template<class Coord>
void kdTree<Coord>::build(const VecCoord& positions)
{
    unsigned int nbp=positions.size();
    UIlist list;   for(unsigned int i=0; i<nbp; i++) list.push_back(i);
    tree.resize(nbp);
    firstNode=build(list,(unsigned char)0, positions);
}

template<class Coord>
void kdTree<Coord>::build(const VecCoord& positions, const vector<unsigned int> &ROI)
{
    unsigned int nbp=ROI.size();
    UIlist list;   for(unsigned int i=0; i<nbp; i++) list.push_back(ROI[i]);
    tree.resize(positions.size());
    firstNode=build(list,(unsigned char)0, positions);
}

template<class Coord>
void kdTree<Coord>::print(const unsigned int index)
{
    std::cout<<index<<"["<<(int)tree[index].splitdir<<"] "<<tree[index].left<<" "<<tree[index].right<<std::endl;
    if(tree[index].left!=index) print(tree[index].left);
    if(tree[index].right!=index) print(tree[index].right);
}

template<class Coord>
unsigned int kdTree<Coord>::build(UIlist &list, unsigned char direction, const VecCoord& positions)
{
    // detect leaf
    if(list.size()==(unsigned int)1)
    {
        unsigned int index=list.front(); list.pop_front();
        tree[index].left=tree[index].right=index;
        tree[index].splitdir=direction;
        return index;
    }
    // ordered list of 1D coord
    distanceSet q;
    UIlist::iterator it;
    for(it=list.begin(); it!=list.end(); it++) q.insert( distanceToPoint(positions[*it][direction],*it));
    it=list.begin();    for(distanceSetIt sit=q.begin(); sit!=q.end(); sit++) {*it=sit->second; it++;}
    // split list in 2
    it=list.begin(); advance (it,list.size()/2);
    UIlist newlist;
    newlist.splice(newlist.begin(),list,list.begin(),it);
    // add node
    unsigned int index=list.front(); list.pop_front();
    tree[index].splitdir=direction;
    tree[index].left=tree[index].right=index;
    // split children recursively
    unsigned char newdirection=direction+1; if(newdirection==dim) newdirection=0;
    if(newlist.size()!=0) tree[index].left=build(newlist,newdirection,positions);
    if(list.size()!=0) tree[index].right=build(list,newdirection,positions);
    // return child index to parent
    return index;
}

template<class Coord>
void kdTree<Coord>::closest(distanceSet &cl,const Coord &x, const unsigned int &currentnode, const VecCoord& positions)
// [zhang94] algorithm
{
    Real Dmax;
    distanceSetIt it=cl.end();
    if(cl.size()==N) { it--; Dmax=it->first; } else Dmax=std::numeric_limits<Real>::max();
    unsigned int splitdir=tree[currentnode].splitdir;
    Coord pos=positions[currentnode];
    Real c1=x[splitdir],c2=pos[splitdir];
    if(abs(c1-c2)<=Dmax)
    {
        Real d=(x-pos).norm();
        if(d<Dmax)
        {
            Dmax=d;
            cl.insert(distanceToPoint(d,currentnode));
            if(cl.size()>N) {it=cl.end(); it--; cl.erase(it);}
        }
    }
    if(tree[currentnode].left!=currentnode)     if(c1-Dmax<c2)  closest(cl,x,tree[currentnode].left,positions);
    if(tree[currentnode].right!=currentnode)    if(c2-Dmax<c1)  closest(cl,x,tree[currentnode].right,positions);
}

// slightly improved version of the above, for one point
template<class Coord>
void kdTree<Coord>::closest(distanceToPoint &cl,const Coord &x, const unsigned int &currentnode, const VecCoord& positions)
{
    Real Dmax=cl.first;
    unsigned int splitdir=tree[currentnode].splitdir;
    Coord pos=positions[currentnode];
    Real c1=x[splitdir],c2=pos[splitdir];
    if(fabs(c1-c2)<=Dmax)
    {
        Real d=(x-pos).norm();
        if(d<Dmax)
        {
            Dmax=d;
            cl.first=d;
            cl.second=currentnode;
        }
    }
    if(tree[currentnode].left!=currentnode)     if(c1-Dmax<c2)  closest(cl,x,tree[currentnode].left,positions);
    if(tree[currentnode].right!=currentnode)    if(c2-Dmax<c1)  closest(cl,x,tree[currentnode].right,positions);
}

template<class Coord>
void kdTree<Coord>::getNClosest(distanceSet &cl, const Coord &x, const VecCoord& positions, const unsigned int n)
{
    N=n;
    cl.clear();
    closest(cl,x,firstNode,positions);
}

template<class Coord>
unsigned int kdTree<Coord>::getClosest(const Coord &x, const VecCoord& positions)
{
    distanceToPoint cl(std::numeric_limits<Real>::max(),firstNode);
    closest(cl,x,firstNode,positions);
    return cl.second;
}

template<class Coord>
void kdTree<Coord>::getNClosestCached(distanceSet &cl,  distanceToPoint &cacheThresh_max, distanceToPoint &cacheThresh_min, Coord &previous_x, const Coord &x, const VecCoord& positions, const unsigned int n)
{
    Real dx=(previous_x-x).norm();
    if(dx>=cacheThresh_max.first || cl.size()<2)
    {
        getNClosest(cl,x,positions,n);
        distanceSetIt it0=cl.begin(), it1=it0; it1++;
        typename distanceSet::reverse_iterator itn=cl.rbegin();
        cacheThresh_max.first=((itn->first)-(it0->first))*(Real)0.5; // half distance between first and last closest points
        cacheThresh_max.second=itn->second;
        cacheThresh_min.first=((it1->first)-(it0->first))*(Real)0.5; // half distance between first and second closest points
        cacheThresh_min.second=it0->second;
        previous_x=x;
//        std::cout<<"not in cache"<<std::endl;
    }
    else if(dx>=cacheThresh_min.first) // in the cache -> update N-1 distances
    {
        distanceSet newset;
        for(distanceSetIt it=cl.begin(); it!=cl.end(); it++)
            if(it->second!=cacheThresh_max.second)
                newset.insert(distanceToPoint((positions[it->second]-x).norm(),it->second));
            else
                newset.insert(distanceToPoint(std::numeric_limits<Real>::max(),it->second));
        cl.swap(newset);
//        std::cout<<"in cache:"<<std::endl;
    }
    else // still the same closest point
    {
        distanceSet newset;
        for(distanceSetIt it=cl.begin(); it!=cl.end(); it++)
            if(it->second==cacheThresh_min.second)
                newset.insert(distanceToPoint((positions[it->second]-x).norm(),it->second));
            else
                newset.insert(distanceToPoint(std::numeric_limits<Real>::max(),it->second));
        cl.swap(newset);
//        std::cout<<"same"<<std::endl;
    }
}

}
}

#endif
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/arch.hpp"
#include "serializer/log/log_serializer.hpp"

namespace stress {
    #include "../stress-client/utils.hpp"
    #include "../stress-client/utils.cc"
    #include "../stress-client/random.cc"
}

class timer_token_t;

struct txn_info_t {
    ticks_t start, end;
};

typedef std::deque<txn_info_t> log_t;

struct txn_callback_t {
    virtual void on_transaction_complete() = 0;
} *cb;

void transact(serializer_t *ser, log_t *log, unsigned inserts, unsigned updates, txn_callback_t *cb) {
    /* If there aren't enough blocks to update, then convert the updates into inserts */
    std::vector<serializer_write_t> writes;

    if (updates > ser->max_block_id()) {
        inserts += updates;
        updates = 0;
    }

    /* To save CPU time (from clearing many bufs) we malloc() one buf and clear it and then
    write all the blocks from that one. I hope this doesn't bias the test. */

    void *dummy_buf = ser->malloc();
    memset(dummy_buf, 0xDB, ser->get_block_size().value());

    writes.reserve(updates + inserts);

    /* As a simple way to avoid updating the same block twice in one transaction, select
    a contiguous range of blocks starting at a random offset within range */

    block_id_t begin = stress::random(0, ser->max_block_id() - updates);

    // We just need some value for this.
    repli_timestamp_t tstamp = repli_timestamp_t::distant_past;
    for (unsigned i = 0; i < updates; i++) {
        writes.push_back(serializer_write_t::make_update(begin + i, tstamp, dummy_buf));
    }

    /* Generate new IDs to insert by simply taking (highest ID + 1) */
    for (unsigned i = 0; i < inserts; i++) {
        writes.push_back(serializer_write_t::make_update(ser->max_block_id() + i, tstamp, dummy_buf));
    }

    do_writes(ser, writes, DEFAULT_DISK_ACCOUNT);

    ser->free(dummy_buf);

    cb->on_transaction_complete();
}

#define RUN_FOREVER (-1)

struct config_t {
    const char *log_file, *tps_log_file;
    log_serializer_static_config_t ser_static_config;
    log_serializer_dynamic_config_t ser_dynamic_config;
    log_serializer_private_dynamic_config_t ser_private_dynamic_config;
    int duration;   /* Seconds */
    unsigned concurrent_txns;
    unsigned inserts_per_txn, updates_per_txn;
};

struct tester_t :
    public thread_message_t,
    public txn_callback_t
{
    log_t *log;
    FILE *tps_log_fd;
    log_serializer_t *ser;
    unsigned active_txns, total_txns;
    config_t *config;
    thread_pool_t *pool;
    bool stop, interrupted;
    timer_token_t *timer;
    ticks_t last_time;
    unsigned txns_last_sec;
    unsigned secs_so_far;
    scoped_ptr_t<io_backender_t> io_backender;

    struct interrupt_msg_t :
        public thread_message_t
    {
        tester_t *tester;
        interrupt_msg_t(tester_t *tester) : tester(tester) { }
        void on_thread_switch() {
            fprintf(stderr, "Interrupted.\n");
            tester->stop_test();
            cancel_timer(tester->timer);
        }
    } interruptor;

    tester_t(config_t *config, thread_pool_t *pool)
        : tps_log_fd(NULL), ser(NULL), active_txns(0), total_txns(0), config(config), pool(pool), stop(false), interrupted(false), last_time(0), txns_last_sec(0), secs_so_far(0), interruptor(this)
    {
        make_io_backender(aio_native, &io_backender);
        last_time = get_ticks();
        if(config->tps_log_file) {
            tps_log_fd = fopen(config->tps_log_file, "a");
        }
    }

    /* When on_thread_switch() is called, it could either be the start message telling us to run the
    test or the shutdown message from call_later_on_this_thread(). We differentiate by checking 'ser'. */
    void on_thread_switch() {
        if (!ser) coro_t::spawn(boost::bind(&tester_t::start, this));
        else coro_t::spawn(boost::bind(&tester_t::shutdown, this));
    }

    void start() {
        if (config->log_file) {
            log = new log_t();
        } else {
            log = NULL;
        }

        fprintf(stderr, "Creating a database...\n");
        filepath_file_opener_t file_opener(config->ser_private_dynamic_config.db_filename, io_backender.get());
        log_serializer_t::create(&file_opener,
                                 config->ser_static_config);

        fprintf(stderr, "Starting serializer...\n");
        ser = new log_serializer_t(config->ser_dynamic_config,
                                   &file_opener,
                                   &get_global_perfmon_collection());
        on_serializer_ready(ser);
    }

    void on_serializer_ready(log_serializer_t *ls) {
        fprintf(stderr, "Running test...\n");
        if(config->duration != RUN_FOREVER) {
            timer = fire_timer_once(config->duration * 1000, &tester_t::on_timer, this);
        }

        linux_thread_message_t *prev_interrupt_message = pool->set_interrupt_message(&interruptor);
        guarantee(prev_interrupt_message == NULL);

        pump();
    }

    static void on_timer(void *self) {
        tester_t *tester = (tester_t *)self;
        fprintf(stderr, "Time's up.\n");
        tester->stop_test();
    }

    void pump() {
        while (active_txns < config->concurrent_txns && !stop) {
            active_txns++;
            total_txns++;
            coro_t::spawn_sometime(boost::bind(transact, ser, log, config->inserts_per_txn, config->updates_per_txn, this));
        }

        // See if we need to report the TPS
        ticks_t cur_time = get_ticks();
        if(ticks_to_secs(cur_time - last_time) >= 1.0f) {
            if(tps_log_fd) {
                fprintf(tps_log_fd, "%d\n", txns_last_sec);
            }

            last_time = cur_time;
            txns_last_sec = 0;
            secs_so_far++;

            // Flush every five seconds in case of a crash
            if(secs_so_far % 5 == 0) {
                fflush(tps_log_fd);
            }
        }

        if (active_txns == 0 && stop) {
            /* Serializer doesn't like shutdown() to be called from within
               on_serializer_write_txn() */
            call_later_on_this_thread(this);
        }
    }

    void stop_test() {

        if (stop) return;
        linux_thread_message_t *prev_interrupt_message = pool->set_interrupt_message(NULL);
        guarantee(prev_interrupt_message == &interruptor);

        fprintf(stderr, "Started %d transactions and completed %d of them\n",
            total_txns, total_txns - active_txns);

        if (tps_log_fd)
            fclose(tps_log_fd);

        if (config->log_file) {
            FILE *log_file = fopen(config->log_file, "w");
            log_t::iterator it;
            for (it = log->begin(); it != log->end(); it++) {
                fprintf(log_file, "%.6f %.6f\n", ticks_to_secs(it->start), ticks_to_secs(it->end));
            }
            fclose(log_file);
            fprintf(stderr, "Wrote log to '%s'\n", config->log_file);
            delete(log);
        }

        stop = true;
        if (active_txns > 0) {
            fprintf(stderr, "Waiting for the remaining %d transactions...\n", active_txns);
        }
    }

    void on_transaction_complete() {
        active_txns--;
        txns_last_sec++;
        pump();
    }

    void shutdown() {
        fprintf(stderr, "Waiting for serializer to shut down...\n");
        delete ser;
        on_serializer_shutdown();
    }

    void on_serializer_shutdown() {
        fprintf(stderr, "Done.\n");
        pool->shutdown_thread_pool();
    }
};

const char *read_arg(int &argc, char **&argv) {
    if (argc == 0) {
        fail_due_to_user_error("Expected another argument at the end.");
    } else {
        argc--;
        return (argv++)[0];
    }
}

void parse_config(int argc, char *argv[], config_t *config) {

    config->ser_private_dynamic_config.db_filename = "rethinkdb_data";
#ifdef SEMANTIC_SERIALIZER_CHECK
    config->ser_private_dynamic_config.semantic_filename = "rethinkdb_data.semantic";
#endif
    config->log_file = NULL;
    config->tps_log_file = NULL;

    // config->ser_static_config uses its own defaults from constructor
    // config->ser_dynamic_config uses its own defaults from constructor

    config->duration = 10;   /* Seconds */
    config->concurrent_txns = 8;
    config->inserts_per_txn = 10;
    config->updates_per_txn = 2;

    read_arg(argc, argv);

    while (argc) {
        const char *flag = read_arg(argc, argv);

        if (strcmp(flag, "-f") == 0) {
            config->ser_private_dynamic_config.db_filename = read_arg(argc, argv);
#ifdef SEMANTIC_SERIALIZER_CHECK
            config->ser_private_dynamic_config.semantic_filename = config->ser_private_dynamic_config.db_filename + ".semantic";
#endif
        } else if (strcmp(flag, "--log") == 0) {
            config->log_file = read_arg(argc, argv);
        } else if (strcmp(flag, "--tps-log") == 0) {
            config->tps_log_file = read_arg(argc, argv);
        } else if (strcmp(flag, "--block-size") == 0) {
            config->ser_static_config.block_size_ = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--extent-size") == 0) {
            config->ser_static_config.extent_size_ = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--active-data-extents") == 0) {
            config->ser_dynamic_config.num_active_data_extents = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--file-zone-size") == 0) {
            config->ser_dynamic_config.file_zone_size = atoi(read_arg(argc, argv));

        } else if (strcmp(flag, "--duration") == 0) {
            config->duration = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--forever") == 0) {
            config->duration = RUN_FOREVER;
        } else if (strcmp(flag, "--concurrent") == 0) {
            config->concurrent_txns = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--inserts-per-txn") == 0) {
            config->inserts_per_txn = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--updates-per-txn") == 0) {
            config->updates_per_txn = atoi(read_arg(argc, argv));

        } else {
            fail_due_to_user_error("Don't know how to handle \"%s\"", flag);
        }
    }

    rassert(config->ser_static_config.block_size().ser_value() > 0);
    rassert(config->ser_static_config.extent_size() > 0);
    rassert(config->ser_dynamic_config.num_active_data_extents > 0);
    rassert(config->ser_dynamic_config.file_zone_size > 0);
    rassert(config->duration > 0 || config->duration == RUN_FOREVER);
    rassert(config->concurrent_txns > 0);
}

int main(int argc, char *argv[]) {

    config_t config;
    parse_config(argc, argv, &config);

    thread_pool_t thread_pool(1, true);
    tester_t tester(&config, &thread_pool);
    thread_pool.run_thread_pool(&tester);

    return 0;
}
<commit_msg>Made serializer-bench not use private_dynamic_config_t.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/arch.hpp"
#include "serializer/log/log_serializer.hpp"

namespace stress {
    #include "../stress-client/utils.hpp"
    #include "../stress-client/utils.cc"
    #include "../stress-client/random.cc"
}

class timer_token_t;

struct txn_info_t {
    ticks_t start, end;
};

typedef std::deque<txn_info_t> log_t;

struct txn_callback_t {
    virtual void on_transaction_complete() = 0;
} *cb;

void transact(serializer_t *ser, log_t *log, unsigned inserts, unsigned updates, txn_callback_t *cb) {
    /* If there aren't enough blocks to update, then convert the updates into inserts */
    std::vector<serializer_write_t> writes;

    if (updates > ser->max_block_id()) {
        inserts += updates;
        updates = 0;
    }

    /* To save CPU time (from clearing many bufs) we malloc() one buf and clear it and then
    write all the blocks from that one. I hope this doesn't bias the test. */

    void *dummy_buf = ser->malloc();
    memset(dummy_buf, 0xDB, ser->get_block_size().value());

    writes.reserve(updates + inserts);

    /* As a simple way to avoid updating the same block twice in one transaction, select
    a contiguous range of blocks starting at a random offset within range */

    block_id_t begin = stress::random(0, ser->max_block_id() - updates);

    // We just need some value for this.
    repli_timestamp_t tstamp = repli_timestamp_t::distant_past;
    for (unsigned i = 0; i < updates; i++) {
        writes.push_back(serializer_write_t::make_update(begin + i, tstamp, dummy_buf));
    }

    /* Generate new IDs to insert by simply taking (highest ID + 1) */
    for (unsigned i = 0; i < inserts; i++) {
        writes.push_back(serializer_write_t::make_update(ser->max_block_id() + i, tstamp, dummy_buf));
    }

    do_writes(ser, writes, DEFAULT_DISK_ACCOUNT);

    ser->free(dummy_buf);

    cb->on_transaction_complete();
}

#define RUN_FOREVER (-1)

struct config_t {
    const char *log_file, *tps_log_file;
    log_serializer_static_config_t ser_static_config;
    log_serializer_dynamic_config_t ser_dynamic_config;
    std::string db_filename;
    int duration;   /* Seconds */
    unsigned concurrent_txns;
    unsigned inserts_per_txn, updates_per_txn;
};

struct tester_t :
    public thread_message_t,
    public txn_callback_t
{
    log_t *log;
    FILE *tps_log_fd;
    log_serializer_t *ser;
    unsigned active_txns, total_txns;
    config_t *config;
    thread_pool_t *pool;
    bool stop, interrupted;
    timer_token_t *timer;
    ticks_t last_time;
    unsigned txns_last_sec;
    unsigned secs_so_far;
    scoped_ptr_t<io_backender_t> io_backender;

    struct interrupt_msg_t :
        public thread_message_t
    {
        tester_t *tester;
        interrupt_msg_t(tester_t *tester) : tester(tester) { }
        void on_thread_switch() {
            fprintf(stderr, "Interrupted.\n");
            tester->stop_test();
            cancel_timer(tester->timer);
        }
    } interruptor;

    tester_t(config_t *config, thread_pool_t *pool)
        : tps_log_fd(NULL), ser(NULL), active_txns(0), total_txns(0), config(config), pool(pool), stop(false), interrupted(false), last_time(0), txns_last_sec(0), secs_so_far(0), interruptor(this)
    {
        make_io_backender(aio_native, &io_backender);
        last_time = get_ticks();
        if(config->tps_log_file) {
            tps_log_fd = fopen(config->tps_log_file, "a");
        }
    }

    /* When on_thread_switch() is called, it could either be the start message telling us to run the
    test or the shutdown message from call_later_on_this_thread(). We differentiate by checking 'ser'. */
    void on_thread_switch() {
        if (!ser) coro_t::spawn(boost::bind(&tester_t::start, this));
        else coro_t::spawn(boost::bind(&tester_t::shutdown, this));
    }

    void start() {
        if (config->log_file) {
            log = new log_t();
        } else {
            log = NULL;
        }

        fprintf(stderr, "Creating a database...\n");
        filepath_file_opener_t file_opener(config->db_filename, io_backender.get());
        log_serializer_t::create(&file_opener,
                                 config->ser_static_config);

        fprintf(stderr, "Starting serializer...\n");
        ser = new log_serializer_t(config->ser_dynamic_config,
                                   &file_opener,
                                   &get_global_perfmon_collection());
        on_serializer_ready(ser);
    }

    void on_serializer_ready(log_serializer_t *ls) {
        fprintf(stderr, "Running test...\n");
        if(config->duration != RUN_FOREVER) {
            timer = fire_timer_once(config->duration * 1000, &tester_t::on_timer, this);
        }

        linux_thread_message_t *prev_interrupt_message = pool->set_interrupt_message(&interruptor);
        guarantee(prev_interrupt_message == NULL);

        pump();
    }

    static void on_timer(void *self) {
        tester_t *tester = (tester_t *)self;
        fprintf(stderr, "Time's up.\n");
        tester->stop_test();
    }

    void pump() {
        while (active_txns < config->concurrent_txns && !stop) {
            active_txns++;
            total_txns++;
            coro_t::spawn_sometime(boost::bind(transact, ser, log, config->inserts_per_txn, config->updates_per_txn, this));
        }

        // See if we need to report the TPS
        ticks_t cur_time = get_ticks();
        if(ticks_to_secs(cur_time - last_time) >= 1.0f) {
            if(tps_log_fd) {
                fprintf(tps_log_fd, "%d\n", txns_last_sec);
            }

            last_time = cur_time;
            txns_last_sec = 0;
            secs_so_far++;

            // Flush every five seconds in case of a crash
            if(secs_so_far % 5 == 0) {
                fflush(tps_log_fd);
            }
        }

        if (active_txns == 0 && stop) {
            /* Serializer doesn't like shutdown() to be called from within
               on_serializer_write_txn() */
            call_later_on_this_thread(this);
        }
    }

    void stop_test() {

        if (stop) return;
        linux_thread_message_t *prev_interrupt_message = pool->set_interrupt_message(NULL);
        guarantee(prev_interrupt_message == &interruptor);

        fprintf(stderr, "Started %d transactions and completed %d of them\n",
            total_txns, total_txns - active_txns);

        if (tps_log_fd)
            fclose(tps_log_fd);

        if (config->log_file) {
            FILE *log_file = fopen(config->log_file, "w");
            log_t::iterator it;
            for (it = log->begin(); it != log->end(); it++) {
                fprintf(log_file, "%.6f %.6f\n", ticks_to_secs(it->start), ticks_to_secs(it->end));
            }
            fclose(log_file);
            fprintf(stderr, "Wrote log to '%s'\n", config->log_file);
            delete(log);
        }

        stop = true;
        if (active_txns > 0) {
            fprintf(stderr, "Waiting for the remaining %d transactions...\n", active_txns);
        }
    }

    void on_transaction_complete() {
        active_txns--;
        txns_last_sec++;
        pump();
    }

    void shutdown() {
        fprintf(stderr, "Waiting for serializer to shut down...\n");
        delete ser;
        on_serializer_shutdown();
    }

    void on_serializer_shutdown() {
        fprintf(stderr, "Done.\n");
        pool->shutdown_thread_pool();
    }
};

const char *read_arg(int &argc, char **&argv) {
    if (argc == 0) {
        fail_due_to_user_error("Expected another argument at the end.");
    } else {
        argc--;
        return (argv++)[0];
    }
}

void parse_config(int argc, char *argv[], config_t *config) {

    config->db_filename = "rethinkdb_data";
    config->log_file = NULL;
    config->tps_log_file = NULL;

    // config->ser_static_config uses its own defaults from constructor
    // config->ser_dynamic_config uses its own defaults from constructor

    config->duration = 10;   /* Seconds */
    config->concurrent_txns = 8;
    config->inserts_per_txn = 10;
    config->updates_per_txn = 2;

    read_arg(argc, argv);

    while (argc) {
        const char *flag = read_arg(argc, argv);

        if (strcmp(flag, "-f") == 0) {
            config->db_filename = read_arg(argc, argv);
        } else if (strcmp(flag, "--log") == 0) {
            config->log_file = read_arg(argc, argv);
        } else if (strcmp(flag, "--tps-log") == 0) {
            config->tps_log_file = read_arg(argc, argv);
        } else if (strcmp(flag, "--block-size") == 0) {
            config->ser_static_config.block_size_ = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--extent-size") == 0) {
            config->ser_static_config.extent_size_ = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--active-data-extents") == 0) {
            config->ser_dynamic_config.num_active_data_extents = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--file-zone-size") == 0) {
            config->ser_dynamic_config.file_zone_size = atoi(read_arg(argc, argv));

        } else if (strcmp(flag, "--duration") == 0) {
            config->duration = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--forever") == 0) {
            config->duration = RUN_FOREVER;
        } else if (strcmp(flag, "--concurrent") == 0) {
            config->concurrent_txns = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--inserts-per-txn") == 0) {
            config->inserts_per_txn = atoi(read_arg(argc, argv));
        } else if (strcmp(flag, "--updates-per-txn") == 0) {
            config->updates_per_txn = atoi(read_arg(argc, argv));

        } else {
            fail_due_to_user_error("Don't know how to handle \"%s\"", flag);
        }
    }

    rassert(config->ser_static_config.block_size().ser_value() > 0);
    rassert(config->ser_static_config.extent_size() > 0);
    rassert(config->ser_dynamic_config.num_active_data_extents > 0);
    rassert(config->ser_dynamic_config.file_zone_size > 0);
    rassert(config->duration > 0 || config->duration == RUN_FOREVER);
    rassert(config->concurrent_txns > 0);
}

int main(int argc, char *argv[]) {

    config_t config;
    parse_config(argc, argv, &config);

    thread_pool_t thread_pool(1, true);
    tester_t tester(&config, &thread_pool);
    thread_pool.run_thread_pool(&tester);

    return 0;
}
<|endoftext|>