Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4078445
  • 博文数量: 251
  • 博客积分: 11197
  • 博客等级: 上将
  • 技术积分: 6862
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-05 14:41
个人简介

@HUST张友东 work@taobao zyd_com@126.com

文章分类

全部博文(251)

文章存档

2014年(10)

2013年(20)

2012年(22)

2011年(74)

2010年(98)

2009年(27)

分类: C/C++

2011-05-27 17:56:39

TCFDBTokyo Cabinet中的fix length定长数据库的实现,key由整数id标示,所有value的长度都在某一个长度范围内,TCFDB为某个记录分配固定宽度的区域。TCFDB的设计与实现是KISS(Keep it simple & stupid)原则很好的一个体现。

 

TCFDB将存储区域分为两部分,头部和记录区,头部包含TCFDB的一些全局信息(长度固定),记录区依次存储多个记录,每个记录开始处存储记录的长度(可能是1,2,4个字节,具体由记录宽度决定),接下来是固定宽度的区域存储value。定长记录默认宽度为255,可以在open前通过tcfdbtune来设置。TCFDB的记录区如下图所示:

 

 

TCFDB将整个数据库映射到内存中,所以数据库的长度是受内存大小的限制的。TCFDBID值顺序存放记录,所以给定ID即可快速定位到记录存储的位置。

 

put接口的实现

根据id定位到记录应该存储的位置,根据put类型(覆盖、保持、追加等)执行存储操作,如果当前操作在transaction中,则将原来的纪录先写到wal log中(用于事务abortrestore)。

 

get接口的实现

根据id定位到记录应该存储的位置,读取记录。

如果当前操作在transaction中,则将操作记录写到wal log中。

 

out接口的实现

根据id定位到记录应该存储的位置,删除记录。TCFDB根据记录的大小判断对应的区域是否存在有记录,0表示没有记录。如果当前操作在transaction中,则将操作记录写到wal log中(用于事务abortrestore)。

 

数据库的遍历

TCFDB提供按照id顺序遍历数据库的接口tcfdbnextid获取下一个记录的id,对于每一个idTCFDB检查对应记录位置的大小值是否为0,如果为0说明没有记录,否则返回记录id。当某个记录加入后,如果记录的位置大于当前文件大小,就会出现文件洞,洞中的数据都为0,所以才会有上面的判断逻辑。

 

事务的实现

TCFDB通过三个方法tcfdbtranbegintcfdbtrancommittcfdbtranabort来实现事务。首先在开始事务之前调用tcfdbtranbegin将数据库当前的内容同步到磁盘(msync),并设置数据库的tran字段为true;当事务完成后,通过tcfdbtrancommit提交事务,其将数据库的更新同步到磁盘,并将wal日志文件截短至0;如果需要中止事务,则调用tcfdbtranabort,其将wal日志文件中的记录restore到文件中,恢复数据库的内容到事务开始前的状态。

 

锁机制

typedef struct {       /* type of structure for a fixed-length database */

  void *mmtx;       /* mutex for method */

  void *amtx;        /* mutex for attribute */

  void *rmtxs;       /* mutexes for records */

  void *tmtx;        /* mutex for transaction */

  void *wmtx;       /* mutex for write ahead logging */

  …..

} TCFDB;

 

TCFDB主要提供了对方法锁、属性锁、记录锁、事务锁、wal日志锁。

l  方法锁是读写锁,对于可能改变数据库内容的操作如out以及某些put操作,会在操作开始前加写锁,否则加读锁,如get

l  属性锁是互斥锁,在更新数据库的头部前需加锁,如在putout时需要更新头部信息。

l  记录锁是读写锁,默认127个,每次对记录的操作需要对某个锁(记录id127取余)加锁,设置127实际上是时间和空间上的折中,如果要达到性能最优化,需对每个记录设置一个锁。另外,TCFDB还提供了对所有记录锁加解锁的接口,tcfdbcopy(拷贝数据库)、tcfdbforeach(对数据库的每一项执行某种操作)两个接口需要对所有记录加锁。

l  事务锁在TCFDB的实现中没有看到过使用,只有初始化和销毁的操作。其实数据库的tran字段已经起到了锁的作用。

l  wal日志锁是互斥锁,tcfdbwalwrite接口在望wal日志写数据前会加锁。


阅读(3044) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~