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