BerkeleyDB学习笔记(二)

九、部分记录读取和存储

1.  在进行数据操作的时候需要为DB->put() or DB->get()的DBT data参数的flags字段设定DB_DBT_PARTIAL标志。同时还要指定doff(偏移量)和dlen(长度)。如"ABCDEFGHIJ",如果doff=3 and dlen=4,其所操作的字符串为"DEFG"。在进行数据部分替换的时候,DB->put()将使用data的data字段和size字段表示的数据替换其doff字段和dlen字段所包含的数据,如果size大于ulen,该key的data item将增大,否则data item将缩小。

2. 在使用DB->get() or DBC->get()获取数据的时候,其返回的data.data指针指向实际包含的数据,由于该指针所指向的地址在缺省情况下是有BDB内部自行分配的,因此当有任何对BDB的handle操作时,该地址将变为无效,这其中包括多线程中的争用。如果打算避免此类问题的发生,需要自行分配内存空间,同时将DBT data的flags标志设定DB_DBT_USERMEM即可。

十、 错误支持

1. DB->db_strerror(error_ret): 其功能和用法类似于Ansi C中的strerror,只是该函数不仅能够处理system errors,也能够处理BDB特定的errno。
2. DB->db_setpfx(),    为后面调用DB->db_err()和DB->db_errx()函数输出错误信息时,提供一致性的前缀。
3. DB->db_err(), 其用法类似printf,只是还会为第二个参数中给出的错误返回值打印出其错误消息。
4. DB->db_errx(), 其用法类似printf,但是比db_err()更简单。

1 #define DATABASE "access.db"
2 void errorExampe() {
3 int ret;
4 (void)dbp->set_errpfx(dbp, program_name);
5
6 if ((ret = dbp->open(dbp,NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
7 dbp->err(dbp, ret, "%s", DATABASE);
8 dbp->errx(dbp, "contact your system administrator: session ID was %d", session_id);
9 return 1;
10 }
11 }

   输出结果:
   my_app: access.db: Permission denied.
   my_app: contact your system administrator: session ID was 14 

十一、 Little Endian对Key排序的影响

     假设用户存放254到257这4个数字以Little Endian的方式put到DB中,其内存布局为:
     254 fe 0 0 0
     255 ff 0 0 0
   256  0 1 0 0
   257  1 1 0 0

   如果将他们视为缺省的lexicographical排序方式,其排序结果如下:
   256  0 1 0 0
   257  1 1 0 0
     254 fe 0 0 0
     255 ff 0 0 0

     如果在Big Endian的体系结构中,他们的内存布局为:
   254 0 0 0 fe
   255 0 0 0 ff
   256 0 0 1 0
   257 0 0 1 1
   结论:推荐使用Big Endian的方式存储整型数据,以便使Tree更加紧凑。
  
   对于数据库文件本身,其byte order是相对独立的,因为在多个拥有不同byte order的machine中copy这些数据文件是没有问题,字节序的处理细节均需交给程序本身来完成。log文件的字节序是有依赖的,因为只能在拥有相同byte order的主机之间进行copy。

十二、Env相关的设置


     1. 环境的目录信息设置。
     dbenv->set_lg_dir(dbenv,"logdir");
     dbenv->set_data_dir(dbenv,"datadir");
     dbenv->set_tmp_dir(dbenv,"temp");
     dbenv->open(dbenv,"/a/database",flags,mode);
     以上代码将日志文件存放于/a/database/logdir,数据文件存放于/a/database/datadir, 临时文件存放于/a/database/temp.

十三、事物

     1. DB_TXN_WRITE_NOSYNC and DB_TXN_NOSYNC标志,将会让事物的commit操作避免了同步的disk IO,从而极大的提高了事物的性能,也同时降低了死锁的风险。
     
     2. 当有多个简单的事物操作同时发生时,如DB->put(),是不会有死锁产生的,因为他们同一时间只是持有一把锁,复杂的事物由于会在很长的时间内同时持有多把锁,因此,如果同时存在多个复杂的事物将会极大的提高死锁的几率。如果出现该类情况,可以考虑将复杂的事物划分为多个子嵌套事物,以便缓解死锁带来的问题。
     
     3. 数据隔离性:下面的事例用于表示多个线程同时从DB中读取同一条记录,并且将其data加一后回写。如果此时没有事物的隔离性保护,由于是并发的在同一条记录进行操作,因而可能会产生race condition,最终会导致错误的结果。

1 int add_color(DB_ENV* dbenv,DB* dbp,char* color, int increment) {
2 DBT key, data;
3 DB_TXN* tid;
4 int fail,original,ret,t_ret;
5 char buf64;
6
7 memset(&key,0,sizeof(key));
8 key.data = color
9 key.size = strlen(color);
10 memset(&data,0,sizeof(data));
11 //设置该标志用于提示BDB负责分配内存(based on malloc function),由caller决定何时通过free释放该内存,
12 //对于多线程同时操作的情况,应该使用该方式,从而避免在BDB的内部多个线程共享同一地址空间。该标志还可以带来
13 //一定的效率提升,由于只是进行了一次内存分配,caller即可以自由的使用,并根据自己的情况决定何时释放,相比于
14 //传统的local memory方式,数据持有者将节省了一次内存copy的工作。
15   data.flags = DB_DBT_MALLOC;
16
17 for (fail = 0;;) {
18 if ((ret = dbenv->txn_begin(dbenv,NULL,&tid,0)) != 0) {
19 dbenv->err(dbenv,ret,"DB_ENV->txn_begin");
20 exit(1);
21 }
22
23 //DB_RMW标志表示在读取数据的时候即直接获取写锁,因为该代码逻辑是获取指定key的数据,加一后回写,
24 //因而最终还是有写操作放生在同一记录上,使用该标志可以降低从读锁到写锁升级过程中而带来的死锁可能。
25   switch (ret = dbp->get(dbp,tid,&key,&data,DB_RMW)) {
26 case 0:
27 original = atoi(data.data);
28 break;
29 case DB_LOCK_DEADLOCK:
30 default:
31 if ((t_ret = tid->abort(tid)) != 0) {
32 dbenv->err(dbenv,t_ret,"DB_TXN->abort");
33 exit(1);
34 }
35 if (fail++ == MAXIMUM_RETRY)
36 return ret;
37 continue;
38 case DB_NOTFOUND:
39 original = 0;
40 break;
41 }
42 if (data.data != NULL)
43 free(data.data);
44
45 snprintf(buf,sizeof(buf),"%d",original + increment);
46 data.data = buf;
47 data.size = strlen(buf) + 1;
48
49 switch (ret = dbp->put(dbp,tid,&key,&data,0)) {
50 case 0:
51 if ((ret = tid->commit(tid,0)) != 0) {
52 dbenv->err(dbenv,t_ret,"DB_TXN->commit");
53 exit(1);
54 }
55 return 0;
56 case DB_LOCK_DEADLOCK:
57 default:
58 if ((t_ret = tid->abort(tid)) != 0) {
59 dbenv->err(dbenv,t_ret,"DB_TXN->abort");
60 exit(1);
61 }
62 if (fail++ == MAXIMUM_RETRY)
63 return ret;
64 break;
65 }
66 }
67 }

     4. 死锁检测通过两种方式进行设置,其一是在dbenv初始化的时候调用该函数 dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT),也可以通过一个独立的线程定时的执行dbenv->lock_detect()方法,前者将会使每次出现conflict的时候都会执行死锁检测,因此会影响并发的性能,后者是在一个单独的线程中定时的完成,所以效率更好。
     
     5. checkpoint,定时的执行dbenv->txn_checkpoint()函数,可以将日志文件中最近更新的数据(上一次执行该函数之后)直接flush到database文件中去。执行checkpoint操作的频率越高,DB_RECOVERY的操作完成的越快。
   
     6. 数据备份,主要分为标准备份和热备份两种。
        标准备份的步骤:
        1) 提交或者放弃所有当前的事物;
        2) 停止所有写操作,读操作可以进行,知道备份完毕;
        3) 在该DBENV上强制执行一个checkponit操作
           4) 运行db_archive工具加-s选项,列出所有当前可用的数据库文件,copy他们到备份介质,推荐将database files放到单独的目录,这样可以直接copy该子目录。
           5) 运行db_archive工具加-l选项,列出所有当前可用的日志文件,copy最后一个日志文件到备份介质。
          
           热备份的步骤:
           1) 在环境中设置DB_HOTBACKUP_IN_PROGRESS标志,其将影响DB_TXN_BULK的行为,致使Bulk操作可以产生日志数据。
           2) 完成标准备份中的第四步骤,确保你使用的copy工具,可以对database page进行原子性copy。
           3) 归档所有的日志文件,将其copy到备份介质,鉴于此,推荐将日志文件存放到环境主目录下的一个单独子目录。注意,一定要保证copy的顺序是先copy数据文件,再copy日志文件,特别是当数据文件和日志文件存放于同一目录下时。
           4) 恢复DB_HOTBACKUP_IN_PROGRESS.
           5) 为了缩短日志的copy时间,可以在hotbackup之前,通过db_archive工具识别出不在使用的日志文件,将其移出当前的目录。
          
     7. 日志移除
        1) db_archive -d 将移除所有不在使用的日志文件。
        2) 调用DB_ENV->log_archive()函数,同时将flags参数设置为DB_ARCH_REMOVE,其效果同1)。
        3) 调用DB_ENV->log_set_config()函数,同时将flags参数设置为DB_LOG_AUTO_REMOVE,这样BDB将自动移除所有不在使用中的日志文件,应用程序同样也没有机会copy这些日志文件到备份介质。

十四、 Replication

   1. 所有被复制的数据库文件必须位于DB_ENV的主目录下面,或者是位于DB_ENV->set_data_dir()中指定的目录中,不能位于其子目录内。
   2. 环境初始化必须包含DB_INIT_REP和DB_THREAD两个标志。
   3. 该结构的DB_ENV必须是支持事务的。
   4. 调用DB_ENV->repmgr_set_local_site()、DB_ENV->repmgr_set_ack_policy()和DB_ENV->repmgr_add_remote_site(), 以便初始化复制的通讯层,最后调用DB_ENV->repmgr_start()方法启动复制管理器。
   5. 其他和Replicatio Manager方式相关的函数:
      1) DB_ENV->rep_set_nsites() 设置Replication Group中BDB的数量,以便用于master失败后的election。
      2) DB_ENV->rep_set_priotiry() 设置优先级,该值越高,在竞选master的过程中,成为master的可能性越高。
      3) DB_ENV->rep_set_timeout() 设置master和slaves之间的heartbeat超时,如果指定时间内没有收到master的HeartBeat,election将被启动。

posted @ 2011-06-05 21:01  OrangeAdmin  阅读(1719)  评论(0编辑  收藏  举报