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