You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
6.2 KiB

  1. // Copyright (c) 2012 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #include "leveldb/dumpfile.h"
  5. #include <cstdio>
  6. #include "db/dbformat.h"
  7. #include "db/filename.h"
  8. #include "db/log_reader.h"
  9. #include "db/version_edit.h"
  10. #include "db/write_batch_internal.h"
  11. #include "leveldb/env.h"
  12. #include "leveldb/iterator.h"
  13. #include "leveldb/options.h"
  14. #include "leveldb/status.h"
  15. #include "leveldb/table.h"
  16. #include "leveldb/write_batch.h"
  17. #include "util/logging.h"
  18. namespace leveldb {
  19. namespace {
  20. bool GuessType(const std::string& fname, FileType* type) {
  21. size_t pos = fname.rfind('/');
  22. std::string basename;
  23. if (pos == std::string::npos) {
  24. basename = fname;
  25. } else {
  26. basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);
  27. }
  28. uint64_t ignored;
  29. return ParseFileName(basename, &ignored, type);
  30. }
  31. // Notified when log reader encounters corruption.
  32. class CorruptionReporter : public log::Reader::Reporter {
  33. public:
  34. void Corruption(size_t bytes, const Status& status) override {
  35. std::string r = "corruption: ";
  36. AppendNumberTo(&r, bytes);
  37. r += " bytes; ";
  38. r += status.ToString();
  39. r.push_back('\n');
  40. dst_->Append(r);
  41. }
  42. WritableFile* dst_;
  43. };
  44. // Print contents of a log file. (*func)() is called on every record.
  45. Status PrintLogContents(Env* env, const std::string& fname,
  46. void (*func)(uint64_t, Slice, WritableFile*),
  47. WritableFile* dst) {
  48. SequentialFile* file;
  49. Status s = env->NewSequentialFile(fname, &file);
  50. if (!s.ok()) {
  51. return s;
  52. }
  53. CorruptionReporter reporter;
  54. reporter.dst_ = dst;
  55. log::Reader reader(file, &reporter, true, 0);
  56. Slice record;
  57. std::string scratch;
  58. while (reader.ReadRecord(&record, &scratch)) {
  59. (*func)(reader.LastRecordOffset(), record, dst);
  60. }
  61. delete file;
  62. return Status::OK();
  63. }
  64. // Called on every item found in a WriteBatch.
  65. class WriteBatchItemPrinter : public WriteBatch::Handler {
  66. public:
  67. void Put(const Slice& key, const Slice& value) override {
  68. std::string r = " put '";
  69. AppendEscapedStringTo(&r, key);
  70. r += "' '";
  71. AppendEscapedStringTo(&r, value);
  72. r += "'\n";
  73. dst_->Append(r);
  74. }
  75. void Delete(const Slice& key) override {
  76. std::string r = " del '";
  77. AppendEscapedStringTo(&r, key);
  78. r += "'\n";
  79. dst_->Append(r);
  80. }
  81. WritableFile* dst_;
  82. };
  83. // Called on every log record (each one of which is a WriteBatch)
  84. // found in a kLogFile.
  85. static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) {
  86. std::string r = "--- offset ";
  87. AppendNumberTo(&r, pos);
  88. r += "; ";
  89. if (record.size() < 12) {
  90. r += "log record length ";
  91. AppendNumberTo(&r, record.size());
  92. r += " is too small\n";
  93. dst->Append(r);
  94. return;
  95. }
  96. WriteBatch batch;
  97. WriteBatchInternal::SetContents(&batch, record);
  98. r += "sequence ";
  99. AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));
  100. r.push_back('\n');
  101. dst->Append(r);
  102. WriteBatchItemPrinter batch_item_printer;
  103. batch_item_printer.dst_ = dst;
  104. Status s = batch.Iterate(&batch_item_printer);
  105. if (!s.ok()) {
  106. dst->Append(" error: " + s.ToString() + "\n");
  107. }
  108. }
  109. Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) {
  110. return PrintLogContents(env, fname, WriteBatchPrinter, dst);
  111. }
  112. // Called on every log record (each one of which is a WriteBatch)
  113. // found in a kDescriptorFile.
  114. static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) {
  115. std::string r = "--- offset ";
  116. AppendNumberTo(&r, pos);
  117. r += "; ";
  118. VersionEdit edit;
  119. Status s = edit.DecodeFrom(record);
  120. if (!s.ok()) {
  121. r += s.ToString();
  122. r.push_back('\n');
  123. } else {
  124. r += edit.DebugString();
  125. }
  126. dst->Append(r);
  127. }
  128. Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) {
  129. return PrintLogContents(env, fname, VersionEditPrinter, dst);
  130. }
  131. Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) {
  132. uint64_t file_size;
  133. RandomAccessFile* file = nullptr;
  134. Table* table = nullptr;
  135. Status s = env->GetFileSize(fname, &file_size);
  136. if (s.ok()) {
  137. s = env->NewRandomAccessFile(fname, &file);
  138. }
  139. if (s.ok()) {
  140. // We use the default comparator, which may or may not match the
  141. // comparator used in this database. However this should not cause
  142. // problems since we only use Table operations that do not require
  143. // any comparisons. In particular, we do not call Seek or Prev.
  144. s = Table::Open(Options(), file, file_size, &table);
  145. }
  146. if (!s.ok()) {
  147. delete table;
  148. delete file;
  149. return s;
  150. }
  151. ReadOptions ro;
  152. ro.fill_cache = false;
  153. Iterator* iter = table->NewIterator(ro);
  154. std::string r;
  155. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  156. r.clear();
  157. ParsedInternalKey key;
  158. if (!ParseInternalKey(iter->key(), &key)) {
  159. r = "badkey '";
  160. AppendEscapedStringTo(&r, iter->key());
  161. r += "' => '";
  162. AppendEscapedStringTo(&r, iter->value());
  163. r += "'\n";
  164. dst->Append(r);
  165. } else {
  166. r = "'";
  167. AppendEscapedStringTo(&r, key.user_key);
  168. r += "' @ ";
  169. AppendNumberTo(&r, key.sequence);
  170. r += " : ";
  171. if (key.type == kTypeDeletion) {
  172. r += "del";
  173. } else if (key.type == kTypeValue) {
  174. r += "val";
  175. } else {
  176. AppendNumberTo(&r, key.type);
  177. }
  178. r += " => '";
  179. AppendEscapedStringTo(&r, iter->value());
  180. r += "'\n";
  181. dst->Append(r);
  182. }
  183. }
  184. s = iter->status();
  185. if (!s.ok()) {
  186. dst->Append("iterator error: " + s.ToString() + "\n");
  187. }
  188. delete iter;
  189. delete table;
  190. delete file;
  191. return Status::OK();
  192. }
  193. } // namespace
  194. Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) {
  195. FileType ftype;
  196. if (!GuessType(fname, &ftype)) {
  197. return Status::InvalidArgument(fname + ": unknown file type");
  198. }
  199. switch (ftype) {
  200. case kLogFile:
  201. return DumpLog(env, fname, dst);
  202. case kDescriptorFile:
  203. return DumpDescriptor(env, fname, dst);
  204. case kTableFile:
  205. return DumpTable(env, fname, dst);
  206. default:
  207. break;
  208. }
  209. return Status::InvalidArgument(fname + ": not a dump-able file type");
  210. }
  211. } // namespace leveldb