dumpfile.cc 6.2 KB

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