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 
Clear()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 
EncodeTo(std::string * dst) const41 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 (const auto& deleted_file_kvp : deleted_files_) {
70     PutVarint32(dst, kDeletedFile);
71     PutVarint32(dst, deleted_file_kvp.first);   // level
72     PutVarint64(dst, deleted_file_kvp.second);  // file number
73   }
74 
75   for (size_t i = 0; i < new_files_.size(); i++) {
76     const FileMetaData& f = new_files_[i].second;
77     PutVarint32(dst, kNewFile);
78     PutVarint32(dst, new_files_[i].first);  // level
79     PutVarint64(dst, f.number);
80     PutVarint64(dst, f.file_size);
81     PutLengthPrefixedSlice(dst, f.smallest.Encode());
82     PutLengthPrefixedSlice(dst, f.largest.Encode());
83   }
84 }
85 
GetInternalKey(Slice * input,InternalKey * dst)86 static bool GetInternalKey(Slice* input, InternalKey* dst) {
87   Slice str;
88   if (GetLengthPrefixedSlice(input, &str)) {
89     return dst->DecodeFrom(str);
90   } else {
91     return false;
92   }
93 }
94 
GetLevel(Slice * input,int * level)95 static bool GetLevel(Slice* input, int* level) {
96   uint32_t v;
97   if (GetVarint32(input, &v) && v < config::kNumLevels) {
98     *level = v;
99     return true;
100   } else {
101     return false;
102   }
103 }
104 
DecodeFrom(const Slice & src)105 Status VersionEdit::DecodeFrom(const Slice& src) {
106   Clear();
107   Slice input = src;
108   const char* msg = nullptr;
109   uint32_t tag;
110 
111   // Temporary storage for parsing
112   int level;
113   uint64_t number;
114   FileMetaData f;
115   Slice str;
116   InternalKey key;
117 
118   while (msg == nullptr && GetVarint32(&input, &tag)) {
119     switch (tag) {
120       case kComparator:
121         if (GetLengthPrefixedSlice(&input, &str)) {
122           comparator_ = str.ToString();
123           has_comparator_ = true;
124         } else {
125           msg = "comparator name";
126         }
127         break;
128 
129       case kLogNumber:
130         if (GetVarint64(&input, &log_number_)) {
131           has_log_number_ = true;
132         } else {
133           msg = "log number";
134         }
135         break;
136 
137       case kPrevLogNumber:
138         if (GetVarint64(&input, &prev_log_number_)) {
139           has_prev_log_number_ = true;
140         } else {
141           msg = "previous log number";
142         }
143         break;
144 
145       case kNextFileNumber:
146         if (GetVarint64(&input, &next_file_number_)) {
147           has_next_file_number_ = true;
148         } else {
149           msg = "next file number";
150         }
151         break;
152 
153       case kLastSequence:
154         if (GetVarint64(&input, &last_sequence_)) {
155           has_last_sequence_ = true;
156         } else {
157           msg = "last sequence number";
158         }
159         break;
160 
161       case kCompactPointer:
162         if (GetLevel(&input, &level) && GetInternalKey(&input, &key)) {
163           compact_pointers_.push_back(std::make_pair(level, key));
164         } else {
165           msg = "compaction pointer";
166         }
167         break;
168 
169       case kDeletedFile:
170         if (GetLevel(&input, &level) && GetVarint64(&input, &number)) {
171           deleted_files_.insert(std::make_pair(level, number));
172         } else {
173           msg = "deleted file";
174         }
175         break;
176 
177       case kNewFile:
178         if (GetLevel(&input, &level) && GetVarint64(&input, &f.number) &&
179             GetVarint64(&input, &f.file_size) &&
180             GetInternalKey(&input, &f.smallest) &&
181             GetInternalKey(&input, &f.largest)) {
182           new_files_.push_back(std::make_pair(level, f));
183         } else {
184           msg = "new-file entry";
185         }
186         break;
187 
188       default:
189         msg = "unknown tag";
190         break;
191     }
192   }
193 
194   if (msg == nullptr && !input.empty()) {
195     msg = "invalid tag";
196   }
197 
198   Status result;
199   if (msg != nullptr) {
200     result = Status::Corruption("VersionEdit", msg);
201   }
202   return result;
203 }
204 
DebugString() const205 std::string VersionEdit::DebugString() const {
206   std::string r;
207   r.append("VersionEdit {");
208   if (has_comparator_) {
209     r.append("\n  Comparator: ");
210     r.append(comparator_);
211   }
212   if (has_log_number_) {
213     r.append("\n  LogNumber: ");
214     AppendNumberTo(&r, log_number_);
215   }
216   if (has_prev_log_number_) {
217     r.append("\n  PrevLogNumber: ");
218     AppendNumberTo(&r, prev_log_number_);
219   }
220   if (has_next_file_number_) {
221     r.append("\n  NextFile: ");
222     AppendNumberTo(&r, next_file_number_);
223   }
224   if (has_last_sequence_) {
225     r.append("\n  LastSeq: ");
226     AppendNumberTo(&r, last_sequence_);
227   }
228   for (size_t i = 0; i < compact_pointers_.size(); i++) {
229     r.append("\n  CompactPointer: ");
230     AppendNumberTo(&r, compact_pointers_[i].first);
231     r.append(" ");
232     r.append(compact_pointers_[i].second.DebugString());
233   }
234   for (const auto& deleted_files_kvp : deleted_files_) {
235     r.append("\n  RemoveFile: ");
236     AppendNumberTo(&r, deleted_files_kvp.first);
237     r.append(" ");
238     AppendNumberTo(&r, deleted_files_kvp.second);
239   }
240   for (size_t i = 0; i < new_files_.size(); i++) {
241     const FileMetaData& f = new_files_[i].second;
242     r.append("\n  AddFile: ");
243     AppendNumberTo(&r, new_files_[i].first);
244     r.append(" ");
245     AppendNumberTo(&r, f.number);
246     r.append(" ");
247     AppendNumberTo(&r, f.file_size);
248     r.append(" ");
249     r.append(f.smallest.DebugString());
250     r.append(" .. ");
251     r.append(f.largest.DebugString());
252   }
253   r.append("\n}\n");
254   return r;
255 }
256 
257 }  // namespace leveldb
258