Смекни!
smekni.com

Реализация высокоуровнего интерфейса вокруг базы данных Berclee DB (стр. 4 из 5)

template<class Key,class Val> class hbTable:public hbPTable

{

public:

//! конструктор принимает массив инициализаторов (в тч индексов)

hbTable(hbEnv& e,hbInit& ini1):hbPTable(e,ini1) {SetRecSize(sizeof(Val));SetKeySize(sizeof(Key));}

//SetRecSize use by QUEUE only

virtual ~hbTable() {}

// более продвинутые функции

int Get(const bexcp& excp, hbTxn *tx,const Key &key,Val *val, u_int32_t flags=0)

{

Get(excp,tx,(Key*)&key,val,flags);

}

int Pget(const bexcp& excp, hbTxn *tx,int n,hbObj *fkey,Key *pkey, Val *val,u_int32_t flags=0)

{

MTRY

hbRec<Key> k;

hbRec<Val> v;

int z=Pget(tx,n,fkey,&k,&v,flags);

*pkey= *(k.getPnt());

*val= *(v.getPnt());

return z;

CATCH_hbExcp

}

int Del(const bexcp& excp, hbTxn *tx, const Key &key,u_int32_t flags=0)

{

Del(excp,tx,(Key*)&key,flags);

}

int tGet(const bexcp& excp, hbTxn *tx, Key *key,Val *val, u_int32_t flags=0)

{

MTRY

hbRec<Key> k(*key);

hbRec<Val> v;

int z = tGet(tx,&k,&v,flags);

*val= *(v.getPnt());

return z;

CATCH_hbExcp

}

int Put(const bexcp& excp, hbTxn *tx,const Key &key, const Val &val, u_int32_t flags=0)

{

Put(excp,tx,(Key*)&key,(Val*)&val,flags);

}

uint Append(const bexcp& excp, hbTxn *tx, Val *val)

{

MTRY

if(GetType() != DB_QUEUE) return 0;

hbRec<uint> k;

hbRec<Val> v(*val);

hbBasetbl::Put(tx,&k,&v,DB_APPEND);

return (uint&)*(k.getPnt());

CATCH_hbExcp

}

uint Append(const bexcp& excp, hbTxn *tx,const Val &val)

{

return Append(excp,tx,(Val*)&val);

}

};

Этот параметризированный класс на самом деле только переопределил сигнатуры методов более удобными и работающими с пользовательскими типами данных.

База данных или объект окружения

Этот объект фактически представляет собой абстракцию базы данных: является контейнером для индексируемых таблиц, отвечает за их открытие, доступ, а также проводит над ними служебные операции экспорта и т.п. На диаграмме это выглядит так:

Описание класса приведено ниже:

class hbEnv

{

DbEnv *env;

bool is_native_log;

Log* LogObj;

//! Путь к файлам

char* path;

//! Количество баз - ломает вектором писать - тогда дольше компилится

int sz;

//! Инишиалайзеры (в количестве равном sz)

hbInit *dbinits;

hbInit *idxinits;

int idxsz;

char* schemaid; // уже проверяется, при открытии из словаря чит. оригин. и сравнивается

//! Мутекс для транзакций

pthread_mutex_t mx;

uint dltype;

//! in secs interval for checkpoints and logarchs

ulong dldelay,bdbchkpoint,bdblogrem;

static void* thf_deadrs(void*);

static void* thf_chkpnt(void*);

static void* thf_logarc(void*);

pthread_t pth_deadrs,pth_chkpnt,pth_logarc;

ushort stflags;

ushort stflags;

bool IsOpenflag;

ushort state;

TDictionary dict;

//char* ConfFile; //имя конф. файла может переопределятся в потомках/ но зачем

FILE* OpenOutputStream(const char* fn,const char* mode);

void CloseOutputStream(FILE* f);

// удаляет все __db.00x файлы т.к там хранится хэш, из-за которого может неверно сработать проверка индексов

protected:

//! Сами тейблы, индексов здесь нет, они в самих тейблах

hbPTable **dbs;

void SetSchemaid(const char* File) {if(schemaid)free(schemaid);schemaid = strdup(File);}

// тэйблы будут создаваться в конструкторе потомка ,и вноситься в dbs

int Close(int);

virtual void UsrClose();

public:

Log* GetLog() {return LogObj;}

operator DbEnv*() {return env;};

DbEnv* operator ->() {return env;}

//DbEnv& GetDbEnv(){ return env;}

const char* GetSchemaId()const {return schemaid;}

const char* GetUuid(const bexcp&, hbTxn *tx);

const char* GetPath()const {return path;}

bool IsOpen() {return state;}

hbEnv(const char *p,envInit& e,ushort flt = LL_DEBUG, Log* LogObj1 = 0);

virtual ~hbEnv();

//st_flags помещ . в DbEnv::set_flags (DB_TXN_NOSYNC)

//op_flags помещ . в Db::open (DB_PRIVATE/DB_THREAD - by default)

// если режим CDS то эти флаги игнорируются за исключением op_flags = DB_PRIVATE!!

void OpenTDSMode(const bexcp& excp, u_int32_t st_flags = 0, u_int32_t op_flags = (DB_THREAD | DB_RECOVER) ) //DB_THREAD | DB_RECOVER_FATAL

{DBOpen(excp, OPEN_TDS,true,st_flags, op_flags);}

void OpenCDSMode(const bexcp& excp, bool opentables = true,u_int32_t op_flags = 0/* только для DB_PRIVATE*/)

{DBOpen(excp, OPEN_CDS,opentables,0,op_flags);}

void Close(const bexcp& excp);

void Close ();

// полная инициализация&создание базы с нуля (предварительное удаление БД)

void Init(const bexcp& excp, u_int32_t op_flags=DB_THREAD);

// Проверка индексов и если надо их корректировка база должна быть в offline

void CheckForIdx(const bexcp& excp, uint bulk_ret_buffer_size = (5 * 1024 * 1024),bool fix = false);

void CheckForRef(const bexcp& excp, uint bulk_ret_buffer_size = (5 * 1024 * 1024));

//! экспорт базы даных

void ExportDB(const bexcp& excp, const char* fn,uint bulk_ret_buffer_size = (5 * 1024 * 1024));

//! импорт базы даных

void ImportDB(const bexcp& excp, const char* fn);

void printf(ushort level,const char* fmt,...); // обвертка под Log::printf

};

Этот класс инкапсулирует работу со словарем, где может храниться информация, полезная для программиста.

Транзакции

Класс транзакций имеет следующий вид:

class hbTxn {

hbEnv& Env;

bexcp excp1;

hbTxn* parent;

DbTxn* Txn;

void SetFlags(){}

hbTxn(const hbTxn& Txn1):Env(Txn1.Env){} //copy constr

hbTxn& operator=(const hbTxn&){return *this;} // :=

public:

operator DbTxn*() {return Txn;};

hbTxn(const bexcp& excp, hbEnv& env1,ullong flags = 0,hbTxn* parent1 = 0); // младшие 32 бита это // обычн . беркл . флаги 33 бит отвечает за немедленный старт транзакции сразу же после создания

hbTxn(const bexcp& excp, hbTxn* parent1,ullong flags = 0);

// --- " ---

~hbTxn();

bool HaveParentTxn() {return parent!=0;}

void Start(const bexcp& excp, ulong flags = 0);

void Commit(const bexcp& excp, ulong flags = 0);

void RollBack(const bexcp& excp);

//void RollBack();

};

Его особенностью является то, что созданный объект транзакции нельзя копировать или создавать копированием. А также такой объект должен создаваться автоматически, то есть как стековая переменная:

try

{

hbTxn tx(excp, parent_tx);

// операции с базой

tx . Commit ();

}

catch (…){}
Как видим, первое - не надо заботиться об удалении объекта транзакции (при любой ситуации), второе – в случае исключения Rollback () вызовется автоматически в деструкторе этого объекта.

Транслятор

Как уже говорилось, задача транслятора состоит в том, чтобы создать по желанию пользователя максимально удобную оболочку для библиотеки в соответствии с его определениями основных элементов базы.

Файл грамматики приведен ниже:

%%

#-------------------------------------------------------

#------ COMMENTS --------------------------------------

#-------------------------------------------------------

#id идентификатор

#string строковый литерал или идентификатор

#num чиловой литерал

#float литерал числа с плавающей точкой

#char символьный литерал

#rawcode ::= любая последователность кода между '{*' и '*}'

file: 'end' {tblproc::Finish();}

| filetext 'end' {tblproc::Finish();}

;

filetext: item

| item filetext

;

item: optionblock

| idxblock

| structblock

| enumblock

| codeblock

| tableblock

;

literal: string {[$_[1],0]}

| num {[$_[1],1]}

| float {[$_[1],2]}

| char {[$_[1],3]}

;

#---------------------------------------------------------

optionblock: 'option' '{' oplist '}' ';'

{tblproc::OptBlockPrint('',$_[3]);}

| 'option' opitem ';'

{tblproc::OptBlockPrint('',[$_[2]]);}

| 'option' id '{' oplist '}' ';'

{tblproc::OptBlockPrint($_[2],$_[4]);}

| 'option' id opitem ';'

{tblproc::OptBlockPrint($_[2],[$_[3]]);}

;

oplist:

opitem ';' {[$_[1]]}

| opitem ';' oplist {push @{$_[3]}, $_[1]; $_[3]}

;

opitem: id '=' literal

{[$_[1],@{$_[3]}[0],0,@{$_[3]}[1]]}

| id '=' id {[$_[1],$_[3] ,1,'']}

;

#---------------------------------------------------------

idxblock: 'idx' id idxitem ';'

{tblproc::IdxBlockPrint($_[2],[$_[3]]);}

| 'idx' id '{' idxitemlist '}' ';'

{tblproc::IdxBlockPrint($_[2],$_[4]);}

;

idxitemlist: idxitem ';' {[$_[1]]}

| idxitem ';' idxitemlist {unshift @{$_[3]},$_[1]; $_[3]}

;

idxitem: idxmod1 id '(' flist1 ')'

{[0,$_[1],$_[2],$_[4],'']}

| idxmod1 id '(' flist1 ')' '{*' rawcode '*}'

{[0,$_[1],$_[2],$_[4],$_[7]]}

| idxmod2 id '(' flist2 ')' {[1,$_[1],$_[2],$_[4],'']}

| idxmod2 id '(' flist2 ')' '{*' rawcode '*}'

{[1,$_[1],$_[2],$_[4],$_[7]]}

;

idxmod1: '.!'

| ':!'

| '%!'

;

idxmod2: '.'

| ':'

| '%'

;

flist1: id {[[$_[1],'']]}

| id ',' flist1 {unshift

@{$_[3]},[$_[1],''];$_[3]}

;

flist2: idxmod3 id {[[$_[2],$_[1]]]}

| idxmod3 id ',' flist2 {unshift

@{$_[4]},[$_[2],$_[1]];$_[4]}

;

idxmod3: '+'

| '-'

| '^'

;

#---------------------------------------------------------

codeblock: code 'decl' '{*' rawcode '*}'

{tblproc::CodeBlockPrint('hh', &bsol;$_[4],0);}

| code 'tab' '{*' rawcode '*}'

{tblproc::CodeBlockPrint('tab', &bsol;$_[4],0);}

| code 'def' '{*' rawcode '*}'

{tblproc::CodeBlockPrint('cc', &bsol;$_[4],0);}

| code 'def' 'top' '{*' rawcode '*}'

{tblproc::CodeBlockPrint('cc', &bsol;$_[5],1);}

| code '{*' rawcode '*}'

{tblproc::CodeBlockPrint('all', &bsol;$_[3],0);}

;

#---------------------------------------------------------

enumblock: 'enum' id '{' enumlist '}' ';'

{tblproc::EnumBlockPrint($_[2],$_[4]);}

| 'enum' id ';'

{tblproc::EnumBlockPrint($_[2],[]);}

;

enumlist: enumitem {[$_[1]]}

| enumitem ',' enumlist {unshift @{$_[3]}, $_[1]; $_[3]}

;

enumitem: id {[$_[1],'']}

| id '=' num {[$_[1],$_[3]]}

;

#---------------------------------------------------------

structblock: 'struct' id '{' structlist '}' ';'

{tblproc::StructBlockPrint($_[2],$_[4]);}

;

structlist: structitem {[$_[1]]}

| structitem structlist {unshift @{$_[2]}, $_[1]; $_[2]}

;

structitem: id pnlistid ';'

{[$_[1],@{$_[2]}[0],@{$_[2]}[1]]}

;

#---------------------------------------------------------

tableblock: tableforward

{tblproc::TableBlockPrint(@{$_[1]}[0],'',[],[]);}

| tablehead ';'

{tblproc::TableBlockPrint(@{$_[1]}[0],@{$_[1]}[1],@{$_[1]}[2], []);}

| tablehead tail ';'

{tblproc::TableBlockPrint(@{$_[1]}[0],@{$_[1]}[1],@{$_[1]}[2], $_[2]);}

;

tail: idxtailitem {$_[1]}

| idxtailitem tail {unshift @{$_[2]},$_[1];$_[2]}

| optiontailitem

| optiontailitem tail

;

tableforward: 'table' id ';' {[$_[2]]}

;

tablehead: 'table' memmodifid '{' memberlist '}'

{[@{$_[2]}[0],@{$_[2]}[1],$_[4]]}

;

memmodifid: id {[$_[1],'']}

| memmodificator id {[$_[2],'$']}

;

memberlist: memberitem {[$_[1]]}

| memberitem memberlist {unshift @{$_[2]}, $_[1]; $_[2]}

;

memberitem: id pnlistid ';'

{[$_[1],@{$_[2]}[0],@{$_[2]}[1],[]]}

| id pnlistid modificator1 ';'

{[$_[1],@{$_[2]}[0],@{$_[2]}[1],$_[3]]}

;

modificator1: idxmodificator {[$_[1], '']}

# | idxmodificator memmodificator {[$_[1], '$','']}

| idxmodificator '{*' rawcode '*}' {[$_[1], $_[3]]}

# | idxmodificator memmodificator '{*' rawcode '*}' {[$_[1], '$', $_[4]]}

;

pnlistid: pnlist id {[$_[1], $_[2]]}

| id {[[], $_[1]]}

;

pnlist: pointer {[$_[1],'']}

| pointer array {[$_[1],$_[2]]}

| array {['',$_[1]]}

;

pointer: '+'

| '-'

| '*'

;

array: '[' id ']' {$_[2]}

| '[' num ']' {$_[2]}

;

idxmodificator: '.!'

| ':!'

| '%!'

| '.+'

| ':+'

| '%+'

| '.-'

| ':-'

| '%-'

| '.^'

| ':^'

| '%^'

;

memmodificator: '$'

;

idxtailitem: 'idx' idxitem {[$_[2]]}

| 'idx' '{' idxitemlist '}' {$_[3]}

;

optiontailitem: 'option' '{' oplist '}'

| 'option' opitem

;

#---------------------------------------------------------

%%

use tblproc;

Основными компонентами этой грамматики являются:

· option – элемент языка, определяющий настройки к конкретной таблице.

· Idx блок – это блок, определяющий параметры индексной таблицы.

· Table блок - блок, определяющий таблицу, ее записи и индексы.