作者:tos
来源:http://hi.baidu.com/dongliqian/item/21e2fb1d07d3fc7a7a5f2565
beansdb在数据存储方面使用了tokyo cabinet. 在beansdb中数据存储在两种文件中:*.tch 和 *.index 。tch文件用于存储数据和meta data。index文件用于存储当前使用的key, version 和 hash。
在代码结构中,hstore.c 和 htree.c用于管理数据。hstore.c中提供了beansdb.c访问数据的接口。主要的接口有: hs_open, hs_set, hs_get, hs_delete, hs_clear, hs_flush, hs_check。 这个文件主要用于维护.tch数据文件。htree.c 主要用来维护hash tree, 即index文件。
beansdb为了提高并发,支持若干个数据库组成一个森林。在查找时,会根据key计算出index,然后到森林中对应的数据库去提取数据。
beansdb中设计了三种数据容器来存储数据:hash database, memory database, hash tree. 其中hash database 和 memory database是真正存储数据的。hash tree起一个辅助的作用。 hash database 和 memory database是基于tokyo cabinet,而hash tree是beansdb自己设计和实现的。hash database是可以持久化的,而memory database是不可以持久化的。
beansdb中支持获取三种数据:1. 普通的数据。 2. meta data (key以?开头). 主要包括了version 和 hash。 3. hash tree的信息。(key以@开头)
当获取普通数据和metadata时,首先会根据key计算出index。然后到相应的memory database中去获取key对应的数据,如果没有查找到,则会到hash database获取数据。key对应的meta data在数据库中就直接存放在value的后面。
当需要获取hash tree的信息时,会根据参数的长度返回相应的森林信息或者hash tree 中某个node节点下存储的item个数以及hash值。
设置数据的流程相对比较麻烦:
1. 从hash tree中获取出key对应的原来数据的hash值和version。
2. 将原来的version和要设置的version进行比较。如果要设置的version更小,则直接返回。
3. 将原来的hash值同新数据计算出的hash值比较。如果旧的hash值同新的hash值相同,则从memory database 和 hash database中获取出key值对应的原有数据,并新数据进行比较。
4. 如果数据不同则将数据写入到memory database中。
5. 将key值对应的新的version和hash值更新到hash tree中。
删除数据的过程如下:
1. 从hash tree中删除掉key值。
2. 从memory database 和 hash database 中删除掉key值和对应的数据。
从上面可以看出数据在更新的时候,只是存放在memory database中,并没有直接更新到hash database中。如果系统出现故障,则更新过的数据就会丢失掉。因此beansdb通过hs_flush机制来对memory database中的数据刷新到hash database中,并同时将hash tree中的数据持久化到hash database。
beansdb同时提供了一个函数hs_scan用来同步hash database 和 hash tree。如果两者中保存的key数量超过了一个阈值,则同步就会发生。同步默认会对结果进行持久化。
以上的持久化和同步都对应着一个线程。
beansdb中的hash tree用来存储key对应的hash, version 以及count信息等。hash tree可以持久化到tokyo cabinet中。这样在每次打开的时候key信息就可以直接从cabinet中读出,不用做费时间的hs_scan调用。
hash tree的结构
同普通的树一样,hash tree也分为叶子节点和内节点。每个内节点有16个子节点。叶子节点中最多存放128个item。每个item中存放了key的名字,hash,version。内节点记录了他的所有的子节点存放的item数目和hash值。内节点的hash值是所有子节点的hash值的和,起一个校验的作用。
hash tree中的数据结构主要由两个部分组成:Node 和 Data。Node对应了hash tree中的内节点。 每一个Node都对应了一个Data。但是只有叶子节点对应的Data才是有用的。在获取key值对应的信息时就回到Data中去获取。当查询一个key时,首先会计算这个key值的index,然后根据index值在内节点中定位子节点。最后定位到某个叶子节点。
在插入key的过程中,如果发现item的个数超出某个限制了,就会将该节点分裂。同样,如果内节点中item的个数少于某个阈值,则会将节点合并。
最后总结一下beansdb到底提供了额外的东西呢?
1. 内建了版本支持。
2. 将memcache和tokyo cabinet合到了一起。
3. 支持查询存储数据的meta data。