当前位置:网站首页 > 技术博客 > 正文

leveldb compaction



英文原文地址https://rawgit.com/google/leveldb/master/doc/index.html

leveldb库提供持久性键值存储。 键和值可以是任意字节数组。 根据用户指定的比较函数,在键值存储器内对键进行排序。

leveldb打开数据库需要指定一个文件系统目录。 数据库的所有内容都存储在此目录中。 以下示例显示如何打开数据库,如有必要,可创建该数据库:

 
  

如果要在数据库 已存在时返回错误 ,请在调用之前添加以下行:

 
  

你也许已经注意到了上面的类型。leveldb中可能遇到错误的大多数函数都返回此类型的值。 您可以检查这样的结果是否正确,并打印相关的错误消息:

 
  

使用完数据库后,只需删除数据库对象。 例:

 
  

数据库提供,和方法来修改/查询数据库。 例如,以下代码将下存储的移动到。

 
  

注意,如果进程在Put Key2 之后、Delete key1之前结束(挂了),会使得value被同时保存在多个key下。使用类进行原子更新一组操作,可以避免这些问题:

 
  

保存对数据库进行的一系列编辑,该批次内的这些修改才能被应用。 注意,我们在Put之前调用Delete,因此如果key1与key2相同,我们不会错误的完全丢弃该值。

除了它的原子性好处,也可以用于通过将放入同一批次来加速批量更新。

默认情况下,每次写入leveldb都是的:将写入从进程推送到操作系统后立即返回。从操作系统内存到底层持久存储的传输是异步的。 对于特定的写操作,可以,以使写操作不会返回,直到正在写入的数据真正写入永久存储器。 (在Posix系统上,这是通过在写操作返回之前调用(...)或(...)或(...,MS_SYNC)实现的。

 
  

异步写操作通常比同步写操作快一千倍。 异步写入的缺点是,机器的崩溃可能导致最后几个更新丢失。 请注意,只是写入进程(即不是机器重新启动)的崩溃不会导致任何损失 ,因为即使为,更新从进程内存推送到操作系统在之后即认为完成。

通常可以安全地使用异步写入。 例如,将大量数据加载到数据库中时,可以通过在崩溃后重新启动批量加载来处理丢失的更新。 混合方案也是可能的,其中每第N次写入是同步的,并且在崩溃的情况下,批量加载刚好在由前一次运行完成的最后同步写入之后重新启动。 (同步写入可以更新描述崩溃时重新启动位置的标记。)

WriteBatch提供了异步写入的替代方法。 多个更新可以放置在同一中,并使用同步写入(即,设置为)一起应用。 同步写入的额外成本将在批次中的所有写入之间摊销。

以下示例演示如何在数据库中打印所有 键-值对

 
  

以下显示了如何仅处理范围[start,limit)中的键:

 
  

您还可以按相反的顺序处理条目。 (注意:反向迭代可能比前向迭代慢一些。)

 
  

快照在键值存储的整个状态上提供一致的只读视图。可能是非的,表示操作应该在某个特定版本的DB状态。 如果为NULL,则读取操作将对当前状态的进行操作

快照由DB::GetSnapshot() 方法创建:

 
  

请注意,当不再需要快照时,应使用DB :: ReleaseSnapshot接口释放快照。这允许实现排除维护状态,只支持从该快照读取。

上面和调用的返回值是类型。Slice是一个简单的结构,包含一个长度和一个指向外部字节数组的指针。返回是比返回的更廉价替代方法,因为我们不需要复制潜在的大和。此外,leveldb方法不返回以null结束的C风格字符串,因为leveldb键和值允许包含字节。

C++ std::string和以null结尾的C风格字符串可以很容易地转换为Slice:

 
  

一个Slice可以很容易的转换回一个C++ string:

 
  

使用Slice时要小心,因为它取决于调用者,以确保在Slice使用时,Slice所指向的外部字节数组保持有效。 例如,以下是buggy:

 
  

当出if语句范围时,将被销毁,的内指针指向的内存将被释放。

前面的例子使用了key的默认排序函数,它。 然而,您可以在打开数据库时提供自定义比较器。 例如,假设每个数据库键由两个数字组成,我们应该按第一个数字排序,用第二个数字断开关系(这里实际上就是按这两个数字组合比较大小)。 首先,定义一个表示这些规则的的适当子类:

 
  

现在创建一个数据库,使用自定义的比较器comparator:

 
  

性能可以通过改变在定义的类型的默认值进行调整。

每个块在被写入永久存储器之前被单独压缩。 压缩默认情况下处于打开状态,因为默认压缩方法非常快,并且会自动禁用不可压缩数据。 在极少数情况下,如果应用程序可能希望完全禁用压缩,应该这样做,基准显示性能改进:

 
  

数据库的内容存储在文件系统中的一组文件中,并且每个文件存储压缩块的序列。 如果options.cache为非NULL,它用于缓存常用的未压缩块内容。

 
  

请注意,高速缓存保存未压缩数据,因此应根据应用程序级数据大小确定大小,而压缩不会对其产生任何影响。(压缩块的缓存由操作系统缓冲区缓存或客户端提供的自定义Env实现)。

当执行批量读取时,应用程序可能希望禁用高速缓存,使得由批量读取处理的数据不会最终取代大部分高速缓存的内容。 设置每个迭代器选项可以实现这一点:

 
  

注意,磁盘传输和高速缓存以一个块()为单位。 相邻的键(根据数据库排序顺序)通常放置在同一个块中。 因此,应用程序可以通过放置彼此靠近在一起的键,并将不常使用的键放置在键空间的单独区域中来提高其性能。

例如,假设我们在leveldb之上实现一个简单的文件系统。 我们可能希望存储的条目的类型是:

 
  

我们可能需要用一个字母前缀标识文件名(比如),并用不同的字母标识的(比如),以便只扫描元数据而不强迫我们提取和缓存庞大的文件内容。

由于leveldb数据在磁盘上的组织方式,单个调用可能涉及从磁盘多次读取。 可选的机制可用于显着减少磁盘读取数。

 
  

上述代码将基于的过滤策略与数据库相关联。 基于Boolm过滤器的过滤依赖于在每个的存储器中(在这种情况下每个密钥是10位,因为这是我们传递给NewBloomFilterPolicy的参数)。 此过滤器将调用所需的 不必要磁盘读取次数 减少大约100倍。增加每个键的bits位将导致更大的减少,但是以更多的内存使用为代价。我们建议不适合将工作集放置在内存中的应用程序,多设置一些随机读取过滤策略。

如果您使用自定义比较器,则应确保您使用的过滤器策略与比较器兼容。 例如,考虑一个比较器,在比较键时忽略尾随空格。 不能与这样的比较器一起使用。 因此,应用程序也应提供一个也忽略尾部空格的自定义过滤器策略。 例如:

 
  

Advanced应用程序可以提供不使用Bloom过滤器,但使用一些其他的机制来总结一组键的过滤策略。 有关详细信息,请参阅。

leveldb将校验和与其存储在文件系统中的所有数据相关联。 提供了两个单独的控件来对这些校验进行主动验证:

  • 可以设置为,以强制代表特定读取从文件系统读取的所有数据的校验和验证。 默认情况下,不进行此类验证。
  • 可以在打开数据库之前设置为true,以使数据库实现在检测到内部损坏时立即引发错误。 根据数据库的哪个部分已损坏,可能在打开数据库时或稍后由另一个数据库操作引发错误。 默认情况下,检查关闭,以便即使数据库的持久存储器的部分已损坏也可以使用数据库。
  • 如果数据库损坏(或者当打开时失败),函数可以用于尽可能多地恢复数据。

方法可用于获取一个或多个范围使用的文件系统空间的大致字节数。

 
  

前面的调用会将size[0]和size [1]设置为范围[a..c)和[x..z)使用的文件系统空间的大致字节数。

由实现发出的所有文件操作(和其他操作系统调用)都通过一个对象进行转调。老练的客户可能希望提供自己的实现以获得更好的控制。 例如,应用程序可以在文件IO调用中引入人工延迟,以限制对系统中的其他活动的影响。

 
  

leveldb可以通过提供由导出特定平台的实现而被移植到新的平台。相关更多详细信息,请参阅

此外,新平台可能需要一个新的默认实现。 有关示例,请参见。

有关leveldb实现的细节可以在以下文档中找到:

  • 实现注意事项
  • 不可变表文件的格式
  • 日志文件格式

版权声明


相关文章:

  • 网络设备器驱动程序2025-06-03 18:01:03
  • java下载安装步骤2025-06-03 18:01:03
  • mysql数据库的函数2025-06-03 18:01:03
  • gtest官方文档2025-06-03 18:01:03
  • redis集群方式有哪几种2025-06-03 18:01:03
  • 舅的电脑课小说2025-06-03 18:01:03
  • java内存模型图解2025-06-03 18:01:03
  • mac代码对比工具2025-06-03 18:01:03
  • udp 套接字2025-06-03 18:01:03
  • php界面怎么显示不出来2025-06-03 18:01:03