Выбрать главу

Depot использует глобальную целочисленную переменную dpecode для хранения кодов ошибок. Когда функции Depot возвращают сбой, dpecode сообщает о том, что произошло (это почти то же самое, что и в случае с переменной errno, которая относится к системным вызовам и библиотеке С). За текстовые сообщения об ошибках отвечает функция dperrmsg().

#include <depot.h>

const char * dperrmsg(int ecode);

Подобно strerror(), функция dperrmsg() принимает код ошибки (обычно из dpecode) и возвращает строку, в которой приводится описание возникшей ошибки.

Функции в API-интерфейсе Depot используют указатель на структуру DEPOT. Это непрозрачная структура (программы, использующие Depot, не могут самостоятельно проверять значения в структуре), однако в ней содержится вся информация, используемая библиотекой для обслуживания файла, хранящегося на диске.

25.2. Основные операции

25.2.1. Открытие файла qdbm

Библиотечная функция dpopen() используется для открытия файлов базы данных.

#include <depot.h>

DB * dpopen(const char * filename, int omode, int bnum);

Первый аргумент представляет имя файла, который будет использоваться для базы данных[176]. Аргумент omode определяет способ доступа к файлу, и должен иметь одно из двух значений: DP_OREADER и DP_OWRITER, в зависимости от того, какой вид доступа к базе данных необходим программе — для чтения или для записи. По умолчанию база данных блокируется, чтобы разрешить нескольким программам доступ для чтения или одной программе доступ для записи. Если приложению не нужна блокировка, производимая qdbm, то DP_ONOLCK может быть объединен с omode битовым "ИЛИ".

Когда приложения создают новые базы данных, они должны также использовать битовое "ИЛИ" с DP_CREAT для отправки qdbm запроса на создание нового файла, если он еще не был создан. Флаг DP_OTRUNC сигнализирует о том, что первоначальное содержимое filename будет удалено и заменено пустой базой данных.

Последний параметр функции dpopen(), bnum, сообщает qdbm о том, сколько сегментов памяти нужно задействовать в хеш-массиве. Чем меньшим будет значение этого параметра, тем меньший размер будет иметь база данных; чем больше будет его значение, тем быстрее она будет работать благодаря сокращению количества конфликтных ситуаций в хеш-памяти. В документации к qdbm рекомендуется, чтобы это значение составляло от половины до величины, в четыре раза большей от того количества элементов, которые, предположительно, будет иметь база данных[177]. Если вы не уверены, какое следует использовать значение, можно присвоить нулевое значение, которое является значением по умолчанию[178].

Функция dpopen() возвращает указатель на структуру DEPOT, который передается остальным функциям Depot. В случае возникновения ошибки функция dpopen() возвращает NULL и устанавливает dpecode.

25.2.2. Закрытие базы данных

Чтобы закрыть файлы базы данных, используйте функцию dpclose().

int dpclose(DEPOT * depot);

Функция dpclose() возвращает нулевое значение после успешного закрытия файлов и ненулевое — при сбое, который может произойти из-за невозможности очистки данных из буферов базы данных. Ниже показан пример программы, которая открывает файл базы данных в текущем каталоге и сразу же закрывает его.

 1: /* qdbmsimple.c */

 2:

 3: #include <depot.h>

 4: #include <errno.h>

 5: #include <fcntl.h>

 6: #include <stdio.h>

 7:

 8: int main(void) {

 9:  DEPOT * dp;

10:

11:  dp = dpopen("test.db", DP_OWRITER | DP_OCREAT, 0);

12:  if (!dp) {

13:   printf("ошибка: %s\n", dperrmsg(dpecode));

14:   return 1;

15:  }

16:

17:  dpclose(dp);

18:

19:  return 0;

20: }

25.2.3. Получение файлового дескриптора

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

int dpfdesc(DEPOT * depot);

Эта функция возвращает файловый дескриптор базы данных depqt[179].

25.2.4. Синхронизация базы данных

qdbm кэширует данные в оперативной памяти для ускорения доступа к базе данных, а ядро Linux кэширует записи на диске, чтобы свести к минимуму задержку между вызовами функции write(). Чтобы база данных, хранящаяся на диске, оставалась согласованной с буферизированными структурами, приложение может осуществлять ее синхронизацию. В процессе синхронизации базы данных qdbm очищает все ее внутренние буферы и вызывает функцию fsync() для файлового дескриптора.

int dpsync(DEPOT * depot);

25.3. Чтение записей

Прочитать записи в базе данных можно двумя способами: посредством поиска записи по ее ключу и путем чтения последовательных пар "ключ-значение".

25.3.1. Чтение определенной записи

Функции dpget() и dpgetwb() производят поиск записей в базе данных по ключу.

int dpget(DEPOT * depot, const char * key, int keySize, int start,

 int max, int * dataSize);

key является элементом (ключом), с помощью которого производится поиск по базе данных, a keySize определяет длину ключа (или значение -1, при котором Depot использует функцию strlen(key) для определения длины ключа). С помощью следующих двух параметров, start и max, можно производить частичное чтение записей; параметр start задает смещение в данных, с которого начнется операция чтения, а max — максимальное количество байтов для чтения. Например, если область данных представляла бы собой массив из четырехбайтовых целочисленных значений int, то в результате присвоения параметру start значения 12 и параметру max значения 8 производилось бы чтение четвертого и пятого элементов массива. Если для чтения доступно менее start байтов, функция dpget() вернет NULL. Чтобы прочитать все байты из данных, параметру max следует присвоить значение -1.

вернуться

176

В отличие от некоторых библиотек баз данных, использующих множество файлов с расширениями .pag и .dir, библиотека Depot использует один файл.

вернуться

177

Хорошее описание хеш-таблиц можно найти в [11].

вернуться

178

Это значение можно изменить только путем оптимизации базы данных с помощью функции dpoptimize(), описание которой можно найти на Web-сайте qdbm.

вернуться

179

Несмотря на то что qdbm обеспечивает доступ к файловому дескриптору, использовать его следует осторожно. Дело в том, что все операции по чтению и записи в файл должны производиться через библиотеку qdbm; операции, не связанные с изменением данных в файле, например, блокировка или установка флага для закрытия после выполнения, допускаются.