天天看点

tokyo cabinet源代码分析(3)

2.3数据记录的写入

   在前面的2节对于内存hash memory的基本数据结构进行了分析。通过tcmdbput将key,value结构写入到内存中。

/*通过tcmdbput进行存储

*先通过key映射到某个map上面

*然后在map上面进行bucket的操作*/

/* Store a record into an on-memory hash database. */

void tcmdbput(TCMDB *mdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){

assert(mdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);

unsigned int mi;

TCMDBHASH(mi, kbuf, ksiz);

if(pthread_rwlock_wrlock((pthread_rwlock_t *)mdb->mmtxs + mi) != 0) return;

tcmapput(mdb->maps[mi], kbuf, ksiz, vbuf, vsiz);

pthread_rwlock_unlock((pthread_rwlock_t *)mdb->mmtxs + mi);

}

2.3.1 Hash算法映射

先通过hash算法,映射到maps数据的元素上。

/*将一个对象存储在map object中*/

/* Store a record into a map object. */

void tcmapput(TCMAP *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz){

assert(map && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);

if(ksiz > TCMAPKMAXSIZ) ksiz = TCMAPKMAXSIZ;

uint32_t hash;

/*第一次HASH映射到map数组上*/

TCMAPHASH1(hash, kbuf, ksiz);

int bidx = hash % map->bnum;

TCMAPREC *rec = map->buckets[bidx];

/*entp保存父节点地址*/

TCMAPREC **entp = map->buckets + bidx;

/*第二次HASH映射到特定map的bucket上*/

TCMAPHASH2(hash, kbuf, ksiz);

hash &= ~TCMAPKMAXSIZ;

再通过hash算法,映射到特定maps元素的buckets数组中。即:先找个MAP,再找buckets。

2.3.2记录初次插入二叉树

我们先讨论初次加入二叉树结构的方法。

/*如果为首次加入,则直接放入到buckets中*/

/*计算需要pad的字节大小*?

int psiz = TCALIGNPAD(ksiz);

map->msiz += ksiz + vsiz;

/*分配key,value,pad大小,末尾'/0'

*rec表示了左右子树,父节点*/

TCMALLOC(rec, sizeof(*rec) + ksiz + psiz + vsiz + 1);

char *dbuf = (char *)rec + sizeof(*rec);

/*在TCMAPREC结构体之后,存放key的内容*/

memcpy(dbuf, kbuf, ksiz);

/*key值通过在末尾增加'/0'分割*/

dbuf[ksiz] = '/0';

rec->ksiz = ksiz | hash;

/*value值的拷贝*/

memcpy(dbuf + ksiz + psiz, vbuf, vsiz);

dbuf[ksiz+psiz+vsiz] = '/0';

/*修改rec记录的大小*/

rec->vsiz = vsiz;

rec->left = NULL;

rec->right = NULL;

/*record的prev节点指向原先的最后一个节点

*构成双向链表结构,并通过Map的first和last

*节点进行连接*/

rec->prev = map->last;

rec->next = NULL;

/*加入到树中*/

*entp = rec;

/*如果该buckets数组为初次插入节点,则first头节点指向该记录*/

if(!map->first) map->first = rec;

/*如果last节点不为空,(已经有插入节点),则将原先节点的next节点

*指向该记录,然后last节点指向新的记录,即:将原先的节点都连接起来*/

if(map->last) map->last->next = rec;

map->last = rec;

/*record记录数增加*/

map->rnum++;

继续阅读