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 (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 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 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 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 212 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