Add Google's LevelDB support
[novacoin.git] / src / leveldb / db / leveldb_main.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   virtual void Corruption(size_t bytes, const Status& status) {
39     printf("corruption: %d bytes; %s\n",
40             static_cast<int>(bytes),
41             status.ToString().c_str());
42   }
43 };
44
45 // Print contents of a log file. (*func)() is called on every record.
46 bool PrintLogContents(Env* env, const std::string& fname,
47                       void (*func)(Slice)) {
48   SequentialFile* file;
49   Status s = env->NewSequentialFile(fname, &file);
50   if (!s.ok()) {
51     fprintf(stderr, "%s\n", s.ToString().c_str());
52     return false;
53   }
54   CorruptionReporter reporter;
55   log::Reader reader(file, &reporter, true, 0);
56   Slice record;
57   std::string scratch;
58   while (reader.ReadRecord(&record, &scratch)) {
59     printf("--- offset %llu; ",
60            static_cast<unsigned long long>(reader.LastRecordOffset()));
61     (*func)(record);
62   }
63   delete file;
64   return true;
65 }
66
67 // Called on every item found in a WriteBatch.
68 class WriteBatchItemPrinter : public WriteBatch::Handler {
69  public:
70   uint64_t offset_;
71   uint64_t sequence_;
72
73   virtual void Put(const Slice& key, const Slice& value) {
74     printf("  put '%s' '%s'\n",
75            EscapeString(key).c_str(),
76            EscapeString(value).c_str());
77   }
78   virtual void Delete(const Slice& key) {
79     printf("  del '%s'\n",
80            EscapeString(key).c_str());
81   }
82 };
83
84
85 // Called on every log record (each one of which is a WriteBatch)
86 // found in a kLogFile.
87 static void WriteBatchPrinter(Slice record) {
88   if (record.size() < 12) {
89     printf("log record length %d is too small\n",
90            static_cast<int>(record.size()));
91     return;
92   }
93   WriteBatch batch;
94   WriteBatchInternal::SetContents(&batch, record);
95   printf("sequence %llu\n",
96          static_cast<unsigned long long>(WriteBatchInternal::Sequence(&batch)));
97   WriteBatchItemPrinter batch_item_printer;
98   Status s = batch.Iterate(&batch_item_printer);
99   if (!s.ok()) {
100     printf("  error: %s\n", s.ToString().c_str());
101   }
102 }
103
104 bool DumpLog(Env* env, const std::string& fname) {
105   return PrintLogContents(env, fname, WriteBatchPrinter);
106 }
107
108 // Called on every log record (each one of which is a WriteBatch)
109 // found in a kDescriptorFile.
110 static void VersionEditPrinter(Slice record) {
111   VersionEdit edit;
112   Status s = edit.DecodeFrom(record);
113   if (!s.ok()) {
114     printf("%s\n", s.ToString().c_str());
115     return;
116   }
117   printf("%s", edit.DebugString().c_str());
118 }
119
120 bool DumpDescriptor(Env* env, const std::string& fname) {
121   return PrintLogContents(env, fname, VersionEditPrinter);
122 }
123
124 bool DumpTable(Env* env, const std::string& fname) {
125   uint64_t file_size;
126   RandomAccessFile* file = NULL;
127   Table* table = NULL;
128   Status s = env->GetFileSize(fname, &file_size);
129   if (s.ok()) {
130     s = env->NewRandomAccessFile(fname, &file);
131   }
132   if (s.ok()) {
133     // We use the default comparator, which may or may not match the
134     // comparator used in this database. However this should not cause
135     // problems since we only use Table operations that do not require
136     // any comparisons.  In particular, we do not call Seek or Prev.
137     s = Table::Open(Options(), file, file_size, &table);
138   }
139   if (!s.ok()) {
140     fprintf(stderr, "%s\n", s.ToString().c_str());
141     delete table;
142     delete file;
143     return false;
144   }
145
146   ReadOptions ro;
147   ro.fill_cache = false;
148   Iterator* iter = table->NewIterator(ro);
149   for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
150     ParsedInternalKey key;
151     if (!ParseInternalKey(iter->key(), &key)) {
152       printf("badkey '%s' => '%s'\n",
153              EscapeString(iter->key()).c_str(),
154              EscapeString(iter->value()).c_str());
155     } else {
156       char kbuf[20];
157       const char* type;
158       if (key.type == kTypeDeletion) {
159         type = "del";
160       } else if (key.type == kTypeValue) {
161         type = "val";
162       } else {
163         snprintf(kbuf, sizeof(kbuf), "%d", static_cast<int>(key.type));
164         type = kbuf;
165       }
166       printf("'%s' @ %8llu : %s => '%s'\n",
167              EscapeString(key.user_key).c_str(),
168              static_cast<unsigned long long>(key.sequence),
169              type,
170              EscapeString(iter->value()).c_str());
171     }
172   }
173   s = iter->status();
174   if (!s.ok()) {
175     printf("iterator error: %s\n", s.ToString().c_str());
176   }
177
178   delete iter;
179   delete table;
180   delete file;
181   return true;
182 }
183
184 bool DumpFile(Env* env, const std::string& fname) {
185   FileType ftype;
186   if (!GuessType(fname, &ftype)) {
187     fprintf(stderr, "%s: unknown file type\n", fname.c_str());
188     return false;
189   }
190   switch (ftype) {
191     case kLogFile:         return DumpLog(env, fname);
192     case kDescriptorFile:  return DumpDescriptor(env, fname);
193     case kTableFile:       return DumpTable(env, fname);
194
195     default: {
196       fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str());
197       break;
198     }
199   }
200   return false;
201 }
202
203 bool HandleDumpCommand(Env* env, char** files, int num) {
204   bool ok = true;
205   for (int i = 0; i < num; i++) {
206     ok &= DumpFile(env, files[i]);
207   }
208   return ok;
209 }
210
211 }
212 }  // namespace leveldb
213
214 static void Usage() {
215   fprintf(
216       stderr,
217       "Usage: leveldbutil command...\n"
218       "   dump files...         -- dump contents of specified files\n"
219       );
220 }
221
222 int main(int argc, char** argv) {
223   leveldb::Env* env = leveldb::Env::Default();
224   bool ok = true;
225   if (argc < 2) {
226     Usage();
227     ok = false;
228   } else {
229     std::string command = argv[1];
230     if (command == "dump") {
231       ok = leveldb::HandleDumpCommand(env, argv+2, argc-2);
232     } else {
233       Usage();
234       ok = false;
235     }
236   }
237   return (ok ? 0 : 1);
238 }