123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- // 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:
- WritableFile* dst_;
- virtual void Corruption(size_t bytes, const Status& status) {
- std::string r = "corruption: ";
- AppendNumberTo(&r, bytes);
- r += " bytes; ";
- r += status.ToString();
- r.push_back('\n');
- dst_->Append(r);
- }
- };
- // 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:
- WritableFile* dst_;
- virtual void Put(const Slice& key, const Slice& value) {
- std::string r = " put '";
- AppendEscapedStringTo(&r, key);
- r += "' '";
- AppendEscapedStringTo(&r, value);
- r += "'\n";
- dst_->Append(r);
- }
- virtual void Delete(const Slice& key) {
- std::string r = " del '";
- AppendEscapedStringTo(&r, key);
- r += "'\n";
- dst_->Append(r);
- }
- };
- // 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();
- }
- } // namespace
- Status 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
|