<commit_before>/**
 * Non-metric Space Library
 *
 * Authors: Bilegsaikhan Naidan (https://github.com/bileg), Leonid Boytsov (http://boytsov.info).
 * With contributions from Lawrence Cayton (http://lcayton.com/) and others.
 *
 * For the complete list of contributors and further details see:
 * https://github.com/searchivarius/NonMetricSpaceLib
 *
 * Copyright (c) 2016
 *
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 */

#include <cmath>

#include "space.h"
#include "rangequery.h"
#include "knnquery.h"

#include <string>

using namespace std;

#include <space/space_sparse_vector_inter.h>
#include <space/space_vector.h>

#include "method/falconn.h"

const string PARAM_HASH_FAMILY                = "hash_family";
const string PARAM_HASH_FAMILY_CROSS_POLYTOPE = "cross_polytope";
const string PARAM_HASH_FAMILY_HYPERPLANE     = "hyperplane";

const string PARAM_STORAGE_HASH_TABLE   = "storage_hash_table";
const string PARAM_NUM_HASH_BITS        = "num_hash_bits";
const string PARAM_NUM_HASH_TABLES      = "num_hash_tables";
const string PARAM_NUM_PROBES           = "num_probes"; // This is going to be a query-time parameter
const string PARAM_NUM_ROTATIONS        = "num_rotations";
const string PARAM_SEED                 = "seed";
const string PARAM_FEATURE_HASHING_DIM  = "feature_hashing_dimension";
const string PARAM_NORM_DATA            = "norm_data";

namespace similarity {

using namespace falconn;

// storage_hash_table_from_string is a modification of FALCONN's python_wrapper.h
StorageHashTable storage_hash_table_from_string(string str) {
  ToLower(str);
  for (int ii = 0; ii < static_cast<int>(kStorageHashTableStrings.size());
       ++ii) {
    if (str == kStorageHashTableStrings[ii]) {
      return StorageHashTable(ii);
    }
  }
  stringstream err;
  err << "Unknown value of the parameter " << PARAM_STORAGE_HASH_TABLE << " valid values are: ";
  for (int ii = 0; ii < static_cast<int>(kStorageHashTableStrings.size()); ++ii) {
    if (ii) err << ",";
    err << kStorageHashTableStrings[ii];
  }
  throw runtime_error(err.str());
}

template <typename dist_t>
 void FALCONN<dist_t>::createDenseDataPoint(const Object* o, DenseFalconnPoint& p, bool normData) const {
  CHECK(sizeof(dist_t)*dim_ == o->datalength());
  const dist_t *pVect = reinterpret_cast<const dist_t*>(o->data());
  for (size_t i = 0; i < dim_; ++i) {
    p[i] = pVect[i];
  }
  if (normData) {
    p.normalize();
  }
}

template <typename dist_t>
void FALCONN<dist_t>::createSparseDataPoint(const Object* o, SparseFalconnPoint& p, bool normData) const {
  p.clear();
  vector<SparseVectElem<dist_t>> target;
  UnpackSparseElements(o->data(), o->datalength(), target);

  dist_t norm = 1;
  if (normData) {
    norm = 0;
    for (const SparseVectElem<dist_t>& e : target) {
      norm += e.val_ *e.val_;
    }
    norm = 1/ sqrt(norm);
  }
  for (const SparseVectElem<dist_t>& e : target) {
    p.push_back(make_pair(e.id_, e.val_ * norm));
  }
}

template <typename dist_t>
void FALCONN<dist_t>::copyData(bool normData) {
  SpaceSparseVectorInter<dist_t>* pSparseSpace = dynamic_cast<SpaceSparseVectorInter<dist_t>*>(&space_);
  VectorSpace<dist_t>*            pDenseSpace  = dynamic_cast<VectorSpace<dist_t>*>(&space_);

  if (data_.empty()) return;
  if (pSparseSpace == nullptr && pDenseSpace == nullptr) {
    throw runtime_error("Only sparse and dense vector spaces are supported!");
  }
  if (pSparseSpace != nullptr) {
    LOG(LIB_INFO) << "Copying a sparse vector data set.";
    sparse_ = true;
    SparseFalconnPoint p;
    for (const Object* o: data_) {
      createSparseDataPoint(o, p, normData);
      falconn_data_sparse_.push_back(p);
    }
  }
  if (pDenseSpace != nullptr) {
    LOG(LIB_INFO) << "Copying a dense vector data set.";
    dim_ = data_[0]->datalength() / sizeof(dist_t);
    DenseFalconnPoint p(dim_);
    for (const Object* o: data_) {
      createDenseDataPoint(o, p, normData);
      falconn_data_dense_.emplace_back(p);
    }
  }
  LOG(LIB_INFO) << "Dataset is copied.";
}

template <typename dist_t>
FALCONN<dist_t>::FALCONN(Space<dist_t>& space,
                         const ObjectVector& data) : data_(data), space_(space), sparse_(false),
                                                     dim_(0), num_probes_(10) {
}

template <typename dist_t>
void FALCONN<dist_t>::CreateIndex(const AnyParams& IndexParams)  {
  AnyParamManager  pmgr(IndexParams);

  LSHConstructionParameters params;
  params.distance_function = DistanceFunction::EuclideanSquared;
  // we want to use all the available threads to set up
  params.num_setup_threads = 0;

  norm_data_ = true;

  pmgr.GetParamOptional(PARAM_NORM_DATA, norm_data_, true);

  copyData(norm_data_);

  pmgr.GetParamOptional(PARAM_SEED, params.seed, 4057218);

  {
    string hash_table_storage_type;
    ToLower(hash_table_storage_type);
    // The flat hash table seems to be the most efficient
    pmgr.GetParamOptional(PARAM_STORAGE_HASH_TABLE, hash_table_storage_type, "flat_hash_table");
    params.storage_hash_table = storage_hash_table_from_string(hash_table_storage_type);
  }

  {
    string lsh_family_str;
    pmgr.GetParamOptional(PARAM_HASH_FAMILY, lsh_family_str, PARAM_HASH_FAMILY_CROSS_POLYTOPE);
    ToLower(lsh_family_str);
    if (lsh_family_str == PARAM_HASH_FAMILY_CROSS_POLYTOPE) {
      params.lsh_family = LSHFamily::CrossPolytope;
    } else if (lsh_family_str == PARAM_HASH_FAMILY_HYPERPLANE) {
      params.lsh_family = LSHFamily::Hyperplane;
    } else {
      PREPARE_RUNTIME_ERR(err)
      << "Unrecognized value of " << PARAM_HASH_FAMILY << " expected one of: "
      << PARAM_HASH_FAMILY_CROSS_POLYTOPE << ", " << PARAM_HASH_FAMILY_HYPERPLANE;
      THROW_RUNTIME_ERR(err);
    }
  }

  /*
   * The number of hash tables affects the memory usage. According to FALCONN's manual,
   * the larger it is, the better (unless it's too large).
   * They also recommend to start with a small number, e.g., 10-50 tables,
   * and then increase it gradually, while observing the effect it makes.
   */
  pmgr.GetParamOptional(PARAM_NUM_HASH_TABLES, params.l, 50);
  /*
   * This parameter controls the number of buckets per table,
   * According to FALCONN's manual, it should be approx. equal to
   * the binary logarithm of the number of data points
   */
  size_t num_hash_bits = max<size_t>(2, static_cast<size_t>(floor(log2(data_.size()>>1))));
  pmgr.GetParamOptional(PARAM_NUM_HASH_BITS, num_hash_bits, num_hash_bits);

  /*
   *  Number of rotations controls the number of pseudo-random rotations for
   *  the cross-polytope LSH, FALCONN's manual advised to set it to 1 for the dense data,
   *  and 2 for the sparse data.
   */
  size_t num_rotations_default = sparse_ ? 2 : 1;
  pmgr.GetParamOptional(PARAM_NUM_ROTATIONS, params.num_rotations, num_rotations_default);

  if (!sparse_) {
    params.dimension = dim_;
    compute_number_of_hash_functions<DenseFalconnPoint>(num_hash_bits, &params);
    falconn_table_dense_ = construct_table<DenseFalconnPoint>(falconn_data_dense_, params);
  } else {
    pmgr.GetParamRequired(PARAM_FEATURE_HASHING_DIM, params.feature_hashing_dimension);
    compute_number_of_hash_functions<SparseFalconnPoint>(num_hash_bits, &params);
    falconn_table_sparse_ = construct_table<SparseFalconnPoint>(falconn_data_sparse_, params);
  }

  LOG(LIB_INFO) << "Normalize data?:      " << norm_data_;
  LOG(LIB_INFO) << "#dim:                 " << params.dimension;
  LOG(LIB_INFO) << "#of feature-hash dim: " << params.feature_hashing_dimension;

  LOG(LIB_INFO) << "Hash family:          " << kLSHFamilyStrings[(size_t)params.lsh_family];
  LOG(LIB_INFO) << "Table storage type:   " << kStorageHashTableStrings[(size_t)params.storage_hash_table];

  LOG(LIB_INFO) << "#of hash tables:      " << params.k;
  LOG(LIB_INFO) << "#of hash bits:        " << num_hash_bits;
  LOG(LIB_INFO) << "#of rotations:        " << params.num_rotations;

  LOG(LIB_INFO) << "seed:                 " << params.seed;

  // Check if a user specified extra parameters, which can be also misspelled variants of existing ones
  pmgr.CheckUnused();
  // Always call ResetQueryTimeParams() to set query-time parameters to their default values
  this->ResetQueryTimeParams();
}

template <typename dist_t>
void FALCONN<dist_t>::Search(KNNQuery<dist_t>* query, IdType) const {
  vector<IdType> ids;

  if (sparse_) {
    SparseFalconnPoint sparseQ;
    createSparseDataPoint(query->QueryObject(), sparseQ, norm_data_);
    falconn_table_sparse_->find_k_nearest_neighbors(sparseQ, query->GetK(), &ids);
  } else {
    DenseFalconnPoint  denseQ(dim_);
    createDenseDataPoint(query->QueryObject(), denseQ, norm_data_);
    falconn_table_dense_->find_k_nearest_neighbors(denseQ, query->GetK(), &ids);
  }
  // Recomputing distances for k nearest neighbors should have a very small impact on overall performance
  for (IdType ii : ids) {
    query->CheckAndAddToResult(data_[ii]);
  }
}

template <typename dist_t>
void
FALCONN<dist_t>::SetQueryTimeParams(const AnyParams& QueryTimeParams) {
  AnyParamManager pmgr(QueryTimeParams);

  pmgr.GetParamOptional(PARAM_NUM_PROBES, num_probes_, num_probes_);
  LOG(LIB_INFO) << PARAM_NUM_PROBES << " = " << num_probes_;
  if (sparse_) falconn_table_sparse_->set_num_probes(num_probes_);
  else falconn_table_dense_->set_num_probes(num_probes_);
  pmgr.CheckUnused();
}

template class FALCONN<float>;
template class FALCONN<double>;

}
<commit_msg>bugfix<commit_after>/**
 * Non-metric Space Library
 *
 * Authors: Bilegsaikhan Naidan (https://github.com/bileg), Leonid Boytsov (http://boytsov.info).
 * With contributions from Lawrence Cayton (http://lcayton.com/) and others.
 *
 * For the complete list of contributors and further details see:
 * https://github.com/searchivarius/NonMetricSpaceLib
 *
 * Copyright (c) 2016
 *
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 */

#include <cmath>

#include "space.h"
#include "rangequery.h"
#include "knnquery.h"

#include <string>

using namespace std;

#include <space/space_sparse_vector_inter.h>
#include <space/space_vector.h>

#include "method/falconn.h"

const string PARAM_HASH_FAMILY                = "hash_family";
const string PARAM_HASH_FAMILY_CROSS_POLYTOPE = "cross_polytope";
const string PARAM_HASH_FAMILY_HYPERPLANE     = "hyperplane";

const string PARAM_STORAGE_HASH_TABLE   = "storage_hash_table";
const string PARAM_NUM_HASH_BITS        = "num_hash_bits";
const string PARAM_NUM_HASH_TABLES      = "num_hash_tables";
const string PARAM_NUM_PROBES           = "num_probes"; // This is going to be a query-time parameter
const string PARAM_NUM_ROTATIONS        = "num_rotations";
const string PARAM_SEED                 = "seed";
const string PARAM_FEATURE_HASHING_DIM  = "feature_hashing_dimension";
const string PARAM_NORM_DATA            = "norm_data";

namespace similarity {

using namespace falconn;

// storage_hash_table_from_string is a modification of FALCONN's python_wrapper.h
StorageHashTable storage_hash_table_from_string(string str) {
  ToLower(str);
  for (int ii = 0; ii < static_cast<int>(kStorageHashTableStrings.size());
       ++ii) {
    if (str == kStorageHashTableStrings[ii]) {
      return StorageHashTable(ii);
    }
  }
  stringstream err;
  err << "Unknown value of the parameter " << PARAM_STORAGE_HASH_TABLE << " valid values are: ";
  for (int ii = 0; ii < static_cast<int>(kStorageHashTableStrings.size()); ++ii) {
    if (ii) err << ",";
    err << kStorageHashTableStrings[ii];
  }
  throw runtime_error(err.str());
}

template <typename dist_t>
 void FALCONN<dist_t>::createDenseDataPoint(const Object* o, DenseFalconnPoint& p, bool normData) const {
  CHECK(sizeof(dist_t)*dim_ == o->datalength());
  const dist_t *pVect = reinterpret_cast<const dist_t*>(o->data());
  for (size_t i = 0; i < dim_; ++i) {
    p[i] = pVect[i];
  }
  if (normData) {
    p.normalize();
  }
}

template <typename dist_t>
void FALCONN<dist_t>::createSparseDataPoint(const Object* o, SparseFalconnPoint& p, bool normData) const {
  p.clear();
  vector<SparseVectElem<dist_t>> target;
  UnpackSparseElements(o->data(), o->datalength(), target);

  dist_t norm = 1;
  if (normData) {
    norm = 0;
    for (const SparseVectElem<dist_t>& e : target) {
      norm += e.val_ *e.val_;
    }
    norm = 1/ sqrt(norm);
  }
  for (const SparseVectElem<dist_t>& e : target) {
    p.push_back(make_pair(e.id_, e.val_ * norm));
  }
}

template <typename dist_t>
void FALCONN<dist_t>::copyData(bool normData) {
  SpaceSparseVectorInter<dist_t>* pSparseSpace = dynamic_cast<SpaceSparseVectorInter<dist_t>*>(&space_);
  VectorSpace<dist_t>*            pDenseSpace  = dynamic_cast<VectorSpace<dist_t>*>(&space_);

  if (data_.empty()) return;
  if (pSparseSpace == nullptr && pDenseSpace == nullptr) {
    throw runtime_error("Only sparse and dense vector spaces are supported!");
  }
  if (pSparseSpace != nullptr) {
    LOG(LIB_INFO) << "Copying a sparse vector data set.";
    sparse_ = true;
    SparseFalconnPoint p;
    dim_ = 0;
    for (const Object* o: data_) {
      createSparseDataPoint(o, p, normData);
      falconn_data_sparse_.push_back(p);
      if (p.size())
        dim_ = max<size_t>(dim_, p.back().first);
    }
  }
  if (pDenseSpace != nullptr) {
    LOG(LIB_INFO) << "Copying a dense vector data set.";
    dim_ = data_[0]->datalength() / sizeof(dist_t);
    DenseFalconnPoint p(dim_);
    for (const Object* o: data_) {
      createDenseDataPoint(o, p, normData);
      falconn_data_dense_.emplace_back(p);
    }
  }
  LOG(LIB_INFO) << "Dataset is copied.";
}

template <typename dist_t>
FALCONN<dist_t>::FALCONN(Space<dist_t>& space,
                         const ObjectVector& data) : data_(data), space_(space), sparse_(false),
                                                     dim_(0), num_probes_(10) {
}

template <typename dist_t>
void FALCONN<dist_t>::CreateIndex(const AnyParams& IndexParams)  {
  AnyParamManager  pmgr(IndexParams);

  LSHConstructionParameters params;
  params.distance_function = DistanceFunction::EuclideanSquared;
  // we want to use all the available threads to set up
  params.num_setup_threads = 0;

  norm_data_ = true;

  pmgr.GetParamOptional(PARAM_NORM_DATA, norm_data_, true);

  copyData(norm_data_);

  pmgr.GetParamOptional(PARAM_SEED, params.seed, 4057218);

  {
    string hash_table_storage_type;
    ToLower(hash_table_storage_type);
    // The flat hash table seems to be the most efficient
    pmgr.GetParamOptional(PARAM_STORAGE_HASH_TABLE, hash_table_storage_type, "flat_hash_table");
    params.storage_hash_table = storage_hash_table_from_string(hash_table_storage_type);
  }

  {
    string lsh_family_str;
    pmgr.GetParamOptional(PARAM_HASH_FAMILY, lsh_family_str, PARAM_HASH_FAMILY_CROSS_POLYTOPE);
    ToLower(lsh_family_str);
    if (lsh_family_str == PARAM_HASH_FAMILY_CROSS_POLYTOPE) {
      params.lsh_family = LSHFamily::CrossPolytope;
    } else if (lsh_family_str == PARAM_HASH_FAMILY_HYPERPLANE) {
      params.lsh_family = LSHFamily::Hyperplane;
    } else {
      PREPARE_RUNTIME_ERR(err)
      << "Unrecognized value of " << PARAM_HASH_FAMILY << " expected one of: "
      << PARAM_HASH_FAMILY_CROSS_POLYTOPE << ", " << PARAM_HASH_FAMILY_HYPERPLANE;
      THROW_RUNTIME_ERR(err);
    }
  }

  /*
   * The number of hash tables affects the memory usage. According to FALCONN's manual,
   * the larger it is, the better (unless it's too large).
   * They also recommend to start with a small number, e.g., 10-50 tables,
   * and then increase it gradually, while observing the effect it makes.
   */
  pmgr.GetParamOptional(PARAM_NUM_HASH_TABLES, params.l, 50);
  /*
   * This parameter controls the number of buckets per table,
   * According to FALCONN's manual, it should be approx. equal to
   * the binary logarithm of the number of data points
   */
  size_t num_hash_bits = max<size_t>(2, static_cast<size_t>(floor(log2(data_.size()>>1))));
  pmgr.GetParamOptional(PARAM_NUM_HASH_BITS, num_hash_bits, num_hash_bits);

  /*
   *  Number of rotations controls the number of pseudo-random rotations for
   *  the cross-polytope LSH, FALCONN's manual advised to set it to 1 for the dense data,
   *  and 2 for the sparse data.
   */
  size_t num_rotations_default = sparse_ ? 2 : 1;
  pmgr.GetParamOptional(PARAM_NUM_ROTATIONS, params.num_rotations, num_rotations_default);

  params.dimension = dim_;

  if (!sparse_) {
    compute_number_of_hash_functions<DenseFalconnPoint>(num_hash_bits, &params);
  } else {
    pmgr.GetParamRequired(PARAM_FEATURE_HASHING_DIM, params.feature_hashing_dimension);
    compute_number_of_hash_functions<SparseFalconnPoint>(num_hash_bits, &params);
  }

  LOG(LIB_INFO) << "Normalize data?:      " << norm_data_;
  LOG(LIB_INFO) << "#dim:                 " << params.dimension;
  LOG(LIB_INFO) << "#of feature-hash dim: " << params.feature_hashing_dimension;

  LOG(LIB_INFO) << "Hash family:          " << kLSHFamilyStrings[(size_t)params.lsh_family];
  LOG(LIB_INFO) << "Table storage type:   " << kStorageHashTableStrings[(size_t)params.storage_hash_table];

  LOG(LIB_INFO) << "#of hash tables:      " << params.k;
  LOG(LIB_INFO) << "#of hash bits:        " << num_hash_bits;
  LOG(LIB_INFO) << "#of rotations:        " << params.num_rotations;

  LOG(LIB_INFO) << "seed:                 " << params.seed;

  // Check if a user specified extra parameters, which can be also misspelled variants of existing ones
  pmgr.CheckUnused();

  if (!sparse_) {
    falconn_table_dense_ = construct_table<DenseFalconnPoint>(falconn_data_dense_, params);
  } else {
    falconn_table_sparse_ = construct_table<SparseFalconnPoint>(falconn_data_sparse_, params);
  }

  // Always call ResetQueryTimeParams() to set query-time parameters to their default values
  this->ResetQueryTimeParams();
}

template <typename dist_t>
void FALCONN<dist_t>::Search(KNNQuery<dist_t>* query, IdType) const {
  vector<IdType> ids;

  if (sparse_) {
    SparseFalconnPoint sparseQ;
    createSparseDataPoint(query->QueryObject(), sparseQ, norm_data_);
    falconn_table_sparse_->find_k_nearest_neighbors(sparseQ, query->GetK(), &ids);
  } else {
    DenseFalconnPoint  denseQ(dim_);
    createDenseDataPoint(query->QueryObject(), denseQ, norm_data_);
    falconn_table_dense_->find_k_nearest_neighbors(denseQ, query->GetK(), &ids);
  }
  // Recomputing distances for k nearest neighbors should have a very small impact on overall performance
  for (IdType ii : ids) {
    query->CheckAndAddToResult(data_[ii]);
  }
}

template <typename dist_t>
void
FALCONN<dist_t>::SetQueryTimeParams(const AnyParams& QueryTimeParams) {
  AnyParamManager pmgr(QueryTimeParams);

  pmgr.GetParamOptional(PARAM_NUM_PROBES, num_probes_, num_probes_);
  LOG(LIB_INFO) << PARAM_NUM_PROBES << " = " << num_probes_;
  if (sparse_) falconn_table_sparse_->set_num_probes(num_probes_);
  else falconn_table_dense_->set_num_probes(num_probes_);
  pmgr.CheckUnused();
}

template class FALCONN<float>;
template class FALCONN<double>;

}
<|endoftext|>


<commit_before>/**
 * @file multi_wrapper_impls.hpp
 *
 * @brief Implementations of methods or functions requiring the definitions of
 * multiple CUDA entity proxy classes. In some cases these are declared in the
 * individual proxy class files, with the other classes forward-declared.
 */
#pragma once
#ifndef MULTI_WRAPPER_IMPLS_HPP_
#define MULTI_WRAPPER_IMPLS_HPP_

#include <cuda/api/stream.hpp>
#include <cuda/api/device.hpp>
#include <cuda/api/event.hpp>

namespace cuda {

// device_t methods

template <bool AssumedCurrent>
inline void device_t<AssumedCurrent>::synchronize(event_t& event)
{
	return synchronize_event(event.id());
}

template <bool AssumedCurrent>
inline void device_t<AssumedCurrent>::synchronize(stream_t<detail::do_not_assume_device_is_current>& stream)
{
	return synchronize_stream(stream.id());
}

template <bool AssumedCurrent>
inline stream_t<AssumedCurrent> device_t<AssumedCurrent>::default_stream() const
{
	// TODO: Perhaps support not-knowing our ID here as well, somehow?
	return stream_t<AssumedCurrent>(id(), stream::default_stream_id);
}

template <bool AssumedCurrent>
inline stream_t<detail::do_not_assume_device_is_current>
device_t<AssumedCurrent>::create_stream(
	bool                will_synchronize_with_default_stream,
	stream::priority_t  priority)
{
	device::current::scoped_override_t<AssumedCurrent> set_device_for_this_scope(id_);
	return stream_t<>(id(), stream::detail::create_on_current_device(
		will_synchronize_with_default_stream, priority));
}

// event_t methods

inline device_t<detail::do_not_assume_device_is_current>
event_t::device() const { return cuda::device::get(device_id_); }

// stream_t methods

template <bool AssumesDeviceIsCurrent>
inline device_t<detail::do_not_assume_device_is_current>
stream_t<AssumesDeviceIsCurrent>::device() const { return cuda::device::get(device_id_); }

namespace event {

/**
 * @brief creates a new execution stream on a device.
 *
 * @note The CUDA API runtime defaults to creating
 * which you synchronize on by busy-waiting. This function does
 * the same for compatibility.
 *
 * @param device The device on which to create the new stream
 * @param uses_blocking_sync When synchronizing on this new evet,
 * shall a thread busy-wait for it, or
 * @param records_timing Can this event be used to record time
 * values (e.g. duration between events)
 * @param interprocess Can multiple processes work with the constructed
 * event?
 * @return The constructed event proxy class
 */
template <bool DeviceAssumedCurrent>
inline event_t create(
	device_t<DeviceAssumedCurrent>  device,
	bool                            uses_blocking_sync = sync_by_busy_waiting,
	bool                            records_timing     = do_record_timings,
	bool                            interprocess       = not_interprocess)
{
	return create(device.id(), uses_blocking_sync, records_timing, interprocess);
}

} // namespace event_t

} // namespace cuda

#endif /* MULTI_WRAPPER_IMPLS_HPP_ */
<commit_msg>Fixed: The `device_t::create_stream()` implementation was failing to take ownership of the newly-created stream - which it should be doing.<commit_after>/**
 * @file multi_wrapper_impls.hpp
 *
 * @brief Implementations of methods or functions requiring the definitions of
 * multiple CUDA entity proxy classes. In some cases these are declared in the
 * individual proxy class files, with the other classes forward-declared.
 */
#pragma once
#ifndef MULTI_WRAPPER_IMPLS_HPP_
#define MULTI_WRAPPER_IMPLS_HPP_

#include <cuda/api/stream.hpp>
#include <cuda/api/device.hpp>
#include <cuda/api/event.hpp>

namespace cuda {

// device_t methods

template <bool AssumedCurrent>
inline void device_t<AssumedCurrent>::synchronize(event_t& event)
{
	return synchronize_event(event.id());
}

template <bool AssumedCurrent>
inline void device_t<AssumedCurrent>::synchronize(stream_t<detail::do_not_assume_device_is_current>& stream)
{
	return synchronize_stream(stream.id());
}

template <bool AssumedCurrent>
inline stream_t<AssumedCurrent> device_t<AssumedCurrent>::default_stream() const
{
	// TODO: Perhaps support not-knowing our ID here as well, somehow?
	return stream_t<AssumedCurrent>(id(), stream::default_stream_id);
}

template <bool AssumedCurrent>
inline stream_t<detail::do_not_assume_device_is_current>
device_t<AssumedCurrent>::create_stream(
	bool                will_synchronize_with_default_stream,
	stream::priority_t  priority)
{
	device::current::scoped_override_t<AssumedCurrent> set_device_for_this_scope(id_);
	constexpr const auto take_ownership = true;
	return stream::wrap(id(), stream::detail::create_on_current_device(
		will_synchronize_with_default_stream, priority), take_ownership);
}

// event_t methods

inline device_t<detail::do_not_assume_device_is_current>
event_t::device() const { return cuda::device::get(device_id_); }

// stream_t methods

template <bool AssumesDeviceIsCurrent>
inline device_t<detail::do_not_assume_device_is_current>
stream_t<AssumesDeviceIsCurrent>::device() const { return cuda::device::get(device_id_); }

namespace event {

/**
 * @brief creates a new execution stream on a device.
 *
 * @note The CUDA API runtime defaults to creating
 * which you synchronize on by busy-waiting. This function does
 * the same for compatibility.
 *
 * @param device The device on which to create the new stream
 * @param uses_blocking_sync When synchronizing on this new evet,
 * shall a thread busy-wait for it, or
 * @param records_timing Can this event be used to record time
 * values (e.g. duration between events)
 * @param interprocess Can multiple processes work with the constructed
 * event?
 * @return The constructed event proxy class
 */
template <bool DeviceAssumedCurrent>
inline event_t create(
	device_t<DeviceAssumedCurrent>  device,
	bool                            uses_blocking_sync = sync_by_busy_waiting,
	bool                            records_timing     = do_record_timings,
	bool                            interprocess       = not_interprocess)
{
	return create(device.id(), uses_blocking_sync, records_timing, interprocess);
}

} // namespace event_t

} // namespace cuda

#endif /* MULTI_WRAPPER_IMPLS_HPP_ */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ActiveMSPList.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2004-07-23 14:09:20 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _FRAMEWORK_SCRIPT_PROVIDER_OPENDOCUMENTLIST_HXX_
#define _FRAMEWORK_SCRIPT_PROVIDER_OPENDOCUMENTLIST_HXX_

#include <hash_map>
#include <map>

#include <osl/mutex.hxx>
#include <rtl/ustring>
#include <cppuhelper/implbase1.hxx>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>

#include <com/sun/star/lang/XEventListener.hpp>
#include <com/sun/star/frame/XModel.hpp>

#include <drafts/com/sun/star/script/provider/XScriptProvider.hpp>
#include <drafts/com/sun/star/script/browse/XBrowseNode.hpp>

namespace func_provider
{
// for simplification
#define css ::com::sun::star
#define dcsss ::drafts::com::sun::star::script

//Typedefs
//=============================================================================

typedef ::std::map < css::uno::Reference< css::frame::XModel >,
                     css::uno::Reference< dcsss::provider::XScriptProvider > > Model_map;

typedef ::std::hash_map< ::rtl::OUString,
    css::uno::Reference< dcsss::provider::XScriptProvider >,
    ::rtl::OUStringHash,
            ::std::equal_to< ::rtl::OUString > > Msp_hash;

class ActiveMSPList : public ::cppu::WeakImplHelper1< css::lang::XEventListener  >
{

public:
    static ActiveMSPList& instance( const css::uno::Reference<
        css::uno::XComponentContext >& xContext );

    ActiveMSPList(  const css::uno::Reference<
        css::uno::XComponentContext > & xContext  );
    ~ActiveMSPList();
    css::uno::Reference< dcsss::provider::XScriptProvider >
        createMSP( const ::rtl::OUString& context )
            throw ( css::uno::RuntimeException );
    css::uno::Reference< dcsss::provider::XScriptProvider >
        createMSP( const css::uno::Any& context )
            throw ( css::uno::RuntimeException );
    css::uno::Sequence< css::uno::Reference< dcsss::provider::XScriptProvider > >
        getActiveProviders();
    //XEventListener
    //======================================================================

    virtual void SAL_CALL disposing( const css::lang::EventObject& Source )
        throw ( css::uno::RuntimeException );

private:
    void addActiveMSP( const css::uno::Reference< css::frame::XModel >& xModel,
                       const css::uno::Reference< dcsss::provider::XScriptProvider >& msp );
    css::uno::Reference< dcsss::provider::XScriptProvider >
        createNewMSP( const ::rtl::OUString& )
            throw ( css::uno::RuntimeException );
    void createNonDocMSPs();
    Msp_hash m_hMsps;
    Model_map m_mModels;
    osl::Mutex m_mutex;
    ::rtl::OUString userDirString;
    ::rtl::OUString shareDirString;
    css::uno::Reference< css::uno::XComponentContext > m_xContext;
};
} // func_provider
#endif
<commit_msg>INTEGRATION: CWS scriptingf6 (1.5.2); FILE MERGED 2004/08/03 14:45:04 dfoster 1.5.2.1: #i32502#<commit_after>/*************************************************************************
 *
 *  $RCSfile: ActiveMSPList.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2004-10-22 14:05:46 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _FRAMEWORK_SCRIPT_PROVIDER_OPENDOCUMENTLIST_HXX_
#define _FRAMEWORK_SCRIPT_PROVIDER_OPENDOCUMENTLIST_HXX_

#include <hash_map>
#include <map>

#include <osl/mutex.hxx>
#include <rtl/ustring>
#include <cppuhelper/implbase1.hxx>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>

#include <com/sun/star/lang/XEventListener.hpp>
#include <com/sun/star/frame/XModel.hpp>

#include <com/sun/star/script/provider/XScriptProvider.hpp>
#include <com/sun/star/script/browse/XBrowseNode.hpp>

namespace func_provider
{
// for simplification
#define css ::com::sun::star

//Typedefs
//=============================================================================

typedef ::std::map < css::uno::Reference< css::frame::XModel >,
                     css::uno::Reference< css::script::provider::XScriptProvider > > Model_map;

typedef ::std::hash_map< ::rtl::OUString,
    css::uno::Reference< css::script::provider::XScriptProvider >,
    ::rtl::OUStringHash,
            ::std::equal_to< ::rtl::OUString > > Msp_hash;

class ActiveMSPList : public ::cppu::WeakImplHelper1< css::lang::XEventListener  >
{

public:
    static ActiveMSPList& instance( const css::uno::Reference<
        css::uno::XComponentContext >& xContext );

    ActiveMSPList(  const css::uno::Reference<
        css::uno::XComponentContext > & xContext  );
    ~ActiveMSPList();
    css::uno::Reference< css::script::provider::XScriptProvider >
        createMSP( const ::rtl::OUString& context )
            throw ( css::uno::RuntimeException );
    css::uno::Reference< css::script::provider::XScriptProvider >
        createMSP( const css::uno::Any& context )
            throw ( css::uno::RuntimeException );
    css::uno::Sequence< css::uno::Reference< css::script::provider::XScriptProvider > >
        getActiveProviders();
    //XEventListener
    //======================================================================

    virtual void SAL_CALL disposing( const css::lang::EventObject& Source )
        throw ( css::uno::RuntimeException );

private:
    void addActiveMSP( const css::uno::Reference< css::frame::XModel >& xModel,
                       const css::uno::Reference< css::script::provider::XScriptProvider >& msp );
    css::uno::Reference< css::script::provider::XScriptProvider >
        createNewMSP( const ::rtl::OUString& )
            throw ( css::uno::RuntimeException );
    void createNonDocMSPs();
    Msp_hash m_hMsps;
    Model_map m_mModels;
    osl::Mutex m_mutex;
    ::rtl::OUString userDirString;
    ::rtl::OUString shareDirString;
    css::uno::Reference< css::uno::XComponentContext > m_xContext;
};
} // func_provider
#endif
<|endoftext|>


<commit_before>/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef TransporterFacade_H
#define TransporterFacade_H

#include <kernel_types.h>
#include <ndb_limits.h>
#include <NdbThread.h>
#include <TransporterRegistry.hpp>
#include <NdbMutex.h>
#include "DictCache.hpp"
#include <BlockNumbers.h>
#include <mgmapi.h>

class ClusterMgr;
class ArbitMgr;
class IPCConfig;
struct ndb_mgm_configuration;
class ConfigRetriever;

class Ndb;
class NdbApiSignal;
class NdbWaiter;

typedef void (* ExecuteFunction)(void *, NdbApiSignal *, LinearSectionPtr ptr[3]);
typedef void (* NodeStatusFunction)(void *, Uint32, bool nodeAlive, bool nfComplete);

extern "C" {
  void* runSendRequest_C(void*);
  void* runReceiveResponse_C(void*);
  void atexit_stop_instance();
}

class TransporterFacade
{
public:
  /**
   * Max number of Ndb objects.
   * (Ndb objects should not be shared by different threads.)
   */
  STATIC_CONST( MAX_NO_THREADS = 4711 );
  TransporterFacade();
  virtual ~TransporterFacade();
  bool init(Uint32, const ndb_mgm_configuration *);

  int start_instance(int, const ndb_mgm_configuration*);
  void stop_instance();

  /**
   * Register this block for sending/receiving signals
   * @return BlockNumber or -1 for failure
   */
  int open(void* objRef, ExecuteFunction, NodeStatusFunction);

  // Close this block number
  int close(BlockNumber blockNumber, Uint64 trans_id);

  // Only sends to nodes which are alive
  int sendSignal(NdbApiSignal * signal, NodeId nodeId);
  int sendSignal(NdbApiSignal*, NodeId,
		 LinearSectionPtr ptr[3], Uint32 secs);
  int sendFragmentedSignal(NdbApiSignal*, NodeId,
			   LinearSectionPtr ptr[3], Uint32 secs);

  // Is node available for running transactions
  bool   get_node_alive(NodeId nodeId) const;
  bool   get_node_stopping(NodeId nodeId) const;
  bool   getIsDbNode(NodeId nodeId) const;
  bool   getIsNodeSendable(NodeId nodeId) const;
  Uint32 getNodeGrp(NodeId nodeId) const;
  Uint32 getNodeSequence(NodeId nodeId) const;

  // Is there space in sendBuffer to send messages
  bool   check_send_size(Uint32 node_id, Uint32 send_size);

  // My own processor id
  NodeId ownId() const;

  void connected();

  void doConnect(int NodeId);
  void reportConnected(int NodeId);
  void doDisconnect(int NodeId);
  void reportDisconnected(int NodeId);

  NodeId get_an_alive_node();
  void ReportNodeAlive(NodeId nodeId);
  void ReportNodeDead(NodeId nodeId);
  void ReportNodeFailureComplete(NodeId nodeId);

  /**
   * Send signal to each registered object
   */
  void for_each(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]);

  void lock_mutex();
  void unlock_mutex();

  // Improving the API performance
  void forceSend(Uint32 block_number);
  void checkForceSend(Uint32 block_number);

  // Close this block number
  int close_local(BlockNumber blockNumber);

  // Scan batch configuration parameters
  Uint32 get_scan_batch_size();
  Uint32 get_batch_byte_size();
  Uint32 get_batch_size();
  Uint32 m_waitfor_timeout; // in milli seconds...

  TransporterRegistry* get_registry() { return theTransporterRegistry;};

/*
  When a thread has sent its signals and is ready to wait for reception
  of these it does normally always wait on a conditional mutex and
  the actual reception is handled by the receiver thread in the NDB API.
  With the below new methods and variables each thread has the possibility
  of becoming owner of the "right" to poll for signals. Effectually this
  means that the thread acts temporarily as a receiver thread.
  For the thread that succeeds in grabbing this "ownership" it will avoid
  a number of expensive calls to conditional mutex and even more expensive
  context switches to wake up.
  When an owner of the poll "right" has completed its own task it is likely
  that there are others still waiting. In this case we pick one of the
  threads as new owner of the poll "right". Since we want to switch owner
  as seldom as possible we always pick the last thread which is likely to
  be the last to complete its reception.
*/
  void external_poll(Uint32 wait_time);
  NdbWaiter* get_poll_owner(void) const { return poll_owner; }
  void set_poll_owner(NdbWaiter* new_owner) { poll_owner= new_owner; }
  Uint32 put_in_cond_wait_queue(NdbWaiter *aWaiter);
  void remove_from_cond_wait_queue(NdbWaiter *aWaiter);
  NdbWaiter* rem_last_from_cond_wait_queue();
  // heart beat received from a node (e.g. a signal came)
  void hb_received(NodeId n);

private:
  void init_cond_wait_queue();
  struct CondWaitQueueElement {
    NdbWaiter *cond_wait_object;
    Uint32 next_cond_wait;
    Uint32 prev_cond_wait;
  };
  NdbWaiter *poll_owner;
  CondWaitQueueElement cond_wait_array[MAX_NO_THREADS];
  Uint32 first_in_cond_wait;
  Uint32 first_free_cond_wait;
  Uint32 last_in_cond_wait;
  /* End poll owner stuff */
  /**
   * Send a signal unconditional of node status (used by ClusterMgr)
   */
  friend class ClusterMgr;
  friend class ArbitMgr;
  friend class MgmtSrvr;
  friend class SignalSender;
  friend class GrepPS;
  friend class ExtSender; ///< @todo Hack to be able to sendSignalUnCond
  friend class GrepSS;
  friend class Ndb;
  friend class Ndb_cluster_connection_impl;
  friend class NdbTransaction;

  int sendSignalUnCond(NdbApiSignal *, NodeId nodeId);

  bool isConnected(NodeId aNodeId);
  void doStop();

  TransporterRegistry* theTransporterRegistry;
  SocketServer m_socket_server;
  int sendPerformedLastInterval;
  int theOwnId;

  NodeId theStartNodeId;

  ClusterMgr* theClusterMgr;
  ArbitMgr* theArbitMgr;

  // Improving the API response time
  int checkCounter;
  Uint32 currentSendLimit;

  void calculateSendLimit();

  // Scan batch configuration parameters
  Uint32 m_scan_batch_size;
  Uint32 m_batch_byte_size;
  Uint32 m_batch_size;

  // Declarations for the receive and send thread
  int  theStopReceive;

  void threadMainSend(void);
  NdbThread* theSendThread;
  void threadMainReceive(void);
  NdbThread* theReceiveThread;

  friend void* runSendRequest_C(void*);
  friend void* runReceiveResponse_C(void*);
  friend void atexit_stop_instance();

  /**
   * Block number handling
   */
private:

  struct ThreadData {
    STATIC_CONST( ACTIVE = (1 << 16) | 1 );
    STATIC_CONST( INACTIVE = (1 << 16) );
    STATIC_CONST( END_OF_LIST = MAX_NO_THREADS + 1 );

    ThreadData(Uint32 initialSize = 32);

    /**
     * Split "object" into 3 list
     *   This to improve locality
     *   when iterating over lists
     */
    struct Object_Execute {
      void * m_object;
      ExecuteFunction m_executeFunction;
    };
    struct NodeStatus_NextFree {
      NodeStatusFunction m_statusFunction;
    };

    Uint32 m_firstFree;
    Vector<Uint32> m_statusNext;
    Vector<Object_Execute> m_objectExecute;
    Vector<NodeStatusFunction> m_statusFunction;

    int open(void* objRef, ExecuteFunction, NodeStatusFunction);
    int close(int number);
    void expand(Uint32 size);

    inline Object_Execute get(Uint16 blockNo) const {
      blockNo -= MIN_API_BLOCK_NO;
      if(likely (blockNo < m_objectExecute.size())){
	return m_objectExecute[blockNo];
      }
      Object_Execute oe = { 0, 0 };
      return oe;
    }

    /**
     * Is the block number used currently
     */
    inline bool getInUse(Uint16 index) const {
      return (m_statusNext[index] & (1 << 16)) != 0;
    }
  } m_threads;

  Uint32 m_max_trans_id;
  Uint32 m_fragmented_signal_id;

  /**
   * execute function
   */
  friend void execute(void * callbackObj, SignalHeader * const header,
                      Uint8 prio,
                      Uint32 * const theData, LinearSectionPtr ptr[3]);

public:
  NdbMutex* theMutexPtr;

public:
  GlobalDictCache m_globalDictCache;
};

class PollGuard
{
  public:
  PollGuard(TransporterFacade *tp, NdbWaiter *aWaiter, Uint32 block_no);
  ~PollGuard() { unlock_and_signal(); }
  int wait_n_unlock(int wait_time, NodeId nodeId, Uint32 state,
                    bool forceSend= false);
  int wait_for_input_in_loop(int wait_time, bool forceSend);
  void wait_for_input(int wait_time);
  int wait_scan(int wait_time, NodeId nodeId, bool forceSend);
  void unlock_and_signal();
  private:
  TransporterFacade *m_tp;
  NdbWaiter *m_waiter;
  Uint32 m_block_no;
  bool m_locked;
};

inline
void
TransporterFacade::lock_mutex()
{
  NdbMutex_Lock(theMutexPtr);
}

inline
void
TransporterFacade::unlock_mutex()
{
  NdbMutex_Unlock(theMutexPtr);
}

#include "ClusterMgr.hpp"

inline
unsigned Ndb_cluster_connection_impl::get_connect_count() const
{
  return TransporterFacade::instance()->theClusterMgr->m_connect_count;
}

inline
bool
TransporterFacade::check_send_size(Uint32 node_id, Uint32 send_size)
{
  return true;
}

inline
bool
TransporterFacade::getIsDbNode(NodeId n) const {
  return
    theClusterMgr->getNodeInfo(n).defined &&
    theClusterMgr->getNodeInfo(n).m_info.m_type == NodeInfo::DB;
}

inline
Uint32
TransporterFacade::getNodeGrp(NodeId n) const {
  return theClusterMgr->getNodeInfo(n).m_state.nodeGroup;
}

inline
bool
TransporterFacade::get_node_alive(NodeId n) const {

  const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n);
  return node.m_alive;
}

inline
void
TransporterFacade::hb_received(NodeId n) {
  theClusterMgr->hb_received(n);
}

inline
bool
TransporterFacade::get_node_stopping(NodeId n) const {
  const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n);
  return ((node.m_state.startLevel == NodeState::SL_STOPPING_1) ||
          (node.m_state.startLevel == NodeState::SL_STOPPING_2));
}

inline
bool
TransporterFacade::getIsNodeSendable(NodeId n) const {
  const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n);
  const Uint32 startLevel = node.m_state.startLevel;

  if (node.m_info.m_type == NodeInfo::DB) {
    if(node.m_state.singleUserMode &&
       ownId() == node.m_state.singleUserApi) {
      return (node.compatible &&
              (node.m_state.startLevel == NodeState::SL_STOPPING_1 ||
               node.m_state.startLevel == NodeState::SL_STARTED ||
               node.m_state.startLevel == NodeState::SL_SINGLEUSER));
      }
      else
        return node.compatible && (startLevel == NodeState::SL_STARTED ||
                                 startLevel == NodeState::SL_STOPPING_1);
  } else {
    ndbout_c("TransporterFacade::getIsNodeSendable: Illegal node type: "
             "%d of node: %d",
             node.m_info.m_type, n);
    abort();
    return false; // to remove compiler warning
  }
}

inline
Uint32
TransporterFacade::getNodeSequence(NodeId n) const {
  return theClusterMgr->getNodeInfo(n).m_info.m_connectCount;
}

inline
Uint32
TransporterFacade::get_scan_batch_size() {
  return m_scan_batch_size;
}

inline
Uint32
TransporterFacade::get_batch_byte_size() {
  return m_batch_byte_size;
}

inline
Uint32
TransporterFacade::get_batch_size() {
  return m_batch_size;
}

#endif // TransporterFacade_H
<commit_msg>corrected merge<commit_after>/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef TransporterFacade_H
#define TransporterFacade_H

#include <kernel_types.h>
#include <ndb_limits.h>
#include <NdbThread.h>
#include <TransporterRegistry.hpp>
#include <NdbMutex.h>
#include "DictCache.hpp"
#include <BlockNumbers.h>
#include <mgmapi.h>

class ClusterMgr;
class ArbitMgr;
class IPCConfig;
struct ndb_mgm_configuration;
class ConfigRetriever;

class Ndb;
class NdbApiSignal;
class NdbWaiter;

typedef void (* ExecuteFunction)(void *, NdbApiSignal *, LinearSectionPtr ptr[3]);
typedef void (* NodeStatusFunction)(void *, Uint32, bool nodeAlive, bool nfComplete);

extern "C" {
  void* runSendRequest_C(void*);
  void* runReceiveResponse_C(void*);
  void atexit_stop_instance();
}

class TransporterFacade
{
public:
  /**
   * Max number of Ndb objects.
   * (Ndb objects should not be shared by different threads.)
   */
  STATIC_CONST( MAX_NO_THREADS = 4711 );
  TransporterFacade();
  virtual ~TransporterFacade();
  bool init(Uint32, const ndb_mgm_configuration *);

  int start_instance(int, const ndb_mgm_configuration*);
  void stop_instance();

  /**
   * Register this block for sending/receiving signals
   * @return BlockNumber or -1 for failure
   */
  int open(void* objRef, ExecuteFunction, NodeStatusFunction);

  // Close this block number
  int close(BlockNumber blockNumber, Uint64 trans_id);

  // Only sends to nodes which are alive
  int sendSignal(NdbApiSignal * signal, NodeId nodeId);
  int sendSignal(NdbApiSignal*, NodeId,
		 LinearSectionPtr ptr[3], Uint32 secs);
  int sendFragmentedSignal(NdbApiSignal*, NodeId,
			   LinearSectionPtr ptr[3], Uint32 secs);

  // Is node available for running transactions
  bool   get_node_alive(NodeId nodeId) const;
  bool   get_node_stopping(NodeId nodeId) const;
  bool   getIsDbNode(NodeId nodeId) const;
  bool   getIsNodeSendable(NodeId nodeId) const;
  Uint32 getNodeGrp(NodeId nodeId) const;
  Uint32 getNodeSequence(NodeId nodeId) const;

  // Is there space in sendBuffer to send messages
  bool   check_send_size(Uint32 node_id, Uint32 send_size);

  // My own processor id
  NodeId ownId() const;

  void connected();

  void doConnect(int NodeId);
  void reportConnected(int NodeId);
  void doDisconnect(int NodeId);
  void reportDisconnected(int NodeId);

  NodeId get_an_alive_node();
  void ReportNodeAlive(NodeId nodeId);
  void ReportNodeDead(NodeId nodeId);
  void ReportNodeFailureComplete(NodeId nodeId);

  /**
   * Send signal to each registered object
   */
  void for_each(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]);

  void lock_mutex();
  void unlock_mutex();

  // Improving the API performance
  void forceSend(Uint32 block_number);
  void checkForceSend(Uint32 block_number);

  // Close this block number
  int close_local(BlockNumber blockNumber);

  // Scan batch configuration parameters
  Uint32 get_scan_batch_size();
  Uint32 get_batch_byte_size();
  Uint32 get_batch_size();
  Uint32 m_waitfor_timeout; // in milli seconds...

  TransporterRegistry* get_registry() { return theTransporterRegistry;};

/*
  When a thread has sent its signals and is ready to wait for reception
  of these it does normally always wait on a conditional mutex and
  the actual reception is handled by the receiver thread in the NDB API.
  With the below new methods and variables each thread has the possibility
  of becoming owner of the "right" to poll for signals. Effectually this
  means that the thread acts temporarily as a receiver thread.
  For the thread that succeeds in grabbing this "ownership" it will avoid
  a number of expensive calls to conditional mutex and even more expensive
  context switches to wake up.
  When an owner of the poll "right" has completed its own task it is likely
  that there are others still waiting. In this case we pick one of the
  threads as new owner of the poll "right". Since we want to switch owner
  as seldom as possible we always pick the last thread which is likely to
  be the last to complete its reception.
*/
  void external_poll(Uint32 wait_time);
  NdbWaiter* get_poll_owner(void) const { return poll_owner; }
  void set_poll_owner(NdbWaiter* new_owner) { poll_owner= new_owner; }
  Uint32 put_in_cond_wait_queue(NdbWaiter *aWaiter);
  void remove_from_cond_wait_queue(NdbWaiter *aWaiter);
  NdbWaiter* rem_last_from_cond_wait_queue();
  // heart beat received from a node (e.g. a signal came)
  void hb_received(NodeId n);

private:
  void init_cond_wait_queue();
  struct CondWaitQueueElement {
    NdbWaiter *cond_wait_object;
    Uint32 next_cond_wait;
    Uint32 prev_cond_wait;
  };
  NdbWaiter *poll_owner;
  CondWaitQueueElement cond_wait_array[MAX_NO_THREADS];
  Uint32 first_in_cond_wait;
  Uint32 first_free_cond_wait;
  Uint32 last_in_cond_wait;
  /* End poll owner stuff */
  /**
   * Send a signal unconditional of node status (used by ClusterMgr)
   */
  friend class ClusterMgr;
  friend class ArbitMgr;
  friend class MgmtSrvr;
  friend class SignalSender;
  friend class GrepPS;
  friend class ExtSender; ///< @todo Hack to be able to sendSignalUnCond
  friend class GrepSS;
  friend class Ndb;
  friend class Ndb_cluster_connection_impl;
  friend class NdbTransaction;

  int sendSignalUnCond(NdbApiSignal *, NodeId nodeId);

  bool isConnected(NodeId aNodeId);
  void doStop();

  TransporterRegistry* theTransporterRegistry;
  SocketServer m_socket_server;
  int sendPerformedLastInterval;
  int theOwnId;

  NodeId theStartNodeId;

  ClusterMgr* theClusterMgr;
  ArbitMgr* theArbitMgr;

  // Improving the API response time
  int checkCounter;
  Uint32 currentSendLimit;

  void calculateSendLimit();

  // Scan batch configuration parameters
  Uint32 m_scan_batch_size;
  Uint32 m_batch_byte_size;
  Uint32 m_batch_size;

  // Declarations for the receive and send thread
  int  theStopReceive;

  void threadMainSend(void);
  NdbThread* theSendThread;
  void threadMainReceive(void);
  NdbThread* theReceiveThread;

  friend void* runSendRequest_C(void*);
  friend void* runReceiveResponse_C(void*);
  friend void atexit_stop_instance();

  /**
   * Block number handling
   */
private:

  struct ThreadData {
    STATIC_CONST( ACTIVE = (1 << 16) | 1 );
    STATIC_CONST( INACTIVE = (1 << 16) );
    STATIC_CONST( END_OF_LIST = MAX_NO_THREADS + 1 );

    ThreadData(Uint32 initialSize = 32);

    /**
     * Split "object" into 3 list
     *   This to improve locality
     *   when iterating over lists
     */
    struct Object_Execute {
      void * m_object;
      ExecuteFunction m_executeFunction;
    };
    struct NodeStatus_NextFree {
      NodeStatusFunction m_statusFunction;
    };

    Uint32 m_firstFree;
    Vector<Uint32> m_statusNext;
    Vector<Object_Execute> m_objectExecute;
    Vector<NodeStatusFunction> m_statusFunction;

    int open(void* objRef, ExecuteFunction, NodeStatusFunction);
    int close(int number);
    void expand(Uint32 size);

    inline Object_Execute get(Uint16 blockNo) const {
      blockNo -= MIN_API_BLOCK_NO;
      if(likely (blockNo < m_objectExecute.size())){
	return m_objectExecute[blockNo];
      }
      Object_Execute oe = { 0, 0 };
      return oe;
    }

    /**
     * Is the block number used currently
     */
    inline bool getInUse(Uint16 index) const {
      return (m_statusNext[index] & (1 << 16)) != 0;
    }
  } m_threads;

  Uint32 m_max_trans_id;
  Uint32 m_fragmented_signal_id;

  /**
   * execute function
   */
  friend void execute(void * callbackObj, SignalHeader * const header,
                      Uint8 prio,
                      Uint32 * const theData, LinearSectionPtr ptr[3]);

public:
  NdbMutex* theMutexPtr;

public:
  GlobalDictCache m_globalDictCache;
};

class PollGuard
{
  public:
  PollGuard(TransporterFacade *tp, NdbWaiter *aWaiter, Uint32 block_no);
  ~PollGuard() { unlock_and_signal(); }
  int wait_n_unlock(int wait_time, NodeId nodeId, Uint32 state,
                    bool forceSend= false);
  int wait_for_input_in_loop(int wait_time, bool forceSend);
  void wait_for_input(int wait_time);
  int wait_scan(int wait_time, NodeId nodeId, bool forceSend);
  void unlock_and_signal();
  private:
  TransporterFacade *m_tp;
  NdbWaiter *m_waiter;
  Uint32 m_block_no;
  bool m_locked;
};

inline
void
TransporterFacade::lock_mutex()
{
  NdbMutex_Lock(theMutexPtr);
}

inline
void
TransporterFacade::unlock_mutex()
{
  NdbMutex_Unlock(theMutexPtr);
}

#include "ClusterMgr.hpp"

inline
unsigned Ndb_cluster_connection_impl::get_connect_count() const
{
  return m_transporter_facade->theClusterMgr->m_connect_count;
}

inline
bool
TransporterFacade::check_send_size(Uint32 node_id, Uint32 send_size)
{
  return true;
}

inline
bool
TransporterFacade::getIsDbNode(NodeId n) const {
  return
    theClusterMgr->getNodeInfo(n).defined &&
    theClusterMgr->getNodeInfo(n).m_info.m_type == NodeInfo::DB;
}

inline
Uint32
TransporterFacade::getNodeGrp(NodeId n) const {
  return theClusterMgr->getNodeInfo(n).m_state.nodeGroup;
}

inline
bool
TransporterFacade::get_node_alive(NodeId n) const {

  const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n);
  return node.m_alive;
}

inline
void
TransporterFacade::hb_received(NodeId n) {
  theClusterMgr->hb_received(n);
}

inline
bool
TransporterFacade::get_node_stopping(NodeId n) const {
  const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n);
  return ((node.m_state.startLevel == NodeState::SL_STOPPING_1) ||
          (node.m_state.startLevel == NodeState::SL_STOPPING_2));
}

inline
bool
TransporterFacade::getIsNodeSendable(NodeId n) const {
  const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n);
  const Uint32 startLevel = node.m_state.startLevel;

  if (node.m_info.m_type == NodeInfo::DB) {
    if(node.m_state.singleUserMode &&
       ownId() == node.m_state.singleUserApi) {
      return (node.compatible &&
              (node.m_state.startLevel == NodeState::SL_STOPPING_1 ||
               node.m_state.startLevel == NodeState::SL_STARTED ||
               node.m_state.startLevel == NodeState::SL_SINGLEUSER));
      }
      else
        return node.compatible && (startLevel == NodeState::SL_STARTED ||
                                 startLevel == NodeState::SL_STOPPING_1);
  } else {
    ndbout_c("TransporterFacade::getIsNodeSendable: Illegal node type: "
             "%d of node: %d",
             node.m_info.m_type, n);
    abort();
    return false; // to remove compiler warning
  }
}

inline
Uint32
TransporterFacade::getNodeSequence(NodeId n) const {
  return theClusterMgr->getNodeInfo(n).m_info.m_connectCount;
}

inline
Uint32
TransporterFacade::get_scan_batch_size() {
  return m_scan_batch_size;
}

inline
Uint32
TransporterFacade::get_batch_byte_size() {
  return m_batch_byte_size;
}

inline
Uint32
TransporterFacade::get_batch_size() {
  return m_batch_size;
}

#endif // TransporterFacade_H
<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "Entity.h"

DC_BEGIN_DREEMCHEST

namespace Ecs {

// ** Entity::Entity
Entity::Entity( void ) : m_flags( 0 )
{

}

// ** Entity::setEcs
void Entity::setEcs( EcsWPtr value )
{
	m_ecs = value;
}

// ** Entity::ecs
EcsWPtr Entity::ecs( void ) const
{
	return m_ecs;
}

// ** Entity::setId
void Entity::setId( const EntityId& value )
{
	m_id = value;
}

// ** Entity::id
const EntityId& Entity::id( void ) const
{
	return m_id;
}

// ** Entity::isSerializable
bool Entity::isSerializable( void ) const
{
    return m_flags.is( Serializable );
}

// ** Entity::setSerializable
void Entity::setSerializable( bool value )
{
    m_flags.set( Serializable, value );
}

// ** Entity::mask
const Bitset& Entity::mask( void ) const
{
	return m_mask;
}

// ** Entity::components
const Entity::Components& Entity::components( void ) const
{
	return m_components;
}

// ** Entity::components
Entity::Components& Entity::components( void )
{
	return m_components;
}

// ** Entity::queueRemoval
void Entity::queueRemoval( void )
{
	m_ecs->removeEntity( m_id );
}

// ** Entity::markAsRemoved
void Entity::markAsRemoved( void )
{
	m_flags.on( Removed );
}

// ** Entity::flags
u8 Entity::flags( void ) const
{
	return m_flags;
}

// ** Entity::setFlags
void Entity::setFlags( u8 value )
{
	m_flags = value;
}

// ** Entity::updateComponentBit
void Entity::updateComponentBit( u32 bit, bool value )
{
	if( value ) {
		m_mask.set( bit );
	} else {
		m_mask.clear( bit );
	}

	if( m_ecs.valid() ) {
		m_ecs->notifyEntityChanged( m_id );
	}
}

#ifndef DC_ECS_NO_SERIALIZATION

// ** Entity::read
void Entity::read( const Io::Storage* storage )
{
	Io::KeyValue ar;
    ar.read( storage );

    SerializationContext ctx( ecs() );
    deserialize( ctx, ar );
}

// ** Entity::write
void Entity::write( Io::Storage* storage ) const
{
    SerializationContext ctx( ecs() );
    Io::KeyValue ar;

    serialize( ctx, ar );
	ar.write( storage );
}

// ** Entity::serialize
void Entity::serialize( SerializationContext& ctx, Io::KeyValue& ar ) const
{
	ar = Io::KeyValue::object();

	ar["Type"]  = typeName();
	ar["_id"]   = id().toString();
    ar["flags"] = static_cast<u8>( m_flags );

	const Components& items = components();

	for( Components::const_iterator i = items.begin(), end = items.end(); i != end; ++i ) {
		CString      key = i->second->typeName();
		Io::KeyValue component;

        i->second->serialize( ctx, component );

		if( component.isNull() ) {
			continue;
		}

		ar[key] = component;
	}
}

// ** Entity::deserialize
void Entity::deserialize( SerializationContext& ctx, const Io::KeyValue& ar )
{
	DC_BREAK_IF( ar.get( "Type", "" ).asString() != typeName() );

	Components& items = components();

    // Set flags
    m_flags = ar["flags"].asUByte();

	// Load all attached components
	for( Components::iterator i = items.begin(), end = items.end(); i != end; ++i ) {
		CString      key = i->second->typeName();
        i->second->deserialize( ctx, ar.get( key ) );
	}

	// Create components from key-value archive
	const Io::KeyValue::Properties& kv = ar.properties();

	for( Io::KeyValue::Properties::const_iterator i = kv.begin(); i != kv.end(); ++i ) {
		if( i->first == "Type" || i->first == "_id" || i->first == "flags" ) {
			continue;
		}

		bool hasComponent = false;

		for( Components::iterator j = items.begin(); j != items.end(); ++j ) {
			if( j->second->typeName() == i->first ) {
				hasComponent = true;
				break;
			}
		}

		if( hasComponent ) {
			continue;
		}

		if( i->second.isNull() ) {
			continue;
		}

		ComponentPtr component = ctx.createComponent( i->first );
        component->deserialize( ctx, i->second );
		attachComponent( component.get() );
	}
}

#endif  /*  !DC_ECS_NO_SERIALIZATION    */

} // namespace Ecs

DC_END_DREEMCHEST<commit_msg>Modified: entity id is serialized as Guid instead of String<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "Entity.h"

DC_BEGIN_DREEMCHEST

namespace Ecs {

// ** Entity::Entity
Entity::Entity( void ) : m_flags( 0 )
{

}

// ** Entity::setEcs
void Entity::setEcs( EcsWPtr value )
{
	m_ecs = value;
}

// ** Entity::ecs
EcsWPtr Entity::ecs( void ) const
{
	return m_ecs;
}

// ** Entity::setId
void Entity::setId( const EntityId& value )
{
	m_id = value;
}

// ** Entity::id
const EntityId& Entity::id( void ) const
{
	return m_id;
}

// ** Entity::isSerializable
bool Entity::isSerializable( void ) const
{
    return m_flags.is( Serializable );
}

// ** Entity::setSerializable
void Entity::setSerializable( bool value )
{
    m_flags.set( Serializable, value );
}

// ** Entity::mask
const Bitset& Entity::mask( void ) const
{
	return m_mask;
}

// ** Entity::components
const Entity::Components& Entity::components( void ) const
{
	return m_components;
}

// ** Entity::components
Entity::Components& Entity::components( void )
{
	return m_components;
}

// ** Entity::queueRemoval
void Entity::queueRemoval( void )
{
	m_ecs->removeEntity( m_id );
}

// ** Entity::markAsRemoved
void Entity::markAsRemoved( void )
{
	m_flags.on( Removed );
}

// ** Entity::flags
u8 Entity::flags( void ) const
{
	return m_flags;
}

// ** Entity::setFlags
void Entity::setFlags( u8 value )
{
	m_flags = value;
}

// ** Entity::updateComponentBit
void Entity::updateComponentBit( u32 bit, bool value )
{
	if( value ) {
		m_mask.set( bit );
	} else {
		m_mask.clear( bit );
	}

	if( m_ecs.valid() ) {
		m_ecs->notifyEntityChanged( m_id );
	}
}

#ifndef DC_ECS_NO_SERIALIZATION

// ** Entity::read
void Entity::read( const Io::Storage* storage )
{
	Io::KeyValue ar;
    ar.read( storage );

    SerializationContext ctx( ecs() );
    deserialize( ctx, ar );
}

// ** Entity::write
void Entity::write( Io::Storage* storage ) const
{
    SerializationContext ctx( ecs() );
    Io::KeyValue ar;

    serialize( ctx, ar );
	ar.write( storage );
}

// ** Entity::serialize
void Entity::serialize( SerializationContext& ctx, Io::KeyValue& ar ) const
{
	ar = Io::KeyValue::object();

	ar["Type"]  = typeName();
	ar["_id"]   = id()/*.toString()*/;
    ar["flags"] = static_cast<u8>( m_flags );

	const Components& items = components();

	for( Components::const_iterator i = items.begin(), end = items.end(); i != end; ++i ) {
		CString      key = i->second->typeName();
		Io::KeyValue component;

        i->second->serialize( ctx, component );

		if( component.isNull() ) {
			continue;
		}

		ar[key] = component;
	}
}

// ** Entity::deserialize
void Entity::deserialize( SerializationContext& ctx, const Io::KeyValue& ar )
{
	DC_BREAK_IF( ar.get( "Type", "" ).asString() != typeName() );

	Components& items = components();

    // Set flags
    m_flags = ar["flags"].asUByte();

	// Load all attached components
	for( Components::iterator i = items.begin(), end = items.end(); i != end; ++i ) {
		CString      key = i->second->typeName();
        i->second->deserialize( ctx, ar.get( key ) );
	}

	// Create components from key-value archive
	const Io::KeyValue::Properties& kv = ar.properties();

	for( Io::KeyValue::Properties::const_iterator i = kv.begin(); i != kv.end(); ++i ) {
		if( i->first == "Type" || i->first == "_id" || i->first == "flags" ) {
			continue;
		}

		bool hasComponent = false;

		for( Components::iterator j = items.begin(); j != items.end(); ++j ) {
			if( j->second->typeName() == i->first ) {
				hasComponent = true;
				break;
			}
		}

		if( hasComponent ) {
			continue;
		}

		if( i->second.isNull() ) {
			continue;
		}

		ComponentPtr component = ctx.createComponent( i->first );
        component->deserialize( ctx, i->second );
		attachComponent( component.get() );
	}
}

#endif  /*  !DC_ECS_NO_SERIALIZATION    */

} // namespace Ecs

DC_END_DREEMCHEST<|endoftext|>


<commit_before>/* Copyright (c) 2012-present Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"

/*!
 * \file commandQueue.cpp
 * \brief  Definitions for HostQueue object.
 *
 * \author Laurent Morichetti
 * \date   October 2008
 */

namespace amd {

HostQueue::HostQueue(Context& context, Device& device, cl_command_queue_properties properties,
                     uint queueRTCUs, Priority priority, const std::vector<uint32_t>& cuMask)
    : CommandQueue(context, device, properties, device.info().queueProperties_, queueRTCUs,
                   priority, cuMask),
      lastEnqueueCommand_(nullptr),
      head_(nullptr),
      tail_(nullptr) {
  if (AMD_DIRECT_DISPATCH) {
    // Initialize the queue
    thread_.Init(this);
  } else {
    if (thread_.state() >= Thread::INITIALIZED) {
      ScopedLock sl(queueLock_);
      thread_.start(this);
      queueLock_.wait();
    }
  }
}

bool HostQueue::terminate() {
  if (AMD_DIRECT_DISPATCH) {
    thread_.Release();
  } else {
    if (Os::isThreadAlive(thread_)) {
      Command* marker = nullptr;

      // Send a finish if the queue is still accepting commands.
      {
        ScopedLock sl(queueLock_);
        if (thread_.acceptingCommands_) {
          marker = new Marker(*this, false);
          if (marker != nullptr) {
            append(*marker);
            queueLock_.notify();
          }
        }
      }
      if (marker != nullptr) {
        marker->awaitCompletion();
        marker->release();
      }

      // Wake-up the command loop, so it can exit
      {
        ScopedLock sl(queueLock_);
        thread_.acceptingCommands_ = false;
        queueLock_.notify();
      }

      // FIXME_lmoriche: fix termination handshake
      while (thread_.state() < Thread::FINISHED) {
        Os::yield();
      }
    }
  }

  if (Agent::shouldPostCommandQueueEvents()) {
    Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
  }

  return true;
}

void HostQueue::finish() {
  Command* command = nullptr;
  if (IS_HIP) {
    command = getLastQueuedCommand(true);
    if (nullptr != command) {
      command->awaitCompletion();
      command->release();
    }
  }
  if (nullptr == command) {
    // Send a finish to make sure we finished all commands
    command = new Marker(*this, false);
    if (command == NULL) {
      return;
    }
    ClPrint(LOG_DEBUG, LOG_CMD, "marker is queued");
    command->enqueue();
    command->awaitCompletion();
    command->release();
  }
  ClPrint(LOG_DEBUG, LOG_CMD, "All commands finished");
}

void HostQueue::loop(device::VirtualDevice* virtualDevice) {
  // Notify the caller that the queue is ready to accept commands.
  {
    ScopedLock sl(queueLock_);
    thread_.acceptingCommands_ = true;
    queueLock_.notify();
  }
  // Create a command batch with all the commands present in the queue.
  Command* head = NULL;
  Command* tail = NULL;
  while (true) {
    // Get one command from the queue
    Command* command = queue_.dequeue();
    if (command == NULL) {
      ScopedLock sl(queueLock_);
      while ((command = queue_.dequeue()) == NULL) {
        if (!thread_.acceptingCommands_) {
          return;
        }
        queueLock_.wait();
      }
    }

    command->retain();

    // Process the command's event wait list.
    const Command::EventWaitList& events = command->eventWaitList();
    bool dependencyFailed = false;

    for (const auto& it : events) {
      // Only wait if the command is enqueued into another queue.
      if (it->command().queue() != this) {
        // Runtime has to flush the current batch only if the dependent wait is blocking
        if (it->command().status() != CL_COMPLETE) {
          virtualDevice->flush(head, true);
          tail = head = NULL;
          dependencyFailed |= !it->awaitCompletion();
        }
      }
    }

    // Insert the command to the linked list.
    if (NULL == head) {  // if the list is empty
      head = tail = command;
    } else {
      tail->setNext(command);
      tail = command;
    }

    if (dependencyFailed) {
      command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
      continue;
    }

    ClPrint(LOG_DEBUG, LOG_CMD, "command (%s) is submitted: %p", getOclCommandKindString(command->type()), command);

    command->setStatus(CL_SUBMITTED);

    // Submit to the device queue.
    command->submit(*virtualDevice);

    // if this is a user invisible marker command, then flush
    if (0 == command->type()) {
      virtualDevice->flush(head);
      tail = head = NULL;
    }
  }  // while (true) {
}

void HostQueue::append(Command& command) {
  // We retain the command here. It will be released when its status
  // changes to CL_COMPLETE
  if ((command.getWaitBits() & 0x1) != 0) {
    finish();
  }
  command.retain();
  command.setStatus(CL_QUEUED);
  queue_.enqueue(&command);
  if (!IS_HIP) {
    return;
  }
  // Set last submitted command
  Command* prevLastEnqueueCommand;
  command.retain();
  {
    // lastCmdLock_ ensures that lastEnqueueCommand() can retain the command before it is swapped
    // out. We want to keep this critical section as short as possible, so the command should be
    // released outside this section.
    ScopedLock l(lastCmdLock_);

    prevLastEnqueueCommand = lastEnqueueCommand_;
    lastEnqueueCommand_ = &command;
  }

  if (prevLastEnqueueCommand != nullptr) {
    prevLastEnqueueCommand->release();
  }
}

bool HostQueue::isEmpty() {
  // Get a snapshot of queue size
  return queue_.empty();
}

Command* HostQueue::getLastQueuedCommand(bool retain) {
  if (AMD_DIRECT_DISPATCH) {
    // The batch update must be lock protected to avoid a race condition
    // when multiple threads submit/flush/update the batch at the same time
    ScopedLock sl(lock());

    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
  } else {
    // Get last submitted command
    ScopedLock l(lastCmdLock_);

    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
  }

  return lastEnqueueCommand_;
}

DeviceQueue::~DeviceQueue() {
  delete virtualDevice_;
  ScopedLock lock(context().lock());
  context().removeDeviceQueue(device(), this);
}

bool DeviceQueue::create() {
  static const bool InteropQueue = true;
  const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
  bool result = false;

  virtualDevice_ = device().createVirtualDevice(this);
  if (virtualDevice_ != NULL) {
    result = true;
    context().addDeviceQueue(device(), this, defaultDeviceQueue);
  }

  return result;
}

}  // namespace amd
<commit_msg>Move returned last command under the lock<commit_after>/* Copyright (c) 2012-present Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"

/*!
 * \file commandQueue.cpp
 * \brief  Definitions for HostQueue object.
 *
 * \author Laurent Morichetti
 * \date   October 2008
 */

namespace amd {

HostQueue::HostQueue(Context& context, Device& device, cl_command_queue_properties properties,
                     uint queueRTCUs, Priority priority, const std::vector<uint32_t>& cuMask)
    : CommandQueue(context, device, properties, device.info().queueProperties_, queueRTCUs,
                   priority, cuMask),
      lastEnqueueCommand_(nullptr),
      head_(nullptr),
      tail_(nullptr) {
  if (AMD_DIRECT_DISPATCH) {
    // Initialize the queue
    thread_.Init(this);
  } else {
    if (thread_.state() >= Thread::INITIALIZED) {
      ScopedLock sl(queueLock_);
      thread_.start(this);
      queueLock_.wait();
    }
  }
}

bool HostQueue::terminate() {
  if (AMD_DIRECT_DISPATCH) {
    thread_.Release();
  } else {
    if (Os::isThreadAlive(thread_)) {
      Command* marker = nullptr;

      // Send a finish if the queue is still accepting commands.
      {
        ScopedLock sl(queueLock_);
        if (thread_.acceptingCommands_) {
          marker = new Marker(*this, false);
          if (marker != nullptr) {
            append(*marker);
            queueLock_.notify();
          }
        }
      }
      if (marker != nullptr) {
        marker->awaitCompletion();
        marker->release();
      }

      // Wake-up the command loop, so it can exit
      {
        ScopedLock sl(queueLock_);
        thread_.acceptingCommands_ = false;
        queueLock_.notify();
      }

      // FIXME_lmoriche: fix termination handshake
      while (thread_.state() < Thread::FINISHED) {
        Os::yield();
      }
    }
  }

  if (Agent::shouldPostCommandQueueEvents()) {
    Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
  }

  return true;
}

void HostQueue::finish() {
  Command* command = nullptr;
  if (IS_HIP) {
    command = getLastQueuedCommand(true);
    if (nullptr != command) {
      command->awaitCompletion();
      command->release();
    }
  }
  if (nullptr == command) {
    // Send a finish to make sure we finished all commands
    command = new Marker(*this, false);
    if (command == NULL) {
      return;
    }
    ClPrint(LOG_DEBUG, LOG_CMD, "marker is queued");
    command->enqueue();
    command->awaitCompletion();
    command->release();
  }
  ClPrint(LOG_DEBUG, LOG_CMD, "All commands finished");
}

void HostQueue::loop(device::VirtualDevice* virtualDevice) {
  // Notify the caller that the queue is ready to accept commands.
  {
    ScopedLock sl(queueLock_);
    thread_.acceptingCommands_ = true;
    queueLock_.notify();
  }
  // Create a command batch with all the commands present in the queue.
  Command* head = NULL;
  Command* tail = NULL;
  while (true) {
    // Get one command from the queue
    Command* command = queue_.dequeue();
    if (command == NULL) {
      ScopedLock sl(queueLock_);
      while ((command = queue_.dequeue()) == NULL) {
        if (!thread_.acceptingCommands_) {
          return;
        }
        queueLock_.wait();
      }
    }

    command->retain();

    // Process the command's event wait list.
    const Command::EventWaitList& events = command->eventWaitList();
    bool dependencyFailed = false;

    for (const auto& it : events) {
      // Only wait if the command is enqueued into another queue.
      if (it->command().queue() != this) {
        // Runtime has to flush the current batch only if the dependent wait is blocking
        if (it->command().status() != CL_COMPLETE) {
          virtualDevice->flush(head, true);
          tail = head = NULL;
          dependencyFailed |= !it->awaitCompletion();
        }
      }
    }

    // Insert the command to the linked list.
    if (NULL == head) {  // if the list is empty
      head = tail = command;
    } else {
      tail->setNext(command);
      tail = command;
    }

    if (dependencyFailed) {
      command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
      continue;
    }

    ClPrint(LOG_DEBUG, LOG_CMD, "command (%s) is submitted: %p", getOclCommandKindString(command->type()), command);

    command->setStatus(CL_SUBMITTED);

    // Submit to the device queue.
    command->submit(*virtualDevice);

    // if this is a user invisible marker command, then flush
    if (0 == command->type()) {
      virtualDevice->flush(head);
      tail = head = NULL;
    }
  }  // while (true) {
}

void HostQueue::append(Command& command) {
  // We retain the command here. It will be released when its status
  // changes to CL_COMPLETE
  if ((command.getWaitBits() & 0x1) != 0) {
    finish();
  }
  command.retain();
  command.setStatus(CL_QUEUED);
  queue_.enqueue(&command);
  if (!IS_HIP) {
    return;
  }
  // Set last submitted command
  Command* prevLastEnqueueCommand;
  command.retain();
  {
    // lastCmdLock_ ensures that lastEnqueueCommand() can retain the command before it is swapped
    // out. We want to keep this critical section as short as possible, so the command should be
    // released outside this section.
    ScopedLock l(lastCmdLock_);

    prevLastEnqueueCommand = lastEnqueueCommand_;
    lastEnqueueCommand_ = &command;
  }

  if (prevLastEnqueueCommand != nullptr) {
    prevLastEnqueueCommand->release();
  }
}

bool HostQueue::isEmpty() {
  // Get a snapshot of queue size
  return queue_.empty();
}

Command* HostQueue::getLastQueuedCommand(bool retain) {
  if (AMD_DIRECT_DISPATCH) {
    // The batch update must be lock protected to avoid a race condition
    // when multiple threads submit/flush/update the batch at the same time
    ScopedLock sl(lock());

    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
    return lastEnqueueCommand_;
  } else {
    // Get last submitted command
    ScopedLock l(lastCmdLock_);

    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
    return lastEnqueueCommand_;
  }
}

DeviceQueue::~DeviceQueue() {
  delete virtualDevice_;
  ScopedLock lock(context().lock());
  context().removeDeviceQueue(device(), this);
}

bool DeviceQueue::create() {
  static const bool InteropQueue = true;
  const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
  bool result = false;

  virtualDevice_ = device().createVirtualDevice(this);
  if (virtualDevice_ != NULL) {
    result = true;
    context().addDeviceQueue(device(), this, defaultDeviceQueue);
  }

  return result;
}

}  // namespace amd
<|endoftext|>