LevelDB是由谷歌编写的一个快速键值存储库,它提供了一个从字符串键到字符串值的有序映射。
作者:Sanjay Ghemawat ([email protected]) 和 Jeff Dean ([email protected])
特性
- 键和值是任意字节数组。
- 数据按键排序存储。
- 调用者可以提供一个自定义比较函数来覆盖排序顺序。
- 基本操作包括
Put(key,value)
、Get(key)
、Delete(key)
。 - 多个更改可以在单个原子批处理中完成。
- 用户可以创建一个临时快照以获取数据的一致视图。
- 支持在数据上向前和向后迭代。
- 数据使用Snappy压缩库自动压缩。
- 外部活动(文件系统操作等)通过虚拟接口中继,因此用户可以自定义操作系统交互。
文档
LevelDB库文档在网络上,并捆绑在源代码中。
限制
- 这不是一个SQL数据库。它没有关系数据模型,不支持SQL查询,也不支持索引。
- 一次只能有一个进程(可能是多线程)访问特定的数据库。
- 库中本身不带客户端-服务器支持。需要此类支持的应用程序必须在其库周围包装自己的服务器。
构建
该项目直接支持CMake。
为POSIX构建
快速开始
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .
为Windows构建
首先生成Visual Studio 2017的项目/解决方案文件
mkdir build
cd build
cmake -G "Visual Studio 15" ..
默认为x86系统。对于64位系统,请运行
cmake -G "Visual Studio 15 Win64" ..
从命令行编译Windows解决方案
devenv /build Debug leveldb.sln
或打开Visual Studio中的leveldb.sln并在其中构建。
有关更高级的使用方法,请参阅CMake文档和CMakeLists.txt
。
参与 leveldb 项目
leveldb 项目欢迎使用贡献。leveldb 的主要目标是成为一个可靠且快速的键/值存储。符合上述功能/限制,并满足以下要求的变化将被考虑。
贡献要求
-
仅限已测试的平台。我们通常只会接受已编译和测试的平台的更改。这意味着 POSIX(用于 Linux 和 macOS)或 Windows。有时会接受非常小的更改,但请将其视为例外而非规则。
-
稳定的 API。我们非常努力地维护一个稳定的 API。可能需要更改使用 leveldb 的项目的更改可能会被拒绝,如果没有足够的利益。
-
测试:所有更改都必须附有一个新的(或更改的)测试,或足够的解释,说明为什么不需要(或更改)新的(或更改的)测试。
-
一致的风格:本项目遵循Google C++ 风格指南。为了确保您的更改格式正确,请运行
clang-format -i --style=file <file>
提交拉取请求
在接受任何拉取请求之前,作者必须首先在https://cla.developers.google.com/上签署贡献者许可协议(CLA)。
为了保持提交时间线线性,请将您的更改压缩为单个提交并在 google/leveldb/master 上 squash,并rebase。这使提交时间线保持线性并更容易与谷歌的内部存储库同步。更多信息请参阅 GitHub 的关于 Git rebase 页面。
性能
以下是运行包含的 db_bench 程序的性能报告(带解释)。结果可能有些嘈杂,但应该足以获得性能估计的大致范围。
设置
我们使用一个包含一百万条记录的数据库。每条记录都有一个16字节的键和一个100字节值。基准测试中使用的值压缩后大约是原始大小的一半。
LevelDB: version 1.1
Date: Sun May 1 12:11:26 2011
CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
CPUCache: 4096 KB
Keys: 16 bytes each
Values: 100 bytes each (50 bytes after compression)
Entries: 1000000
Raw Size: 110.6 MB (estimated)
File Size: 62.9 MB (estimated)
写入性能
"fill"基准测试创建一个全新的数据库,顺序或随机排序。"fillsync"基准测试在每个操作后将数据从操作系统刷新到磁盘;其他写入操作将数据留在操作系统缓冲区缓存中一段时间。"overwrite"基准测试执行随机写入,更新数据库中现有键的值。
fillseq : 1.765 micros/op; 62.7 MB/s
fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops)
fillrandom : 2.460 micros/op; 45.0 MB/s
overwrite : 2.380 micros/op; 46.5 MB/s
上面的每个"op"都对应单个键/值对的写入。也就是说,一个随机写入基准测试大约每秒进行40万个写入。
每个"fillsync"操作的代价(0.3毫秒)比磁盘寻址(通常10毫秒)低得多。我们认为这是因为硬盘本身已在内存中缓冲更新,并在数据写至磁片之前做出响应。这可能是安全的,也可能不安全,这取决于硬盘是否有足够的电量在断电时保存其内存。
读取性能
我们列出按顺序正向和反向读取的性能以及随机查找的性能。请注意,由基准测试创建的数据库相当小。因此,报告描述了当工作集适合内存时leveldb的性能。读取不在操作系统缓冲区缓存中的数据将主要由从磁盘获取数据所需的1个或2个磁盘寻址所决定。写入性能通常不受工作集是否适合内存的影响。
readrandom : 16.677 micros/op; (approximately 60,000 reads per second)
readseq : 0.476 micros/op; 232.3 MB/s
readreverse : 0.724 micros/op; 152.9 MB/s
LevelDB将在后台压缩其底层存储数据以提高读取性能。上面列出的结果是进行大量随机写入后立即进行的。压缩后的结果(通常是自动触发的)会更好。
readrandom : 11.602 micros/op; (approximately 85,000 reads per second)
readseq : 0.423 micros/op; 261.8 MB/s
readreverse : 0.663 micros/op; 166.9 MB/s
读取中的高成本部分来自于从磁盘读取的块重复解压缩。如果我们为leveldb提供足够的缓存来在内存中保留未解压缩的块,读取性能将再次得到改善。
readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction)
readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction)
代码库内容
参见doc/index.md获取更多说明。参见doc/impl.md获取实现概述。
公开接口位于include/*.h。调用方不应包含或依赖此包中任何其他头文件的详细信息。这些内部API可能会提前没有通知而更改。
头文件引导
-
include/db.h:DB的主接口:从这里开始
-
include/options.h:控制整个数据库的行为,以及控制单个读取和写入的行为。
-
include/comparator.h:用户指定比较函数的抽象。如果您只想按字节顺序比较键,可以使用默认比较器,但如果客户端想要自定义顺序(例如,处理不同的字符编码等),则可以编写自己的比较器实现。
-
include/iterator.h:遍历数据的接口。您可以从DB对象中获取迭代器。
-
include/write_batch.h:将多个更新原子应用到数据库的接口。
-
include/slice.h:用于维护对其他字节数组的指针和长度的简单模块。
-
include/status.h:状态从许多公开接口返回,用于报告成功和各种类型的错误。
-
include/env.h:操作系统环境的抽象。此接口的posix实现位于util/env_posix.cc
-
include/table.h, include/table_builder.h:大多数客户端可能不会直接使用的底层模块