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