/ src / leveldb / db / version_edit.cc
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 (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  
 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  
 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  
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  
205  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  DeleteFile: ");
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