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 (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
GetInternalKey(Slice * input,InternalKey * dst)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
GetLevel(Slice * input,int * level)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
DecodeFrom(const Slice & src)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
DebugString() const212 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
267