Berkeley DB 环境用来封装一个或多个数据库,日志文件和区域文件。区域文件是共享内存区,它里面包括数据库环境信息像内存池cache页等。只有数据库文件可以在不同的字节序机器间移动,日志文件只能在相同的字节序机器间移动。而区域文件(Region files)常常对于一个特定的机器来说是独一无二的,可能只能在指定的操作系统的某个版本上移动间移动。
一个环境可以被很多进程和线程共享。一个环境包含其它目录的资源也是可能的。应用程序经常选择把资源分布到其他目录或磁盘来提高性能或其他原因。尽管如此,默认的,数据库,共享区(锁,日志,内存池和事务共享内存区域)和日志文件将存储在同一个同层次目录中。
意识到所有应用程序共享一个数据库环境默认的相信彼此非常重要。他们能访问对方的数据,因为那些数据在同一个共享内存区,他们也共享资源像buffer空间和锁。与此同时,任何应用程序使用同一个数据库,必须共享一个环境,如果想在他们之间保持一致性的话。
Creating a database environment
环境对于bdb的可移植性和灵活性是非常重要的。为了增强可移植性,和快速灾难恢复,建议尽量使用相对路径。建议使用配置文件放置环境参数而不要直接写到程序里,可以避免每次移植时修改和编译源文件。
bdb 环境由db_env_create 和 DB_ENV->open接口创建和描述,再需要定制的地方,比如把log文件存储到不同的磁盘驱动器里,或选择一个特殊cache大小,应用程序描述这些定制信息通过创建配置文件,或者传参数给其他DB_ENV 处理函数。
一旦一个环境被创建,被指定相对路径的数据库文件,都将相对与环境的home目录来创建。用相对目录允许整个环境轻易的移动。简化了在不同目录和不同系统中重建和恢复的步骤。
应用程序首先通过db_env_create方法获得一个环境句柄,然后调用DB_ENV->open来创建或合并数据库环境。这儿有很多选项你可以在调用DB_ENV->open时设置来定制你的环境。这些选项大致可以分为四类:
子系统初始化选项:这些标志指明哪些bdb子系统将因为环境被初始化,和哪些操作将自动发生当数据库在环境中被访问的时候。这些标志包括 DB_INIT_CDB, DB_INIT_LOCK, DB_INIT_LOG, DB_INIT_MPOOL, and DB_INIT_TXN。The DB_INIT_CDB标志为bdb并发数据存储做初始化工作。其他标志初始化单个子系统;也就是说,当DB_INIT_LOCK被指定,应用程序读写在这个环境中打开的数据库时,将使用locking子系统以确保它们不覆盖对方的对数据的改动。
恢复选项:这些包括DB_RECOVER 和 DB_RECOVER_FATAL选项,他们表明在环境被打开要作正常用途使用前,恢复(recovery)将要进行。
命名选项:这包括DB_USE_ENVIRON 和 DB_USE_ENVIRON_ROOT,修改如何在环境中给文件命名。
混杂选项:例如DB_CREATE选项使底层数据库文件被创建是必需的。更多的应用还指定
仅仅DB_INIT_MPOOL标志或者指定其它所有4个子系统的初始化标志(DB_INIT_MPOOL, DB_INIT_LOCK, DB_INIT_LOG, and DB_INIT_TXN)。
以前的配置只是想简单的用一些基本的访问方法接口用一个共享底层缓冲池,但是没有关心当应用程序或系统出现故障时的可恢复性。以后是一些需要提供可恢复性的应用。也有一些很稀少的情况下,其它的初始化标志组合成为可能。
DB_RECOVER在当应用程序想在运行的时做一些必需的数据库恢复的时候被指定。也就是说,是否在上次运行时,系统或应用程序出现了故障,想在再次运行前使数据恢复到可用状态。不过,在没有任何数据需要恢复的情况下,指定这个标志也不为错。
DB_RECOVER_FATAL 标志有更特殊的用途。它执行灾难性的数据库恢复,通常需要做一些初始化的安排;也就是归档log文件被带回到文件系统。应用程序通常不指定这个标志,取而代之的是,在这种很稀有的情况下,db_recover 公用程序将会派上用场不用你自己写。
下面是一个简单的为事务程序打开一个数据库环境的例子:
DB_ENV *
db_setup(home, data_dir, errfp, progname)
char *home, *data_dir, *progname;
FILE *errfp;
{
DB_ENV *dbenv;
int ret;
/*
* Create an environment and initialize it for additional error
* reporting.
*/
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
return (NULL);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
/*
* Specify the shared memory buffer pool cachesize: 5MB.
* Databases are in a subdirectory of the environment home.
*/
if ((ret = dbenv->set_cachesize(dbenv, 0, 5 * 1024 * 1024, 0)) != 0) {
dbenv->err(dbenv, ret, "set_cachesize");
goto err;
}
if ((ret = dbenv->set_data_dir(dbenv, data_dir)) != 0) {
dbenv->err(dbenv, ret, "set_data_dir: %s", data_dir);
goto err;
}
/* Open the environment with full transactional support. */
if ((ret = dbenv->open(dbenv, home, DB_CREATE |
DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN, 0)) != 0) {
dbenv->err(dbenv, ret, "environment open: %s", home);
goto err;
}
return (dbenv);
err: (void)dbenv->close(dbenv, 0);
return (NULL);
Opening databases within the environment
一旦环境被创建,数据库句柄将可能在这个环境中打开,这由db_create函数通过指定特定的环境作为参数来实现。
文件命名,数据库操作,和错误处理等都将因为这个指定的环境而被做。例如,如果DB_INIT_LOCK 或 DB_INIT_CDB 标志被指定,当环境被创建或被合并时,数据库操作将为应用程序自动的执行所有必要的锁操作。
下面是一个简单的例子,在一个环境中打开两个数据库:
DB_ENV *dbenv;
DB *dbp1, *dbp2;
int ret;
dbenv = NULL;
dbp1 = dbp2 = NULL;
/*
* Create an environment and initialize it for additional error
* reporting.
*/
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
return (ret);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
/* Open an environment with just a memory pool. */
if ((ret =
dbenv->open(dbenv, home, DB_CREATE | DB_INIT_MPOOL, 0)) != 0) {
dbenv->err(dbenv, ret, "environment open: %s", home);
goto err;
}
/* Open database #1. */
if ((ret = db_create(&dbp1, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "database create");
goto err;
}
if ((ret = dbp1->open(dbp1,
NULL, DATABASE1, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbenv->err(dbenv, ret, "DB->open: %s", DATABASE1);
goto err;
}
/* Open database #2. */
if ((ret = db_create(&dbp2, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "database create");
goto err;
}
if ((ret = dbp2->open(dbp2,
NULL, DATABASE2, NULL, DB_HASH, DB_CREATE, 0664)) != 0) {
dbenv->err(dbenv, ret, "DB->open: %s", DATABASE2);
goto err;
}
return (0);
err: if (dbp2 != NULL)
(void)dbp2->close(dbp2, 0);
if (dbp1 != NULL)
(void)dbp2->close(dbp1, 0);
(void)dbenv->close(dbenv, 0);
return (1);
}
Error support
db_strerror能根据一个bdb的一个错误返回值返回一个指向错误信息的指针。它可以处理系统的错误返回值也能处理bdb特有的返回值。
例如:
int ret;
if ((ret = dbenv->set_cachesize(dbenv, 0, 32 * 1024, 1)) != 0) {
fprintf(stderr, "set_cachesize failed: %s\n", db_strerror(ret));
return (1);
}
这儿也有两个附加的错误处理函数:DB_ENV->err 和 DB_ENV->errx。
DB_ENV->err函数追加标准错误字符串到已构造好的信息,而DB_ENV->errx不那样。
错误信息可以通过DB_ENV->set_errpfx被配置成总包含一个固定的东西,例如,应用程序名称。还可以把错误信息输入到一个指定的文件中,例如:
int ret;
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, program_name);
if ((ret = dbenv->open(dbenv, home,
DB_CREATE | DB_INIT_LOG | DB_INIT_TXN | DB_USE_ENVIRON, 0))
!= 0) {
dbenv->err(dbenv, ret, "open: %s", home);
dbenv->errx(dbenv,"contact your system administrator:
session ID was %d",session_id);
return (1);
}
例如应用程序名为"my_app", 环境的home目录为 "/tmp/home",出错信息将是这样的:
my_app: open: /tmp/home: Permission denied.
my_app: contact your system administrator: session ID was 2
DB_CONFIG configuration file
几乎所有可以指定给DB_ENV那些方法的配置信息,也都能通过一个配置文件来指定。如果一被命名为DB_CONFIG的文件存在于数据库hone目录下,它将会一行行的按NAME VALUE的格式读入。
NAME和VALUE之间用一个或者多个空格来分割。凡是那一行的开头是空格或#的,都将被忽略为注释。
NAME VALUE具体值可以在对用的方法中查到例如DB_ENV->set_data_dir。
DB_CONFIG 配置文件的目的是允许管理员定制不依赖于应用程序的环境。例如,可以移动数据库log文件和数据文件到不同的地方,而不用重新编译应用程序。另外,因为 DB_CONFIG文件是当数据库环境被打开时读取的,它可以用来覆盖在那以前配置的规则。例如,可以定义一个更合理的cache大小,来覆盖以前已经编译到程序中的值。
