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