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.
6 #include "db/dbformat.h"
7 #include "db/filename.h"
8 #include "db/log_reader.h"
9 #include "db/version_edit.h"
10 #include "db/write_batch_internal.h"
11 #include "leveldb/env.h"
12 #include "leveldb/iterator.h"
13 #include "leveldb/options.h"
14 #include "leveldb/status.h"
15 #include "leveldb/table.h"
16 #include "leveldb/write_batch.h"
17 #include "util/logging.h"
23 bool GuessType(const std::string& fname, FileType* type) {
24 size_t pos = fname.rfind('/');
26 if (pos == std::string::npos) {
29 basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);
32 return ParseFileName(basename, &ignored, type);
35 // Notified when log reader encounters corruption.
36 class CorruptionReporter : public log::Reader::Reporter {
39 virtual void Corruption(size_t bytes, const Status& status) {
40 std::string r = "corruption: ";
41 AppendNumberTo(&r, bytes);
43 r += status.ToString();
49 // Print contents of a log file. (*func)() is called on every record.
50 Status PrintLogContents(Env* env, const std::string& fname,
51 void (*func)(uint64_t, Slice, WritableFile*),
54 Status s = env->NewSequentialFile(fname, &file);
58 CorruptionReporter reporter;
60 log::Reader reader(file, &reporter, true, 0);
63 while (reader.ReadRecord(&record, &scratch)) {
64 (*func)(reader.LastRecordOffset(), record, dst);
70 // Called on every item found in a WriteBatch.
71 class WriteBatchItemPrinter : public WriteBatch::Handler {
74 virtual void Put(const Slice& key, const Slice& value) {
75 std::string r = " put '";
76 AppendEscapedStringTo(&r, key);
78 AppendEscapedStringTo(&r, value);
82 virtual void Delete(const Slice& key) {
83 std::string r = " del '";
84 AppendEscapedStringTo(&r, key);
91 // Called on every log record (each one of which is a WriteBatch)
92 // found in a kLogFile.
93 static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) {
94 std::string r = "--- offset ";
95 AppendNumberTo(&r, pos);
97 if (record.size() < 12) {
98 r += "log record length ";
99 AppendNumberTo(&r, record.size());
100 r += " is too small\n";
105 WriteBatchInternal::SetContents(&batch, record);
107 AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));
110 WriteBatchItemPrinter batch_item_printer;
111 batch_item_printer.dst_ = dst;
112 Status s = batch.Iterate(&batch_item_printer);
114 dst->Append(" error: " + s.ToString() + "\n");
118 Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) {
119 return PrintLogContents(env, fname, WriteBatchPrinter, dst);
122 // Called on every log record (each one of which is a WriteBatch)
123 // found in a kDescriptorFile.
124 static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) {
125 std::string r = "--- offset ";
126 AppendNumberTo(&r, pos);
129 Status s = edit.DecodeFrom(record);
134 r += edit.DebugString();
139 Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) {
140 return PrintLogContents(env, fname, VersionEditPrinter, dst);
143 Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) {
145 RandomAccessFile* file = NULL;
147 Status s = env->GetFileSize(fname, &file_size);
149 s = env->NewRandomAccessFile(fname, &file);
152 // We use the default comparator, which may or may not match the
153 // comparator used in this database. However this should not cause
154 // problems since we only use Table operations that do not require
155 // any comparisons. In particular, we do not call Seek or Prev.
156 s = Table::Open(Options(), file, file_size, &table);
165 ro.fill_cache = false;
166 Iterator* iter = table->NewIterator(ro);
168 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
170 ParsedInternalKey key;
171 if (!ParseInternalKey(iter->key(), &key)) {
173 AppendEscapedStringTo(&r, iter->key());
175 AppendEscapedStringTo(&r, iter->value());
180 AppendEscapedStringTo(&r, key.user_key);
182 AppendNumberTo(&r, key.sequence);
184 if (key.type == kTypeDeletion) {
186 } else if (key.type == kTypeValue) {
189 AppendNumberTo(&r, key.type);
192 AppendEscapedStringTo(&r, iter->value());
199 dst->Append("iterator error: " + s.ToString() + "\n");
210 Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) {
212 if (!GuessType(fname, &ftype)) {
213 return Status::InvalidArgument(fname + ": unknown file type");
216 case kLogFile: return DumpLog(env, fname, dst);
217 case kDescriptorFile: return DumpDescriptor(env, fname, dst);
218 case kTableFile: return DumpTable(env, fname, dst);
222 return Status::InvalidArgument(fname + ": not a dump-able file type");
225 } // namespace leveldb