mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-03 13:02:00 +00:00
dbms: development.
This commit is contained in:
parent
c8e544b0f6
commit
2dbd493503
35
dbms/include/DB/AggregateFunction.h
Normal file
35
dbms/include/DB/AggregateFunction.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef DBMS_AGGREGATE_FUNCTION_H
|
||||
#define DBMS_AGGREGATE_FUNCTION_H
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Агрегатная функция
|
||||
* Шаблонный параметр здесь только потому что непонятно, как сделать forward declaration Field из Field.h.
|
||||
*/
|
||||
template<typename Field>
|
||||
class IAggregateFunction
|
||||
{
|
||||
public:
|
||||
virtual void add(const Field & a) = 0;
|
||||
|
||||
virtual Field getValue() const = 0;
|
||||
|
||||
/** Бинарная сериализация и десериализация состояния для передачи по сети.
|
||||
* При чём, deserializeMerge производит объединение текущего и считываемого состояний.
|
||||
*/
|
||||
virtual void serialize(std::ostream & ostr) const = 0;
|
||||
virtual void deserializeMerge(std::istream & istr) = 0;
|
||||
|
||||
/** Объединение состояния агрегатной функции с состоянием другой агрегатной функции. */
|
||||
virtual void merge(const IAggregateFunction & rhs) = 0;
|
||||
|
||||
virtual ~IAggregateFunction() {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
24
dbms/include/DB/Column.h
Normal file
24
dbms/include/DB/Column.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef DBMS_COLUMN_H
|
||||
#define DBMS_COLUMN_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
#include <DB/ColumnType.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Столбец - часть ColumnGroup, которая, в свою очередь - часть таблицы
|
||||
*/
|
||||
struct Column
|
||||
{
|
||||
std::string name;
|
||||
Poco::SharedPtr<IColumnType> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
32
dbms/include/DB/ColumnGroup.h
Normal file
32
dbms/include/DB/ColumnGroup.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef DBMS_COLUMN_GROUP_H
|
||||
#define DBMS_COLUMN_GROUP_H
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
#include <DB/Column.h>
|
||||
#include <DB/PrimaryKey.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** ColumnGroup - часть таблицы, которая хранится отдельно.
|
||||
* Может состоять из одного, нескольких или всех столбцов таблицы.
|
||||
* Таблица состоит из column-групп.
|
||||
*/
|
||||
struct ColumnGroup
|
||||
{
|
||||
/// Номера столбцов
|
||||
typedef std::vector<size_t> ColumnNumbers;
|
||||
ColumnNumbers column_numbers;
|
||||
|
||||
/// Первичный ключ
|
||||
Poco::SharedPtr<IPrimaryKey> primary_key;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -36,17 +36,19 @@ public:
|
||||
|
||||
/// Бинарная сериализация - для сохранения на диск / в сеть и т. п.
|
||||
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 deserializeBinary(DB::Field & field, std::istream & istr) const = 0;
|
||||
|
||||
/** Текстовая сериализация - для вывода на экран / сохранения в текстовый файл и т. п.
|
||||
* Считается, что разделители, а также escape-инг обязан делать вызывающий.
|
||||
*/
|
||||
virtual void serializeText(const DB::Field & field, std::ostream & ostr) const = 0;
|
||||
virtual void deserializeText(DB::Field & field, std::istream & ostr) const = 0;
|
||||
virtual void deserializeText(DB::Field & field, std::istream & istr) 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;
|
||||
template <typename SerializationTag> void deserialize(DB::Field & field, std::istream & istr) const;
|
||||
|
||||
virtual ~IColumnType() {}
|
||||
};
|
||||
|
||||
|
||||
@ -288,7 +290,7 @@ public:
|
||||
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
|
||||
{
|
||||
const std::string & str = boost::get<String>(field);
|
||||
writeVarUInt(str.size(), ostr);
|
||||
writeVarUInt(UInt(str.size()), ostr);
|
||||
ostr << str;
|
||||
}
|
||||
|
||||
@ -335,7 +337,7 @@ public:
|
||||
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
|
||||
{
|
||||
const String & str = boost::get<String>(field);
|
||||
if (str.size() != size)
|
||||
if (UInt(str.size()) != size)
|
||||
throw Exception("Incorrect size of value of type " + getName()
|
||||
+ ": " + Poco::NumberFormatter::format(str.size()), ErrorCodes::INCORRECT_SIZE_OF_VALUE);
|
||||
|
||||
@ -383,8 +385,8 @@ public:
|
||||
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
|
||||
{
|
||||
const FieldVector & vec = boost::get<FieldVector>(field);
|
||||
writeVarUInt(vec.size(), ostr);
|
||||
for (UInt i = 0; i < vec.size(); ++i)
|
||||
writeVarUInt(UInt(vec.size()), ostr);
|
||||
for (UInt i(0); i < vec.size(); ++i)
|
||||
nested_type->serializeBinary(vec[i], ostr);
|
||||
}
|
||||
|
||||
@ -394,14 +396,14 @@ public:
|
||||
UInt size;
|
||||
readVarUInt(size, istr);
|
||||
vec.resize(size);
|
||||
for (UInt i = 0; i < size; ++i)
|
||||
for (UInt i(0); i < size; ++i)
|
||||
nested_type->deserializeBinary(vec[i], istr);
|
||||
}
|
||||
|
||||
void serializeText(const DB::Field & field, std::ostream & ostr) const
|
||||
{
|
||||
const FieldVector & vec = boost::get<FieldVector>(field);
|
||||
for (UInt i = 0; i < vec.size(); ++i)
|
||||
for (UInt i(0); i < vec.size(); ++i)
|
||||
{
|
||||
std::stringstream stream;
|
||||
nested_type->serializeText(vec[i], stream);
|
||||
@ -441,11 +443,11 @@ public:
|
||||
{
|
||||
const FieldVector & vec = boost::get<FieldVector>(field);
|
||||
|
||||
if (vec.size() != size)
|
||||
if (UInt(vec.size()) != size)
|
||||
throw Exception("Incorrect size of value of type " + getName()
|
||||
+ ": " + Poco::NumberFormatter::format(vec.size()), ErrorCodes::INCORRECT_SIZE_OF_VALUE);
|
||||
|
||||
for (UInt i = 0; i < size; ++i)
|
||||
for (UInt i(0); i < size; ++i)
|
||||
nested_type->serializeBinary(vec[i], ostr);
|
||||
}
|
||||
|
||||
@ -453,14 +455,14 @@ public:
|
||||
{
|
||||
FieldVector & vec = boost::get<FieldVector>(field);
|
||||
vec.resize(size);
|
||||
for (UInt i = 0; i < size; ++i)
|
||||
for (UInt i(0); i < size; ++i)
|
||||
nested_type->deserializeBinary(vec[i], istr);
|
||||
}
|
||||
|
||||
void serializeText(const DB::Field & field, std::ostream & ostr) const
|
||||
{
|
||||
const FieldVector & vec = boost::get<FieldVector>(field);
|
||||
for (UInt i = 0; i < size; ++i)
|
||||
for (UInt i(0); i < size; ++i)
|
||||
{
|
||||
std::stringstream stream;
|
||||
nested_type->serializeText(vec[i], stream);
|
||||
|
@ -14,6 +14,11 @@ namespace ErrorCodes
|
||||
INCORRECT_PARAMETER_FOR_TYPE,
|
||||
INCORRECT_SIZE_OF_VALUE,
|
||||
METHOD_NOT_IMPLEMENTED,
|
||||
CANT_READ_INDEX_FILE,
|
||||
TOO_FEW_COLUMNS_FOR_KEY,
|
||||
PRIMARY_KEY_WAS_NOT_ATTACHED,
|
||||
CANT_READ_DATA_FILE,
|
||||
TOO_MANY_COLUMNS_FOR_KEY
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,17 @@
|
||||
#include <vector>
|
||||
|
||||
#include <Poco/Types.h>
|
||||
#include <Poco/Void.h>
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
#include <boost/strong_typedef.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/variant/recursive_variant.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
#include <DB/Exception.h>
|
||||
#include <DB/ErrorCodes.h>
|
||||
#include <DB/AggregateFunction.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -21,8 +25,7 @@ namespace DB
|
||||
typedef Poco::Int64 Int;
|
||||
typedef Poco::UInt64 UInt;
|
||||
typedef std::string String;
|
||||
|
||||
struct Null {};
|
||||
BOOST_STRONG_TYPEDEF(char, Null);
|
||||
|
||||
|
||||
/** Используется для хранения значений в памяти
|
||||
@ -36,56 +39,19 @@ typedef boost::make_recursive_variant<
|
||||
UInt,
|
||||
String,
|
||||
Null,
|
||||
Poco::SharedPtr<IAggregateFunction<boost::recursive_variant_> >,
|
||||
std::vector<boost::recursive_variant_> /// FieldVector
|
||||
>::type Field;
|
||||
|
||||
typedef std::vector<Field> FieldVector; /// Значение типа "массив"
|
||||
typedef Poco::SharedPtr<IAggregateFunction<Field> > AggregateFunctionPtr;
|
||||
|
||||
|
||||
/** Визитор по умолчанию, который ничего не делает
|
||||
* - нужно для того, чтобы наследоваться от него и писать меньше кода
|
||||
* для визиторов, которые делают что-то содержательное только для нескольких вариантов.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
};
|
||||
/// почему-то у boost::variant определены операторы < и ==, но не остальные операторы сравнения
|
||||
inline bool operator!= (const Field & lhs, const Field & rhs) { return !(lhs == rhs); }
|
||||
inline bool operator<= (const Field & lhs, const Field & rhs) { return lhs < rhs || lhs == rhs; }
|
||||
inline bool operator>= (const Field & lhs, const Field & rhs) { return !(lhs < rhs); }
|
||||
inline bool operator> (const Field & lhs, const Field & rhs) { return !(lhs < rhs) && !(lhs == rhs); }
|
||||
|
||||
|
||||
/** Возвращает true, если вариант - Null */
|
||||
@ -97,6 +63,32 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** Принимает два значения Field, обновляет первое вторым.
|
||||
* Если только первое - не агрегатная функция, результат обновления - замена первого вторым.
|
||||
* Иначе - добавление к агрегатной функции значения или объединение агрегатных функций.
|
||||
*/
|
||||
class FieldVisitorUpdate : public boost::static_visitor<>
|
||||
{
|
||||
public:
|
||||
template <typename T, typename U>
|
||||
void operator() (T & x, const U & y) const
|
||||
{
|
||||
x = y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator() (AggregateFunctionPtr & x, const T & y) const
|
||||
{
|
||||
x->add(y);
|
||||
}
|
||||
|
||||
void operator() (AggregateFunctionPtr & x, const AggregateFunctionPtr & y) const
|
||||
{
|
||||
x->merge(*y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
82
dbms/include/DB/PrimaryKey.h
Normal file
82
dbms/include/DB/PrimaryKey.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef DBMS_PRIMARY_KEY_H
|
||||
#define DBMS_PRIMARY_KEY_H
|
||||
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
#include <DB/RowSet.h>
|
||||
#include <DB/TablePartReader.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class ColumnGroup;
|
||||
class Table;
|
||||
|
||||
|
||||
/** Первичный ключ - самая важная часть БД.
|
||||
* Отвечает за:
|
||||
* - определение, в каком файле (или не файле) хранятся данные;
|
||||
* - поиск данных и обновление данных;
|
||||
* - структура хранения данных (сжатие, etc.)
|
||||
* - конкуррентный доступ к данным (блокировки, etc.)
|
||||
*
|
||||
* Присутствуют следующие особенности первичного ключа:
|
||||
* - может состоять из нескольких частей. Например, значения первых нескольких столбцов индексируются
|
||||
* с помощью файловой системы для удобства бэкапа и устаревания данных; а значения остальных столбцов
|
||||
* индексируются с помощью B-дерева.
|
||||
* - может не полностью индексировать столбцы, однозначно идентифицирующие строку в таблице -
|
||||
* для работы с пачками строк.
|
||||
*/
|
||||
class IPrimaryKey
|
||||
{
|
||||
friend class Table;
|
||||
|
||||
private:
|
||||
/** Установить указатель на таблицу и кол-группу.
|
||||
* - часть инициализации, которая выполняется при инициализации таблицы.
|
||||
* (инициализация первичного ключа выполняется в два шага:
|
||||
* 1 - конструктор,
|
||||
* 2 - добавление к таблице (выполняется в конструкторе Table))
|
||||
*/
|
||||
virtual void addToTable(Table * table_, ColumnGroup * column_group_) = 0;
|
||||
|
||||
public:
|
||||
/** Прочитать данные, соответствующие точному значению ключа или префиксу.
|
||||
* Возвращает объект, с помощью которого можно последовательно читать данные.
|
||||
*/
|
||||
virtual Poco::SharedPtr<ITablePartReader> read(const Row & key) = 0;
|
||||
|
||||
/** Записать пачку данных в таблицу, обновляя существующие данные, если они есть.
|
||||
* @param data - набор данных вида ключ (набор столбцов) -> значение (набор столбцов)
|
||||
* @param mask - битовая маска - какие столбцы входят в кол-группу,
|
||||
* которую индексирует этот первичный ключ
|
||||
*/
|
||||
virtual void merge(const AggregatedRowSet & data, const ColumnMask & mask) = 0;
|
||||
|
||||
virtual ~IPrimaryKey() {}
|
||||
};
|
||||
|
||||
|
||||
/** Реализует метод addToTable(),
|
||||
* а также содержит члены table, column_group.
|
||||
*/
|
||||
class PrimaryKeyBase : public IPrimaryKey
|
||||
{
|
||||
protected:
|
||||
/// Слабые указатели на таблицу и column_group, которые владеют этим первичным ключём.
|
||||
Table * table;
|
||||
ColumnGroup * column_group;
|
||||
|
||||
PrimaryKeyBase() : table(0), column_group(0) {}
|
||||
|
||||
void addToTable(Table * table_, ColumnGroup * column_group_)
|
||||
{
|
||||
table = table_;
|
||||
column_group = column_group_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
58
dbms/include/DB/PrimaryKeyNone.h
Normal file
58
dbms/include/DB/PrimaryKeyNone.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef DBMS_PRIMARY_KEY_NONE_H
|
||||
#define DBMS_PRIMARY_KEY_NONE_H
|
||||
|
||||
#include <Poco/SharedPtr.h>
|
||||
#include <Poco/File.h>
|
||||
#include <Poco/FileStream.h>
|
||||
|
||||
#include <DB/PrimaryKey.h>
|
||||
#include <DB/TablePartReader.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Самый простой первичный ключ - ничего не индексирует;
|
||||
* для чтения или обновления приходится читать файл целиком.
|
||||
* - удобно для логов.
|
||||
*/
|
||||
class PrimaryKeyNone : public PrimaryKeyBase
|
||||
{
|
||||
friend class PrimaryKeyNoneTablePartReader;
|
||||
private:
|
||||
std::string path;
|
||||
std::string name;
|
||||
std::string data_file_name;
|
||||
|
||||
Poco::File data_file;
|
||||
|
||||
public:
|
||||
/** Путь со слешем на конце. */
|
||||
PrimaryKeyNone(const std::string & path_, const std::string & name_);
|
||||
|
||||
/** Просто дописывает данные в конец. */
|
||||
void merge(const AggregatedRowSet & data, const ColumnMask & mask);
|
||||
|
||||
/** Прочитать данные, префикс ключа которых совпадает с key */
|
||||
Poco::SharedPtr<ITablePartReader> read(const Row & key);
|
||||
};
|
||||
|
||||
|
||||
class PrimaryKeyNoneTablePartReader : public ITablePartReader
|
||||
{
|
||||
friend class PrimaryKeyNone;
|
||||
private:
|
||||
const Row key;
|
||||
/// слабый указатель на первичный ключ
|
||||
PrimaryKeyNone * pk;
|
||||
Poco::FileInputStream istr;
|
||||
|
||||
PrimaryKeyNoneTablePartReader(const Row & key_, PrimaryKeyNone * pk_);
|
||||
|
||||
public:
|
||||
bool fetch(Row & row);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
64
dbms/include/DB/PrimaryKeyPlain.h
Normal file
64
dbms/include/DB/PrimaryKeyPlain.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef DBMS_PRIMARY_KEY_PLAIN_H
|
||||
#define DBMS_PRIMARY_KEY_PLAIN_H
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <Poco/SharedPtr.h>
|
||||
#include <Poco/BinaryReader.h>
|
||||
|
||||
#include <DB/Table.h>
|
||||
|
||||
#include <DB/PrimaryKey.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Простой, "плоский" первичный ключ.
|
||||
* Хранит список смещений в бинарном файле, список свободных блоков - в другом бинарном файле.
|
||||
* Поиск в этом файле линейный.
|
||||
* При обновлении данных, индексный файл полностью перезаписывается.
|
||||
* Файл с данными не сжатый.
|
||||
* Индекс полностью загружается в память во время работы.
|
||||
*/
|
||||
class PrimaryKeyPlain : public PrimaryKeyBase
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
std::string name;
|
||||
|
||||
std::string data_file_name;
|
||||
std::string offsets_file_name;
|
||||
std::string free_blocks_file_name;
|
||||
|
||||
Poco::File data_file;
|
||||
Poco::File offsets_file;
|
||||
Poco::File free_blocks_file;
|
||||
|
||||
struct Offset
|
||||
{
|
||||
size_t offset; /// смещение от начала файла
|
||||
size_t size; /// размер данных
|
||||
|
||||
bool operator< (const Offset & rhs) const
|
||||
{
|
||||
return size < rhs.size;
|
||||
}
|
||||
};
|
||||
|
||||
std::map<Row, Offset> offsets;
|
||||
std::set<Offset> free_blocks;
|
||||
|
||||
public:
|
||||
/** Путь со слешем на конце. */
|
||||
PrimaryKeyPlain(const std::string & path_, const std::string & name_);
|
||||
|
||||
void addToTable(Table * table_, ColumnGroup * column_group_);
|
||||
|
||||
void merge(const AggregatedRowSet & data, const ColumnMask & mask);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,17 +1,21 @@
|
||||
#ifndef DBMS_ROW_H
|
||||
#define DBMS_ROW_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <DB/Field.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Используется для хранения строк в памяти
|
||||
* - при обработке запроса, для временных таблиц, для результата.
|
||||
*/
|
||||
/** Строка или часть строки.
|
||||
* Используется для хранения строк в памяти
|
||||
* - при обработке запроса, для временных таблиц, для результата.
|
||||
*/
|
||||
typedef std::vector<Field> Row;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
26
dbms/include/DB/RowSet.h
Normal file
26
dbms/include/DB/RowSet.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef DBMS_ROW_SET_H
|
||||
#define DBMS_ROW_SET_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <DB/Row.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Набор строк. */
|
||||
typedef std::vector<Row> RowSet;
|
||||
|
||||
/** Набор строк, использующийся в качестве результата запроса с агрегатными функциями,
|
||||
* а также как массив для загрузки данных в таблицу.
|
||||
*/
|
||||
typedef std::map<Row, Row> AggregatedRowSet;
|
||||
|
||||
/** Битовая маска столбцов. */
|
||||
typedef std::vector<bool> ColumnMask;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
57
dbms/include/DB/Table.h
Normal file
57
dbms/include/DB/Table.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef DBMS_TABLE_H
|
||||
#define DBMS_TABLE_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
#include <DB/Column.h>
|
||||
#include <DB/ColumnGroup.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class Table
|
||||
{
|
||||
friend class PrimaryKeyNone;
|
||||
friend class PrimaryKeyNoneTablePartReader;
|
||||
friend class PrimaryKeyPlain;
|
||||
|
||||
public:
|
||||
typedef std::vector<Column> Columns;
|
||||
typedef std::vector<size_t> ColumnNumbers;
|
||||
typedef std::vector<ColumnGroup> ColumnGroups;
|
||||
|
||||
private:
|
||||
/// Имя таблицы
|
||||
std::string name;
|
||||
|
||||
/// Столбцы
|
||||
Poco::SharedPtr<Columns> columns;
|
||||
|
||||
/// Столбцы, которые относятся к первичному ключу
|
||||
Poco::SharedPtr<ColumnNumbers> primary_key_column_numbers;
|
||||
|
||||
/// Группы столбцов
|
||||
Poco::SharedPtr<ColumnGroups> column_groups;
|
||||
|
||||
public:
|
||||
Table(const std::string & name_,
|
||||
const Poco::SharedPtr<Columns> columns_,
|
||||
const Poco::SharedPtr<ColumnNumbers> primary_key_column_numbers_,
|
||||
const Poco::SharedPtr<ColumnGroups> column_groups_)
|
||||
: name(name_),
|
||||
columns(columns_),
|
||||
primary_key_column_numbers(primary_key_column_numbers_),
|
||||
column_groups(column_groups_)
|
||||
{
|
||||
/// Пропишем в первичных ключах в кол-группах указатель на таблицу и кол-группу
|
||||
for (ColumnGroups::iterator it = column_groups->begin(); it != column_groups->end(); ++it)
|
||||
it->primary_key->addToTable(this, &*it);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
21
dbms/include/DB/TablePartReader.h
Normal file
21
dbms/include/DB/TablePartReader.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef DBMS_TABLE_PART_READER_H
|
||||
#define DBMS_TABLE_PART_READER_H
|
||||
|
||||
#include <DB/Row.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class ITablePartReader
|
||||
{
|
||||
public:
|
||||
/// прочитать следующую строку, вернуть false, если строк больше нет
|
||||
virtual bool fetch(Row & row) = 0;
|
||||
|
||||
virtual ~ITablePartReader() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
87
dbms/src/PrimaryKeyNone.cpp
Normal file
87
dbms/src/PrimaryKeyNone.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include <DB/Exception.h>
|
||||
#include <DB/ErrorCodes.h>
|
||||
#include <DB/Table.h>
|
||||
#include <DB/ColumnGroup.h>
|
||||
|
||||
#include <DB/PrimaryKeyNone.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
PrimaryKeyNone::PrimaryKeyNone(const std::string & path_, const std::string & name_)
|
||||
: path(path_),
|
||||
name(name_),
|
||||
data_file_name(path + name + ".dat"),
|
||||
data_file(data_file_name)
|
||||
{
|
||||
/// создаём файлы, если их ещё нет
|
||||
data_file.createFile();
|
||||
}
|
||||
|
||||
|
||||
void PrimaryKeyNone::merge(const AggregatedRowSet & data, const ColumnMask & mask)
|
||||
{
|
||||
if (!table || !column_group)
|
||||
throw Exception("Primary key was not attached to table and column group",
|
||||
ErrorCodes::PRIMARY_KEY_WAS_NOT_ATTACHED);
|
||||
|
||||
/// просто дописываем данные в конец файла
|
||||
Poco::FileOutputStream ostr(data_file_name, std::ios::out | std::ios::binary | std::ios::app);
|
||||
|
||||
for (AggregatedRowSet::const_iterator it = data.begin(); it != data.end(); ++it)
|
||||
{
|
||||
for (size_t j = 0; j != it->first.size(); ++j)
|
||||
if (mask[j])
|
||||
table->columns->at(column_group->column_numbers[j]).type->serializeBinary(it->first[j], ostr);
|
||||
|
||||
for (size_t j = 0; j != it->second.size(); ++j)
|
||||
if (mask[j + it->first.size()])
|
||||
table->columns->at(
|
||||
column_group->column_numbers[j + it->first.size()]
|
||||
).type->serializeBinary(it->second[j], ostr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Poco::SharedPtr<ITablePartReader> PrimaryKeyNone::read(const Row & key)
|
||||
{
|
||||
return new PrimaryKeyNoneTablePartReader(key, this);
|
||||
}
|
||||
|
||||
|
||||
PrimaryKeyNoneTablePartReader::PrimaryKeyNoneTablePartReader(
|
||||
const Row & key_, PrimaryKeyNone * pk_)
|
||||
: key(key_), pk(pk_), istr(pk->data_file_name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PrimaryKeyNoneTablePartReader::fetch(Row & row)
|
||||
{
|
||||
if (key.size() > pk->column_group->column_numbers.size())
|
||||
throw Exception("Too many columns specified for key", ErrorCodes::TOO_MANY_COLUMNS_FOR_KEY);
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (size_t i = 0; i < pk->column_group->column_numbers.size(); ++i)
|
||||
pk->table->columns->at(pk->column_group->column_numbers[i]).type->deserializeBinary(row[i], istr);
|
||||
|
||||
/// проверим, что ключи совпадают (замечание: столбцы ключа всегда идут первыми)
|
||||
for (size_t i = 0; i < key.size(); ++i)
|
||||
if (key[i] != row[i])
|
||||
continue;
|
||||
|
||||
if (istr.eof())
|
||||
return false;
|
||||
|
||||
if (istr.fail())
|
||||
throw Exception("Cannot read data file " + pk->data_file_name
|
||||
, ErrorCodes::CANT_READ_DATA_FILE);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
99
dbms/src/PrimaryKeyPlain.cpp
Normal file
99
dbms/src/PrimaryKeyPlain.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include <Poco/File.h>
|
||||
#include <Poco/FileStream.h>
|
||||
#include <Poco/BinaryWriter.h>
|
||||
|
||||
#include <DB/PrimaryKeyPlain.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
PrimaryKeyPlain::PrimaryKeyPlain(const std::string & path_, const std::string & name_)
|
||||
: path(path_),
|
||||
name(name_),
|
||||
data_file_name(path + name + ".dat"),
|
||||
offsets_file_name(path + name + ".idx"),
|
||||
free_blocks_file_name(path + name + ".blk"),
|
||||
data_file(data_file_name),
|
||||
offsets_file(offsets_file_name),
|
||||
free_blocks_file(free_blocks_file_name)
|
||||
{
|
||||
/// создаём файлы, если их ещё нет
|
||||
data_file.createFile();
|
||||
offsets_file.createFile();
|
||||
free_blocks_file.createFile();
|
||||
|
||||
/// прочитаем список свободных блоков
|
||||
Poco::FileInputStream free_blocks_istr(free_blocks_file_name);
|
||||
Poco::BinaryReader free_blocks_reader(free_blocks_istr);
|
||||
|
||||
while (1)
|
||||
{
|
||||
Offset offset;
|
||||
free_blocks_reader >> offset.offset >> offset.size;
|
||||
|
||||
if (free_blocks_istr.eof())
|
||||
break;
|
||||
|
||||
if (free_blocks_istr.fail())
|
||||
throw Exception("Cannot read index file " + free_blocks_file_name
|
||||
, ErrorCodes::CANT_READ_INDEX_FILE);
|
||||
|
||||
free_blocks.insert(offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrimaryKeyPlain::addToTable(Table * table_, ColumnGroup * column_group_)
|
||||
{
|
||||
PrimaryKeyBase::addToTable(table_, column_group_);
|
||||
|
||||
/// прочитаем список смещений
|
||||
Poco::FileInputStream offsets_istr(offsets_file_name);
|
||||
Poco::BinaryReader offsets_reader(offsets_istr);
|
||||
|
||||
while (1)
|
||||
{
|
||||
Row key;
|
||||
for (Table::ColumnNumbers::const_iterator it = table->primary_key_column_numbers->begin();
|
||||
it != table->primary_key_column_numbers->end();
|
||||
++it)
|
||||
{
|
||||
key.push_back(Field());
|
||||
table->columns->at(*it).type->deserializeBinary(key.back(), offsets_istr);
|
||||
}
|
||||
Offset offset;
|
||||
offsets_reader >> offset.offset >> offset.size;
|
||||
|
||||
if (offsets_istr.eof())
|
||||
break;
|
||||
|
||||
if (offsets_istr.fail())
|
||||
throw Exception("Cannot read index file " + offsets_file_name
|
||||
, ErrorCodes::CANT_READ_INDEX_FILE);
|
||||
|
||||
offsets[key] = offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrimaryKeyPlain::merge(const AggregatedRowSet & data, const ColumnMask & mask)
|
||||
{
|
||||
/* std::set<Row> keys;
|
||||
|
||||
for (Result::const_iterator it = data.begin(); it != data.end(); ++it)
|
||||
{
|
||||
if (data->first.size() < columns.size())
|
||||
throw Exception("Too few columns for key", ErrorCodes::TOO_FEW_COLUMNS_FOR_KEY);
|
||||
|
||||
Row key;
|
||||
for (size_t j = 0; j < columns.size(); ++j)
|
||||
key.push_back(it->first[j]);
|
||||
|
||||
keys.insert(key);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
85
dbms/src/tests/primary_key_none.cpp
Normal file
85
dbms/src/tests/primary_key_none.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include <iostream>
|
||||
#include <Poco/Stopwatch.h>
|
||||
|
||||
#include <DB/Table.h>
|
||||
#include <DB/Column.h>
|
||||
#include <DB/ColumnType.h>
|
||||
#include <DB/PrimaryKeyNone.h>
|
||||
#include <DB/RowSet.h>
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
Poco::Stopwatch stopwatch;
|
||||
|
||||
/// создаём таблицу
|
||||
DB::Column column0;
|
||||
column0.name = "ID";
|
||||
column0.type = new DB::ColumnTypeVarUInt;
|
||||
|
||||
DB::Column column1;
|
||||
column1.name = "PageViews";
|
||||
column1.type = new DB::ColumnTypeVarUInt;
|
||||
|
||||
DB::Column column2;
|
||||
column2.name = "URL";
|
||||
column2.type = new DB::ColumnTypeText;
|
||||
|
||||
Poco::SharedPtr<DB::Table::Columns> columns = new DB::Table::Columns;
|
||||
columns->push_back(column0);
|
||||
columns->push_back(column1);
|
||||
columns->push_back(column2);
|
||||
|
||||
Poco::SharedPtr<DB::Table::ColumnNumbers> primary_key_column_numbers = new DB::Table::ColumnNumbers;
|
||||
primary_key_column_numbers->push_back(0);
|
||||
|
||||
DB::ColumnGroup column_group0;
|
||||
column_group0.column_numbers.push_back(0);
|
||||
column_group0.column_numbers.push_back(1);
|
||||
column_group0.column_numbers.push_back(2);
|
||||
column_group0.primary_key = new DB::PrimaryKeyNone("./", "TestPrimaryKeyNone");
|
||||
|
||||
Poco::SharedPtr<DB::Table::ColumnGroups> column_groups = new DB::Table::ColumnGroups;
|
||||
column_groups->push_back(column_group0);
|
||||
|
||||
DB::Table table("TestTable", columns, primary_key_column_numbers, column_groups);
|
||||
|
||||
/// создаём набор данных
|
||||
DB::AggregatedRowSet data;
|
||||
{
|
||||
DB::Row key;
|
||||
key.push_back(DB::Field(DB::UInt(0)));
|
||||
key.push_back(DB::Field(DB::UInt(0)));
|
||||
key.push_back(DB::Field(DB::String("")));
|
||||
|
||||
DB::Row value;
|
||||
|
||||
stopwatch.restart();
|
||||
|
||||
for (int i = 0; i < 1000000; ++i)
|
||||
{
|
||||
key[0] = DB::UInt(i);
|
||||
key[1] = DB::UInt(i * 123456789 % 1000000);
|
||||
key[2] = "http://www.google.com/custom?cof=LW%3A277%3BL%3Ahttp%3A%2F%2Fwww.boost.org%2Fboost.png%3BLH%3A86%3BAH%3Acenter%3BGL%3A0%3BS%3Ahttp%3A%2F%2Fwww.boost.org%3BAWFID%3A9b83d16ce652ed5a%3B&sa=Google+Search&domains=www.boost.org%3Blists.boost.org&hq=site%3Awww.boost.org+OR+site%3Alists.boost.org&q=boost%3A%3Ablank";
|
||||
|
||||
data[key] = value;
|
||||
}
|
||||
|
||||
stopwatch.stop();
|
||||
std::cout << "Filling data: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
|
||||
}
|
||||
|
||||
/// заполняем таблицу
|
||||
{
|
||||
DB::ColumnMask mask(3, true);
|
||||
|
||||
stopwatch.restart();
|
||||
|
||||
column_group0.primary_key->merge(data, mask);
|
||||
|
||||
stopwatch.stop();
|
||||
std::cout << "Saving data: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
17
dbms/src/tests/variant.cpp
Normal file
17
dbms/src/tests/variant.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <iostream>
|
||||
#include <boost/variant.hpp>
|
||||
#include <DB/Field.h>
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
DB::Field f1(DB::UInt(10));
|
||||
DB::Field f2(DB::String("test"));
|
||||
|
||||
std::cout << (f1 < f1) << std::endl;
|
||||
std::cout << (f1 < f2) << std::endl;
|
||||
std::cout << (f1 == f1) << std::endl;
|
||||
std::cout << (f1 == f2) << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
@ -66,6 +66,10 @@ public:
|
||||
ostr << '}' << "," << std::endl;
|
||||
}
|
||||
|
||||
void operator() (const DB::AggregateFunctionPtr & x) const
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream & ostr;
|
||||
unsigned indent;
|
||||
@ -75,14 +79,23 @@ private:
|
||||
class TimesTwoVisitor : public boost::static_visitor<>
|
||||
{
|
||||
public:
|
||||
template <typename T> void operator() (T & x) const { x *= 2; }
|
||||
void operator() (DB::Int & x) const { x *= 2; }
|
||||
void operator() (DB::UInt & x) const { x *= 2; }
|
||||
|
||||
void operator() (DB::Null & x) const {}
|
||||
void operator() (DB::String & x) const { x = ""; }
|
||||
void operator() (DB::FieldVector & x) const
|
||||
void operator() (const DB::String & x) const
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (const DB::Null & x) const
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (const DB::FieldVector & x) const
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (const DB::AggregateFunctionPtr & x) const
|
||||
{
|
||||
TimesTwoVisitor visitor;
|
||||
std::for_each(x.begin(), x.end(), boost::apply_visitor(visitor));
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user