TCBDB存储结构

TCBDBtokyo cabinet的一部分,实现了基于B+树的key/value存储,本文简单介绍TCBDB中分支及叶子节点的存储结构。

 

分支节点(非叶子节点)的结构

 

typedef struct {                         // type of structure for a page index

  uint64_t pid;                          // ID number of the referring page

  int ksiz;                              // size of the key region

} BDBIDX;

 

typedef struct {                         // type of structure for a node page

  uint64_t id;                           // ID number of the node

  uint64_t heir;                         // ID of the child before the first index

  TCPTRLIST *idxs;                       // list of indices

  bool dirty;                            // whether to be written back

  bool dead;                            // whether to be removed

} BDBNODE;

 

每个节点作为一个TCHDBvalue进行存储,对应的key为节点的ID(通过ID值则可获取节点存储的信息),叶子节点和分支节点的ID值会在不同的范围内,每个节点的value不能超过一个pagepage的值默认为65536

 

分支节点应该包括mkey以及m+1一个节点指针(索引), idxs即用于存储节点的索引信息,比第一个key关键字小的子节点的指针存放在BDBNODEheir字段中,这样保证剩余的信息是结构化的。

 

BDBIDX中包含一个key的大小和一个节点指针(ID)信息,实际的key则紧接在该结构之后,mBDIDX加一个heir字段组成分支节点的索引。

 

节点信息序列化到磁盘上按照多个{[heir][pid][ksiz][kvalue]}存储的,这样当需要获取节点信息时,通过反序列化即可获得节点的内存结构。

 

 

叶子节点的结构

 

typedef struct {                         // type of structure for a record

  int ksiz;                              // size of the key region

  int vsiz;                              // size of the value region

  TCLIST *rest;                          // list of value objects

} BDBREC;

 

typedef struct {                         // type of structure for a leaf page

  uint64_t id;                           // ID number of the leaf

  TCPTRLIST *recs;                       // list of records

  int size;                              // predicted size of serialized buffer

  uint64_t prev;                         // ID number of the previous leaf

  uint64_t next;                         // ID number of the next leaf

  bool dirty;                            // whether to be written back

  bool dead;                             // whether to be removed

} BDBLEAF;

 

叶子节点用于实际存储数据,每个叶子包含指向前后叶子节点的指针(对应叶子节点的ID)。每个叶子节点中包含多个records<key, value-list>,因TCBDB允许key重复出现,即一个key可对应多个valueBDBREC中存储一个key以及其对应的所有value的信息。

 

TCBDB元信息

TCBDB的头部会包含一些整个数据库的元信息,包括分支节点成员个数,叶节点成员个数,root节点的id,第一个叶节点的id,最后一个叶节点的id,叶节点数,分支节点数,记录数等信息。

 

当需要访问TCBDB的某个key对应的value时,会从root节点进行查找,并通过分支节点的索引定位到叶子节点,然后在叶子节点中二分查找指定的key对应的记录。为了加速查找过程, TCBDB将最近访问的节点进行了缓存。


2011123日补充:

TCBDB为区分叶子节点和分支节点,叶子和分支id在使用TCHDB进行存储时使用不同范围的ID,临界点为BDBNODEIDBASE。另外,TCBDB将最近访问的nodeleaf进行缓存,因为在一次存储或删除对象的过程中,可能多次访问路径上的节点。


存储(put)一个对象,包含如下步骤:

(1)  从根节点起,按查找路径下降至叶子节点(id < BDBNODEIDBASE)停止,此id即为对象应该插入的叶子节点,并在下降的过程中记录路径上的所有节点id.

(2)  put的对象插入到叶子节点中,如果叶子节点中对象个数超出限定值(lmemb)或者叶子节点的总大小超出限定值(lsmax),则需要对叶子节点进行分裂。

(3)  分裂了叶子节点后需要在父分支节点中增加一个索引项,这可能导致分支节点索引个数超出阈值(nmemb),因此要沿着下降的路径(在步骤1中记录)上升至根节点,对需要分裂的分支进行分裂,该过程可能导致树增高。


删除(out)一个对象,包含如下步骤:

(1)  put过程相同,找到对应的叶子节点,记录从根到叶子节点的路径。

(2)  从叶子节点中删除对应的对象,如果叶子节点中无任何对象了,则需要kill掉该叶子节点,并从叶子节点的父节点删除索引项,如果父节点中再无任何索引,则需要kill掉父节点。

在删除节点时,并没有严格按照B+树的定义进行,只有在叶子(分支)节点中再无任何对象(索引)时才将对应的节点移除,可能因为在实际的系统应用中,删除操作本身并不多,没有必要完全按照定义来进行删除。

lnumnnum并非表示B树当前的叶子、分支数,而时代表创建过的叶子、节点数,因每创建一个新的叶子,都是直接使用++lnum,而且在删除叶子的时候也没有减少lnum的值。


posted @ 2013-04-19 14:12  ydzhang  阅读(411)  评论(0编辑  收藏  举报