git / moonbite-core / src/leveldb/db/dumpfile.cc · raw

// Copyright (c) 2012 The LevelDB Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file. See the AUTHORS file for names of contributors.#include "leveldb/dumpfile.h"#include <stdio.h>#include "db/dbformat.h"#include "db/filename.h"#include "db/log_reader.h"#include "db/version_edit.h"#include "db/write_batch_internal.h"#include "leveldb/env.h"#include "leveldb/iterator.h"#include "leveldb/options.h"#include "leveldb/status.h"#include "leveldb/table.h"#include "leveldb/write_batch.h"#include "util/logging.h"namespace leveldb {namespace {bool GuessType(const std::string& fname, FileType* type) {  size_t pos = fname.rfind('/');  std::string basename;  if (pos == std::string::npos) {    basename = fname;  } else {    basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);  }  uint64_t ignored;  return ParseFileName(basename, &ignored, type);}// Notified when log reader encounters corruption.class CorruptionReporter : public log::Reader::Reporter { public:  void Corruption(size_t bytes, const Status& status) override {    std::string r = "corruption: ";    AppendNumberTo(&r, bytes);    r += " bytes; ";    r += status.ToString();    r.push_back('\n');    dst_->Append(r);  }  WritableFile* dst_;};// Print contents of a log file. (*func)() is called on every record.Status PrintLogContents(Env* env, const std::string& fname,                        void (*func)(uint64_t, Slice, WritableFile*),                        WritableFile* dst) {  SequentialFile* file;  Status s = env->NewSequentialFile(fname, &file);  if (!s.ok()) {    return s;  }  CorruptionReporter reporter;  reporter.dst_ = dst;  log::Reader reader(file, &reporter, true, 0);  Slice record;  std::string scratch;  while (reader.ReadRecord(&record, &scratch)) {    (*func)(reader.LastRecordOffset(), record, dst);  }  delete file;  return Status::OK();}// Called on every item found in a WriteBatch.class WriteBatchItemPrinter : public WriteBatch::Handler { public:  void Put(const Slice& key, const Slice& value) override {    std::string r = "  put '";    AppendEscapedStringTo(&r, key);    r += "' '";    AppendEscapedStringTo(&r, value);    r += "'\n";    dst_->Append(r);  }  void Delete(const Slice& key) override {    std::string r = "  del '";    AppendEscapedStringTo(&r, key);    r += "'\n";    dst_->Append(r);  }  WritableFile* dst_;};// Called on every log record (each one of which is a WriteBatch)// found in a kLogFile.static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) {  std::string r = "--- offset ";  AppendNumberTo(&r, pos);  r += "; ";  if (record.size() < 12) {    r += "log record length ";    AppendNumberTo(&r, record.size());    r += " is too small\n";    dst->Append(r);    return;  }  WriteBatch batch;  WriteBatchInternal::SetContents(&batch, record);  r += "sequence ";  AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));  r.push_back('\n');  dst->Append(r);  WriteBatchItemPrinter batch_item_printer;  batch_item_printer.dst_ = dst;  Status s = batch.Iterate(&batch_item_printer);  if (!s.ok()) {    dst->Append("  error: " + s.ToString() + "\n");  }}Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) {  return PrintLogContents(env, fname, WriteBatchPrinter, dst);}// Called on every log record (each one of which is a WriteBatch)// found in a kDescriptorFile.static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) {  std::string r = "--- offset ";  AppendNumberTo(&r, pos);  r += "; ";  VersionEdit edit;  Status s = edit.DecodeFrom(record);  if (!s.ok()) {    r += s.ToString();    r.push_back('\n');  } else {    r += edit.DebugString();  }  dst->Append(r);}Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) {  return PrintLogContents(env, fname, VersionEditPrinter, dst);}Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) {  uint64_t file_size;  RandomAccessFile* file = nullptr;  Table* table = nullptr;  Status s = env->GetFileSize(fname, &file_size);  if (s.ok()) {    s = env->NewRandomAccessFile(fname, &file);  }  if (s.ok()) {    // We use the default comparator, which may or may not match the    // comparator used in this database. However this should not cause    // problems since we only use Table operations that do not require    // any comparisons.  In particular, we do not call Seek or Prev.    s = Table::Open(Options(), file, file_size, &table);  }  if (!s.ok()) {    delete table;    delete file;    return s;  }  ReadOptions ro;  ro.fill_cache = false;  Iterator* iter = table->NewIterator(ro);  std::string r;  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {    r.clear();    ParsedInternalKey key;    if (!ParseInternalKey(iter->key(), &key)) {      r = "badkey '";      AppendEscapedStringTo(&r, iter->key());      r += "' => '";      AppendEscapedStringTo(&r, iter->value());      r += "'\n";      dst->Append(r);    } else {      r = "'";      AppendEscapedStringTo(&r, key.user_key);      r += "' @ ";      AppendNumberTo(&r, key.sequence);      r += " : ";      if (key.type == kTypeDeletion) {        r += "del";      } else if (key.type == kTypeValue) {        r += "val";      } else {        AppendNumberTo(&r, key.type);      }      r += " => '";      AppendEscapedStringTo(&r, iter->value());      r += "'\n";      dst->Append(r);    }  }  s = iter->status();  if (!s.ok()) {    dst->Append("iterator error: " + s.ToString() + "\n");  }  delete iter;  delete table;  delete file;  return Status::OK();}}  // namespaceStatus DumpFile(Env* env, const std::string& fname, WritableFile* dst) {  FileType ftype;  if (!GuessType(fname, &ftype)) {    return Status::InvalidArgument(fname + ": unknown file type");  }  switch (ftype) {    case kLogFile:      return DumpLog(env, fname, dst);    case kDescriptorFile:      return DumpDescriptor(env, fname, dst);    case kTableFile:      return DumpTable(env, fname, dst);    default:      break;  }  return Status::InvalidArgument(fname + ": not a dump-able file type");}}  // namespace leveldb