读操作

leveldb提供给用户两种进行读取数据的接口:

  • 直接通过Get接口读取数据;
  • 首先创建一个snapshot,基于该snapshot调用Get接口读取数据;两者的本质是一样的,只不过第一种调用方式默认地以当前数据库的状态创建了一个snapshot,并基于此snapshot进行读取。

读者可能不了解snapshot(快照)到底是什么?简单地来说,就是数据库在某一个时刻的状态。基于一个快照进行数据的读取,读到的内容不会因为后续数据的更改而改变。

由于两种方式本质都是基于快照进行读取的,因此在介绍读操作之前,首先介绍快照。

快照

快照代表着数据库某一个时刻的状态,在leveldb中,作者巧妙地用一个整型数来代表一个数据库状态。

在leveldb中,用户对同一个key的若干次修改(包括删除)是以维护多条数据项的方式进行存储的(直至进行compaction时才会合并成同一条记录),每条数据项都会被赋予一个序列号,代表这条数据项的新旧状态。一条数据项的序列号越大,表示其中代表的内容为最新值。

因此,每一个序列号,其实就代表着leveldb的一个状态。换句话说,每一个序列号都可以作为一个状态快照。

当用户主动或者被动地创建一个快照时,leveldb会以当前最新的序列号对其赋值。例如图中用户在序列号为98的时刻创建了一个快照,并且基于该快照读取key为“name”的数据时,即便此刻用户将"name"的值修改为"dog",再删除,用户读取到的内容仍然是“cat”。

读操作 - 图1

所以,利用快照能够保证数据库进行并发的读写操作。

在获取到一个快照之后,leveldb会为本次查询的key构建一个internalKey(格式如上文所述),其中internalKey的seq字段使用的便是快照对应的seq。通过这种方式可以过滤掉所有seq大于快照号的数据项