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