DBMS: development.

This commit is contained in:
Alexey Milovidov 2009-07-17 18:08:48 +00:00
parent aafe93c440
commit ea150ca671
11 changed files with 1192 additions and 0 deletions

View File

@ -0,0 +1,293 @@
#ifndef DBMS_COLUMN_TYPE_H
#define DBMS_COLUMN_TYPE_H
#include <ostream>
#include <Poco/SharedPtr.h>
#include <Poco/BinaryWriter.h>
#include <Poco/BinaryReader.h>
#include <Poco/NumberParser.h>
#include <Poco/NumberFormatter.h>
#include <DB/Field.h>
#include <DB/Exception.h>
#include <DB/ErrorCodes.h>
#include <DB/VarInt.h>
namespace DB
{
/** Метаданные типа для хранения (столбца).
* Содержит методы для сериализации/десериализации.
*/
class IColumnType
{
public:
/// Основное имя типа (например, BIGINT UNSIGNED).
virtual std::string getName() const = 0;
/// Бинарная сериализация - для сохранения на диск / в сеть и т. п.
virtual void serializeBinary(const DB::Field & field, std::ostream & ostr) const = 0;
virtual void deserializeBinary(DB::Field & field, std::istream & ostr) const = 0;
/// Текстовая сериализация - для вывода на экран / сохранения в текстовый файл и т. п.
virtual void serializeText(const DB::Field & field, std::ostream & ostr) const = 0;
virtual void deserializeText(DB::Field & field, std::istream & ostr) const = 0;
/// Шаблонные методы для параметризуемого типа сериализации.
template <typename SerializationTag> void serialize(const DB::Field & field, std::ostream & ostr) const;
template <typename SerializationTag> void deserialize(DB::Field & field, std::istream & ostr) const;
};
struct BinarySerializationTag;
struct TextSerializationTag;
template <typename SerializationTag> struct SerializeImpl;
template <typename SerializationTag>
void IColumnType::serialize(const DB::Field & field, std::ostream & ostr) const
{
SerializeImpl<SerializationTag>::serialize(this, field, ostr);
}
template <typename SerializationTag>
void IColumnType::deserialize(DB::Field & field, std::istream & ostr) const
{
SerializeImpl<SerializationTag>::deserialize(this, field, ostr);
}
template <> struct SerializeImpl<BinarySerializationTag>
{
static inline void serialize(const IColumnType * column, const DB::Field & field, std::ostream & ostr)
{
column->serializeBinary(field, ostr);
}
static inline void deserialize(const IColumnType * column, DB::Field & field, std::istream & ostr)
{
column->deserializeBinary(field, ostr);
}
};
template <> struct SerializeImpl<TextSerializationTag>
{
static inline void serialize(const IColumnType * column, const DB::Field & field, std::ostream & ostr)
{
column->serializeText(field, ostr);
}
static inline void deserialize(const IColumnType * column, DB::Field & field, std::istream & ostr)
{
column->deserializeText(field, ostr);
}
};
class ColumnTypeUInt64 : public IColumnType
{
public:
std::string getName() const { return "UInt64"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
Poco::BinaryWriter w(ostr);
w << boost::get<UInt>(field);
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
Poco::BinaryReader r(istr);
r >> boost::get<UInt>(field);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << boost::get<UInt>(field);
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
istr >> boost::get<UInt>(field);
}
};
class ColumnTypeUInt32 : public IColumnType
{
public:
std::string getName() const { return "UInt32"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
Poco::BinaryWriter w(ostr);
w << static_cast<Poco::UInt32>(boost::get<UInt>(field));
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
Poco::BinaryReader r(istr);
Poco::UInt32 x;
r >> x;
boost::get<UInt>(field) = x;
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << static_cast<Poco::UInt32>(boost::get<UInt>(field));
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
Poco::UInt32 x;
istr >> x;
boost::get<UInt>(field) = x;
}
};
class ColumnTypeInt64 : public IColumnType
{
public:
std::string getName() const { return "Int64"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
Poco::BinaryWriter w(ostr);
w << boost::get<Int>(field);
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
Poco::BinaryReader r(istr);
r >> boost::get<Int>(field);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << boost::get<Int>(field);
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
istr >> boost::get<Int>(field);
}
};
class ColumnTypeInt32 : public IColumnType
{
public:
std::string getName() const { return "Int32"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
Poco::BinaryWriter w(ostr);
w << static_cast<Poco::Int32>(boost::get<Int>(field));
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
Poco::BinaryReader r(istr);
Poco::Int32 x;
r >> x;
boost::get<Int>(field) = x;
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << static_cast<Poco::Int32>(boost::get<Int>(field));
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
Poco::Int32 x;
istr >> x;
boost::get<Int>(field) = x;
}
};
class ColumnTypeVarUInt : public IColumnType
{
public:
std::string getName() const { return "VarUInt"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
writeVarUInt(boost::get<UInt>(field), ostr);
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
readVarUInt(boost::get<UInt>(field), istr);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << boost::get<UInt>(field);
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
istr >> boost::get<UInt>(field);
}
};
class ColumnTypeVarInt : public IColumnType
{
public:
std::string getName() const { return "VarInt"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
writeVarInt(boost::get<Int>(field), ostr);
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
readVarInt(boost::get<Int>(field), istr);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << boost::get<Int>(field);
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
istr >> boost::get<Int>(field);
}
};
class ColumnTypeFactory
{
public:
static Poco::SharedPtr<IColumnType> get(const std::string & name)
{
if (name == "VarUInt")
return new ColumnTypeVarUInt;
if (name == "VarInt")
return new ColumnTypeVarInt;
if (name == "UInt32")
return new ColumnTypeUInt32;
if (name == "UInt64")
return new ColumnTypeUInt64;
if (name == "Int32")
return new ColumnTypeUInt32;
if (name == "Int64")
return new ColumnTypeUInt64;
throw Exception("Unknown column type " + name, ErrorCodes::UNKNOWN_COLUMN_TYPE);
}
};
}
#endif

View File

@ -0,0 +1,19 @@
#ifndef DBMS_ERROR_CODES_H
#define DBMS_ERROR_CODES_H
namespace DB
{
namespace ErrorCodes
{
enum ErrorCodes
{
UNIMPLEMENTED_VISITOR_FOR_VARIANT = 1,
UNKNOWN_COLUMN_TYPE,
};
}
}
#endif

View File

@ -0,0 +1,16 @@
#ifndef DBMS_EXCEPTION_H
#define DBMS_EXCEPTION_H
#include <Poco/Exception.h>
namespace DB
{
/** Тип исключения, чтобы отличать его от других.
*/
POCO_DECLARE_EXCEPTION(Foundation_API, Exception, Poco::Exception);
}
#endif

101
dbms/include/DB/Field.h Normal file
View File

@ -0,0 +1,101 @@
#ifndef DBMS_FIELD_H
#define DBMS_FIELD_H
#include <string>
#include <vector>
#include <Poco/Types.h>
#include <boost/variant.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <DB/Exception.h>
#include <DB/ErrorCodes.h>
namespace DB
{
typedef Poco::Int64 Int;
typedef Poco::UInt64 UInt;
typedef std::string String;
struct Null {};
/** Используется для хранения значений в памяти
* - перед сериализацией и после десериализации из БД или результата.
* - при обработке запроса, для временных таблиц, для результата.
* Типов данных для хранения больше, чем перечисленных здесь внутренних представлений в памяти.
* Метаданные этих типов, а также правила их сериализации/десериализации находятся в файле ColumnType.h
*/
typedef boost::make_recursive_variant<
Int,
UInt,
String,
Null,
std::vector<boost::recursive_variant_> /// FieldVector
>::type Field;
typedef std::vector<Field> FieldVector; /// Значение типа "массив"
/** Визитор по умолчанию, который ничего не делает
* - нужно для того, чтобы наследоваться от него и писать меньше кода
* для визиторов, которые делают что-то содержательное только для нескольких вариантов.
*/
class FieldVisitorDefaultNothing : public boost::static_visitor<>
{
public:
template <typename T> void operator() (const T & x) const {}
};
/** Визитор по умолчанию, который для всех вариантов кидает исключение
* - нужно для того, чтобы наследоваться от него и писать меньше кода
* для визиторов, которые делают что-то содержательное только для нескольких вариантов,
* но передача в него других вариантов должна вызывать runtime ошибку.
*/
class FieldVisitorDefaultThrow : public boost::static_visitor<>
{
public:
void operator() (const DB::Int & x) const
{
throw Exception("Unimplemented visitor for variant Int", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::UInt & x) const
{
throw Exception("Unimplemented visitor for variant UInt", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::String & x) const
{
throw Exception("Unimplemented visitor for variant String", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::Null & x) const
{
throw Exception("Unimplemented visitor for variant Null", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::FieldVector & x) const
{
throw Exception("Unimplemented visitor for variant FieldVector", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
};
/** Возвращает true, если вариант - Null */
class FieldVisitorIsNull : public boost::static_visitor<bool>
{
public:
template <typename T> bool operator() (const T & x) const { return false; }
bool operator() (const DB::Null & x) const { return true; }
};
}
#endif

17
dbms/include/DB/Row.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef DBMS_ROW_H
#define DBMS_ROW_H
#include <DB/Field.h>
namespace DB
{
/** Используется для хранения строк в памяти
* - при обработке запроса, для временных таблиц, для результата.
*/
typedef std::vector<Field> Row;
}
#endif

36
dbms/include/DB/VarInt.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef DB_VARINT_H
#define DB_VARINT_H
#include <DB/Field.h>
namespace DB
{
/** Записать UInt64 в формате переменной длины (base128) */
void writeVarUInt(UInt x, std::ostream & ostr);
/** Прочитать UInt64, записанный в формате переменной длины (base128) */
void readVarUInt(UInt & x, std::istream & istr);
/** Записать Int64 в формате переменной длины (base128) */
inline void writeVarInt(Int x, std::ostream & ostr)
{
writeVarUInt(static_cast<UInt>((x << 1) ^ (x >> 63)), ostr);
}
/** Прочитать Int64, записанный в формате переменной длины (base128) */
inline void readVarInt(Int & x, std::istream & istr)
{
readVarUInt(reinterpret_cast<UInt&>(x), istr);
x = ((x >> 1) ^ (x << 63));
}
}
#endif

10
dbms/src/Exception.cpp Normal file
View File

@ -0,0 +1,10 @@
#include <typeinfo>
#include <DB/Exception.h>
namespace DB
{
POCO_IMPLEMENT_EXCEPTION(Exception, Poco::Exception, "DB::Exception");
}

140
dbms/src/VarInt.cpp Normal file
View File

@ -0,0 +1,140 @@
#include <DB/VarInt.h>
#include <Poco/Types.h>
namespace DB
{
void writeVarUInt(UInt x, std::ostream & ostr)
{
static char buf[9];
buf[0] = static_cast<Poco::UInt8>(x | 0x80);
if (x >= (1ULL << 7))
{
buf[1] = static_cast<Poco::UInt8>((x >> 7) | 0x80);
if (x >= (1ULL << 14))
{
buf[2] = static_cast<Poco::UInt8>((x >> 14) | 0x80);
if (x >= (1ULL << 21))
{
buf[3] = static_cast<Poco::UInt8>((x >> 21) | 0x80);
if (x >= (1ULL << 28))
{
buf[4] = static_cast<Poco::UInt8>((x >> 28) | 0x80);
if (x >= (1ULL << 35))
{
buf[5] = static_cast<Poco::UInt8>((x >> 35) | 0x80);
if (x >= (1ULL << 42))
{
buf[6] = static_cast<Poco::UInt8>((x >> 42) | 0x80);
if (x >= (1ULL << 49))
{
buf[7] = static_cast<Poco::UInt8>((x >> 49) | 0x80);
if (x >= (1ULL << 56))
{
buf[8] = static_cast<Poco::UInt8>((x >> 56) | 0x80);
ostr.write(buf, 9);
}
else
{
buf[7] &= 0x7F;
ostr.write(buf, 8);
}
}
else
{
buf[6] &= 0x7F;
ostr.write(buf, 7);
}
}
else
{
buf[5] &= 0x7F;
ostr.write(buf, 6);
}
}
else
{
buf[4] &= 0x7F;
ostr.write(buf, 5);
}
}
else
{
buf[3] &= 0x7F;
ostr.write(buf, 4);
}
}
else
{
buf[2] &= 0x7F;
ostr.write(buf, 3);
}
}
else
{
buf[1] &= 0x7F;
ostr.write(buf, 2);
}
}
else
{
buf[0] &= 0x7F;
ostr.write(buf, 1);
}
}
void readVarUInt(UInt & x, std::istream & istr)
{
int byte;
byte = istr.get();
x = static_cast<Poco::UInt64>(byte) & 0x7F;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 7;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 14;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 21;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 28;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 35;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 42;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 49;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 56;
}
}
}
}
}
}
}
}
}
}

322
dbms/src/tests/base128.cpp Normal file
View File

@ -0,0 +1,322 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <Poco/Types.h>
#include <Poco/BinaryWriter.h>
#include <Poco/BinaryReader.h>
#include <Poco/Stopwatch.h>
#include <Poco/Exception.h>
#include <Poco/NumberFormatter.h>
void writeVarUInt(Poco::UInt64 x, std::ostream & ostr)
{
static char buf[9];
buf[0] = static_cast<Poco::UInt8>(x | 0x80);
if (x >= (1ULL << 7))
{
buf[1] = static_cast<Poco::UInt8>((x >> 7) | 0x80);
if (x >= (1ULL << 14))
{
buf[2] = static_cast<Poco::UInt8>((x >> 14) | 0x80);
if (x >= (1ULL << 21))
{
buf[3] = static_cast<Poco::UInt8>((x >> 21) | 0x80);
if (x >= (1ULL << 28))
{
buf[4] = static_cast<Poco::UInt8>((x >> 28) | 0x80);
if (x >= (1ULL << 35))
{
buf[5] = static_cast<Poco::UInt8>((x >> 35) | 0x80);
if (x >= (1ULL << 42))
{
buf[6] = static_cast<Poco::UInt8>((x >> 42) | 0x80);
if (x >= (1ULL << 49))
{
buf[7] = static_cast<Poco::UInt8>((x >> 49) | 0x80);
if (x >= (1ULL << 56))
{
buf[8] = static_cast<Poco::UInt8>((x >> 56) | 0x80);
ostr.write(buf, 9);
}
else
{
buf[7] &= 0x7F;
ostr.write(buf, 8);
}
}
else
{
buf[6] &= 0x7F;
ostr.write(buf, 7);
}
}
else
{
buf[5] &= 0x7F;
ostr.write(buf, 6);
}
}
else
{
buf[4] &= 0x7F;
ostr.write(buf, 5);
}
}
else
{
buf[3] &= 0x7F;
ostr.write(buf, 4);
}
}
else
{
buf[2] &= 0x7F;
ostr.write(buf, 3);
}
}
else
{
buf[1] &= 0x7F;
ostr.write(buf, 2);
}
}
else
{
buf[0] &= 0x7F;
ostr.write(buf, 1);
}
}
void readVarUInt(Poco::UInt64 & x, std::istream & istr)
{
int byte;
byte = istr.get();
x = static_cast<Poco::UInt64>(byte) & 0x7F;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 7;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 14;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 21;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 28;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 35;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 42;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 49;
if (byte & 0x80)
{
byte = istr.get();
x |= (static_cast<Poco::UInt64>(byte) & 0x7F) << 56;
}
}
}
}
}
}
}
}
}
void readVarUInt_2(Poco::UInt64 & x, std::istream & istr)
{
static char buf[9];
istr.read(buf, 9);
x = static_cast<Poco::UInt64>(buf[0]) & 0x7F;
if (buf[0] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[1]) & 0x7F) << 7;
if (buf[1] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[2]) & 0x7F) << 14;
if (buf[2] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[3]) & 0x7F) << 21;
if (buf[3] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[4]) & 0x7F) << 28;
if (buf[4] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[5]) & 0x7F) << 35;
if (buf[5] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[6]) & 0x7F) << 42;
if (buf[6] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[7]) & 0x7F) << 49;
if (buf[7] & 0x80)
{
x |= (static_cast<Poco::UInt64>(buf[8]) & 0x7F) << 56;
}
else
{
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
istr.unget();
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
}
}
else
{
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
istr.unget();
}
}
void writeVarInt(Poco::Int64 x, std::ostream & ostr)
{
writeVarUInt(static_cast<Poco::UInt64>((x << 1) ^ (x >> 63)), ostr);
}
void readVarInt(Poco::Int64 & x, std::istream & istr)
{
readVarUInt_2(reinterpret_cast<Poco::UInt64&>(x), istr);
x = ((x >> 1) ^ (x << 63));
}
int main(int argc, char ** argv)
{
try
{
Poco::Stopwatch stopwatch;
Poco::Timestamp::TimeDiff elapsed;
Poco::Int64 start = 0;//1234567890123456789LL;
{
std::ofstream ostr("tmp1");
stopwatch.restart();
for (Poco::Int64 i = start; i < start + 10000000; i++)
writeVarInt(i, ostr);
stopwatch.stop();
elapsed = stopwatch.elapsed();
std::cout << "writeVarInt: " << static_cast<double>(elapsed) / 1000000 << std::endl;
}
{
std::ifstream ostr("tmp1");
Poco::Int64 x;
stopwatch.restart();
for (Poco::Int64 i = start; i < start + 10000000; i++)
{
readVarInt(x, ostr);
if (x != i)
throw Poco::Exception(Poco::NumberFormatter::format(i));
}
stopwatch.stop();
elapsed = stopwatch.elapsed();
std::cout << "readVarInt: " << static_cast<double>(elapsed) / 1000000 << std::endl;
}
{
std::ofstream ostr("tmp3");
Poco::BinaryWriter writer(ostr);
stopwatch.restart();
for (Poco::Int64 i = start; i < start + 10000000; i++)
writer << i;
stopwatch.stop();
elapsed = stopwatch.elapsed();
std::cout << "BinaryWriter: " << static_cast<double>(elapsed) / 1000000 << std::endl;
}
{
std::ofstream ostr("tmp4");
stopwatch.restart();
for (Poco::Int64 i = start; i < start + 10000000; i++)
ostr.write(reinterpret_cast<char*>(&i), 8);
stopwatch.stop();
elapsed = stopwatch.elapsed();
std::cout << "ostream::write: " << static_cast<double>(elapsed) / 1000000 << std::endl;
}
}
catch (const Poco::Exception & e)
{
std::cout << e.message() << std::endl;
throw;
}
return 0;
}

View File

@ -0,0 +1,74 @@
#include <iostream>
#include <fstream>
#include <Poco/Stopwatch.h>
#include <Poco/Timespan.h>
#include <Poco/Exception.h>
#include <DB/ColumnType.h>
int main(int argc, char ** argv)
{
DB::FieldVector vec;
vec.reserve(10000000);
Poco::Stopwatch stopwatch;
Poco::SharedPtr<DB::IColumnType> column_type = DB::ColumnTypeFactory::get("VarUInt");
{
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
vec.push_back(DB::UInt(i));
}
stopwatch.stop();
std::cout << "Filling array: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
{
std::ofstream ostr("test");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
column_type->serializeBinary(vec[i], ostr);
}
stopwatch.stop();
std::cout << "Serialization: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
{
std::ifstream istr("test");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
column_type->deserializeBinary(vec[i], istr);
}
stopwatch.stop();
std::cout << "Deserialization: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
{
std::ofstream ostr("test2");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
column_type->serializeText(vec[i], ostr);
ostr.put('\t');
}
stopwatch.stop();
std::cout << "Serialization (text): " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
{
std::ifstream istr("test2");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
column_type->deserializeText(vec[i], istr);
}
stopwatch.stop();
std::cout << "Deserialization (text): " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
return 0;
}

View File

@ -0,0 +1,164 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <functional>
#include <cmath>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/get.hpp>
#include <boost/any.hpp>
#include <Poco/Stopwatch.h>
#include <Poco/Timespan.h>
#include <Poco/Exception.h>
#include <DB/Field.h>
#include <DB/ColumnType.h>
class FieldOutVisitor : public boost::static_visitor<>
{
public:
FieldOutVisitor(std::ostream & ostr_, unsigned indent_ = 0)
: ostr(ostr_), indent(indent_) {}
void operator() (const DB::Int & x) const
{
for (unsigned i = 0; i < indent; ++i)
ostr.put('\t');
ostr << x << "," << std::endl;
}
void operator() (const DB::UInt & x) const
{
for (unsigned i = 0; i < indent; ++i)
ostr.put('\t');
ostr << x << "," << std::endl;
}
void operator() (const DB::String & x) const
{
for (unsigned i = 0; i < indent; ++i)
ostr.put('\t');
ostr << x << "," << std::endl;
}
void operator() (const DB::Null & x) const
{
for (unsigned i = 0; i < indent; ++i)
ostr.put('\t');
ostr << "NULL," << std::endl;
}
void operator() (const DB::FieldVector & x) const
{
for (unsigned i = 0; i < indent; ++i)
ostr.put('\t');
ostr << '{' << std::endl;
FieldOutVisitor visitor(ostr, indent + 1);
std::for_each(x.begin(), x.end(), boost::apply_visitor(visitor));
for (unsigned i = 0; i < indent; ++i)
ostr.put('\t');
ostr << '}' << "," << std::endl;
}
private:
std::ostream & ostr;
unsigned indent;
};
class TimesTwoVisitor : public boost::static_visitor<>
{
public:
template <typename T> void operator() (T & x) const { x *= 2; }
void operator() (DB::Null & x) const {}
void operator() (DB::String & x) const { x = ""; }
void operator() (DB::FieldVector & x) const
{
TimesTwoVisitor visitor;
std::for_each(x.begin(), x.end(), boost::apply_visitor(visitor));
}
};
class DynamicTimesTwoVisitor
{
public:
void operator() (boost::any & x) const
{
if (x.type() == typeid(DB::UInt))
boost::any_cast<DB::UInt&>(x) *= 2;
else if (x.type() == typeid(DB::String))
boost::any_cast<DB::String&>(x) = "";
else
throw Poco::Exception("Unknown type");
}
};
int main(int argc, char ** argv)
{
Poco::Stopwatch stopwatch;
{
DB::FieldVector arr;
DB::Field field(arr);
DB::FieldVector & vec = boost::get<DB::FieldVector>(field);
vec.reserve(10000000);
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
if (i % 100 != 0)
vec.push_back(DB::UInt(10));
else
vec.push_back("http://www.boost.org/doc/libs/1_39_0/doc/html/variant/tutorial.html#variant.tutorial.recursive.recursive-variant");
}
stopwatch.stop();
std::cout << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
stopwatch.restart();
boost::apply_visitor(TimesTwoVisitor(), field);
stopwatch.stop();
std::cout << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
//std::ofstream ostr("/dev/null");
//boost::apply_visitor(FieldOutVisitor(ostr), field);
sleep(10);
}
{
std::vector<boost::any> vec;
vec.reserve(10000000);
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
{
if (i % 100 != 0)
vec.push_back(DB::UInt(10));
else
vec.push_back(DB::String("http://www.boost.org/doc/libs/1_39_0/doc/html/variant/tutorial.html#variant.tutorial.recursive.recursive-variant"));
}
stopwatch.stop();
std::cout << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
stopwatch.restart();
DynamicTimesTwoVisitor visitor;
std::for_each(vec.begin(), vec.end(), visitor);
stopwatch.stop();
Poco::Timestamp::TimeDiff elapsed(stopwatch.elapsed());
std::cout << static_cast<double>(elapsed) / 1000000 << std::endl;
sleep(10);
}
return 0;
}