Merge branch 'MSVC' of https://github.com/fsb4000/novacoin into fsb4000-MSVC
[novacoin.git] / src / leveldb / db / dumpfile.cc
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 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.
36 class CorruptionReporter : public log::Reader::Reporter {
37  public:
38   WritableFile* dst_;
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.
71 class WriteBatchItemPrinter : public WriteBatch::Handler {
72  public:
73   WritableFile* dst_;
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 ";
107   AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));
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 = "'";
180       AppendEscapedStringTo(&r, key.user_key);
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