创建和提取SST文件

RocksDB为用户提供了一些api,这些api可用于创建SST文件,这些文件可在以后使用。 如果您有一个需要快速加载数据的用例,但是创建数据的过程可以离线完成,那么这将非常有用。

创建SST文件

rocksdb::SstFileWriter可以用来创建SST文件。 创建SstFileWriter对象之后,可以打开一个文件,将行插入其中并完成。

这是一个如何在/home/usr/file1.sst中创建SST文件的示例

  1. Options options;
  2. SstFileWriter sst_file_writer(EnvOptions(), options);
  3. // Path to where we will write the SST file
  4. std::string file_path = "/home/usr/file1.sst";
  5. // Open the file for writing
  6. Status s = sst_file_writer.Open(file_path);
  7. if (!s.ok()) {
  8. printf("Error while opening file %s, Error: %s\n", file_path.c_str(),
  9. s.ToString().c_str());
  10. return 1;
  11. }
  12. // Insert rows into the SST file, note that inserted keys must be
  13. // strictly increasing (based on options.comparator)
  14. for (...) {
  15. s = sst_file_writer.Put(key, value);
  16. if (!s.ok()) {
  17. printf("Error while adding Key: %s, Error: %s\n", key.c_str(),
  18. s.ToString().c_str());
  19. return 1;
  20. }
  21. }
  22. // Close the file
  23. s = sst_file_writer.Finish();
  24. if (!s.ok()) {
  25. printf("Error while finishing file %s, Error: %s\n", file_path.c_str(),
  26. s.ToString().c_str());
  27. return 1;
  28. }
  29. return 0;

现在,我们的SST文件位于 /home/usr/file1.sst.

请注意:

  • 传递给SstFileWriter的选项将用于确定用于创建SST文件的表类型、压缩选项等。
  • 传递给SstFileWriter的比较器必须与将吸收该文件的DB中使用的比较器完全相同。
  • 必须按照严格递增的顺序插入行。

通过检查include/rocksdb/sst_file_writer.h (https://github.com/facebook/rocksdb/blob/master/include/rocksdb/sst_file_writer.h),您可以了解关于SstFileWriter的更多信息

摄取SST文件很简单,只需调用DB::IngestExternalFile()并将文件路径作为std::string的向量传递

  1. IngestExternalFileOptions ifo;
  2. // Ingest the 2 passed SST files into the DB
  3. Status s = db_->IngestExternalFile({"/home/usr/file1.sst", "/home/usr/file2.sst"}, ifo);
  4. if (!s.ok()) {
  5. printf("Error while adding file %s and %s, Error %s\n",
  6. file_path1.c_str(), file_path2.c_str(), s.ToString().c_str());
  7. return 1;
  8. }

您可以通过检查include/rocksdb/db.h中的DB::IngestExternalFile() 和 DB::IngestExternalFiles()了解更多信息。 DB::IngestExternalFiles()在”全有或全无”属性之后为多个列族摄取一组外部SST文件。 如果函数返回Status::OK,那么所有感兴趣的列族的所有文件都将被成功摄取。 如果函数返回non-OK状态,那么没有一个文件进入任何列族。

当你摄入一个文件时会发生什么

当您调用DB::IngestExternalFile()时,我们会这样做

  • 将文件复制或链接到DB目录中
  • 块(而不是跳过)写入数据库,因为我们必须保持一致的数据库状态,所以我们必须确保我们可以安全地为我们要摄取的文件中的所有键分配正确的序列号
  • 如果文件键范围与memtable键范围重叠,则刷新memtable
  • 将文件分配到lsm树中可能的最佳级别
  • 为文件分配一个全局序列号
  • 向数据库写入简历

我们选择lsm树中满足这些条件的最低层

  • 文件可以放在这个级别
  • 文件key范围不与上层的任何密钥重叠
  • 该文件不会与运行到此级别的压缩的输出重叠

全局序列号

使用SstFileWriter创建的文件在它们的metablock中有一个叫做全局序列号的特殊字段,当这个字段被使用时,这个文件中的所有键开始起作用,就好像它们有这样的序列号一样。 当我们摄取一个文件时,我们给这个文件中的所有键分配一个序列号。在RocksDB 5.16之前,RocksDB总是使用随机写入更新SST文件元组锁中的全局序列号字段。 从RocksDB 5.16开始,RocksDB允许用户选择是否通过IngestExternalFileOptions::write_global_seqno更新该字段。 如果该字段在摄入期间没有更新,那么RocksDB在访问文件时使用清单和表属性中的信息来推断全局序列号。如果底层文件系统不支持随机写入,这将非常有用。 如果需要考虑向后兼容性,请将此选项设置为true,以便RocksDB 5.16或更新版本摄入的外部SST文件可以由RocksDB 5.15或更老版本打开。

摄入之前

从5.5开始,IngestExternalFile()将加载一个支持后台摄取的外部SST文件列表,这意味着如果ingest_behind==true,将跳过重复的键。 在这种模式下,我们将始终摄入在底部模式水平。要跳过正在摄取的文件中的重复键,而不是覆盖该键下的现有数据。

用例

在不覆盖现有更新版本的数据的情况下,回填数据库中的一些历史数据。这个选项只能在数据库运行allow_ingest_behind=true时使用。 所有的文件都将在seqno=0的最底层被摄取