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