/*
	ObjESSty-1
*/

/*
	Измерение производительности oess db при массовом
	создании/удалении объектов.
*/

#include <iostream>
#include <stdexcept>
#include <set>

#include <ctime>
#include <cstdio>
#include <cstdlib>

#include <oess_1/defs/h/ex.hpp>

#include <oess_1/stdsn/h/inout_templ.hpp>

#include <oess_1/db/cln/h/local_db.hpp>

class	data_t
	:	public oess_1::stdsn::serializable_t
	{
		typedef oess_1::stdsn::serializable_t	base_type_t;

		OESS_SERIALIZER( data_t )
	private :
		std::string	m_data;

	public :
		data_t()
			{}
		data_t( const char * data, std::size_t data_size )
			:	m_data( data, data_size )
			{}
		data_t( const data_t & o )
			{
				(*this) = o;
			}
		virtual ~data_t()
			{}

		data_t &
		operator=( const data_t & o )
			{
				base_type_t::operator=( o );
				m_data = o.m_data;

				return *this;
			}
	};

#include "main.ddl.cpp"

class	test_suite_t
	{
	public :
		virtual void
		run() = 0;
	};

typedef std::set< oess_1::ent_id_t >	ent_id_set_t;

class	object_creator_suite_t
	:	public test_suite_t
	{
	private :
		oess_1::db::cln::db_t &	m_db;
		ent_id_set_t &	m_entities;

	public :
		object_creator_suite_t(
			oess_1::db::cln::db_t & db,
			ent_id_set_t & entities )
			:	m_db( db )
			,	m_entities( entities )
			{
				std::srand( std::clock() );
			}

		virtual void
		run();
	};

void
object_creator_suite_t::run()
	{
		static char buf[ 100 * 1024 ];
		static char filler;

		int len = 0;
		do
		{
			len = rand() % sizeof( buf );
		} while( !len );

		for( int i = 0; i != len; ++i )
			buf[ i ] = filler++;

		m_entities.insert(
			m_db.ent_create( "test", data_t( buf, len ) ) );
	}

class	object_destroyer_suite_t
	:	public test_suite_t
	{
	private :
		oess_1::db::cln::db_t &	m_db;
		ent_id_set_t::const_iterator	m_current;

	public :
		object_destroyer_suite_t(
			oess_1::db::cln::db_t & db,
			const ent_id_set_t & entities )
			:	m_db( db )
			,	m_current( entities.begin() )
			{}

		virtual void
		run();
	};

void
object_destroyer_suite_t::run()
	{
		m_db.ent_destroy( *(m_current++) );
	}

void
run_and_measure(
	test_suite_t & suite )
{
	const unsigned long cycles = 10000ul;
	std::clock_t start, finish;

	start = std::clock();
	for( unsigned long i = 0; i != cycles; ++i )
		suite.run();
	finish = std::clock();

	double duration = double( finish - start ) / CLOCKS_PER_SEC;
	double price = duration / cycles;
	std::printf( "duration: %g, price: %g\n", duration, price );
}

int
main( int, char ** )
	{
		try {
			const std::string physic_name(
				"./test/bench/oess_db/create_remove/db" );

			oess_1::db::cln::local_db_t db( physic_name );
			db.query_db()->slice_create( "test" );

			ent_id_set_t entities;

			object_creator_suite_t creator( *(db.query_db()), entities );
			run_and_measure( creator );

			object_destroyer_suite_t destroyer( *(db.query_db()), entities );
			run_and_measure( destroyer );

		return 0;
		}
		catch( oess_1::ex_t & x ) {
			std::cerr << "*** " << x.query_err_code() << " ***"
				<< std::endl;
		}
		catch( ... ) {
			std::cerr << "Oops! Unknown exception!" << std::endl;
		}

		return 1;
	}
