1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10 #include "db/version_edit.h"
11
12 #include "db/blob/blob_index.h"
13 #include "db/version_set.h"
14 #include "logging/event_logger.h"
15 #include "rocksdb/slice.h"
16 #include "test_util/sync_point.h"
17 #include "util/coding.h"
18 #include "util/string_util.h"
19
20 namespace ROCKSDB_NAMESPACE {
21 // The unknown file checksum.
22 const std::string kUnknownFileChecksum("");
23 // The unknown sst file checksum function name.
24 const std::string kUnknownFileChecksumFuncName("Unknown");
25
26 namespace {
27
28 // Tag numbers for serialized VersionEdit. These numbers are written to
29 // disk and should not be changed. The number should be forward compatible so
30 // users can down-grade RocksDB safely. A future Tag is ignored by doing '&'
31 // between Tag and kTagSafeIgnoreMask field.
32 enum Tag : uint32_t {
33 kComparator = 1,
34 kLogNumber = 2,
35 kNextFileNumber = 3,
36 kLastSequence = 4,
37 kCompactPointer = 5,
38 kDeletedFile = 6,
39 kNewFile = 7,
40 // 8 was used for large value refs
41 kPrevLogNumber = 9,
42 kMinLogNumberToKeep = 10,
43
44 // these are new formats divergent from open source leveldb
45 kNewFile2 = 100,
46 kNewFile3 = 102,
47 kNewFile4 = 103, // 4th (the latest) format version of adding files
48 kColumnFamily = 200, // specify column family for version edit
49 kColumnFamilyAdd = 201,
50 kColumnFamilyDrop = 202,
51 kMaxColumnFamily = 203,
52
53 kInAtomicGroup = 300,
54
55 // Mask for an unidentified tag from the future which can be safely ignored.
56 kTagSafeIgnoreMask = 1 << 13,
57
58 // Forward compatible (aka ignorable) records
59 kDbId,
60 kBlobFileAddition,
61 kBlobFileGarbage,
62 };
63
64 enum NewFileCustomTag : uint32_t {
65 kTerminate = 1, // The end of customized fields
66 kNeedCompaction = 2,
67 // Since Manifest is not entirely forward-compatible, we currently encode
68 // kMinLogNumberToKeep as part of NewFile as a hack. This should be removed
69 // when manifest becomes forward-comptabile.
70 kMinLogNumberToKeepHack = 3,
71 kOldestBlobFileNumber = 4,
72 kOldestAncesterTime = 5,
73 kFileCreationTime = 6,
74 kFileChecksum = 7,
75 kFileChecksumFuncName = 8,
76
77 // If this bit for the custom tag is set, opening DB should fail if
78 // we don't know this field.
79 kCustomTagNonSafeIgnoreMask = 1 << 6,
80
81 // Forward incompatible (aka unignorable) fields
82 kPathId,
83 };
84
85 } // anonymous namespace
86
PackFileNumberAndPathId(uint64_t number,uint64_t path_id)87 uint64_t PackFileNumberAndPathId(uint64_t number, uint64_t path_id) {
88 assert(number <= kFileNumberMask);
89 return number | (path_id * (kFileNumberMask + 1));
90 }
91
UpdateBoundaries(const Slice & key,const Slice & value,SequenceNumber seqno,ValueType value_type)92 void FileMetaData::UpdateBoundaries(const Slice& key, const Slice& value,
93 SequenceNumber seqno,
94 ValueType value_type) {
95 if (smallest.size() == 0) {
96 smallest.DecodeFrom(key);
97 }
98 largest.DecodeFrom(key);
99 fd.smallest_seqno = std::min(fd.smallest_seqno, seqno);
100 fd.largest_seqno = std::max(fd.largest_seqno, seqno);
101
102 #ifndef ROCKSDB_LITE
103 if (value_type == kTypeBlobIndex) {
104 BlobIndex blob_index;
105 const Status s = blob_index.DecodeFrom(value);
106 if (!s.ok()) {
107 return;
108 }
109
110 if (blob_index.IsInlined()) {
111 return;
112 }
113
114 if (blob_index.HasTTL()) {
115 return;
116 }
117
118 // Paranoid check: this should not happen because BlobDB numbers the blob
119 // files starting from 1.
120 if (blob_index.file_number() == kInvalidBlobFileNumber) {
121 return;
122 }
123
124 if (oldest_blob_file_number == kInvalidBlobFileNumber ||
125 oldest_blob_file_number > blob_index.file_number()) {
126 oldest_blob_file_number = blob_index.file_number();
127 }
128 }
129 #else
130 (void)value;
131 (void)value_type;
132 #endif
133 }
134
Clear()135 void VersionEdit::Clear() {
136 max_level_ = 0;
137 db_id_.clear();
138 comparator_.clear();
139 log_number_ = 0;
140 prev_log_number_ = 0;
141 next_file_number_ = 0;
142 max_column_family_ = 0;
143 min_log_number_to_keep_ = 0;
144 last_sequence_ = 0;
145 has_db_id_ = false;
146 has_comparator_ = false;
147 has_log_number_ = false;
148 has_prev_log_number_ = false;
149 has_next_file_number_ = false;
150 has_max_column_family_ = false;
151 has_min_log_number_to_keep_ = false;
152 has_last_sequence_ = false;
153 deleted_files_.clear();
154 new_files_.clear();
155 blob_file_additions_.clear();
156 blob_file_garbages_.clear();
157 column_family_ = 0;
158 is_column_family_add_ = false;
159 is_column_family_drop_ = false;
160 column_family_name_.clear();
161 is_in_atomic_group_ = false;
162 remaining_entries_ = 0;
163 }
164
EncodeTo(std::string * dst) const165 bool VersionEdit::EncodeTo(std::string* dst) const {
166 if (has_db_id_) {
167 PutVarint32(dst, kDbId);
168 PutLengthPrefixedSlice(dst, db_id_);
169 }
170 if (has_comparator_) {
171 PutVarint32(dst, kComparator);
172 PutLengthPrefixedSlice(dst, comparator_);
173 }
174 if (has_log_number_) {
175 PutVarint32Varint64(dst, kLogNumber, log_number_);
176 }
177 if (has_prev_log_number_) {
178 PutVarint32Varint64(dst, kPrevLogNumber, prev_log_number_);
179 }
180 if (has_next_file_number_) {
181 PutVarint32Varint64(dst, kNextFileNumber, next_file_number_);
182 }
183 if (has_max_column_family_) {
184 PutVarint32Varint32(dst, kMaxColumnFamily, max_column_family_);
185 }
186 if (has_last_sequence_) {
187 PutVarint32Varint64(dst, kLastSequence, last_sequence_);
188 }
189 for (const auto& deleted : deleted_files_) {
190 PutVarint32Varint32Varint64(dst, kDeletedFile, deleted.first /* level */,
191 deleted.second /* file number */);
192 }
193
194 bool min_log_num_written = false;
195 for (size_t i = 0; i < new_files_.size(); i++) {
196 const FileMetaData& f = new_files_[i].second;
197 if (!f.smallest.Valid() || !f.largest.Valid()) {
198 return false;
199 }
200 PutVarint32(dst, kNewFile4);
201 PutVarint32Varint64(dst, new_files_[i].first /* level */, f.fd.GetNumber());
202 PutVarint64(dst, f.fd.GetFileSize());
203 PutLengthPrefixedSlice(dst, f.smallest.Encode());
204 PutLengthPrefixedSlice(dst, f.largest.Encode());
205 PutVarint64Varint64(dst, f.fd.smallest_seqno, f.fd.largest_seqno);
206 // Customized fields' format:
207 // +-----------------------------+
208 // | 1st field's tag (varint32) |
209 // +-----------------------------+
210 // | 1st field's size (varint32) |
211 // +-----------------------------+
212 // | bytes for 1st field |
213 // | (based on size decoded) |
214 // +-----------------------------+
215 // | |
216 // | ...... |
217 // | |
218 // +-----------------------------+
219 // | last field's size (varint32)|
220 // +-----------------------------+
221 // | bytes for last field |
222 // | (based on size decoded) |
223 // +-----------------------------+
224 // | terminating tag (varint32) |
225 // +-----------------------------+
226 //
227 // Customized encoding for fields:
228 // tag kPathId: 1 byte as path_id
229 // tag kNeedCompaction:
230 // now only can take one char value 1 indicating need-compaction
231 //
232 PutVarint32(dst, NewFileCustomTag::kOldestAncesterTime);
233 std::string varint_oldest_ancester_time;
234 PutVarint64(&varint_oldest_ancester_time, f.oldest_ancester_time);
235 TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:VarintOldestAncesterTime",
236 &varint_oldest_ancester_time);
237 PutLengthPrefixedSlice(dst, Slice(varint_oldest_ancester_time));
238
239 PutVarint32(dst, NewFileCustomTag::kFileCreationTime);
240 std::string varint_file_creation_time;
241 PutVarint64(&varint_file_creation_time, f.file_creation_time);
242 TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:VarintFileCreationTime",
243 &varint_file_creation_time);
244 PutLengthPrefixedSlice(dst, Slice(varint_file_creation_time));
245
246 PutVarint32(dst, NewFileCustomTag::kFileChecksum);
247 PutLengthPrefixedSlice(dst, Slice(f.file_checksum));
248
249 PutVarint32(dst, NewFileCustomTag::kFileChecksumFuncName);
250 PutLengthPrefixedSlice(dst, Slice(f.file_checksum_func_name));
251
252 if (f.fd.GetPathId() != 0) {
253 PutVarint32(dst, NewFileCustomTag::kPathId);
254 char p = static_cast<char>(f.fd.GetPathId());
255 PutLengthPrefixedSlice(dst, Slice(&p, 1));
256 }
257 if (f.marked_for_compaction) {
258 PutVarint32(dst, NewFileCustomTag::kNeedCompaction);
259 char p = static_cast<char>(1);
260 PutLengthPrefixedSlice(dst, Slice(&p, 1));
261 }
262 if (has_min_log_number_to_keep_ && !min_log_num_written) {
263 PutVarint32(dst, NewFileCustomTag::kMinLogNumberToKeepHack);
264 std::string varint_log_number;
265 PutFixed64(&varint_log_number, min_log_number_to_keep_);
266 PutLengthPrefixedSlice(dst, Slice(varint_log_number));
267 min_log_num_written = true;
268 }
269 if (f.oldest_blob_file_number != kInvalidBlobFileNumber) {
270 PutVarint32(dst, NewFileCustomTag::kOldestBlobFileNumber);
271 std::string oldest_blob_file_number;
272 PutVarint64(&oldest_blob_file_number, f.oldest_blob_file_number);
273 PutLengthPrefixedSlice(dst, Slice(oldest_blob_file_number));
274 }
275 TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:NewFile4:CustomizeFields",
276 dst);
277
278 PutVarint32(dst, NewFileCustomTag::kTerminate);
279 }
280
281 for (const auto& blob_file_addition : blob_file_additions_) {
282 PutVarint32(dst, kBlobFileAddition);
283 blob_file_addition.EncodeTo(dst);
284 }
285
286 for (const auto& blob_file_garbage : blob_file_garbages_) {
287 PutVarint32(dst, kBlobFileGarbage);
288 blob_file_garbage.EncodeTo(dst);
289 }
290
291 // 0 is default and does not need to be explicitly written
292 if (column_family_ != 0) {
293 PutVarint32Varint32(dst, kColumnFamily, column_family_);
294 }
295
296 if (is_column_family_add_) {
297 PutVarint32(dst, kColumnFamilyAdd);
298 PutLengthPrefixedSlice(dst, Slice(column_family_name_));
299 }
300
301 if (is_column_family_drop_) {
302 PutVarint32(dst, kColumnFamilyDrop);
303 }
304
305 if (is_in_atomic_group_) {
306 PutVarint32(dst, kInAtomicGroup);
307 PutVarint32(dst, remaining_entries_);
308 }
309 return true;
310 }
311
GetInternalKey(Slice * input,InternalKey * dst)312 static bool GetInternalKey(Slice* input, InternalKey* dst) {
313 Slice str;
314 if (GetLengthPrefixedSlice(input, &str)) {
315 dst->DecodeFrom(str);
316 return dst->Valid();
317 } else {
318 return false;
319 }
320 }
321
GetLevel(Slice * input,int * level,const char **)322 bool VersionEdit::GetLevel(Slice* input, int* level, const char** /*msg*/) {
323 uint32_t v = 0;
324 if (GetVarint32(input, &v)) {
325 *level = v;
326 if (max_level_ < *level) {
327 max_level_ = *level;
328 }
329 return true;
330 } else {
331 return false;
332 }
333 }
334
DecodeNewFile4From(Slice * input)335 const char* VersionEdit::DecodeNewFile4From(Slice* input) {
336 const char* msg = nullptr;
337 int level = 0;
338 FileMetaData f;
339 uint64_t number = 0;
340 uint32_t path_id = 0;
341 uint64_t file_size = 0;
342 SequenceNumber smallest_seqno = 0;
343 SequenceNumber largest_seqno = kMaxSequenceNumber;
344 if (GetLevel(input, &level, &msg) && GetVarint64(input, &number) &&
345 GetVarint64(input, &file_size) && GetInternalKey(input, &f.smallest) &&
346 GetInternalKey(input, &f.largest) &&
347 GetVarint64(input, &smallest_seqno) &&
348 GetVarint64(input, &largest_seqno)) {
349 // See comments in VersionEdit::EncodeTo() for format of customized fields
350 while (true) {
351 uint32_t custom_tag = 0;
352 Slice field;
353 if (!GetVarint32(input, &custom_tag)) {
354 return "new-file4 custom field";
355 }
356 if (custom_tag == kTerminate) {
357 break;
358 }
359 if (!GetLengthPrefixedSlice(input, &field)) {
360 return "new-file4 custom field length prefixed slice error";
361 }
362 switch (custom_tag) {
363 case kPathId:
364 if (field.size() != 1) {
365 return "path_id field wrong size";
366 }
367 path_id = field[0];
368 if (path_id > 3) {
369 return "path_id wrong vaue";
370 }
371 break;
372 case kOldestAncesterTime:
373 if (!GetVarint64(&field, &f.oldest_ancester_time)) {
374 return "invalid oldest ancester time";
375 }
376 break;
377 case kFileCreationTime:
378 if (!GetVarint64(&field, &f.file_creation_time)) {
379 return "invalid file creation time";
380 }
381 break;
382 case kFileChecksum:
383 f.file_checksum = field.ToString();
384 break;
385 case kFileChecksumFuncName:
386 f.file_checksum_func_name = field.ToString();
387 break;
388 case kNeedCompaction:
389 if (field.size() != 1) {
390 return "need_compaction field wrong size";
391 }
392 f.marked_for_compaction = (field[0] == 1);
393 break;
394 case kMinLogNumberToKeepHack:
395 // This is a hack to encode kMinLogNumberToKeep in a
396 // forward-compatible fashion.
397 if (!GetFixed64(&field, &min_log_number_to_keep_)) {
398 return "deleted log number malformatted";
399 }
400 has_min_log_number_to_keep_ = true;
401 break;
402 case kOldestBlobFileNumber:
403 if (!GetVarint64(&field, &f.oldest_blob_file_number)) {
404 return "invalid oldest blob file number";
405 }
406 break;
407 default:
408 if ((custom_tag & kCustomTagNonSafeIgnoreMask) != 0) {
409 // Should not proceed if cannot understand it
410 return "new-file4 custom field not supported";
411 }
412 break;
413 }
414 }
415 } else {
416 return "new-file4 entry";
417 }
418 f.fd =
419 FileDescriptor(number, path_id, file_size, smallest_seqno, largest_seqno);
420 new_files_.push_back(std::make_pair(level, f));
421 return nullptr;
422 }
423
DecodeFrom(const Slice & src)424 Status VersionEdit::DecodeFrom(const Slice& src) {
425 Clear();
426 Slice input = src;
427 const char* msg = nullptr;
428 uint32_t tag = 0;
429
430 // Temporary storage for parsing
431 int level = 0;
432 FileMetaData f;
433 Slice str;
434 InternalKey key;
435 while (msg == nullptr && GetVarint32(&input, &tag)) {
436 switch (tag) {
437 case kDbId:
438 if (GetLengthPrefixedSlice(&input, &str)) {
439 db_id_ = str.ToString();
440 has_db_id_ = true;
441 } else {
442 msg = "db id";
443 }
444 break;
445 case kComparator:
446 if (GetLengthPrefixedSlice(&input, &str)) {
447 comparator_ = str.ToString();
448 has_comparator_ = true;
449 } else {
450 msg = "comparator name";
451 }
452 break;
453
454 case kLogNumber:
455 if (GetVarint64(&input, &log_number_)) {
456 has_log_number_ = true;
457 } else {
458 msg = "log number";
459 }
460 break;
461
462 case kPrevLogNumber:
463 if (GetVarint64(&input, &prev_log_number_)) {
464 has_prev_log_number_ = true;
465 } else {
466 msg = "previous log number";
467 }
468 break;
469
470 case kNextFileNumber:
471 if (GetVarint64(&input, &next_file_number_)) {
472 has_next_file_number_ = true;
473 } else {
474 msg = "next file number";
475 }
476 break;
477
478 case kMaxColumnFamily:
479 if (GetVarint32(&input, &max_column_family_)) {
480 has_max_column_family_ = true;
481 } else {
482 msg = "max column family";
483 }
484 break;
485
486 case kMinLogNumberToKeep:
487 if (GetVarint64(&input, &min_log_number_to_keep_)) {
488 has_min_log_number_to_keep_ = true;
489 } else {
490 msg = "min log number to kee";
491 }
492 break;
493
494 case kLastSequence:
495 if (GetVarint64(&input, &last_sequence_)) {
496 has_last_sequence_ = true;
497 } else {
498 msg = "last sequence number";
499 }
500 break;
501
502 case kCompactPointer:
503 if (GetLevel(&input, &level, &msg) &&
504 GetInternalKey(&input, &key)) {
505 // we don't use compact pointers anymore,
506 // but we should not fail if they are still
507 // in manifest
508 } else {
509 if (!msg) {
510 msg = "compaction pointer";
511 }
512 }
513 break;
514
515 case kDeletedFile: {
516 uint64_t number = 0;
517 if (GetLevel(&input, &level, &msg) && GetVarint64(&input, &number)) {
518 deleted_files_.insert(std::make_pair(level, number));
519 } else {
520 if (!msg) {
521 msg = "deleted file";
522 }
523 }
524 break;
525 }
526
527 case kNewFile: {
528 uint64_t number = 0;
529 uint64_t file_size = 0;
530 if (GetLevel(&input, &level, &msg) && GetVarint64(&input, &number) &&
531 GetVarint64(&input, &file_size) &&
532 GetInternalKey(&input, &f.smallest) &&
533 GetInternalKey(&input, &f.largest)) {
534 f.fd = FileDescriptor(number, 0, file_size);
535 new_files_.push_back(std::make_pair(level, f));
536 } else {
537 if (!msg) {
538 msg = "new-file entry";
539 }
540 }
541 break;
542 }
543 case kNewFile2: {
544 uint64_t number = 0;
545 uint64_t file_size = 0;
546 SequenceNumber smallest_seqno = 0;
547 SequenceNumber largest_seqno = kMaxSequenceNumber;
548 if (GetLevel(&input, &level, &msg) && GetVarint64(&input, &number) &&
549 GetVarint64(&input, &file_size) &&
550 GetInternalKey(&input, &f.smallest) &&
551 GetInternalKey(&input, &f.largest) &&
552 GetVarint64(&input, &smallest_seqno) &&
553 GetVarint64(&input, &largest_seqno)) {
554 f.fd = FileDescriptor(number, 0, file_size, smallest_seqno,
555 largest_seqno);
556 new_files_.push_back(std::make_pair(level, f));
557 } else {
558 if (!msg) {
559 msg = "new-file2 entry";
560 }
561 }
562 break;
563 }
564
565 case kNewFile3: {
566 uint64_t number = 0;
567 uint32_t path_id = 0;
568 uint64_t file_size = 0;
569 SequenceNumber smallest_seqno = 0;
570 SequenceNumber largest_seqno = kMaxSequenceNumber;
571 if (GetLevel(&input, &level, &msg) && GetVarint64(&input, &number) &&
572 GetVarint32(&input, &path_id) && GetVarint64(&input, &file_size) &&
573 GetInternalKey(&input, &f.smallest) &&
574 GetInternalKey(&input, &f.largest) &&
575 GetVarint64(&input, &smallest_seqno) &&
576 GetVarint64(&input, &largest_seqno)) {
577 f.fd = FileDescriptor(number, path_id, file_size, smallest_seqno,
578 largest_seqno);
579 new_files_.push_back(std::make_pair(level, f));
580 } else {
581 if (!msg) {
582 msg = "new-file3 entry";
583 }
584 }
585 break;
586 }
587
588 case kNewFile4: {
589 msg = DecodeNewFile4From(&input);
590 break;
591 }
592
593 case kBlobFileAddition: {
594 BlobFileAddition blob_file_addition;
595 const Status s = blob_file_addition.DecodeFrom(&input);
596 if (!s.ok()) {
597 return s;
598 }
599
600 blob_file_additions_.emplace_back(blob_file_addition);
601 break;
602 }
603
604 case kBlobFileGarbage: {
605 BlobFileGarbage blob_file_garbage;
606 const Status s = blob_file_garbage.DecodeFrom(&input);
607 if (!s.ok()) {
608 return s;
609 }
610
611 blob_file_garbages_.emplace_back(blob_file_garbage);
612 break;
613 }
614
615 case kColumnFamily:
616 if (!GetVarint32(&input, &column_family_)) {
617 if (!msg) {
618 msg = "set column family id";
619 }
620 }
621 break;
622
623 case kColumnFamilyAdd:
624 if (GetLengthPrefixedSlice(&input, &str)) {
625 is_column_family_add_ = true;
626 column_family_name_ = str.ToString();
627 } else {
628 if (!msg) {
629 msg = "column family add";
630 }
631 }
632 break;
633
634 case kColumnFamilyDrop:
635 is_column_family_drop_ = true;
636 break;
637
638 case kInAtomicGroup:
639 is_in_atomic_group_ = true;
640 if (!GetVarint32(&input, &remaining_entries_)) {
641 if (!msg) {
642 msg = "remaining entries";
643 }
644 }
645 break;
646
647 default:
648 if (tag & kTagSafeIgnoreMask) {
649 // Tag from future which can be safely ignored.
650 // The next field must be the length of the entry.
651 uint32_t field_len;
652 if (!GetVarint32(&input, &field_len) ||
653 static_cast<size_t>(field_len) > input.size()) {
654 if (!msg) {
655 msg = "safely ignoreable tag length error";
656 }
657 } else {
658 input.remove_prefix(static_cast<size_t>(field_len));
659 }
660 } else {
661 msg = "unknown tag";
662 }
663 break;
664 }
665 }
666
667 if (msg == nullptr && !input.empty()) {
668 msg = "invalid tag";
669 }
670
671 Status result;
672 if (msg != nullptr) {
673 result = Status::Corruption("VersionEdit", msg);
674 }
675 return result;
676 }
677
DebugString(bool hex_key) const678 std::string VersionEdit::DebugString(bool hex_key) const {
679 std::string r;
680 r.append("VersionEdit {");
681 if (has_db_id_) {
682 r.append("\n DB ID: ");
683 r.append(db_id_);
684 }
685 if (has_comparator_) {
686 r.append("\n Comparator: ");
687 r.append(comparator_);
688 }
689 if (has_log_number_) {
690 r.append("\n LogNumber: ");
691 AppendNumberTo(&r, log_number_);
692 }
693 if (has_prev_log_number_) {
694 r.append("\n PrevLogNumber: ");
695 AppendNumberTo(&r, prev_log_number_);
696 }
697 if (has_next_file_number_) {
698 r.append("\n NextFileNumber: ");
699 AppendNumberTo(&r, next_file_number_);
700 }
701 if (has_max_column_family_) {
702 r.append("\n MaxColumnFamily: ");
703 AppendNumberTo(&r, max_column_family_);
704 }
705 if (has_min_log_number_to_keep_) {
706 r.append("\n MinLogNumberToKeep: ");
707 AppendNumberTo(&r, min_log_number_to_keep_);
708 }
709 if (has_last_sequence_) {
710 r.append("\n LastSeq: ");
711 AppendNumberTo(&r, last_sequence_);
712 }
713 for (const auto& deleted_file : deleted_files_) {
714 r.append("\n DeleteFile: ");
715 AppendNumberTo(&r, deleted_file.first);
716 r.append(" ");
717 AppendNumberTo(&r, deleted_file.second);
718 }
719 for (size_t i = 0; i < new_files_.size(); i++) {
720 const FileMetaData& f = new_files_[i].second;
721 r.append("\n AddFile: ");
722 AppendNumberTo(&r, new_files_[i].first);
723 r.append(" ");
724 AppendNumberTo(&r, f.fd.GetNumber());
725 r.append(" ");
726 AppendNumberTo(&r, f.fd.GetFileSize());
727 r.append(" ");
728 r.append(f.smallest.DebugString(hex_key));
729 r.append(" .. ");
730 r.append(f.largest.DebugString(hex_key));
731 if (f.oldest_blob_file_number != kInvalidBlobFileNumber) {
732 r.append(" blob_file:");
733 AppendNumberTo(&r, f.oldest_blob_file_number);
734 }
735 r.append(" oldest_ancester_time:");
736 AppendNumberTo(&r, f.oldest_ancester_time);
737 r.append(" file_creation_time:");
738 AppendNumberTo(&r, f.file_creation_time);
739 r.append(" file_checksum:");
740 r.append(f.file_checksum);
741 r.append(" file_checksum_func_name: ");
742 r.append(f.file_checksum_func_name);
743 }
744
745 for (const auto& blob_file_addition : blob_file_additions_) {
746 r.append("\n BlobFileAddition: ");
747 r.append(blob_file_addition.DebugString());
748 }
749
750 for (const auto& blob_file_garbage : blob_file_garbages_) {
751 r.append("\n BlobFileGarbage: ");
752 r.append(blob_file_garbage.DebugString());
753 }
754
755 r.append("\n ColumnFamily: ");
756 AppendNumberTo(&r, column_family_);
757 if (is_column_family_add_) {
758 r.append("\n ColumnFamilyAdd: ");
759 r.append(column_family_name_);
760 }
761 if (is_column_family_drop_) {
762 r.append("\n ColumnFamilyDrop");
763 }
764 if (is_in_atomic_group_) {
765 r.append("\n AtomicGroup: ");
766 AppendNumberTo(&r, remaining_entries_);
767 r.append(" entries remains");
768 }
769 r.append("\n}\n");
770 return r;
771 }
772
DebugJSON(int edit_num,bool hex_key) const773 std::string VersionEdit::DebugJSON(int edit_num, bool hex_key) const {
774 JSONWriter jw;
775 jw << "EditNumber" << edit_num;
776
777 if (has_db_id_) {
778 jw << "DB ID" << db_id_;
779 }
780 if (has_comparator_) {
781 jw << "Comparator" << comparator_;
782 }
783 if (has_log_number_) {
784 jw << "LogNumber" << log_number_;
785 }
786 if (has_prev_log_number_) {
787 jw << "PrevLogNumber" << prev_log_number_;
788 }
789 if (has_next_file_number_) {
790 jw << "NextFileNumber" << next_file_number_;
791 }
792 if (has_max_column_family_) {
793 jw << "MaxColumnFamily" << max_column_family_;
794 }
795 if (has_min_log_number_to_keep_) {
796 jw << "MinLogNumberToKeep" << min_log_number_to_keep_;
797 }
798 if (has_last_sequence_) {
799 jw << "LastSeq" << last_sequence_;
800 }
801
802 if (!deleted_files_.empty()) {
803 jw << "DeletedFiles";
804 jw.StartArray();
805
806 for (const auto& deleted_file : deleted_files_) {
807 jw.StartArrayedObject();
808 jw << "Level" << deleted_file.first;
809 jw << "FileNumber" << deleted_file.second;
810 jw.EndArrayedObject();
811 }
812
813 jw.EndArray();
814 }
815
816 if (!new_files_.empty()) {
817 jw << "AddedFiles";
818 jw.StartArray();
819
820 for (size_t i = 0; i < new_files_.size(); i++) {
821 jw.StartArrayedObject();
822 jw << "Level" << new_files_[i].first;
823 const FileMetaData& f = new_files_[i].second;
824 jw << "FileNumber" << f.fd.GetNumber();
825 jw << "FileSize" << f.fd.GetFileSize();
826 jw << "SmallestIKey" << f.smallest.DebugString(hex_key);
827 jw << "LargestIKey" << f.largest.DebugString(hex_key);
828 if (f.oldest_blob_file_number != kInvalidBlobFileNumber) {
829 jw << "OldestBlobFile" << f.oldest_blob_file_number;
830 }
831 jw.EndArrayedObject();
832 }
833
834 jw.EndArray();
835 }
836
837 if (!blob_file_additions_.empty()) {
838 jw << "BlobFileAdditions";
839
840 jw.StartArray();
841
842 for (const auto& blob_file_addition : blob_file_additions_) {
843 jw.StartArrayedObject();
844 jw << blob_file_addition;
845 jw.EndArrayedObject();
846 }
847
848 jw.EndArray();
849 }
850
851 if (!blob_file_garbages_.empty()) {
852 jw << "BlobFileGarbages";
853
854 jw.StartArray();
855
856 for (const auto& blob_file_garbage : blob_file_garbages_) {
857 jw.StartArrayedObject();
858 jw << blob_file_garbage;
859 jw.EndArrayedObject();
860 }
861
862 jw.EndArray();
863 }
864
865 jw << "ColumnFamily" << column_family_;
866
867 if (is_column_family_add_) {
868 jw << "ColumnFamilyAdd" << column_family_name_;
869 }
870 if (is_column_family_drop_) {
871 jw << "ColumnFamilyDrop" << column_family_name_;
872 }
873 if (is_in_atomic_group_) {
874 jw << "AtomicGroup" << remaining_entries_;
875 }
876
877 jw.EndObject();
878
879 return jw.Get();
880 }
881
882 } // namespace ROCKSDB_NAMESPACE
883