在附带的文档里,降低死锁:
减少锁占用的时间,比如cursor及时关闭,同一个事务下尽可能少的操作
对于只读的线程,考虑使用snapshot,另说这种会占用更多的内存
将访问量最大的项尽可能放在事务的末端
二级数据库带有事务功能并且可能出现并发时,必须在app里实现retry功能,因为不能避免死锁
有多线程读和至少一个写时就可能产生死锁, 每一个操作都需要对DB_LOCK_DEADLOCK进行判断
深入理解Berkeley DB的锁:理论与实践篇
Configuring Berkley db for high throughput multithreaded 100gig - terrabyte scale inverted index construction
可参考的一个stackoverflow问答
http://blog.nosqlfan.com/html/1317.html介绍了事务持久化的知识
Memcachedb中对BDB事务的使用
Berkeley DB 事务的提交,这里面有很多不错的东西值得一读
Optimizing Put Performance in Berkeley DB
上面这篇是stackoverflow的回答,讲了事务写如何提速
Berkeley DB, concurrent queues
这篇也用到了事务,及设置
可以试着使用 DB_TXN_NOSYNC/DB_TXN_WRITE_NOSYNC,和增加cache提高性能
另一些可参考的文件:
Berkeley DB: C -Transaction
Berkeley DB示例程序详解
具体实现可以参考subversion的事务处理部分,其中trail.c中的代码可借鉴价值很大,svn_fs_base__retry_txn完成了具体的事务操作
oracle forums里争论的一个帖子,事务/多线程/多表
事务处理阅读笔记
1. env需要开的子系统,logging(打开txn会自动开logging),mpool,经常还需要locking
db需要auto_commit
2. log记录所有操作,将来可能用于db的恢复,因此对完整性有帮助,通常暂存在内存中直到事务被提交,可以配置log的行为
3. 提交事务部意味着数据被写入磁盘,只有在检查点和cache满时才写入
4. 非持久事务指的是不在提交事务前将log写入磁盘,修改这种默认的情况可以减少IO从而提高性能
5. 关于auto_commit(不适用于cursor),如果对方法不提供txn handle,则每个方法会是一个独立的txn
6. 嵌套事务,在大事务中有局部的小事务独立执行
7. cursor,创建cursor时指定txn可以起到保护作用,其他时候不需要
8. 二级db,最简单的办法就是打开时使用auto_commit,此外没有需要注意的事项了
9. 配置事务子系统,设置最大并行的事务数,通常不需要这么做,除非有多个线程有多个活跃的事务
10. 锁/死锁,这个看看别的开源咋用的吧;访问前需要首先获取lock,导致其他线程无法读写被lock的object;被lock的对象指的是page,它含有多条key和data
write lock是独占性的直到完成;read lock是非独占性的,共享的,但是它不能与modify同时存在
11. 事务提交或放弃意味着lock也被释放;非事务性操作会一直保持lock到操作完成,cursor的操作将保持到下一个位置或关闭
只有write lock会被block,read lock之间不会被block;使用snapshot isolation避免read lock;
或lowering yourisolation requirements means that your application can experience improved throughput dueto reduced lock contention.
Reduce your application's isolation guarantees;Use snapshot isolation for read-only threads
12. 使用cursor遍历数据库,考虑使用read committed的隔离级别
13. 读/修改/写,如果你需要这种操作,需要使用DB_RMW这种flag
14. 设立checkpoint
15. 需要定期清理无用的log,否则会吃掉大量的空间Call DB_ENV->log_set_config()method with the DB_LOG_AUTO_REMOVE
我的处理方法:数据库表的改变有相关联的(即一个变,另一个或几个也跟着变),这些放在一个TXN里,失败则重新来,同时检测死锁,以此为前提,尽量使TXN包括的处理占用时间最短