Add Google's LevelDB support
[novacoin.git] / src / leveldb / db / version_edit.cc
1 // Copyright (c) 2011 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 "db/version_edit.h"
6
7 #include "db/version_set.h"
8 #include "util/coding.h"
9
10 namespace leveldb {
11
12 // Tag numbers for serialized VersionEdit.  These numbers are written to
13 // disk and should not be changed.
14 enum Tag {
15   kComparator           = 1,
16   kLogNumber            = 2,
17   kNextFileNumber       = 3,
18   kLastSequence         = 4,
19   kCompactPointer       = 5,
20   kDeletedFile          = 6,
21   kNewFile              = 7,
22   // 8 was used for large value refs
23   kPrevLogNumber        = 9
24 };
25
26 void VersionEdit::Clear() {
27   comparator_.clear();
28   log_number_ = 0;
29   prev_log_number_ = 0;
30   last_sequence_ = 0;
31   next_file_number_ = 0;
32   has_comparator_ = false;
33   has_log_number_ = false;
34   has_prev_log_number_ = false;
35   has_next_file_number_ = false;
36   has_last_sequence_ = false;
37   deleted_files_.clear();
38   new_files_.clear();
39 }
40
41 void VersionEdit::EncodeTo(std::string* dst) const {
42   if (has_comparator_) {
43     PutVarint32(dst, kComparator);
44     PutLengthPrefixedSlice(dst, comparator_);
45   }
46   if (has_log_number_) {
47     PutVarint32(dst, kLogNumber);
48     PutVarint64(dst, log_number_);
49   }
50   if (has_prev_log_number_) {
51     PutVarint32(dst, kPrevLogNumber);
52     PutVarint64(dst, prev_log_number_);
53   }
54   if (has_next_file_number_) {
55     PutVarint32(dst, kNextFileNumber);
56     PutVarint64(dst, next_file_number_);
57   }
58   if (has_last_sequence_) {
59     PutVarint32(dst, kLastSequence);
60     PutVarint64(dst, last_sequence_);
61   }
62
63   for (size_t i = 0; i < compact_pointers_.size(); i++) {
64     PutVarint32(dst, kCompactPointer);
65     PutVarint32(dst, compact_pointers_[i].first);  // level
66     PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode());
67   }
68
69   for (DeletedFileSet::const_iterator iter = deleted_files_.begin();
70        iter != deleted_files_.end();
71        ++iter) {
72     PutVarint32(dst, kDeletedFile);
73     PutVarint32(dst, iter->first);   // level
74     PutVarint64(dst, iter->second);  // file number
75   }
76
77   for (size_t i = 0; i < new_files_.size(); i++) {
78     const FileMetaData& f = new_files_[i].second;
79     PutVarint32(dst, kNewFile);
80     PutVarint32(dst, new_files_[i].first);  // level
81     PutVarint64(dst, f.number);
82     PutVarint64(dst, f.file_size);
83     PutLengthPrefixedSlice(dst, f.smallest.Encode());
84     PutLengthPrefixedSlice(dst, f.largest.Encode());
85   }
86 }
87
88 static bool GetInternalKey(Slice* input, InternalKey* dst) {
89   Slice str;
90   if (GetLengthPrefixedSlice(input, &str)) {
91     dst->DecodeFrom(str);
92     return true;
93   } else {
94     return false;
95   }
96 }
97
98 static bool GetLevel(Slice* input, int* level) {
99   uint32_t v;
100   if (GetVarint32(input, &v) &&
101       v < config::kNumLevels) {
102     *level = v;
103     return true;
104   } else {
105     return false;
106   }
107 }
108
109 Status VersionEdit::DecodeFrom(const Slice& src) {
110   Clear();
111   Slice input = src;
112   const char* msg = NULL;
113   uint32_t tag;
114
115   // Temporary storage for parsing
116   int level;
117   uint64_t number;
118   FileMetaData f;
119   Slice str;
120   InternalKey key;
121
122   while (msg == NULL && GetVarint32(&input, &tag)) {
123     switch (tag) {
124       case kComparator:
125         if (GetLengthPrefixedSlice(&input, &str)) {
126           comparator_ = str.ToString();
127           has_comparator_ = true;
128         } else {
129           msg = "comparator name";
130         }
131         break;
132
133       case kLogNumber:
134         if (GetVarint64(&input, &log_number_)) {
135           has_log_number_ = true;
136         } else {
137           msg = "log number";
138         }
139         break;
140
141       case kPrevLogNumber:
142         if (GetVarint64(&input, &prev_log_number_)) {
143           has_prev_log_number_ = true;
144         } else {
145           msg = "previous log number";
146         }
147         break;
148
149       case kNextFileNumber:
150         if (GetVarint64(&input, &next_file_number_)) {
151           has_next_file_number_ = true;
152         } else {
153           msg = "next file number";
154         }
155         break;
156
157       case kLastSequence:
158         if (GetVarint64(&input, &last_sequence_)) {
159           has_last_sequence_ = true;
160         } else {
161           msg = "last sequence number";
162         }
163         break;
164
165       case kCompactPointer:
166         if (GetLevel(&input, &level) &&
167             GetInternalKey(&input, &key)) {
168           compact_pointers_.push_back(std::make_pair(level, key));
169         } else {
170           msg = "compaction pointer";
171         }
172         break;
173
174       case kDeletedFile:
175         if (GetLevel(&input, &level) &&
176             GetVarint64(&input, &number)) {
177           deleted_files_.insert(std::make_pair(level, number));
178         } else {
179           msg = "deleted file";
180         }
181         break;
182
183       case kNewFile:
184         if (GetLevel(&input, &level) &&
185             GetVarint64(&input, &f.number) &&
186             GetVarint64(&input, &f.file_size) &&
187             GetInternalKey(&input, &f.smallest) &&
188             GetInternalKey(&input, &f.largest)) {
189           new_files_.push_back(std::make_pair(level, f));
190         } else {
191           msg = "new-file entry";
192         }
193         break;
194
195       default:
196         msg = "unknown tag";
197         break;
198     }
199   }
200
201   if (msg == NULL && !input.empty()) {
202     msg = "invalid tag";
203   }
204
205   Status result;
206   if (msg != NULL) {
207     result = Status::Corruption("VersionEdit", msg);
208   }
209   return result;
210 }
211
212 std::string VersionEdit::DebugString() const {
213   std::string r;
214   r.append("VersionEdit {");
215   if (has_comparator_) {
216     r.append("\n  Comparator: ");
217     r.append(comparator_);
218   }
219   if (has_log_number_) {
220     r.append("\n  LogNumber: ");
221     AppendNumberTo(&r, log_number_);
222   }
223   if (has_prev_log_number_) {
224     r.append("\n  PrevLogNumber: ");
225     AppendNumberTo(&r, prev_log_number_);
226   }
227   if (has_next_file_number_) {
228     r.append("\n  NextFile: ");
229     AppendNumberTo(&r, next_file_number_);
230   }
231   if (has_last_sequence_) {
232     r.append("\n  LastSeq: ");
233     AppendNumberTo(&r, last_sequence_);
234   }
235   for (size_t i = 0; i < compact_pointers_.size(); i++) {
236     r.append("\n  CompactPointer: ");
237     AppendNumberTo(&r, compact_pointers_[i].first);
238     r.append(" ");
239     r.append(compact_pointers_[i].second.DebugString());
240   }
241   for (DeletedFileSet::const_iterator iter = deleted_files_.begin();
242        iter != deleted_files_.end();
243        ++iter) {
244     r.append("\n  DeleteFile: ");
245     AppendNumberTo(&r, iter->first);
246     r.append(" ");
247     AppendNumberTo(&r, iter->second);
248   }
249   for (size_t i = 0; i < new_files_.size(); i++) {
250     const FileMetaData& f = new_files_[i].second;
251     r.append("\n  AddFile: ");
252     AppendNumberTo(&r, new_files_[i].first);
253     r.append(" ");
254     AppendNumberTo(&r, f.number);
255     r.append(" ");
256     AppendNumberTo(&r, f.file_size);
257     r.append(" ");
258     r.append(f.smallest.DebugString());
259     r.append(" .. ");
260     r.append(f.largest.DebugString());
261   }
262   r.append("\n}\n");
263   return r;
264 }
265
266 }  // namespace leveldb