<commit_before>#pragma once

#include <string>
#include <functional>
#include <cmath>
#include <random>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <utility>
#include "tbb/parallel_sort.h"
#include "tbb/parallel_for_each.h"
#include "tbb/mutex.h"
#include "tbb/pipeline.h"
#include "util.hpp"
#include "point.hpp"

#define VALUE(x) std::cout << #x "=" << x << std::endl

namespace psh
{
	template<uint d, class T>
	class map
	{
		static_assert(d > 0, "d must be larger than 0.");
	public:
		struct data_t
		{
			point<d> location;
			T contents;
		};

		struct bucket : public std::vector<data_t>
		{
			uint phi_index;

			bucket(uint phi_index) : phi_index(phi_index) { }
			friend bool operator<(const bucket& lhs, const bucket& rhs) {
				return lhs.size() > rhs.size();
			}
		};

		struct entry
		{
			uint k;
			uint hk;
			T contents;

			entry() : k(1), hk(1), contents(T()) { };
			entry(const data_t& data, uint M2) : k(1), contents(data.contents)
			{
				rehash(data, M2);
			}

			static constexpr uint h(const point<d>& p, uint M2, uint k)
			{
				return p * point<d>::increasing_pow(k) * M2;
			}

			void rehash(const point<d>& location, uint M2, uint new_k = 1)
			{
				k = new_k;
				hk = h(location, M2, k);
			}

			void rehash(const data_t& data, uint M2, uint new_k = 1)
			{
				rehash(data.location, M2, new_k);
			}

			constexpr bool equals(const point<d>& p, uint M2) const
			{
				return hk == h(p, M2, k);
			}
		};

		struct entry_large : public entry
		{
			point<d> location;
			entry_large() : entry(), location(point<d>()) { };
			entry_large(const data_t& data, uint M2)
				: entry(data, M2), location(data.location) { };
			void rehash(uint M2) { entry::rehash(location, M2, entry::k + 1); };
		};

		uint M0;
		uint M1;
		uint M2;
		uint n;
		uint m_bar;
		uint m;
		uint r_bar;
		uint r;
		std::vector<point<d>> phi;
		std::vector<entry> H;
		std::default_random_engine generator;

		map(const std::vector<data_t>& data, const point<d>& domain_size)
			: n(data.size()), m_bar(std::ceil(std::pow(n, 1.0f / d))), m(std::pow(m_bar, d)),
			  r_bar(std::ceil(std::pow(n / d, 1.0f / d)) - 1), generator(time(0))
		{
			M0 = prime();
			while ((M1 = prime()) == M0);
			M2 = prime();

			VALUE(m);
			VALUE(m_bar);

			VALUE(M0);
			VALUE(M1);
			VALUE(M2);

			bool create_succeeded = false;

			std::uniform_int_distribution<uint> m_dist(0, m - 1);

			do
			{
				r_bar += d;
				r = std::pow(r_bar, d);
				VALUE(r);
				VALUE(r_bar);

				create_succeeded = create(data, domain_size, m_dist);

			} while (!create_succeeded);
		}

		uint prime()
		{
			static const std::vector<uint> primes{ 53, 97, 193, 389, 769, 1543, 3079,
				6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869,
				3145739, 6291469 };
			static std::uniform_int_distribution<uint> prime_dist(0, primes.size() - 1);

			return primes[prime_dist(generator)];
		}

		bool bad_m_r()
		{
			auto m_mod_r = m_bar % r_bar;
			return m_mod_r == 1 || m_mod_r == r - 1;
		}

		void insert(const bucket& b, std::vector<entry_large>& H_hat, std::vector<bool>& H_b_hat,
			const decltype(phi)& phi_hat)
		{
			for (auto& element : b)
			{
				auto hashed = h(element.location, phi_hat);
				auto i = point_to_index<d>(hashed, m_bar, m);
				H_hat[i] = entry_large(element, M2);
				H_b_hat[i] = true;
			}
		}

		bool jiggle_offsets(std::vector<entry_large>& H_hat, std::vector<bool>& H_b_hat,
			decltype(phi)& phi_hat, const bucket& b,
			std::uniform_int_distribution<uint>& m_dist)
		{
			uint start_offset = m_dist(generator);

			bool found = false;
			point<d> found_offset;
			tbb::mutex mutex;

			uint chunk_index = 0;
			const uint num_cores = 8;
			const uint group_size = r / num_cores + 1;

			tbb::parallel_pipeline(num_cores,
				tbb::make_filter<void, uint>(tbb::filter::serial,
					[&, group_size](tbb::flow_control& fc) {
						if (found || chunk_index >= r)
						{
							fc.stop();
						}
						chunk_index += group_size;
						return chunk_index;
					}) &
				tbb::make_filter<uint, void>(tbb::filter::parallel,
					[&, group_size](uint i0)
					{
						for (uint i = i0; i < i0 + group_size && !found; i++)
						{
							auto phi_offset = index_to_point<d>((start_offset + i) % m, m_bar, m);

							bool collision = false;
							for (auto& element : b)
							{
								auto h0 = M0 * element.location;
								auto h1 = M1 * element.location;
								auto index = point_to_index<d>(h1, r_bar, r);
								auto offset = index == b.phi_index ? phi_offset : phi_hat[index];
								auto hash = h0 + offset;

								collision = H_b_hat[point_to_index<d>(hash, m_bar, m)];
								if (collision)
									break;
							}

							if (!collision)
							{
								tbb::mutex::scoped_lock lock(mutex);
								if (!found)
								{
									found = true;
									found_offset = phi_offset;
								}
							}
						}
					})
				);
			if (found)
			{
				phi_hat[b.phi_index] = found_offset;
				insert(b, H_hat, H_b_hat, phi_hat);
				return true;
			}
			return false;
		}

		std::vector<bucket> create_buckets(const std::vector<data_t>& data)
		{
			std::vector<bucket> buckets;
			buckets.reserve(r);
			{
				uint i = 0;
				std::generate_n(std::back_inserter(buckets), r, [&] {
						return bucket(i++);
					});
			}

			for (auto& element : data)
			{
				auto h1 = M1 * element.location;
				buckets[point_to_index<d>(h1, r_bar, r)].push_back(element);
			}

			std::cout << "buckets created" << std::endl;

			tbb::parallel_sort(buckets.begin(), buckets.end());
			std::cout << "buckets sorted" << std::endl;

			return buckets;
		}

		bool create(const std::vector<data_t>& data, const point<d>& domain_size,
			std::uniform_int_distribution<uint>& m_dist)
		{
			decltype(phi) phi_hat(r);
			std::vector<entry_large> H_hat(m);
			std::vector<bool> H_b_hat(m, false);
			std::cout << "creating " << r << " buckets" << std::endl;

			if (bad_m_r())
				return false;

			auto buckets = create_buckets(data);
			std::cout << "jiggling offsets" << std::endl;

			for (uint i = 0; i < buckets.size(); i++)
			{
				if (buckets[i].size() == 0)
					break;
				if (i % (buckets.size() / 10) == 0)
					std::cout << (100 * i) / buckets.size() << "% done" << std::endl;

				if (!jiggle_offsets(H_hat, H_b_hat, phi_hat, buckets[i], m_dist))
				{
					return false;
				}
			}

			std::cout << "done!" << std::endl;
			phi = std::move(phi_hat);
			hash_positions(data, domain_size, H_hat);
			std::copy(H_hat.begin(), H_hat.end(), std::back_inserter(H));

			return true;
		}

		void hash_positions(const std::vector<data_t>& data, const point<d>& domain_size,
			std::vector<entry_large>& H_hat)
		{
			// domain_size - 1 to get the highest indices in each direction
			// width is assumed to be equal in all directions
			// we don't expect it to roll over so we mod by the maximum uint, -1
			// and then add 1 to get the size, not the index
			uint domain_i_max = point_to_index<d>(domain_size - 1, domain_size[0],
				uint(-1)) + 1;
			std::vector<bool> indices(m);
			{
				uint j = 0;
				uint k = point_to_index<d>(data[j].location, domain_size[0], uint(-1));

				// first sweep
				for (uint i = 0; i < domain_i_max; i++)
				{
					if (k == i)
					{
						j++;
						k = point_to_index<d>(data[j].location, domain_size[0], uint(-1));
						continue;
					}
					// for each point p in original image which is empty

					auto p = index_to_point<d>(i, domain_size[0], uint(-1));
					uint l = point_to_index<d>(h(p), m_bar, m);
					if (H_hat[l].hk == entry::h(p, M2, 1))
					{
						//     if (get(p).hk == p.hk)
						//         indices.add(p)
						indices[l] = true;
					}
				}
				std::cout << "data size: " << data.size() << std::endl;
				std::cout << "indices size: " << indices.size() << std::endl;
			}

			std::unordered_map<uint, std::vector<uint>> collisions;
			{
				// second sweep
				for (uint i = 0; i < domain_i_max; i++)
				{
					// for each point p in original image

					auto p = index_to_point<d>(i, domain_size[0], uint(-1));
					uint l = point_to_index<d>(h(p), m_bar, m);
					// it's like collect everyone that maps to the same thing
					if (indices[l])
					{
						collisions[l].push_back(i);
					}
				}
			}

			// third sweep
			tbb::parallel_for_each(collisions.begin(), collisions.end(),
				[&](const decltype(collisions)::value_type& kvp)
				{
					fix_k(H_hat[kvp.first], kvp.first, kvp.second, domain_size);
				});
		}

		void fix_k(entry_large& H_entry, uint l, const std::vector<uint>& collisions,
			const point<d>& domain_size)
		{
			// l == location in H
			H_entry.rehash(M2);

			bool success = true;
			for (uint i : collisions)
			{
				// i == index in U, does not exist in input data
				// if one of these have the same hk as H_entry
				// break, success = false, call the po-po
				auto p = index_to_point<d>(i, domain_size[0], uint(-1));
				uint hk = entry::h(p, M2, H_entry.k);
				if (H_entry.location != p && H_entry.hk == hk)
				{
					success = false;
					break;
				}
			}
			if (!success)
				fix_k(H_entry, l, collisions, domain_size);
		}

		point<d> h(const point<d>& p, const decltype(phi)& phi_hat) const
		{
			auto h0 = M0 * p;
			auto h1 = M1 * p;
			auto i = point_to_index<d>(h1, r_bar, r);
			auto offset = phi_hat[i];
			return h0 + offset;
		}

		point<d> h(const point<d>& p) const
		{
			return h(p, phi);
		}

		T get(const point<d>& p) const
		{
			auto i = point_to_index<d>(h(p), m_bar, m);
			if (H[i].equals(p, M2))
				return H[i].contents;
			else
				throw std::out_of_range("Element not found in map");
		}

		uint memory_size() const
		{
			return sizeof(*this)
				+ sizeof(typename decltype(phi)::value_type) * phi.capacity()
				+ sizeof(typename decltype(H)::value_type) * H.capacity();
		}
	};
}<commit_msg>parallelized the first and second sweeps in 'hash_positions'<commit_after>#pragma once

#include <string>
#include <functional>
#include <cmath>
#include <random>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <utility>
#include "tbb/parallel_sort.h"
#include "tbb/parallel_for.h"
#include "tbb/parallel_for_each.h"
#include "tbb/mutex.h"
#include "tbb/pipeline.h"
#include "util.hpp"
#include "point.hpp"

#define VALUE(x) std::cout << #x "=" << x << std::endl

namespace psh
{
	template<uint d, class T>
	class map
	{
		static_assert(d > 0, "d must be larger than 0.");
	public:
		struct data_t
		{
			point<d> location;
			T contents;
		};

		struct bucket : public std::vector<data_t>
		{
			uint phi_index;

			bucket(uint phi_index) : phi_index(phi_index) { }
			friend bool operator<(const bucket& lhs, const bucket& rhs) {
				return lhs.size() > rhs.size();
			}
		};

		struct entry
		{
			uint k;
			uint hk;
			T contents;

			entry() : k(1), hk(1), contents(T()) { };
			entry(const data_t& data, uint M2) : k(1), contents(data.contents)
			{
				rehash(data, M2);
			}

			static constexpr uint h(const point<d>& p, uint M2, uint k)
			{
				return p * point<d>::increasing_pow(k) * M2;
			}

			void rehash(const point<d>& location, uint M2, uint new_k = 1)
			{
				k = new_k;
				hk = h(location, M2, k);
			}

			void rehash(const data_t& data, uint M2, uint new_k = 1)
			{
				rehash(data.location, M2, new_k);
			}

			constexpr bool equals(const point<d>& p, uint M2) const
			{
				return hk == h(p, M2, k);
			}
		};

		struct entry_large : public entry
		{
			point<d> location;
			entry_large() : entry(), location(point<d>()) { };
			entry_large(const data_t& data, uint M2)
				: entry(data, M2), location(data.location) { };
			void rehash(uint M2) { entry::rehash(location, M2, entry::k + 1); };
		};

		uint M0;
		uint M1;
		uint M2;
		uint n;
		uint m_bar;
		uint m;
		uint r_bar;
		uint r;
		std::vector<point<d>> phi;
		std::vector<entry> H;
		std::default_random_engine generator;

		map(const std::vector<data_t>& data, const point<d>& domain_size)
			: n(data.size()), m_bar(std::ceil(std::pow(n, 1.0f / d))), m(std::pow(m_bar, d)),
			  r_bar(std::ceil(std::pow(n / d, 1.0f / d)) - 1), generator(time(0))
		{
			M0 = prime();
			while ((M1 = prime()) == M0);
			M2 = prime();

			VALUE(m);
			VALUE(m_bar);

			VALUE(M0);
			VALUE(M1);
			VALUE(M2);

			bool create_succeeded = false;

			std::uniform_int_distribution<uint> m_dist(0, m - 1);

			do
			{
				r_bar += d;
				r = std::pow(r_bar, d);
				VALUE(r);
				VALUE(r_bar);

				create_succeeded = create(data, domain_size, m_dist);

			} while (!create_succeeded);
		}

		uint prime()
		{
			static const std::vector<uint> primes{ 53, 97, 193, 389, 769, 1543, 3079,
				6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869,
				3145739, 6291469 };
			static std::uniform_int_distribution<uint> prime_dist(0, primes.size() - 1);

			return primes[prime_dist(generator)];
		}

		bool bad_m_r()
		{
			auto m_mod_r = m_bar % r_bar;
			return m_mod_r == 1 || m_mod_r == r - 1;
		}

		void insert(const bucket& b, std::vector<entry_large>& H_hat, std::vector<bool>& H_b_hat,
			const decltype(phi)& phi_hat)
		{
			for (auto& element : b)
			{
				auto hashed = h(element.location, phi_hat);
				auto i = point_to_index<d>(hashed, m_bar, m);
				H_hat[i] = entry_large(element, M2);
				H_b_hat[i] = true;
			}
		}

		bool jiggle_offsets(std::vector<entry_large>& H_hat, std::vector<bool>& H_b_hat,
			decltype(phi)& phi_hat, const bucket& b,
			std::uniform_int_distribution<uint>& m_dist)
		{
			uint start_offset = m_dist(generator);

			bool found = false;
			point<d> found_offset;
			tbb::mutex mutex;

			uint chunk_index = 0;
			const uint num_cores = 8;
			const uint group_size = r / num_cores + 1;

			tbb::parallel_pipeline(num_cores,
				tbb::make_filter<void, uint>(tbb::filter::serial,
					[&, group_size](tbb::flow_control& fc) {
						if (found || chunk_index >= r)
						{
							fc.stop();
						}
						chunk_index += group_size;
						return chunk_index;
					}) &
				tbb::make_filter<uint, void>(tbb::filter::parallel,
					[&, group_size](uint i0)
					{
						for (uint i = i0; i < i0 + group_size && !found; i++)
						{
							auto phi_offset = index_to_point<d>((start_offset + i) % m, m_bar, m);

							bool collision = false;
							for (auto& element : b)
							{
								auto h0 = M0 * element.location;
								auto h1 = M1 * element.location;
								auto index = point_to_index<d>(h1, r_bar, r);
								auto offset = index == b.phi_index ? phi_offset : phi_hat[index];
								auto hash = h0 + offset;

								collision = H_b_hat[point_to_index<d>(hash, m_bar, m)];
								if (collision)
									break;
							}

							if (!collision)
							{
								tbb::mutex::scoped_lock lock(mutex);
								if (!found)
								{
									found = true;
									found_offset = phi_offset;
								}
							}
						}
					})
				);
			if (found)
			{
				phi_hat[b.phi_index] = found_offset;
				insert(b, H_hat, H_b_hat, phi_hat);
				return true;
			}
			return false;
		}

		std::vector<bucket> create_buckets(const std::vector<data_t>& data)
		{
			std::vector<bucket> buckets;
			buckets.reserve(r);
			{
				uint i = 0;
				std::generate_n(std::back_inserter(buckets), r, [&] {
						return bucket(i++);
					});
			}

			for (auto& element : data)
			{
				auto h1 = M1 * element.location;
				buckets[point_to_index<d>(h1, r_bar, r)].push_back(element);
			}

			std::cout << "buckets created" << std::endl;

			tbb::parallel_sort(buckets.begin(), buckets.end());
			std::cout << "buckets sorted" << std::endl;

			return buckets;
		}

		bool create(const std::vector<data_t>& data, const point<d>& domain_size,
			std::uniform_int_distribution<uint>& m_dist)
		{
			decltype(phi) phi_hat(r);
			std::vector<entry_large> H_hat(m);
			std::vector<bool> H_b_hat(m, false);
			std::cout << "creating " << r << " buckets" << std::endl;

			if (bad_m_r())
				return false;

			auto buckets = create_buckets(data);
			std::cout << "jiggling offsets" << std::endl;

			for (uint i = 0; i < buckets.size(); i++)
			{
				if (buckets[i].size() == 0)
					break;
				if (i % (buckets.size() / 10) == 0)
					std::cout << (100 * i) / buckets.size() << "% done" << std::endl;

				if (!jiggle_offsets(H_hat, H_b_hat, phi_hat, buckets[i], m_dist))
				{
					return false;
				}
			}

			std::cout << "done!" << std::endl;
			phi = std::move(phi_hat);
			hash_positions(data, domain_size, H_hat);
			std::copy(H_hat.begin(), H_hat.end(), std::back_inserter(H));

			return true;
		}

		void hash_positions(const std::vector<data_t>& data, const point<d>& domain_size,
			std::vector<entry_large>& H_hat)
		{
			// domain_size - 1 to get the highest indices in each direction
			// width is assumed to be equal in all directions
			// we don't expect it to roll over so we mod by the maximum uint, -1
			// and then add 1 to get the size, not the index
			uint domain_i_max = point_to_index<d>(domain_size - 1, domain_size[0],
				uint(-1)) + 1;

			tbb::mutex mutex;

			std::vector<bool> indices(m, false);
			{
				std::vector<bool> data_b(domain_i_max);
				for (uint i = 0; i < data.size(); i++)
				{
					data_b[point_to_index<d>(data[i].location, domain_size[0], uint(-1))] = true;
				}
				// first sweep
				tbb::parallel_for(uint(0), domain_i_max, [&](uint i)
					{
						// for each point p in original image which is empty
						if (data_b[i])
						{
							return;
						}

						auto p = index_to_point<d>(i, domain_size[0], uint(-1));
						uint l = point_to_index<d>(h(p), m_bar, m);

						if (H_hat[l].hk == entry::h(p, M2, 1))
						{
							// if (get(p).hk == p.hk)
							//     indices.add(p)
							indices[l] = true;
						}
					});
				std::cout << "data size: " << data.size() << std::endl;
				std::cout << "indices size: " << indices.size() << std::endl;
			}

			std::unordered_map<uint, std::vector<uint>> collisions;
			// second sweep
			tbb::parallel_for(uint(0), domain_i_max, [&](uint i)
				{
					// for each point p in original image

					auto p = index_to_point<d>(i, domain_size[0], uint(-1));
					uint l = point_to_index<d>(h(p), m_bar, m);

					// collect everyone that maps to the same thing
					if (indices[l])
					{
						tbb::mutex::scoped_lock lock(mutex);
						collisions[l].push_back(i);
					}
				});

			// third sweep
			tbb::parallel_for_each(collisions.begin(), collisions.end(),
				[&](const decltype(collisions)::value_type& kvp)
				{
					fix_k(H_hat[kvp.first], kvp.first, kvp.second, domain_size);
				});
		}

		void fix_k(entry_large& H_entry, uint l, const std::vector<uint>& collisions,
			const point<d>& domain_size)
		{
			// l == location in H
			H_entry.rehash(M2);

			bool success = true;
			for (uint i : collisions)
			{
				// i == index in U, does not exist in input data
				// if one of these have the same hk as H_entry
				// break, success = false, call the po-po
				auto p = index_to_point<d>(i, domain_size[0], uint(-1));
				uint hk = entry::h(p, M2, H_entry.k);
				if (H_entry.location != p && H_entry.hk == hk)
				{
					success = false;
					break;
				}
			}
			if (!success)
				fix_k(H_entry, l, collisions, domain_size);
		}

		point<d> h(const point<d>& p, const decltype(phi)& phi_hat) const
		{
			auto h0 = M0 * p;
			auto h1 = M1 * p;
			auto i = point_to_index<d>(h1, r_bar, r);
			auto offset = phi_hat[i];
			return h0 + offset;
		}

		point<d> h(const point<d>& p) const
		{
			return h(p, phi);
		}

		T get(const point<d>& p) const
		{
			auto i = point_to_index<d>(h(p), m_bar, m);
			if (H[i].equals(p, M2))
				return H[i].contents;
			else
				throw std::out_of_range("Element not found in map");
		}

		uint memory_size() const
		{
			return sizeof(*this)
				+ sizeof(typename decltype(phi)::value_type) * phi.capacity()
				+ sizeof(typename decltype(H)::value_type) * H.capacity();
		}
	};
}<|endoftext|>


<commit_before>// $Id$
/**
 * @file extract-ddlraw.C
 * @brief Tool to extract DDL raw data.
 *
 * Usage:
 *

 *   aliroot -b -q 'extract-ddlraw.C("raw.root", 768, 769)' | tee extract-ddlraw.log
 *

 *
 * This macro is an example for the AliHLTRawReaderPublisherComponent.
 * It extracts the DDL payload from an AliRawReader in a given equipment
 * range. Input can be either a root file or the path to the directory
 * containing the 'rawx' sub folders.
 *
 * A light-weight AliReconstruction-like setup creates the appropriate
 * RawReader for the specified input and uses the standard AliHLTReconstructor
 * to run a small HLT chain. The chain utilizes the AliRawReaderPublisher
 * to extract the payload of the equipments and writes this to files.
 *
 * @note In this example the AliHLTRawReaderPublisherComponent does not set any data
 * type nor specification for the published data blocks. Please remember
 * to provide appropriate arguments via '-datatype' and '-dataspec'
 * arguments (see AliHLTRawReaderPublisherComponent).
 *
 * @author Matthias.Richter@ift.uib.no
 * @ingroup alihlt_tutorial
 */
void extract_ddlraw(const char* input, int iMinDDLno, int iMaxDDLno)
{
  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // some defaults
  const char* baseName="RAW.ddl";

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // setup of the RawReader
  if (!input) {
    cerr << "invalid path" << endl;
    cerr << "usage: aliroot -b -q 'extract-ddlraw.C(\"raw.root\", 768, 769)'" << endl;
    return;
  }

  AliRawReader* pRawReader=AliRawReader::Create(input);
  if (!pRawReader) {
    cout << "can not open RawReader for file " << input << endl;
    return;
  }
  if (!pRawReader->NextEvent()) {
    cerr << "no events available" << endl;
    return;
  }

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // setup of the HLT system
  AliHLTSystem* pHLT=AliHLTPluginBase::GetInstance();
  if (!pHLT) {
    cerr << "fatal error: can not get HLT instance" << endl;
  }

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // the configuration chain
  // we show two possible configurations:
  //  1. having one publisher for each ddl, the configurations are created
  //     in a loop
  //  2. all in one publisher
  // can be easily switched with the following
  bool bAllInOne=false;

  TString writerInput;
  TString arg;

  if (!bAllInOne) {
    // create one publisher for each ddl
    for (int ddlno=iMinDDLno; ddlno<=iMaxDDLno; ddlno++) {
      TString arg, publisher;

      // raw data publisher components
      arg.Form("-minid %d -skipempty -verbose", ddlno);
      publisher.Form("DP_%d", ddlno);
      // see AliHLTRawReaderPublisherComponent
      AliHLTConfiguration pubconf(publisher.Data(), "AliRawReaderPublisher", NULL , arg.Data());

      if (!writerInput.IsNull()) writerInput+=" ";
      writerInput+=publisher;
    }
  } else {
    // publish all ddls by the same component, this is much more
    // effective as it avoids repeated parsing through the data
    arg.Form("-minid %d -maxid %d -skipempty -verbose", iMinDDLno, iMaxDDLno);
    // see AliHLTRawReaderPublisherComponent
    AliHLTConfiguration pubconf("publisher", "AliRawReaderPublisher", NULL , arg.Data());
    if (!writerInput.IsNull()) writerInput+=" ";
    writerInput+="publisher";
  }

  // the writer configuration is the same for both
  arg.Form("-specfmt=_%%d -subdir=raw%%d -blcknofmt= -idfmt= -datafile %s", baseName);
  // see AliHLTFileWriter
  AliHLTConfiguration fwconf("sink1", "FileWriter"   , writerInput.Data(), arg.Data());

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // the reconstructor setup
  AliHLTReconstructor hltRec;
  hltRec.SetOption("libAliHLTUtil.so loglevel=0x7c chains=sink1");
  if (hltRec.Init()<0) {
    cerr << "initialization of reconstructor failed" << endl;
    return;
  }

  // this is just a dummy ESD to provide valid parameters to the
  // reconstructor
  AliESDEvent* pESD = new AliESDEvent;
  pESD->CreateStdContent();

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // the reconstruction loop
  Int_t event=0;
  UChar_t* pData=NULL;
  pRawReader->RewindEvents();
  while (pRawReader->NextEvent()) {
    cout << "=======================================================" << endl;
    cout << "event " << event << endl;
    cout << "-------------------------------------------------------" << endl;
    pRawReader->Reset();
    hltRec.Reconstruct(pRawReader, NULL);
    event++;
  }

  delete pESD;
}

void extract_ddlraw()
{
  cerr << "===============================================================" << endl;
  cerr << "usage: aliroot -b -q 'extract-ddlraw.C(\"raw.root\", 768, 769)'" << endl << endl;
  cerr << "please provide input, min and max equipment id" << endl;
  cerr << "===============================================================" << endl;
}
<commit_msg>maintenace of the extract-ddlraw macro - new parameter added to specify max number of events - connect to Grid if input is a remote file - use one single publisher for all links - skipping of CTP initialization in the HLTReconstructor in order to avoid CDB access<commit_after>// $Id$
/**
 * @file extract-ddlraw.C
 * @brief Tool to extract DDL raw data.
 *
 * Usage:
 *

 *   aliroot -b -q 'extract-ddlraw.C("raw.root", 768, 769)' | tee extract-ddlraw.log
 *

 *
 * This macro is an example for the AliHLTRawReaderPublisherComponent.
 * It extracts the DDL payload from an AliRawReader in a given equipment
 * range. Input can be either a root file or the path to the directory
 * containing the 'rawx' sub folders.
 *
 * A light-weight AliReconstruction-like setup creates the appropriate
 * RawReader for the specified input and uses the standard AliHLTReconstructor
 * to run a small HLT chain. The chain utilizes the AliRawReaderPublisher
 * to extract the payload of the equipments and writes this to files.
 *
 * @note In this example the AliHLTRawReaderPublisherComponent does not set any data
 * type nor specification for the published data blocks. Please remember
 * to provide appropriate arguments via '-datatype' and '-dataspec'
 * arguments (see AliHLTRawReaderPublisherComponent).
 *
 * @author Matthias.Richter@ift.uib.no
 * @ingroup alihlt_tutorial
 */
void extract_ddlraw(const char* input, int iMinDDLno, int iMaxDDLno, int nofEvents=-1)
{
  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // some defaults
  const char* baseName="RAW.ddl";

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // setup of the RawReader
  if (!input) {
    cerr << "invalid path" << endl;
    cerr << "usage: aliroot -b -q 'extract-ddlraw.C(\"raw.root\", 768, 769)'" << endl;
    return;
  }

  TString strfile=input;
  if (strfile.Contains("://") && !strfile.Contains("local://")) {
    TGrid::Connect("alien");
  }

  AliRawReader* pRawReader=AliRawReader::Create(input);
  if (!pRawReader) {
    cout << "can not open RawReader for file " << input << endl;
    return;
  }

  if (!pRawReader->NextEvent()) {
    cerr << "no events available" << endl;
    return;
  }

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // setup of the HLT system
  AliHLTSystem* pHLT=AliHLTPluginBase::GetInstance();
  if (!pHLT) {
    cerr << "fatal error: can not get HLT instance" << endl;
  }

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // the configuration chain
  // we show two possible configurations:
  //  1. having one publisher for each ddl, the configurations are created
  //     in a loop
  //  2. all in one publisher
  // can be easily switched with the following
  bool bAllInOne=true;

  TString writerInput;
  TString arg;

  if (!bAllInOne) {
    // create one publisher for each ddl
    for (int ddlno=iMinDDLno; ddlno<=iMaxDDLno; ddlno++) {
      TString arg, publisher;

      // raw data publisher components
      arg.Form("-minid %d -skipempty -verbose", ddlno);
      publisher.Form("DP_%d", ddlno);
      // see AliHLTRawReaderPublisherComponent
      AliHLTConfiguration pubconf(publisher.Data(), "AliRawReaderPublisher", NULL , arg.Data());

      if (!writerInput.IsNull()) writerInput+=" ";
      writerInput+=publisher;
    }
  } else {
    // publish all ddls by the same component, this is much more
    // effective as it avoids repeated parsing through the data
    arg.Form("-minid %d -maxid %d -skipempty -verbose", iMinDDLno, iMaxDDLno);
    // see AliHLTRawReaderPublisherComponent
    AliHLTConfiguration pubconf("publisher", "AliRawReaderPublisher", NULL , arg.Data());
    if (!writerInput.IsNull()) writerInput+=" ";
    writerInput+="publisher";
  }

  // the writer configuration is the same for both
  arg.Form("-specfmt=_%%d -subdir=raw%%d -blcknofmt= -idfmt= -datafile %s", baseName);
  // see AliHLTFileWriter
  AliHLTConfiguration fwconf("sink1", "FileWriter"   , writerInput.Data(), arg.Data());

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // the reconstructor setup
  AliHLTReconstructor hltRec;
  hltRec.SetOption("libAliHLTUtil.so loglevel=0x7c chains=sink1 ignore-hltout ignore-ctp");
  if (hltRec.Init()<0) {
    cerr << "initialization of reconstructor failed" << endl;
    return;
  }

  // this is just a dummy ESD to provide valid parameters to the
  // reconstructor
  AliESDEvent* pESD = new AliESDEvent;
  pESD->CreateStdContent();

  /////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////
  //
  // the reconstruction loop
  Int_t event=0;
  UChar_t* pData=NULL;
  pRawReader->RewindEvents();
  while (pRawReader->NextEvent() &&
	 (nofEvents<0 || event<nofEvents)) {
    cout << "=======================================================" << endl;
    cout << "event " << event << endl;
    cout << "-------------------------------------------------------" << endl;
    pRawReader->Reset();
    hltRec.Reconstruct(pRawReader, NULL);
    event++;
  }

  delete pESD;
}

void extract_ddlraw()
{
  cerr << "===============================================================" << endl;
  cerr << "usage: aliroot -b -q 'extract-ddlraw.C(\"raw.root\", 768, 769)'" << endl << endl;
  cerr << "please provide input, min and max equipment id" << endl;
  cerr << "===============================================================" << endl;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: itemholderbase.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-11-11 13:51:08 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#ifndef INCLUDED_SVTOOLS_ITEMHOLDERBASE_HXX_
#define INCLUDED_SVTOOLS_ITEMHOLDERBASE_HXX_

//-----------------------------------------------
// includes

#include <vector>

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

//-----------------------------------------------
// definitions

struct ItemHolderMutexBase
{
    ::osl::Mutex m_aLock;
};

enum EItem
{
    E_ACCELCFG                      ,   //
    E_ACCESSIBILITYOPTIONS          ,   // 2
    E_ADDXMLTOSTORAGEOPTIONS        ,   //
    E_APEARCFG                      ,   // 2

    E_CJKOPTIONS                    ,   // 2
    E_CMDOPTIONS                    ,   //
    E_COLORCFG                      ,   // 2
    E_COMPATIBILITY                 ,   //
    E_CTLOPTIONS                    ,   // 2

    E_DEFAULTOPTIONS                ,   //
    E_DYNAMICMENUOPTIONS            ,   //

    E_EVENTCFG                      ,   //
    E_EXTENDEDSECURITYOPTIONS       ,   //

    E_FLTRCFG                       ,   //
    E_FONTOPTIONS                   ,   //
    E_FONTSUBSTCONFIG               ,   // 2

    E_HELPOPTIONS                   ,   // 2
    E_HISTORYOPTIONS                ,   //

    E_INETOPTIONS                   ,   //
    E_INTERNALOPTIONS               ,   //

    E_JAVAOPTIONS                   ,   //

    E_LANGUAGEOPTIONS               ,   // 2
    E_LINGUCFG                      ,   //
    E_LOCALISATIONOPTIONS           ,   //

    E_MENUOPTIONS                   ,   //
    E_MISCCFG                       ,   // 2
    E_MISCOPTIONS                   ,   //
    E_MODULEOPTIONS                 ,   //

    E_OPTIONSDLGOPTIONS             ,   //
    E_OPTIONS3D                     ,   //

    E_PATHOPTIONS                   ,   //
    E_PRINTOPTIONS                  ,   // 2
    E_PRINTFILEOPTIONS              ,   // 2
    E_PRINTWARNINGOPTIONS           ,   //

    E_REGOPTIONS                    ,   //

    E_SAVEOPTIONS                   ,   //
    E_SEARCHOPT                     ,   //
    E_SECURITYOPTIONS               ,   //
    E_SOURCEVIEWCONFIG              ,   //
    E_STARTOPTIONS                  ,   //
    E_SYSLOCALEOPTIONS              ,   // 2

    E_UNDOOPTIONS                   ,   // 2
    E_USEROPTIONS                   ,   // 2

    E_VIEWOPTIONS_DIALOG            ,   //
    E_VIEWOPTIONS_TABDIALOG         ,   //
    E_VIEWOPTIONS_TABPAGE           ,   //
    E_VIEWOPTIONS_WINDOW            ,   //

    E_WORKINGSETOPTIONS             ,   //

    E_XMLACCELCFG                       //
};

struct TItemInfo
{
    TItemInfo()
        : pItem(0)
    {}

    void* pItem;
    EItem eItem;
};

typedef ::std::vector< TItemInfo > TItems;

#endif // INCLUDED_SVTOOLS_ITEMHOLDERBASE_HXX_
<commit_msg>INTEGRATION: CWS warnings01 (1.5.98); FILE MERGED 2006/01/27 16:43:22 sb 1.5.98.1: #i53898# Made code warning-free.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: itemholderbase.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 20:45:22 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#ifndef INCLUDED_SVTOOLS_ITEMHOLDERBASE_HXX_
#define INCLUDED_SVTOOLS_ITEMHOLDERBASE_HXX_

//-----------------------------------------------
// includes

#include <vector>

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

namespace svt { namespace detail { class Options; } }

//-----------------------------------------------
// definitions

struct ItemHolderMutexBase
{
    ::osl::Mutex m_aLock;
};

enum EItem
{
    E_ACCELCFG                      ,   //
    E_ACCESSIBILITYOPTIONS          ,   // 2
    E_ADDXMLTOSTORAGEOPTIONS        ,   //
    E_APEARCFG                      ,   // 2

    E_CJKOPTIONS                    ,   // 2
    E_CMDOPTIONS                    ,   //
    E_COLORCFG                      ,   // 2
    E_COMPATIBILITY                 ,   //
    E_CTLOPTIONS                    ,   // 2

    E_DEFAULTOPTIONS                ,   //
    E_DYNAMICMENUOPTIONS            ,   //

    E_EVENTCFG                      ,   //
    E_EXTENDEDSECURITYOPTIONS       ,   //

    E_FLTRCFG                       ,   //
    E_FONTOPTIONS                   ,   //
    E_FONTSUBSTCONFIG               ,   // 2

    E_HELPOPTIONS                   ,   // 2
    E_HISTORYOPTIONS                ,   //

    E_INETOPTIONS                   ,   //
    E_INTERNALOPTIONS               ,   //

    E_JAVAOPTIONS                   ,   //

    E_LANGUAGEOPTIONS               ,   // 2
    E_LINGUCFG                      ,   //
    E_LOCALISATIONOPTIONS           ,   //

    E_MENUOPTIONS                   ,   //
    E_MISCCFG                       ,   // 2
    E_MISCOPTIONS                   ,   //
    E_MODULEOPTIONS                 ,   //

    E_OPTIONSDLGOPTIONS             ,   //
    E_OPTIONS3D                     ,   //

    E_PATHOPTIONS                   ,   //
    E_PRINTOPTIONS                  ,   // 2
    E_PRINTFILEOPTIONS              ,   // 2
    E_PRINTWARNINGOPTIONS           ,   //

    E_REGOPTIONS                    ,   //

    E_SAVEOPTIONS                   ,   //
    E_SEARCHOPT                     ,   //
    E_SECURITYOPTIONS               ,   //
    E_SOURCEVIEWCONFIG              ,   //
    E_STARTOPTIONS                  ,   //
    E_SYSLOCALEOPTIONS              ,   // 2

    E_UNDOOPTIONS                   ,   // 2
    E_USEROPTIONS                   ,   // 2

    E_VIEWOPTIONS_DIALOG            ,   //
    E_VIEWOPTIONS_TABDIALOG         ,   //
    E_VIEWOPTIONS_TABPAGE           ,   //
    E_VIEWOPTIONS_WINDOW            ,   //

    E_WORKINGSETOPTIONS             ,   //

    E_XMLACCELCFG                       //
};

struct TItemInfo
{
    TItemInfo()
        : pItem(0)
    {}

    svt::detail::Options * pItem;
    EItem eItem;
};

typedef ::std::vector< TItemInfo > TItems;

#endif // INCLUDED_SVTOOLS_ITEMHOLDERBASE_HXX_
<|endoftext|>


<commit_before>#ifndef XCORR_H
#define XCORR_H

#include <complex>
#include <cstring>

extern "C" {
#include <fftw3.h>
}

inline void
xcorr_fftw_c2c(const std::vector<std::complex<double>> &signala,
    const std::vector<std::complex<double>> &signalb,
    std::vector<std::complex<double>> &result, int N)
{
	int N2 = 2 * N - 1;

	std::vector<std::complex<double>> signala_ext(N2);
	std::vector<std::complex<double>> signalb_ext(N2);

	// zero padding
	std::memcpy(signala_ext.data() + (N - 1), signala.data(),
	    sizeof(std::complex<double>) * N);
	std::memcpy(
	    signalb_ext.data(), signalb.data(), sizeof(std::complex<double>) * N);

	std::vector<std::complex<double>> outa(N2);
	std::vector<std::complex<double>> outb(N2);
	std::vector<std::complex<double>> out(N2);

	fftw_plan pa = fftw_plan_dft_1d(N2,
	    reinterpret_cast<fftw_complex *>(signala_ext.data()),
	    reinterpret_cast<fftw_complex *>(outa.data()), FFTW_FORWARD,
	    FFTW_ESTIMATE);
	fftw_plan pb = fftw_plan_dft_1d(N2,
	    reinterpret_cast<fftw_complex *>(signalb_ext.data()),
	    reinterpret_cast<fftw_complex *>(outb.data()), FFTW_FORWARD,
	    FFTW_ESTIMATE);
	fftw_plan px =
	    fftw_plan_dft_1d(N2, reinterpret_cast<fftw_complex *>(out.data()),
	        reinterpret_cast<fftw_complex *>(result.data()), FFTW_BACKWARD,
	        FFTW_ESTIMATE);

	fftw_execute(pa);
	fftw_execute(pb);

	std::complex<double> scale = {1.0 / (2 * N - 1), 0.0};
	std::complex<double> outb_i_tmp;
	for (int i = 0; i < N2; ++i) {
		std::memcpy(&outb_i_tmp, &outb[i], sizeof(fftw_complex));
		out[i] = outa[i] * std::conj(outb_i_tmp) * scale;
	}

	fftw_execute(px);

	fftw_destroy_plan(pa);
	fftw_destroy_plan(pb);
	fftw_destroy_plan(px);

	fftw_cleanup();
	return;
}

inline void
xcorr_fftw_r2c(const std::vector<double> &signala,
    const std::vector<double> &signalb,
    std::vector<std::complex<double>> &result, int N)
{
	int N2 = 2 * N - 1;

	std::vector<double> signala_ext(N2);
	std::vector<double> signalb_ext(N2);

	// zero padding
	std::memcpy(signala_ext.data() + (N - 1), signala.data(), sizeof(double) * N);
	std::memcpy(signalb_ext.data(), signalb.data(), sizeof(double) * N);

	std::vector<std::complex<double>> outa(N2);
	std::vector<std::complex<double>> outb(N2);
	std::vector<std::complex<double>> out(N2);

	fftw_plan pa =
	    fftw_plan_dft_r2c_1d(N2, reinterpret_cast<double *>(signala_ext.data()),
	        reinterpret_cast<fftw_complex *>(outa.data()), FFTW_ESTIMATE);
	fftw_plan pb =
	    fftw_plan_dft_r2c_1d(N2, reinterpret_cast<double *>(signalb_ext.data()),
	        reinterpret_cast<fftw_complex *>(outb.data()), FFTW_ESTIMATE);

	fftw_plan px =
	    fftw_plan_dft_1d(N2, reinterpret_cast<fftw_complex *>(out.data()),
	        reinterpret_cast<fftw_complex *>(result.data()), FFTW_BACKWARD,
	        FFTW_ESTIMATE);

	fftw_execute(pa);
	fftw_execute(pb);

	std::complex<double> scale = {1.0 / (2 * N - 1), 0.0};
	for (int i = 0; i < N2; ++i)
		out[i] = outa[i] * conj(outb[i]) * scale;

	fftw_execute(px);

	fftw_destroy_plan(pa);
	fftw_destroy_plan(pb);
	fftw_destroy_plan(px);

	fftw_cleanup();

	return;
}

inline void
xcorr_fftw_r2r(const std::vector<double> &signala,
    const std::vector<double> &signalb, std::vector<double> &result, int N)
{
	int N2 = 2 * N - 1;
	std::vector<std::complex<double>> result_cmplx(N2);
	xcorr_fftw_r2c(signala, signalb, result_cmplx, N);
	for (int x = 0; x < 2 * N - 1; ++x) {
		double real = std::real(result_cmplx[x]);
		double real_dest = result[x];
		std::memcpy(&real_dest, &real, sizeof(double));
	}
}

inline void
xcorr_timedomain(const void *signala, const void *signalb, void *result, int N)
{
	for (int tau = 0; tau < 2 * N - 1; ++tau) {
		std::complex<double> acf = {0, 0};
		for (int i = 0; i < N; ++i) {
			const int signala_idx = (i + tau) % (2 * N - 1);
			const std::complex<double> conjb =
			    conj(((std::complex<double> *)signalb)[i]);
			const double factor =
			    (signala_idx >= N)
			        ? std::real(
			              ((std::complex<double> *)signala)[signala_idx - N])
			        : 1.0;
			acf += factor * conjb;
		}
		((std::complex<double> *)result)[tau] = acf;
	}
	return;
}

#endif /* XCORR_H */
<commit_msg>Missing vector import in xcorr.hpp<commit_after>#ifndef XCORR_H
#define XCORR_H

#include <complex>
#include <cstring>
#include <vector>

extern "C" {
#include <fftw3.h>
}

inline void
xcorr_fftw_c2c(const std::vector<std::complex<double>> &signala,
    const std::vector<std::complex<double>> &signalb,
    std::vector<std::complex<double>> &result, int N)
{
	int N2 = 2 * N - 1;

	std::vector<std::complex<double>> signala_ext(N2);
	std::vector<std::complex<double>> signalb_ext(N2);

	// zero padding
	std::memcpy(signala_ext.data() + (N - 1), signala.data(),
	    sizeof(std::complex<double>) * N);
	std::memcpy(
	    signalb_ext.data(), signalb.data(), sizeof(std::complex<double>) * N);

	std::vector<std::complex<double>> outa(N2);
	std::vector<std::complex<double>> outb(N2);
	std::vector<std::complex<double>> out(N2);

	fftw_plan pa = fftw_plan_dft_1d(N2,
	    reinterpret_cast<fftw_complex *>(signala_ext.data()),
	    reinterpret_cast<fftw_complex *>(outa.data()), FFTW_FORWARD,
	    FFTW_ESTIMATE);
	fftw_plan pb = fftw_plan_dft_1d(N2,
	    reinterpret_cast<fftw_complex *>(signalb_ext.data()),
	    reinterpret_cast<fftw_complex *>(outb.data()), FFTW_FORWARD,
	    FFTW_ESTIMATE);
	fftw_plan px =
	    fftw_plan_dft_1d(N2, reinterpret_cast<fftw_complex *>(out.data()),
	        reinterpret_cast<fftw_complex *>(result.data()), FFTW_BACKWARD,
	        FFTW_ESTIMATE);

	fftw_execute(pa);
	fftw_execute(pb);

	std::complex<double> scale = {1.0 / (2 * N - 1), 0.0};
	std::complex<double> outb_i_tmp;
	for (int i = 0; i < N2; ++i) {
		std::memcpy(&outb_i_tmp, &outb[i], sizeof(fftw_complex));
		out[i] = outa[i] * std::conj(outb_i_tmp) * scale;
	}

	fftw_execute(px);

	fftw_destroy_plan(pa);
	fftw_destroy_plan(pb);
	fftw_destroy_plan(px);

	fftw_cleanup();
	return;
}

inline void
xcorr_fftw_r2c(const std::vector<double> &signala,
    const std::vector<double> &signalb,
    std::vector<std::complex<double>> &result, int N)
{
	int N2 = 2 * N - 1;

	std::vector<double> signala_ext(N2);
	std::vector<double> signalb_ext(N2);

	// zero padding
	std::memcpy(signala_ext.data() + (N - 1), signala.data(), sizeof(double) * N);
	std::memcpy(signalb_ext.data(), signalb.data(), sizeof(double) * N);

	std::vector<std::complex<double>> outa(N2);
	std::vector<std::complex<double>> outb(N2);
	std::vector<std::complex<double>> out(N2);

	fftw_plan pa =
	    fftw_plan_dft_r2c_1d(N2, reinterpret_cast<double *>(signala_ext.data()),
	        reinterpret_cast<fftw_complex *>(outa.data()), FFTW_ESTIMATE);
	fftw_plan pb =
	    fftw_plan_dft_r2c_1d(N2, reinterpret_cast<double *>(signalb_ext.data()),
	        reinterpret_cast<fftw_complex *>(outb.data()), FFTW_ESTIMATE);

	fftw_plan px =
	    fftw_plan_dft_1d(N2, reinterpret_cast<fftw_complex *>(out.data()),
	        reinterpret_cast<fftw_complex *>(result.data()), FFTW_BACKWARD,
	        FFTW_ESTIMATE);

	fftw_execute(pa);
	fftw_execute(pb);

	std::complex<double> scale = {1.0 / (2 * N - 1), 0.0};
	for (int i = 0; i < N2; ++i)
		out[i] = outa[i] * conj(outb[i]) * scale;

	fftw_execute(px);

	fftw_destroy_plan(pa);
	fftw_destroy_plan(pb);
	fftw_destroy_plan(px);

	fftw_cleanup();

	return;
}

inline void
xcorr_fftw_r2r(const std::vector<double> &signala,
    const std::vector<double> &signalb, std::vector<double> &result, int N)
{
	int N2 = 2 * N - 1;
	std::vector<std::complex<double>> result_cmplx(N2);
	xcorr_fftw_r2c(signala, signalb, result_cmplx, N);
	for (int x = 0; x < 2 * N - 1; ++x) {
		double real = std::real(result_cmplx[x]);
		double real_dest = result[x];
		std::memcpy(&real_dest, &real, sizeof(double));
	}
}

inline void
xcorr_timedomain(const void *signala, const void *signalb, void *result, int N)
{
	for (int tau = 0; tau < 2 * N - 1; ++tau) {
		std::complex<double> acf = {0, 0};
		for (int i = 0; i < N; ++i) {
			const int signala_idx = (i + tau) % (2 * N - 1);
			const std::complex<double> conjb =
			    conj(((std::complex<double> *)signalb)[i]);
			const double factor =
			    (signala_idx >= N)
			        ? std::real(
			              ((std::complex<double> *)signala)[signala_idx - N])
			        : 1.0;
			acf += factor * conjb;
		}
		((std::complex<double> *)result)[tau] = acf;
	}
	return;
}

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


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"
#include <Eigen/LU>

template<typename MatrixType> void inverse(const MatrixType& m)
{
  using std::abs;
  typedef typename MatrixType::Index Index;
  /* this test covers the following files:
     Inverse.h
  */
  Index rows = m.rows();
  Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;

  MatrixType m1(rows, cols),
             m2(rows, cols),
             identity = MatrixType::Identity(rows, rows);
  createRandomPIMatrixOfRank(rows,rows,rows,m1);
  m2 = m1.inverse();
  VERIFY_IS_APPROX(m1, m2.inverse() );

  VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));

  VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
  VERIFY_IS_APPROX(identity, m1 * m1.inverse() );

  VERIFY_IS_APPROX(m1, m1.inverse().inverse() );

  // since for the general case we implement separately row-major and col-major, test that
  VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));

#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;

  //computeInverseAndDetWithCheck tests
  //First: an invertible matrix
  bool invertible;
  RealScalar det;

  m2.setZero();
  m1.computeInverseAndDetWithCheck(m2, det, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);
  VERIFY_IS_APPROX(det, m1.determinant());

  m2.setZero();
  m1.computeInverseWithCheck(m2, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);

  //Second: a rank one matrix (not invertible, except for 1x1 matrices)
  VectorType v3 = VectorType::Random(rows);
  MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
  m3.computeInverseAndDetWithCheck(m4, det, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
  VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1));
  m3.computeInverseWithCheck(m4, invertible);
  VERIFY( rows==1 ? invertible : !invertible );

  // check with submatrices
  {
    Matrix<Scalar, MatrixType::RowsAtCompileTime+1, MatrixType::RowsAtCompileTime+1, MatrixType::Options> m3;
    m3.setRandom();
    m2 = m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>().inverse();
    VERIFY_IS_APPROX( (m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>()), m2.inverse() );
  }
#endif

  // check in-place inversion
  if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
  {
    // in-place is forbidden
    VERIFY_RAISES_ASSERT(m1 = m1.inverse());
  }
  else
  {
    m2 = m1.inverse();
    m1 = m1.inverse();
    VERIFY_IS_APPROX(m1,m2);
  }
}

void test_inverse()
{
  int s = 0;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( inverse(Matrix2d()) );
    CALL_SUBTEST_3( inverse(Matrix3f()) );
    CALL_SUBTEST_4( inverse(Matrix4f()) );
    CALL_SUBTEST_4( inverse(Matrix<float,4,4,DontAlign>()) );
    s = internal::random<int>(50,320);
    CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
    s = internal::random<int>(25,100);
    CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
    CALL_SUBTEST_7( inverse(Matrix4d()) );
    CALL_SUBTEST_7( inverse(Matrix<double,4,4,DontAlign>()) );
  }
  TEST_SET_BUT_UNUSED_VARIABLE(s)
}
<commit_msg>Fix inverse unit test making sure we try to invert an invertible matrix<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"
#include <Eigen/LU>

template<typename MatrixType> void inverse(const MatrixType& m)
{
  using std::abs;
  typedef typename MatrixType::Index Index;
  /* this test covers the following files:
     Inverse.h
  */
  Index rows = m.rows();
  Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;

  MatrixType m1(rows, cols),
             m2(rows, cols),
             identity = MatrixType::Identity(rows, rows);
  createRandomPIMatrixOfRank(rows,rows,rows,m1);
  m2 = m1.inverse();
  VERIFY_IS_APPROX(m1, m2.inverse() );

  VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));

  VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
  VERIFY_IS_APPROX(identity, m1 * m1.inverse() );

  VERIFY_IS_APPROX(m1, m1.inverse().inverse() );

  // since for the general case we implement separately row-major and col-major, test that
  VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));

#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;

  //computeInverseAndDetWithCheck tests
  //First: an invertible matrix
  bool invertible;
  RealScalar det;

  m2.setZero();
  m1.computeInverseAndDetWithCheck(m2, det, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);
  VERIFY_IS_APPROX(det, m1.determinant());

  m2.setZero();
  m1.computeInverseWithCheck(m2, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);

  //Second: a rank one matrix (not invertible, except for 1x1 matrices)
  VectorType v3 = VectorType::Random(rows);
  MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
  m3.computeInverseAndDetWithCheck(m4, det, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
  VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1));
  m3.computeInverseWithCheck(m4, invertible);
  VERIFY( rows==1 ? invertible : !invertible );

  // check with submatrices
  {
    Matrix<Scalar, MatrixType::RowsAtCompileTime+1, MatrixType::RowsAtCompileTime+1, MatrixType::Options> m3;
    m3.setRandom();
    m3.topLeftCorner(rows,rows) = m1;
    m2 = m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>().inverse();
    VERIFY_IS_APPROX( (m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>()), m2.inverse() );
  }
#endif

  // check in-place inversion
  if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
  {
    // in-place is forbidden
    VERIFY_RAISES_ASSERT(m1 = m1.inverse());
  }
  else
  {
    m2 = m1.inverse();
    m1 = m1.inverse();
    VERIFY_IS_APPROX(m1,m2);
  }
}

void test_inverse()
{
  int s = 0;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( inverse(Matrix2d()) );
    CALL_SUBTEST_3( inverse(Matrix3f()) );
    CALL_SUBTEST_4( inverse(Matrix4f()) );
    CALL_SUBTEST_4( inverse(Matrix<float,4,4,DontAlign>()) );
    s = internal::random<int>(50,320);
    CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
    s = internal::random<int>(25,100);
    CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
    CALL_SUBTEST_7( inverse(Matrix4d()) );
    CALL_SUBTEST_7( inverse(Matrix<double,4,4,DontAlign>()) );
  }
  TEST_SET_BUT_UNUSED_VARIABLE(s)
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qHas_Syslog
#include    <syslog.h>
#endif

#include    "../Characters/CString/Utilities.h"
#include    "../Characters/Format.h"
#include    "../Debug/Trace.h"
#include    "BlockingQueue.h"
#include    "Common.h"
#include    "Process.h"
#include    "Thread.h"
#include    "TimeOutException.h"

#include    "Logger.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Configuration;
using   namespace   Stroika::Foundation::Execution;

using   Time::DurationSecondsType;

/*
 ********************************************************************************
 ******************************** Execution::Logger *****************************
 ********************************************************************************
 */
Logger  Logger::sThe_;

const EnumNames<Logger::Priority>   Logger::Stroika_Enum_Names(Priority) = {
    { Logger::Priority::eDebug, L"Debug" },
    { Logger::Priority::eInfo, L"Info" },
    { Logger::Priority::eNotice, L"Notice" },
    { Logger::Priority::eWarning, L"Warning" },
    { Logger::Priority::eError, L"Error" },
    { Logger::Priority::eCriticalError, L"CriticalError" },
    { Logger::Priority::eAlertError, L"AlertError" },
    { Logger::Priority::eEmergency, L"Emergency" },
};

namespace {
    BlockingQueue<pair<Logger::Priority, String>>   sOutMsgQ_;
    Execution::Thread                               sBookkeepingThread_;
    bool                                            sOutQMaybeNeedsFlush_ = true;       // sligt optimziation of not using buffering

    Synchronized<Memory::Optional<DurationSecondsType>>       sSuppressDuplicatesThreshold_;

    struct LastMsg_ {
        mutex                               fMutex_;     // mutex so we can update related variables together
        pair<Logger::Priority, String>      fLastMsgSent_;
        Time::DurationSecondsType           fLastSentAt = 0.0;
        unsigned int                        fRepeatCount_ = 0;
    };
    LastMsg_    sLastMsg_;
}

Logger::Logger ()
    : fAppender_ ()
    , fMinLogLevel_ (Priority::eInfo)
    , fBufferingEnabled_ (false)
{
}

void    Logger::SetAppender (const shared_ptr<IAppenderRep>& rep)
{
    fAppender_ = rep;
}

void    Logger::Log_ (Priority logLevel, const String& format, va_list argList)
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp.get () != nullptr) {
        auto p = pair<Logger::Priority, String> (logLevel, Characters::FormatV (format.c_str (), argList));
        if (sSuppressDuplicatesThreshold_.IsPresent ()) {
            auto    critSec { make_unique_lock (sLastMsg_.fMutex_) };
            if (p == sLastMsg_.fLastMsgSent_) {
                sLastMsg_.fRepeatCount_++;
                sLastMsg_.fLastSentAt = Time::GetTickCount ();
                return; // so will be handled later
            }
            else {
                if (sLastMsg_.fRepeatCount_ > 0) {
                    FlushDupsWarning_ ();
                }
                sLastMsg_.fLastMsgSent_ = p;
                sLastMsg_.fRepeatCount_ = 0;
                sLastMsg_.fLastSentAt = Time::GetTickCount ();
            }
        }
        if (GetBufferingEnabled ()) {
            sOutQMaybeNeedsFlush_ = true;
            sOutMsgQ_.AddTail (p);
        }
        else {
            if (sOutQMaybeNeedsFlush_) {
                FlushBuffer (); // in case recently disabled
            }
            tmp->Log (p.first, p.second);
        }
    }
}

void        Logger::SetBufferingEnabled (bool logBufferingEnabled)
{
    sThe_.fBufferingEnabled_ = logBufferingEnabled;
    UpdateBookkeepingThread_ ();
}

void        Logger::FlushBuffer ()
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp != nullptr) {
        while (true) {
            auto p = sOutMsgQ_.RemoveHeadIfPossible ();
            if (p.IsPresent ()) {
                tmp->Log (p->first, p->second);
            }
            else {
                return; // no more entries
            }
        }
    }
    sOutQMaybeNeedsFlush_ = false;
}

Memory::Optional<Time::DurationSecondsType> Logger::GetSuppressDuplicates ()
{
    return Memory::Optional<Time::DurationSecondsType> (sSuppressDuplicatesThreshold_);
}

void    Logger::SetSuppressDuplicates (const Memory::Optional<DurationSecondsType>& suppressDuplicatesThreshold)
{
    Require (suppressDuplicatesThreshold.IsMissing () or * suppressDuplicatesThreshold > 0.0);
    if (sSuppressDuplicatesThreshold_ != suppressDuplicatesThreshold) {
        sSuppressDuplicatesThreshold_ = suppressDuplicatesThreshold;
        UpdateBookkeepingThread_ ();
    }
}

void    Logger::FlushDupsWarning_ ()
{
    if (sLastMsg_.fRepeatCount_ > 0) {
        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
        if (tmp != nullptr) {
            if (sLastMsg_.fRepeatCount_ == 1) {
                tmp->Log (sLastMsg_.fLastMsgSent_.first, sLastMsg_.fLastMsgSent_.second);
            }
            else {
                tmp->Log (sLastMsg_.fLastMsgSent_.first,  Characters::Format (L"[%d duplicates suppressed]: %s", sLastMsg_.fRepeatCount_ - 1, sLastMsg_.fLastMsgSent_.second.c_str ()));
            }
        }
        sLastMsg_.fRepeatCount_ = 0;
        sLastMsg_.fLastMsgSent_.second.clear ();
    }
}

void    Logger::UpdateBookkeepingThread_ ()
{
    sBookkeepingThread_.AbortAndWaitForDone ();
    sBookkeepingThread_ = Thread ();  // so null

    Time::DurationSecondsType   suppressDuplicatesThreshold =   sSuppressDuplicatesThreshold_.Value (0);
    bool                        suppressDuplicates          =   suppressDuplicatesThreshold > 0;
    if (suppressDuplicates or GetBufferingEnabled ()) {
        if (suppressDuplicates) {
            sBookkeepingThread_ = Thread ([suppressDuplicatesThreshold] () {
                while (true) {
                    DurationSecondsType time2Wait = max (static_cast<DurationSecondsType> (2), suppressDuplicatesThreshold);    // never wait less than this
                    try {
                        auto p = sOutMsgQ_.RemoveHead (time2Wait);
                        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                        if (tmp != nullptr) {
                            tmp->Log (p.first, p.second);
                        }
                    }
                    catch (const TimeOutException&) {
                    }
                    {
                        auto    critSec { make_unique_lock (sLastMsg_.fMutex_) };
                        if (sLastMsg_.fRepeatCount_ > 0 and sLastMsg_.fLastSentAt + suppressDuplicatesThreshold < Time::GetTickCount ()) {
                            FlushDupsWarning_ ();
                        }
                    }
                }
            });
        }
        else {
            sBookkeepingThread_ = Thread ([] () {
                while (true) {
                    auto p = sOutMsgQ_.RemoveHead ();
                    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                    if (tmp != nullptr) {
                        tmp->Log (p.first, p.second);
                    }
                }
            });
        }
        sBookkeepingThread_.SetThreadName (L"Logger Bookkeeping");
        sBookkeepingThread_.SetThreadPriority (Thread::Priority::eBelowNormal);
        sBookkeepingThread_.Start ();
    }

    // manually push out pending messages
    FlushBuffer ();
}

/*
 ********************************************************************************
 ************************** Execution::IAppenderRep *****************************
 ********************************************************************************
 */
Logger::IAppenderRep::~IAppenderRep ()
{
}

#if     qHas_Syslog
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
namespace   {
    string mkMsg_ (const String& applicationName)
    {
        return Characters::CString::Format ("%s[%d]", applicationName.AsNarrowSDKString ().c_str (), GetCurrentProcessID ());
    }
}
Logger::SysLogAppender::SysLogAppender (const String& applicationName)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, LOG_DAEMON);    // not sure what facility to pass?
}

Logger::SysLogAppender::SysLogAppender (const String& applicationName, int facility)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, facility);
}

Logger::SysLogAppender::~SysLogAppender ()
{
    closelog ();
}

void    Logger::SysLogAppender::Log (Priority logLevel, const String& message)
{
    DbgTrace (L"SYSLOG: %s: %s", Stroika_Enum_Names(Priority).GetName (logLevel), message.c_str ());
    int sysLogLevel = LOG_NOTICE;   // doesnt matter cuz assert error if hit
    switch (logLevel) {
        case Priority::eDebug:
            sysLogLevel = LOG_DEBUG;
            break;
        case Priority::eInfo:
            sysLogLevel = LOG_INFO;
            break;
        case Priority::eNotice:
            sysLogLevel = LOG_NOTICE;
            break;
        case Priority::eWarning:
            sysLogLevel = LOG_WARNING;
            break;
        case Priority::eError:
            sysLogLevel = LOG_ERROR;
            break;
        case Priority::eCriticalError:
            sysLogLevel = LOG_CRIT;
            break;
        case Priority::eAlertError:
            sysLogLevel = LOG_ALERT;
            break;
        case Priority::eEmergency:
            sysLogLevel = LOG_EMERG;
            break;
        default:
            RequireNotReached ();
    }
    syslog (sysLogLevel, "%s", message.AsNarrowSDKString ().c_str ());
}
#endif

/*
 ********************************************************************************
 ************************** Execution::FileAppender *****************************
 ********************************************************************************
 */
Logger::FileAppender::FileAppender (const String& fileName)
{
    AssertNotImplemented ();
}

void    Logger::FileAppender::Log (Priority logLevel, const String& message)
{
    AssertNotImplemented ();
}

#if     qPlatform_Windows
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
Logger::WindowsEventLogAppender::WindowsEventLogAppender ()
{
}

void    Logger::WindowsEventLogAppender::Log (Priority logLevel, const String& message)
{
    /*
     * VERY QUICK HACK - AT LEAST DUMPS SOME INFO TO EVENTLOG - BUT MUCH TWEAKING LEFT TODO
     */
    const   TCHAR   kEventSourceName[]  =   _T ("xxxtest");
    WORD    eventType   =   EVENTLOG_ERROR_TYPE;
    switch (logLevel) {
        case Priority::eDebug:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eInfo:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eNotice:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eWarning:
            eventType = EVENTLOG_WARNING_TYPE;
            break;
        case Priority::eError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eAlertError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eEmergency:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
    }
#define CATEGORY_Normal                  0x00000001L
    WORD    eventCategoryID =   CATEGORY_Normal;
    // See SPR#565 for wierdness - where I cannot really get these paid attention to
    // by the Windows EventLog. So had to use the .Net eventlogger. It SEEMS
#define EVENT_Message                    0x00000064L
    const   DWORD   kEventID            =   EVENT_Message;
    HANDLE  hEventSource = RegisterEventSource (NULL, kEventSourceName);
    Verify (hEventSource != NULL);
    SDKString tmp = message.AsSDKString ();
    const Characters::SDKChar* msg = tmp.c_str ();
    Verify (::ReportEvent (
                hEventSource,
                eventType,
                eventCategoryID,
                kEventID,
                NULL,
                (WORD)1,
                0,
                &msg,
                NULL
            )
           );
    Verify (::DeregisterEventSource (hEventSource));
}
#endif<commit_msg>fixed typo<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qHas_Syslog
#include    <syslog.h>
#endif

#include    "../Characters/CString/Utilities.h"
#include    "../Characters/Format.h"
#include    "../Debug/Trace.h"
#include    "BlockingQueue.h"
#include    "Common.h"
#include    "Process.h"
#include    "Thread.h"
#include    "TimeOutException.h"

#include    "Logger.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Configuration;
using   namespace   Stroika::Foundation::Execution;

using   Time::DurationSecondsType;

/*
 ********************************************************************************
 ******************************** Execution::Logger *****************************
 ********************************************************************************
 */
Logger  Logger::sThe_;

const EnumNames<Logger::Priority>   Logger::Stroika_Enum_Names(Priority) = {
    { Logger::Priority::eDebug, L"Debug" },
    { Logger::Priority::eInfo, L"Info" },
    { Logger::Priority::eNotice, L"Notice" },
    { Logger::Priority::eWarning, L"Warning" },
    { Logger::Priority::eError, L"Error" },
    { Logger::Priority::eCriticalError, L"CriticalError" },
    { Logger::Priority::eAlertError, L"AlertError" },
    { Logger::Priority::eEmergency, L"Emergency" },
};

namespace {
    BlockingQueue<pair<Logger::Priority, String>>   sOutMsgQ_;
    Execution::Thread                               sBookkeepingThread_;
    bool                                            sOutQMaybeNeedsFlush_ = true;       // sligt optimziation of not using buffering

    Synchronized<Memory::Optional<DurationSecondsType>>       sSuppressDuplicatesThreshold_;

    struct LastMsg_ {
        mutex                               fMutex_;     // mutex so we can update related variables together
        pair<Logger::Priority, String>      fLastMsgSent_;
        Time::DurationSecondsType           fLastSentAt = 0.0;
        unsigned int                        fRepeatCount_ = 0;
    };
    LastMsg_    sLastMsg_;
}

Logger::Logger ()
    : fAppender_ ()
    , fMinLogLevel_ (Priority::eInfo)
    , fBufferingEnabled_ (false)
{
}

void    Logger::SetAppender (const shared_ptr<IAppenderRep>& rep)
{
    fAppender_ = rep;
}

void    Logger::Log_ (Priority logLevel, const String& format, va_list argList)
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp.get () != nullptr) {
        auto p = pair<Logger::Priority, String> (logLevel, Characters::FormatV (format.c_str (), argList));
        if (sSuppressDuplicatesThreshold_.IsPresent ()) {
            auto    critSec { make_unique_lock (sLastMsg_.fMutex_) };
            if (p == sLastMsg_.fLastMsgSent_) {
                sLastMsg_.fRepeatCount_++;
                sLastMsg_.fLastSentAt = Time::GetTickCount ();
                return; // so will be handled later
            }
            else {
                if (sLastMsg_.fRepeatCount_ > 0) {
                    FlushDupsWarning_ ();
                }
                sLastMsg_.fLastMsgSent_ = p;
                sLastMsg_.fRepeatCount_ = 0;
                sLastMsg_.fLastSentAt = Time::GetTickCount ();
            }
        }
        if (GetBufferingEnabled ()) {
            sOutQMaybeNeedsFlush_ = true;
            sOutMsgQ_.AddTail (p);
        }
        else {
            if (sOutQMaybeNeedsFlush_) {
                FlushBuffer (); // in case recently disabled
            }
            tmp->Log (p.first, p.second);
        }
    }
}

void        Logger::SetBufferingEnabled (bool logBufferingEnabled)
{
    sThe_.fBufferingEnabled_ = logBufferingEnabled;
    UpdateBookkeepingThread_ ();
}

void        Logger::FlushBuffer ()
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp != nullptr) {
        while (true) {
            auto p = sOutMsgQ_.RemoveHeadIfPossible ();
            if (p.IsPresent ()) {
                tmp->Log (p->first, p->second);
            }
            else {
                return; // no more entries
            }
        }
    }
    sOutQMaybeNeedsFlush_ = false;
}

Memory::Optional<Time::DurationSecondsType> Logger::GetSuppressDuplicates ()
{
    return Memory::Optional<Time::DurationSecondsType> (sSuppressDuplicatesThreshold_);
}

void    Logger::SetSuppressDuplicates (const Memory::Optional<DurationSecondsType>& suppressDuplicatesThreshold)
{
    Require (suppressDuplicatesThreshold.IsMissing () or * suppressDuplicatesThreshold > 0.0);
    if (sSuppressDuplicatesThreshold_ != suppressDuplicatesThreshold) {
        sSuppressDuplicatesThreshold_ = suppressDuplicatesThreshold;
        UpdateBookkeepingThread_ ();
    }
}

void    Logger::FlushDupsWarning_ ()
{
    if (sLastMsg_.fRepeatCount_ > 0) {
        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
        if (tmp != nullptr) {
            if (sLastMsg_.fRepeatCount_ == 1) {
                tmp->Log (sLastMsg_.fLastMsgSent_.first, sLastMsg_.fLastMsgSent_.second);
            }
            else {
                tmp->Log (sLastMsg_.fLastMsgSent_.first,  Characters::Format (L"[%d duplicates suppressed]: %s", sLastMsg_.fRepeatCount_ - 1, sLastMsg_.fLastMsgSent_.second.c_str ()));
            }
        }
        sLastMsg_.fRepeatCount_ = 0;
        sLastMsg_.fLastMsgSent_.second.clear ();
    }
}

void    Logger::UpdateBookkeepingThread_ ()
{
    sBookkeepingThread_.AbortAndWaitForDone ();
    sBookkeepingThread_ = Thread ();  // so null

    Time::DurationSecondsType   suppressDuplicatesThreshold =   sSuppressDuplicatesThreshold_.Value (0);
    bool                        suppressDuplicates          =   suppressDuplicatesThreshold > 0;
    if (suppressDuplicates or GetBufferingEnabled ()) {
        if (suppressDuplicates) {
            sBookkeepingThread_ = Thread ([suppressDuplicatesThreshold] () {
                while (true) {
                    DurationSecondsType time2Wait = max (static_cast<DurationSecondsType> (2), suppressDuplicatesThreshold);    // never wait less than this
                    try {
                        auto p = sOutMsgQ_.RemoveHead (time2Wait);
                        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                        if (tmp != nullptr) {
                            tmp->Log (p.first, p.second);
                        }
                    }
                    catch (const TimeOutException&) {
                    }
                    {
                        auto    critSec { make_unique_lock (sLastMsg_.fMutex_) };
                        if (sLastMsg_.fRepeatCount_ > 0 and sLastMsg_.fLastSentAt + suppressDuplicatesThreshold < Time::GetTickCount ()) {
                            FlushDupsWarning_ ();
                        }
                    }
                }
            });
        }
        else {
            sBookkeepingThread_ = Thread ([] () {
                while (true) {
                    auto p = sOutMsgQ_.RemoveHead ();
                    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                    if (tmp != nullptr) {
                        tmp->Log (p.first, p.second);
                    }
                }
            });
        }
        sBookkeepingThread_.SetThreadName (L"Logger Bookkeeping");
        sBookkeepingThread_.SetThreadPriority (Thread::Priority::eBelowNormal);
        sBookkeepingThread_.Start ();
    }

    // manually push out pending messages
    FlushBuffer ();
}

/*
 ********************************************************************************
 ************************** Execution::IAppenderRep *****************************
 ********************************************************************************
 */
Logger::IAppenderRep::~IAppenderRep ()
{
}

#if     qHas_Syslog
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
namespace   {
    string mkMsg_ (const String& applicationName)
    {
        return Characters::CString::Format ("%s[%d]", applicationName.AsNarrowSDKString ().c_str (), GetCurrentProcessID ());
    }
}
Logger::SysLogAppender::SysLogAppender (const String& applicationName)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, LOG_DAEMON);    // not sure what facility to pass?
}

Logger::SysLogAppender::SysLogAppender (const String& applicationName, int facility)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, facility);
}

Logger::SysLogAppender::~SysLogAppender ()
{
    closelog ();
}

void    Logger::SysLogAppender::Log (Priority logLevel, const String& message)
{
    DbgTrace (L"SYSLOG: %s: %s", Stroika_Enum_Names(Priority).GetName (logLevel), message.c_str ());
    int sysLogLevel = LOG_NOTICE;   // doesnt matter cuz assert error if hit
    switch (logLevel) {
        case Priority::eDebug:
            sysLogLevel = LOG_DEBUG;
            break;
        case Priority::eInfo:
            sysLogLevel = LOG_INFO;
            break;
        case Priority::eNotice:
            sysLogLevel = LOG_NOTICE;
            break;
        case Priority::eWarning:
            sysLogLevel = LOG_WARNING;
            break;
        case Priority::eError:
            sysLogLevel = LOG_ERR;
            break;
        case Priority::eCriticalError:
            sysLogLevel = LOG_CRIT;
            break;
        case Priority::eAlertError:
            sysLogLevel = LOG_ALERT;
            break;
        case Priority::eEmergency:
            sysLogLevel = LOG_EMERG;
            break;
        default:
            RequireNotReached ();
    }
    syslog (sysLogLevel, "%s", message.AsNarrowSDKString ().c_str ());
}
#endif

/*
 ********************************************************************************
 ************************** Execution::FileAppender *****************************
 ********************************************************************************
 */
Logger::FileAppender::FileAppender (const String& fileName)
{
    AssertNotImplemented ();
}

void    Logger::FileAppender::Log (Priority logLevel, const String& message)
{
    AssertNotImplemented ();
}

#if     qPlatform_Windows
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
Logger::WindowsEventLogAppender::WindowsEventLogAppender ()
{
}

void    Logger::WindowsEventLogAppender::Log (Priority logLevel, const String& message)
{
    /*
     * VERY QUICK HACK - AT LEAST DUMPS SOME INFO TO EVENTLOG - BUT MUCH TWEAKING LEFT TODO
     */
    const   TCHAR   kEventSourceName[]  =   _T ("xxxtest");
    WORD    eventType   =   EVENTLOG_ERROR_TYPE;
    switch (logLevel) {
        case Priority::eDebug:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eInfo:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eNotice:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eWarning:
            eventType = EVENTLOG_WARNING_TYPE;
            break;
        case Priority::eError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eAlertError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eEmergency:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
    }
#define CATEGORY_Normal                  0x00000001L
    WORD    eventCategoryID =   CATEGORY_Normal;
    // See SPR#565 for wierdness - where I cannot really get these paid attention to
    // by the Windows EventLog. So had to use the .Net eventlogger. It SEEMS
#define EVENT_Message                    0x00000064L
    const   DWORD   kEventID            =   EVENT_Message;
    HANDLE  hEventSource = RegisterEventSource (NULL, kEventSourceName);
    Verify (hEventSource != NULL);
    SDKString tmp = message.AsSDKString ();
    const Characters::SDKChar* msg = tmp.c_str ();
    Verify (::ReportEvent (
                hEventSource,
                eventType,
                eventCategoryID,
                kEventID,
                NULL,
                (WORD)1,
                0,
                &msg,
                NULL
            )
           );
    Verify (::DeregisterEventSource (hEventSource));
}
#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; version 2 of the License.

   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 */

//
//  ndbapi_async1.cpp: Using asynchronous transactions in NDB API
//
//
//  Correct output from this program is:
//
//  Successful insert.
//  Successful insert.

#include <mysql.h>
#include <NdbApi.hpp>

// Used for cout
#include <iostream>

#define PRINT_ERROR(code,msg) \
  std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
            << ", code: " << code \
            << ", msg: " << msg << "." << std::endl
#define MYSQLERROR(mysql) { \
  PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
  exit(-1); }
#define APIERROR(error) \
  { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
              << error.code << ", msg: " << error.message << "." << std::endl; \
    exit(-1); }

static void create_table(MYSQL &);
static void drop_table(MYSQL &);
static void callback(int result, NdbTransaction* NdbObject, void* aObject);

int main(int argc, char** argv)
{
  if (argc != 3)
  {
    std::cout << "Arguments are <socket mysqld> <connect_string cluster>.\n";
    exit(-1);
  }
  char * mysqld_sock  = argv[1];
  const char *connectstring = argv[2];
  ndb_init();

  Ndb_cluster_connection *cluster_connection=
    new Ndb_cluster_connection(connectstring); // Object representing the cluster

  int r= cluster_connection->connect(5 /* retries               */,
				     3 /* delay between retries */,
				     1 /* verbose               */);
  if (r > 0)
  {
    std::cout
      << "Cluster connect failed, possibly resolved with more retries.\n";
    exit(-1);
  }
  else if (r < 0)
  {
    std::cout
      << "Cluster connect failed.\n";
    exit(-1);
  }

  if (cluster_connection->wait_until_ready(30,0))
  {
    std::cout << "Cluster was not ready within 30 secs." << std::endl;
    exit(-1);
  }

  // connect to mysql server
  MYSQL mysql;
  if ( !mysql_init(&mysql) ) {
    std::cout << "mysql_init failed\n";
    exit(-1);
  }
  if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
			   0, mysqld_sock, 0) )
    MYSQLERROR(mysql);

  /********************************************
   * Connect to database via mysql-c          *
   ********************************************/
  mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
  if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
  create_table(mysql);

  Ndb* myNdb = new Ndb( cluster_connection,
			"TEST_DB_1" );  // Object representing the database

  NdbTransaction*  myNdbTransaction[2];   // For transactions
  NdbOperation*   myNdbOperation;       // For operations

  if (myNdb->init(2) == -1) {          // Want two parallel insert transactions
    APIERROR(myNdb->getNdbError());
    exit(-1);
  }

  /******************************************************
   * Insert (we do two insert transactions in parallel) *
   ******************************************************/
  const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
  const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
  if (myTable == NULL)
    APIERROR(myDict->getNdbError());
  for (int i = 0; i < 2; i++) {
    myNdbTransaction[i] = myNdb->startTransaction();
    if (myNdbTransaction[i] == NULL) APIERROR(myNdb->getNdbError());

    myNdbOperation = myNdbTransaction[i]->getNdbOperation(myTable);
    if (myNdbOperation == NULL) APIERROR(myNdbTransaction[i]->getNdbError());

    myNdbOperation->insertTuple();
    myNdbOperation->equal("ATTR1", 20 + i);
    myNdbOperation->setValue("ATTR2", 20 + i);

    // Prepare transaction (the transaction is NOT yet sent to NDB)
    myNdbTransaction[i]->executeAsynchPrepare(NdbTransaction::Commit,
					      &callback, NULL);
  }

  // Send all transactions to NDB
  myNdb->sendPreparedTransactions(0);

  // Poll all transactions
  myNdb->pollNdb(3000, 2);

  // Close all transactions
  for (int i = 0; i < 2; i++)
    myNdb->closeTransaction(myNdbTransaction[i]);

  delete myNdb;
  delete cluster_connection;

  drop_table(mysql);

  ndb_end(0);
  return 0;
}

/*********************************************************
 * Create a table named MYTABLENAME if it does not exist *
 *********************************************************/
static void create_table(MYSQL &mysql)
{
  if (mysql_query(&mysql,
		  "CREATE TABLE"
		  "  MYTABLENAME"
		  "    (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
		  "     ATTR2 INT UNSIGNED NOT NULL)"
		  "  ENGINE=NDB"))
    MYSQLERROR(mysql);
}

/***********************************
 * Drop a table named MYTABLENAME
 ***********************************/
static void drop_table(MYSQL &mysql)
{
  if (mysql_query(&mysql,
		  "DROP TABLE"
		  "  MYTABLENAME"))
    MYSQLERROR(mysql);
}

/*
 *   callback : This is called when the transaction is polled
 *
 *   (This function must have three arguments:
 *   - The result of the transaction,
 *   - The NdbTransaction object, and
 *   - A pointer to an arbitrary object.)
 */

static void
callback(int result, NdbTransaction* myTrans, void* aObject)
{
  if (result == -1) {
    std::cout << "Poll error: " << std::endl;
    APIERROR(myTrans->getNdbError());
  } else {
    std::cout << "Successful insert." << std::endl;
  }
}
<commit_msg>wait_until_ready may return greater that 1 since wait time for second node to connect is 0<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; version 2 of the License.

   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 */

//
//  ndbapi_async1.cpp: Using asynchronous transactions in NDB API
//
//
//  Correct output from this program is:
//
//  Successful insert.
//  Successful insert.

#include <mysql.h>
#include <NdbApi.hpp>

// Used for cout
#include <iostream>

#define PRINT_ERROR(code,msg) \
  std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
            << ", code: " << code \
            << ", msg: " << msg << "." << std::endl
#define MYSQLERROR(mysql) { \
  PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
  exit(-1); }
#define APIERROR(error) \
  { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
              << error.code << ", msg: " << error.message << "." << std::endl; \
    exit(-1); }

static void create_table(MYSQL &);
static void drop_table(MYSQL &);
static void callback(int result, NdbTransaction* NdbObject, void* aObject);

int main(int argc, char** argv)
{
  if (argc != 3)
  {
    std::cout << "Arguments are <socket mysqld> <connect_string cluster>.\n";
    exit(-1);
  }
  char * mysqld_sock  = argv[1];
  const char *connectstring = argv[2];
  ndb_init();

  Ndb_cluster_connection *cluster_connection=
    new Ndb_cluster_connection(connectstring); // Object representing the cluster

  int r= cluster_connection->connect(5 /* retries               */,
				     3 /* delay between retries */,
				     1 /* verbose               */);
  if (r > 0)
  {
    std::cout
      << "Cluster connect failed, possibly resolved with more retries.\n";
    exit(-1);
  }
  else if (r < 0)
  {
    std::cout
      << "Cluster connect failed.\n";
    exit(-1);
  }

  if (cluster_connection->wait_until_ready(30,0) < 0)
  {
    std::cout << "Cluster was not ready within 30 secs." << std::endl;
    exit(-1);
  }

  // connect to mysql server
  MYSQL mysql;
  if ( !mysql_init(&mysql) ) {
    std::cout << "mysql_init failed\n";
    exit(-1);
  }
  if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
			   0, mysqld_sock, 0) )
    MYSQLERROR(mysql);

  /********************************************
   * Connect to database via mysql-c          *
   ********************************************/
  mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
  if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
  create_table(mysql);

  Ndb* myNdb = new Ndb( cluster_connection,
			"TEST_DB_1" );  // Object representing the database

  NdbTransaction*  myNdbTransaction[2];   // For transactions
  NdbOperation*   myNdbOperation;       // For operations

  if (myNdb->init(2) == -1) {          // Want two parallel insert transactions
    APIERROR(myNdb->getNdbError());
    exit(-1);
  }

  /******************************************************
   * Insert (we do two insert transactions in parallel) *
   ******************************************************/
  const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
  const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
  if (myTable == NULL)
    APIERROR(myDict->getNdbError());
  for (int i = 0; i < 2; i++) {
    myNdbTransaction[i] = myNdb->startTransaction();
    if (myNdbTransaction[i] == NULL) APIERROR(myNdb->getNdbError());

    myNdbOperation = myNdbTransaction[i]->getNdbOperation(myTable);
    if (myNdbOperation == NULL) APIERROR(myNdbTransaction[i]->getNdbError());

    myNdbOperation->insertTuple();
    myNdbOperation->equal("ATTR1", 20 + i);
    myNdbOperation->setValue("ATTR2", 20 + i);

    // Prepare transaction (the transaction is NOT yet sent to NDB)
    myNdbTransaction[i]->executeAsynchPrepare(NdbTransaction::Commit,
					      &callback, NULL);
  }

  // Send all transactions to NDB
  myNdb->sendPreparedTransactions(0);

  // Poll all transactions
  myNdb->pollNdb(3000, 2);

  // Close all transactions
  for (int i = 0; i < 2; i++)
    myNdb->closeTransaction(myNdbTransaction[i]);

  delete myNdb;
  delete cluster_connection;

  drop_table(mysql);

  ndb_end(0);
  return 0;
}

/*********************************************************
 * Create a table named MYTABLENAME if it does not exist *
 *********************************************************/
static void create_table(MYSQL &mysql)
{
  if (mysql_query(&mysql,
		  "CREATE TABLE"
		  "  MYTABLENAME"
		  "    (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
		  "     ATTR2 INT UNSIGNED NOT NULL)"
		  "  ENGINE=NDB"))
    MYSQLERROR(mysql);
}

/***********************************
 * Drop a table named MYTABLENAME
 ***********************************/
static void drop_table(MYSQL &mysql)
{
  if (mysql_query(&mysql,
		  "DROP TABLE"
		  "  MYTABLENAME"))
    MYSQLERROR(mysql);
}

/*
 *   callback : This is called when the transaction is polled
 *
 *   (This function must have three arguments:
 *   - The result of the transaction,
 *   - The NdbTransaction object, and
 *   - A pointer to an arbitrary object.)
 */

static void
callback(int result, NdbTransaction* myTrans, void* aObject)
{
  if (result == -1) {
    std::cout << "Poll error: " << std::endl;
    APIERROR(myTrans->getNdbError());
  } else {
    std::cout << "Successful insert." << std::endl;
  }
}
<|endoftext|>