leveldb_main.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. virtual void Corruption(size_t bytes, const Status& status) {
  34. printf("corruption: %d bytes; %s\n",
  35. static_cast<int>(bytes),
  36. status.ToString().c_str());
  37. }
  38. };
  39. // Print contents of a log file. (*func)() is called on every record.
  40. bool PrintLogContents(Env* env, const std::string& fname,
  41. void (*func)(Slice)) {
  42. SequentialFile* file;
  43. Status s = env->NewSequentialFile(fname, &file);
  44. if (!s.ok()) {
  45. fprintf(stderr, "%s\n", s.ToString().c_str());
  46. return false;
  47. }
  48. CorruptionReporter reporter;
  49. log::Reader reader(file, &reporter, true, 0);
  50. Slice record;
  51. std::string scratch;
  52. while (reader.ReadRecord(&record, &scratch)) {
  53. printf("--- offset %llu; ",
  54. static_cast<unsigned long long>(reader.LastRecordOffset()));
  55. (*func)(record);
  56. }
  57. delete file;
  58. return true;
  59. }
  60. // Called on every item found in a WriteBatch.
  61. class WriteBatchItemPrinter : public WriteBatch::Handler {
  62. public:
  63. uint64_t offset_;
  64. uint64_t sequence_;
  65. virtual void Put(const Slice& key, const Slice& value) {
  66. printf(" put '%s' '%s'\n",
  67. EscapeString(key).c_str(),
  68. EscapeString(value).c_str());
  69. }
  70. virtual void Delete(const Slice& key) {
  71. printf(" del '%s'\n",
  72. EscapeString(key).c_str());
  73. }
  74. };
  75. // Called on every log record (each one of which is a WriteBatch)
  76. // found in a kLogFile.
  77. static void WriteBatchPrinter(Slice record) {
  78. if (record.size() < 12) {
  79. printf("log record length %d is too small\n",
  80. static_cast<int>(record.size()));
  81. return;
  82. }
  83. WriteBatch batch;
  84. WriteBatchInternal::SetContents(&batch, record);
  85. printf("sequence %llu\n",
  86. static_cast<unsigned long long>(WriteBatchInternal::Sequence(&batch)));
  87. WriteBatchItemPrinter batch_item_printer;
  88. Status s = batch.Iterate(&batch_item_printer);
  89. if (!s.ok()) {
  90. printf(" error: %s\n", s.ToString().c_str());
  91. }
  92. }
  93. bool DumpLog(Env* env, const std::string& fname) {
  94. return PrintLogContents(env, fname, WriteBatchPrinter);
  95. }
  96. // Called on every log record (each one of which is a WriteBatch)
  97. // found in a kDescriptorFile.
  98. static void VersionEditPrinter(Slice record) {
  99. VersionEdit edit;
  100. Status s = edit.DecodeFrom(record);
  101. if (!s.ok()) {
  102. printf("%s\n", s.ToString().c_str());
  103. return;
  104. }
  105. printf("%s", edit.DebugString().c_str());
  106. }
  107. bool DumpDescriptor(Env* env, const std::string& fname) {
  108. return PrintLogContents(env, fname, VersionEditPrinter);
  109. }
  110. bool DumpTable(Env* env, const std::string& fname) {
  111. uint64_t file_size;
  112. RandomAccessFile* file = NULL;
  113. Table* table = NULL;
  114. Status s = env->GetFileSize(fname, &file_size);
  115. if (s.ok()) {
  116. s = env->NewRandomAccessFile(fname, &file);
  117. }
  118. if (s.ok()) {
  119. // We use the default comparator, which may or may not match the
  120. // comparator used in this database. However this should not cause
  121. // problems since we only use Table operations that do not require
  122. // any comparisons. In particular, we do not call Seek or Prev.
  123. s = Table::Open(Options(), file, file_size, &table);
  124. }
  125. if (!s.ok()) {
  126. fprintf(stderr, "%s\n", s.ToString().c_str());
  127. delete table;
  128. delete file;
  129. return false;
  130. }
  131. ReadOptions ro;
  132. ro.fill_cache = false;
  133. Iterator* iter = table->NewIterator(ro);
  134. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  135. ParsedInternalKey key;
  136. if (!ParseInternalKey(iter->key(), &key)) {
  137. printf("badkey '%s' => '%s'\n",
  138. EscapeString(iter->key()).c_str(),
  139. EscapeString(iter->value()).c_str());
  140. } else {
  141. char kbuf[20];
  142. const char* type;
  143. if (key.type == kTypeDeletion) {
  144. type = "del";
  145. } else if (key.type == kTypeValue) {
  146. type = "val";
  147. } else {
  148. snprintf(kbuf, sizeof(kbuf), "%d", static_cast<int>(key.type));
  149. type = kbuf;
  150. }
  151. printf("'%s' @ %8llu : %s => '%s'\n",
  152. EscapeString(key.user_key).c_str(),
  153. static_cast<unsigned long long>(key.sequence),
  154. type,
  155. EscapeString(iter->value()).c_str());
  156. }
  157. }
  158. s = iter->status();
  159. if (!s.ok()) {
  160. printf("iterator error: %s\n", s.ToString().c_str());
  161. }
  162. delete iter;
  163. delete table;
  164. delete file;
  165. return true;
  166. }
  167. bool DumpFile(Env* env, const std::string& fname) {
  168. FileType ftype;
  169. if (!GuessType(fname, &ftype)) {
  170. fprintf(stderr, "%s: unknown file type\n", fname.c_str());
  171. return false;
  172. }
  173. switch (ftype) {
  174. case kLogFile: return DumpLog(env, fname);
  175. case kDescriptorFile: return DumpDescriptor(env, fname);
  176. case kTableFile: return DumpTable(env, fname);
  177. default: {
  178. fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str());
  179. break;
  180. }
  181. }
  182. return false;
  183. }
  184. bool HandleDumpCommand(Env* env, char** files, int num) {
  185. bool ok = true;
  186. for (int i = 0; i < num; i++) {
  187. ok &= DumpFile(env, files[i]);
  188. }
  189. return ok;
  190. }
  191. }
  192. } // namespace leveldb
  193. static void Usage() {
  194. fprintf(
  195. stderr,
  196. "Usage: leveldbutil command...\n"
  197. " dump files... -- dump contents of specified files\n"
  198. );
  199. }
  200. int main(int argc, char** argv) {
  201. leveldb::Env* env = leveldb::Env::Default();
  202. bool ok = true;
  203. if (argc < 2) {
  204. Usage();
  205. ok = false;
  206. } else {
  207. std::string command = argv[1];
  208. if (command == "dump") {
  209. ok = leveldb::HandleDumpCommand(env, argv+2, argc-2);
  210. } else {
  211. Usage();
  212. ok = false;
  213. }
  214. }
  215. return (ok ? 0 : 1);
  216. }