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