dumpfile.cc raw

   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
 233