出处:http://www.cnblogs.com/stephen-liu74
一、通用配置
1. 选择合适的access method(BTree、Hash、Queue or RecNo)
2. (DB->set_pagesize)选择合适的pagesize,处于性能考虑,最好和os的block size匹配,除非每个key/value的数据很大,如果pagesize过小,会导致overflow page的问。
3. DB->set_cachesize
4. DB->set_lorder设置字节序。
5. DB->set_flag(DB_DUP)设置BTree的存储是否支持duplicate keys,缺省情况不支持重复键。DB->get()只是返回重复键中的第一个键值对,重复键数据的获取只能通过DBC-> get(), 重复键的插入缺省行为是append方式,如果打算自定义需要通过DBC->put(),同时制定DB_AFTER, DB_BEFORE, DB_KEYFIRST or DB_KEYLAST.
6. DB->set_flag(DB_DUPSORT)设置data为自动排序模式,这将极大的提高searching和join的效率。DB->set_dup_compare可以设置data的自定义排序方法。如果该表示已经设置,BDB则不允许生成duplicate data,即key/value都是相同的。
二、BTree配置
1. DB->set_bt_compare, 用户可以自定义key的比较函数
1 int compare_int(DB* dbp,const DBT *a, const DBT*b) { 2 int ai, bi; 3 memcpy(&ai,a->data,sizeof(int)); 4 memcpy(&bi,b->data,sizeof(int)); 5 return ai- bi; 6 } 7 8 //比较前5个字符的比较函数 9 int compare_dbt(DB* dbp,const DBT*a, const DBT *b) { 10 int len; 11 u_char *p1, *p2; 12 for (p1= a->data, p2= b->data, len= 5; len--;++p1,++p2) { 13 if (*p1!= *p2) 14 return (long)*p1- (long)*p2; 15 } 16 return0; 17 }
1 u_int32_t compare_prefix(DB* dbp,const DBT *a, const DBT*b) { 2 size_t cnt, len; 3 u_int8_t *p1,*p2; 4 cnt = 1; 5 len = a->size> b->size? b->size : a->size; 6 for (p1= a->data, p2= b->data; len--;++p1,++p2,++cnt) { 7 if (*p1!= *p2) 8 return cnt; 9 } 10 11 if (a->size< b->size) 12 return a->size+ 1; 13 if (b->size< a->size) 14 return b->size+ 1; 15 return b->size; 16 }
3. DB->set_bt_minkey, 用于设置DB中每个page上可容纳的key/value的最小数量,参考如下公式:
maximum_size = page_size / (minimum_keys * 2)
之所以minimum_key乘以2,是因为key和value在page中需要占用两个slot,此例中,如果page_size = 8k, minimum_keys = 2,那么任何key或value超过2k的项都将存入overflow page。
4. DB->set_bt_compress(dbp,NULL,NULL), 后面两个NULL参数表示使用BDB自带的缺省压缩和解压缩算法,该函数需要在DB被打开之前调用。
三、Hash配置
1. DB->set_h_ffactor() 设置填充因子,用于确定每个hash bucket中可能容纳key/value的一个近似值,以决定hash table应该在什么时候增长或缩短。请参照以下设置方式
(pagesize - 32) / (average_key_size + average_data_size + 8)
2. DB->set_h_hash(), 设置自定义的hash方法。
3. DB->set_h_nelem(), 用于设定hash table中可能容纳的element数量,如果设置的比较接近真实情况,将更好的避免由于hash bucket动态增长而带来的性能损失,设置该值时也需要考虑设置fill factor。
四、Recno和Queue配置
1. DB->set_re_len(),用于设置fixed-length记录的长度。短于该长度的数据,将用DB->set_re_pad中设置的字符进行尾部填充,长于该值的data,将会导致一个错误发生。
五、DB Partitioning
1. 只用BTree和Hash两种方式可以支持partitioning。
2. DB->set_partition(),DB->set_partition_dirs(), 这两个函数用于对DB进行partition,他们必须在数据库第一次被open之前调用,一旦partition成功之后,其partition的scheme将不能再改变。其中后面的函数主要用于指定partition文件所在的home directory。分区策略是,可以给partition指定其所包含的key的值,也可以通过回调函数的方式,通过回调函数的返回值来确定该键应该存放的partition。
a--f to go on partition 0
g--p to go on partition 1
q--z to go on partition 2
如果打算使用数组的方式进行partition,set_partition中回调函数参数为NULL。
如果打算使用回调的方式进行partition,set_partition中分区提示数组参数为NULL。
3. DB->set_partition_dirs(),该函数必须在数据库创建和打开之前设定,一旦成功设定并打开DB,该值将不可变。推荐设置和partition相同数量的dirs。dir可以通过绝对和相对路径支出,可以位于不同的磁盘。如果DB的打开是基于Environment的,在设置之前,需要保证所设定目录已经存在于DB_ENV->add_data_dir()的列表中。
六、Secondary Indexes
1. 可以通过给key/value中value的部分信息建立索引,作为secondary db,其key为期望的索引数据,value为primary db的key。
2. 如果删除primary中的数据,相关的secondary数据也会自动删除,反之亦然。通过DB->pget和DBC->pget()可以通过secondary的查询获取primary中key和value。但是不能直接在secondary DB中直接插入数据。
七、DB Cursor
1. DB_CONSUME标志:Read-and-Delete, 这个标志只能用于Queue类型的DB,头部记录将被返回并删除。
2. DB->join: 相等性连接。请参照以下示例:
八、Bulk获取和更新
1. DB_MULTIPLE和DB_MULTIPLE_KEY分别对应于获取所有指定key的duplicate data和多个keys/values
DB_MULTIPLE_INIT用于最初的初始化调用。
DB_MULTIPLE_NEXT: 该宏总是和DB_MULTIPLE标志绑定使用。
DB_MULTIPLE_KEY_NEXT: 该宏总是和DB_MULTIPLE_KEY标志绑定使用,同时要求底层db的类型为BTree or Hash。
DB_MULTIPLE_RECNO_NEXT: 该宏总是和DB_MULTIPLE_KEY标志绑定使用,同时要求底层db的类型为Queue or Recno。
在调用DB->get() or DBC->get()的时候,将DBT data参数data字段指向buffer,ulen表示buffer的长度,flags字段需要设置为DB_DBT_USERMEM
九、部分记录读取和存储
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()更简单。
输出结果:
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,最终会导致错误的结果。
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将被启动。