boltdb阅读II
文章目录
【注意】最后更新于 November 2, 2018,文中内容可能已过时,请谨慎使用。
我们继续上篇的bolt源码阅读。
文件锁
数据库由于有读写操作,所以会在一定情况下会有多个进程同时写一个文件的情况。
|
|
bolt使用系统的文件锁来防止多个进程同时对一个文件操作。这样就进一步防止了用户创建了两个不同的实例对一个数据库操作导致的问题的发生。 写入函数很简单,直接使用
|
|
系统默认的写入方式写入文件。
文件判断
通过使用了上述的OpenFile函数,系统中可能已经存在数据,也有可能没有存在,因此需要进行判断
|
|
如果连文件信息都无法获取,则直接认定出错,无需进行后续的处理。如果文件大小为0,代表是一个新的文件,需要对数据库进行初始化。否则的话需要读取数据库文件。
初始化
为了方便从头理解,我们就从初始化一个数据库开始读起。
|
|
初始化函数多个几个我们刚刚没有看到的内容,我们一步一步来分析。 首先,bolt使用mmap进行内存与文件系统的映射转换,因此,在一个操作系统中,需要知道给定的分页大小。我们假设系统给定的分页大小是4096。 首先创建了4*4096长度的字节数组。然后每次都往buf中写入数据,每次写入的都是4096(pageSize)大小。
page
在这个地方,出现了第一个我们需要认识的数据类型page。
我们先在这停一下,来了解下page。
|
|
这里面,id就是指每一个页面的Id
flags是表示页面的数据类型,包含branchPageFlag、leafPageFlag等四种。
其次是count,也就是页面内存储元素的个数,包括branchPageElement和leafPageElement。
接下来的overflow字面意思是溢出,就是指页面是否有超出了pageSize的大小,需要进行连接。
ptr是指的数据element开始的地址。
我们画个示意图了解一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
+---------------+
| Id |
| |
+---------------+
| Flags |
| |
| |
+---------------+
| Count |
| |
+---------------+
| overflow |
| |
ptr+--------> +---------------+
| |
| |
| Elements |
| |
| |
| |
| |
| |
| |
| |
+---------------+ |
这就是一个页面的结构。 为什么ptr不再内存中呢?
|
|
可以看出,pageHeaderSize到ptr就结束了。所以ptr仅仅是一个分界线而已。
meta
除此之外,源码中还有一个meta结构,我们一并分析下。
|
|
首先magic,就是一个表名是bolt的数字,没有太多的意义。
version,版本号。
pageSize在我们的文件判断中有段代码是db.pageSize = int(m.pageSize)就是代表的页面大小。
flags没有看到如何使用。
root是数据库的一个根bucket
freelist,就是指的空闲页面的标号
pgid,记录的是数据库一共存了多少页
txid,交易Id,表示数据库当前进行的版本。
checksum,校验和,确保以后读取的信息没有错误。
配置
现在我们继续回到初始化,可以看到,程序首先将前两个page设置为metaPage,其中meta的配置如下
|
|
我们主要关注freelist和pgid。
可以看到freelist设置为2,也就是我们接下来要设置的freelist页。
pgid设置为4,因为我们再创建buf数组时制定的大小是4*pageSize,所以一共有四个page。
接下来bolt配置page3(freelist页)和page4(leafPage页)
|
|
没有什么难以理解的地方。
然后系统将buf写入文件中。
|
|
初始化结束。