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

exp: exp '+' exp

| exp '-' exp

;

Правило справа может быть пустым

input: #empty

| input line

;

Для задания явного приоритета в случае неоднозначности следует использовать директиву %prec, дающую правилу высокий приоритет.

exp: '-' exp %prec NEG { -$_[1] }

| exp '+' exp { $_[1] + $_[3] }

| NUM

;

Примечательно, что YAPP позволяет встраивать в синтаксический анализатор семантику. Это организуется путем добавления в конце правила конструкций {…}, ограничивающих Perl-команды. Они встраиваются в синтаксический анализатор и выполняются после применения анализатором этого правила. Такой код может возвращать некоторую величину, используемую в определении следующего правила по дереву.

Переменные $_[1] , $_[n] являются параметрами и хранят значения разобранного правила.

Нижняя секция может содержать корректный Perl-код, встраиваемый в конце сформированного синтаксического анализатора. Там можно указать лексер, процедуру анализа ошибок.

5.Структура разрабатываемой программы

Идеология оболочки состоит в том, что пользователь будущей базы данных сначала описывает на специальном языке структуры данных, из которых должны состоять таблицы в базе (то есть фактически интерфейсы) их ссылочные связи, индексы и т.п. Затем при помощи специального транслятора он получает готовый С++ код, реализующий интерфейс работы с базой данных, определенный пользователем, включая саму базу, ее таблицы, записи данных, транзакции и некоторые другие объекты. Код, генерируемый транслятором, на самом деле, является тоже оболочкой. Дело в том, что многие части транслятора имеют под собой общее основание. Эти статические классы и функции можно выделить в библиотеку. Еще одна причина для этого - семантика самого транслятора должна быть как можно проще. И как следствие этого, сокращаются размеры генерируемых файлов.

Полученный программный код остается только включить в проект и использовать уже готовые объекты базы данных и таблиц.

Новая база данных должна располагать такими возможностями:

· Добавление пользовательских данных их модификация и удаление.

· Открытие базы в нескольких режимах: например, в нормальном многопользовательском транзакционном режиме, безопасном режиме (как правило, для монопольного доступа и используется утилитами), а также в режиме восстановления базы данных.

· Импорта данных, то есть, представления данных в некотором текстовом формате, и их перемещение в пустую базу данных

· Экспорта данных, то есть, перемещение данных из базы, и представление их в определенном текстовом формате в файле, удобном для чтения. Является взаимно обратной операцией предыдущей.

· Проверки индексной целостности. Дело в том, что иногда, вследствие различных внешних факторов (например, перепад напряжения), теряется актуальность и корректность данных в индексных таблицах, и их необходимо периодически проверять и в случае необходимости восстанавливать.

· Проверки ссылочной целостности. То есть проверка корректности логических зависимостей между таблицами в базе.

Итак, вся оболочка состоит из следующих частей:

1. Собственно, базовая библиотека статических классов, для высокоуровневой работы с Berkeley, необходимая транслятору.

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

Библиотека классов

«Движок» представляет собой библиотеку классов, которые с одной стороны являются надстройками вокруг стандартных соответствующих структур, а с другой стороны делают их интерфейс более удобным и инкапсулируют часть работы транслятора. Основными компонентами являются:

· Транзакции

· Исключения

· Базовые записи

· Таблицы

· Базы данных

· Курсоры

Базовые записи

Базовая запись - это элементарная единица хранения в таблице. Описание ее класса:

//! базовый класс для записей с vtable pointer

class hbObj{

Dbt dbt;

protected:

void dbtInit(uint s,void* d)

{

dbt.set_flags(DB_DBT_USERMEM);

dbt.set_ulen(s);

dbt.set_size(s);

dbt.set_data(d);

}

public:

operator Dbt*(){return &dbt;}

void* getData(void) {return dbt.get_data();};

uint getSize(void) {return dbt.get_size();};

hbObj() {}

virtual ~hbObj() {}

};

Этот класс не совсем удобен для непосредственного использования. Дело в том, что он ничего не знает об исходных данных, которые будет в себе содержать. Этими данными могут быть, например, размер структуры в памяти и некоторые ее методы. Простейшим решением будет введение шаблона с передачей типа хранимой структуры как его параметра.

//! реальный класс, который приводится к Dbt

template <class A> class hbRec:public hbObj

{

A data;

public:

A* getPnt(void) { return &data;} // если в в A массив то можно переопределить операцию & для А

hbRec() { memset(&data,0,sizeof(A));dbtInit(sizeof(A),&data);}

hbRec(const hbRec<A>& a):data(a.data) { dbtInit(sizeof(A),&data);}

hbRec(const A& a) :data(a) { dbtInit(sizeof(A),&data);}

void SetData(const A& a) { data = a;dbtInit(sizeof(A),&data);}

virtual ~hbRec() {}

};

Таблицы

Диаграмма отношений существующих таблиц приведена ниже:

57

По аналогии с записями существует базовый класс таблиц hbBasetbl, который поддерживает работу со всеми стандартными типами таблиц (Hash, Btree, Queue). Фактически ее тип является ее состоянием и определяется в момент открытия.

class hbBasetbl

{

// нужен для того чтобы set_flags вызывалась ровно один раз

uint Set_flg_Counter;

ushort state;

// флаг, показывающ. открыта ли сама таблица, необходим для экстр. закрытия в случае некоректного

// открытия

bool tableopen;

hbInit ini;

protected:

uint recsize;

uint keysize; //только для DB_HASH

Db *table;

virtual void UsrOpen(hbTxn *tx,FileConf& conf,bool openidx,hbInitRt* irt = 0,u_int32_t op_flags = 0);

virtual void UsrClose();

void SetRecSize(uint recsize1){recsize = recsize1;}

void SetKeySize(uint keysize1){keysize = keysize1;}

uint GetType() {return ini.type;}

bool IsDup() return (ini.st_flags & DB_DUP

public:

hbEnv& env;

operator Db*(){return table;}

Db* operator ->(){return table;}

const char* GetDbName(){return ini.dbname;}

hbBasetbl(hbEnv& e,hbInit&);

virtual ~hbBasetbl(){ if(state) Close();}

void Open(hbTxn *tx,FileConf& conf,bool openidx,hbInitRt* irt = 0,u_int32_t op_flags = 0);

void Close();

virtual void Create(hbTxn *tx,FileConf& conf,hbInitRt* irt = 0,u_int32_t op_flags = 0);

virtual int Get(hbTxn *tx,hbObj *key,hbObj *val,u_int32_t flags=0); // в стиле С (без исключений)

virtual int Pget(hbTxn *tx,hbObj *fkey,hbObj *pkey, // в стиле С (без исключений)

hbObj *val, u_int32_t flags=0);

virtual int Del(hbTxn *tx,hbObj *key,u_int32_t flags=0); // в стиле С (без исключений)

virtual int tGet(hbTxn *tx,hbObj *key,hbObj *val,u_int32_t flags=0); // в стиле С++

virtual int tPget(hbTxn *tx,hbObj *fkey,hbObj *pkey, hbObj *val, u_int32_t flags=0); // в стиле С++

virtual int tDel(hbTxn *tx,hbObj *key,u_int32_t flags=0); // в стиле С++

virtual int Put(hbTxn *tx,hbObj *key,hbObj *val,u_int32_t flags=0);

bool IsOpen(){return state;}

};

Для ускорения доступа по какому-то критерию к данным в таблицах вводятся индексные таблицы. Ими могут быть любые из перечисленных, конечно в соответствии с их особенностями. Класс hbBasetbl является с одной стороны базовым классом, содержащим всю рутинную работу с флагами и основными операциями с таблицей, а с другой стороны -финальным классом для индексной таблицы.

Этот класс является базовым, и совсем неудобен для работы, если эта таблица является индексированной (то есть имеет индексы - другие индексные таблицы). Необходим еще один класс, который будет обобщением понятия индексируемой таблицы и являться контейнером для таких индексных таблиц. Этот класс представлен ниже.

Страницы: 1, 2, 3, 4, 5, 6, 7



2012 © Все права защищены
При использовании материалов активная ссылка на источник обязательна.