xref: /aosp_15_r20/external/leveldb/db/dumpfile.cc (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
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