Coverage Report

Created: 2025-10-26 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/db/version_edit.cc
Line
Count
Source
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 "table/unique_id_impl.h"
17
#include "test_util/sync_point.h"
18
#include "util/coding.h"
19
#include "util/string_util.h"
20
21
namespace ROCKSDB_NAMESPACE {
22
23
namespace {}  // anonymous namespace
24
25
919k
uint64_t PackFileNumberAndPathId(uint64_t number, uint64_t path_id) {
26
919k
  assert(number <= kFileNumberMask);
27
919k
  return number | (path_id * (kFileNumberMask + 1));
28
919k
}
29
30
Status FileMetaData::UpdateBoundaries(const Slice& key, const Slice& value,
31
                                      SequenceNumber seqno,
32
55.0k
                                      ValueType value_type) {
33
55.0k
  if (value_type == kTypeBlobIndex) {
34
0
    BlobIndex blob_index;
35
0
    const Status s = blob_index.DecodeFrom(value);
36
0
    if (!s.ok()) {
37
0
      return s;
38
0
    }
39
40
0
    if (!blob_index.IsInlined() && !blob_index.HasTTL()) {
41
0
      if (blob_index.file_number() == kInvalidBlobFileNumber) {
42
0
        return Status::Corruption("Invalid blob file number");
43
0
      }
44
45
0
      if (oldest_blob_file_number == kInvalidBlobFileNumber ||
46
0
          oldest_blob_file_number > blob_index.file_number()) {
47
0
        oldest_blob_file_number = blob_index.file_number();
48
0
      }
49
0
    }
50
0
  }
51
52
55.0k
  if (smallest.size() == 0) {
53
19.3k
    smallest.DecodeFrom(key);
54
19.3k
  }
55
55.0k
  largest.DecodeFrom(key);
56
55.0k
  fd.smallest_seqno = std::min(fd.smallest_seqno, seqno);
57
55.0k
  fd.largest_seqno = std::max(fd.largest_seqno, seqno);
58
59
55.0k
  return Status::OK();
60
55.0k
}
61
62
381k
void VersionEdit::Clear() { *this = VersionEdit(); }
63
64
bool VersionEdit::EncodeTo(std::string* dst,
65
463k
                           std::optional<size_t> ts_sz) const {
66
463k
  assert(!IsNoManifestWriteDummy());
67
463k
  if (has_db_id_) {
68
57.6k
    PutVarint32(dst, kDbId);
69
57.6k
    PutLengthPrefixedSlice(dst, db_id_);
70
57.6k
  }
71
463k
  if (has_comparator_) {
72
82.5k
    assert(has_persist_user_defined_timestamps_);
73
82.5k
    PutVarint32(dst, kComparator);
74
82.5k
    PutLengthPrefixedSlice(dst, comparator_);
75
82.5k
  }
76
463k
  if (has_log_number_) {
77
149k
    PutVarint32Varint64(dst, kLogNumber, log_number_);
78
149k
  }
79
463k
  if (has_prev_log_number_) {
80
191k
    PutVarint32Varint64(dst, kPrevLogNumber, prev_log_number_);
81
191k
  }
82
463k
  if (has_next_file_number_) {
83
235k
    PutVarint32Varint64(dst, kNextFileNumber, next_file_number_);
84
235k
  }
85
463k
  if (has_max_column_family_) {
86
41.3k
    PutVarint32Varint32(dst, kMaxColumnFamily, max_column_family_);
87
41.3k
  }
88
463k
  if (has_min_log_number_to_keep_) {
89
71.5k
    PutVarint32Varint64(dst, kMinLogNumberToKeep, min_log_number_to_keep_);
90
71.5k
  }
91
463k
  if (has_last_sequence_) {
92
300k
    PutVarint32Varint64(dst, kLastSequence, last_sequence_);
93
300k
  }
94
463k
  for (size_t i = 0; i < compact_cursors_.size(); i++) {
95
0
    if (compact_cursors_[i].second.Valid()) {
96
0
      PutVarint32(dst, kCompactCursor);
97
0
      PutVarint32(dst, compact_cursors_[i].first);  // level
98
0
      PutLengthPrefixedSlice(dst, compact_cursors_[i].second.Encode());
99
0
    }
100
0
  }
101
463k
  for (const auto& deleted : deleted_files_) {
102
12.3k
    PutVarint32Varint32Varint64(dst, kDeletedFile, deleted.first /* level */,
103
12.3k
                                deleted.second /* file number */);
104
12.3k
  }
105
106
463k
  bool min_log_num_written = false;
107
108
463k
  assert(new_files_.empty() || ts_sz.has_value());
109
565k
  for (size_t i = 0; i < new_files_.size(); i++) {
110
102k
    const FileMetaData& f = new_files_[i].second;
111
102k
    if (!f.smallest.Valid() || !f.largest.Valid() ||
112
102k
        f.epoch_number == kUnknownEpochNumber) {
113
0
      return false;
114
0
    }
115
102k
    EncodeToNewFile4(f, new_files_[i].first, ts_sz.value(),
116
102k
                     has_min_log_number_to_keep_, min_log_number_to_keep_,
117
102k
                     min_log_num_written, dst);
118
102k
  }
119
120
463k
  for (const auto& blob_file_addition : blob_file_additions_) {
121
0
    PutVarint32(dst, kBlobFileAddition);
122
0
    blob_file_addition.EncodeTo(dst);
123
0
  }
124
125
463k
  for (const auto& blob_file_garbage : blob_file_garbages_) {
126
0
    PutVarint32(dst, kBlobFileGarbage);
127
0
    blob_file_garbage.EncodeTo(dst);
128
0
  }
129
130
463k
  for (const auto& wal_addition : wal_additions_) {
131
0
    PutVarint32(dst, kWalAddition2);
132
0
    std::string encoded;
133
0
    wal_addition.EncodeTo(&encoded);
134
0
    PutLengthPrefixedSlice(dst, encoded);
135
0
  }
136
137
463k
  if (!wal_deletion_.IsEmpty()) {
138
30.5k
    PutVarint32(dst, kWalDeletion2);
139
30.5k
    std::string encoded;
140
30.5k
    wal_deletion_.EncodeTo(&encoded);
141
30.5k
    PutLengthPrefixedSlice(dst, encoded);
142
30.5k
  }
143
144
  // 0 is default and does not need to be explicitly written
145
463k
  if (column_family_ != 0) {
146
85.1k
    PutVarint32Varint32(dst, kColumnFamily, column_family_);
147
85.1k
  }
148
149
463k
  if (is_column_family_add_) {
150
34.0k
    PutVarint32(dst, kColumnFamilyAdd);
151
34.0k
    PutLengthPrefixedSlice(dst, Slice(column_family_name_));
152
34.0k
  }
153
154
463k
  if (is_column_family_drop_) {
155
17.0k
    PutVarint32(dst, kColumnFamilyDrop);
156
17.0k
  }
157
158
463k
  if (is_in_atomic_group_) {
159
0
    PutVarint32(dst, kInAtomicGroup);
160
0
    PutVarint32(dst, remaining_entries_);
161
0
  }
162
163
463k
  if (HasFullHistoryTsLow()) {
164
0
    PutVarint32(dst, kFullHistoryTsLow);
165
0
    PutLengthPrefixedSlice(dst, full_history_ts_low_);
166
0
  }
167
168
463k
  if (HasPersistUserDefinedTimestamps()) {
169
    // persist_user_defined_timestamps flag should be logged in the same
170
    // VersionEdit as the user comparator name.
171
82.5k
    assert(has_comparator_);
172
82.5k
    PutVarint32(dst, kPersistUserDefinedTimestamps);
173
82.5k
    char p = static_cast<char>(persist_user_defined_timestamps_);
174
82.5k
    PutLengthPrefixedSlice(dst, Slice(&p, 1));
175
82.5k
  }
176
177
463k
  if (HasSubcompactionProgress()) {
178
0
    PutVarint32(dst, kSubcompactionProgress);
179
0
    std::string progress_data;
180
0
    subcompaction_progress_.EncodeTo(&progress_data);
181
0
    PutLengthPrefixedSlice(dst, progress_data);
182
0
  }
183
184
463k
  return true;
185
463k
}
186
187
void VersionEdit::EncodeToNewFile4(const FileMetaData& f, int level,
188
                                   size_t ts_sz,
189
                                   bool has_min_log_number_to_keep,
190
                                   uint64_t min_log_number_to_keep,
191
                                   bool& min_log_num_written,
192
102k
                                   std::string* dst) {
193
102k
  PutVarint32(dst, kNewFile4);
194
102k
  PutVarint32Varint64(dst, level, f.fd.GetNumber());
195
102k
  PutVarint64(dst, f.fd.GetFileSize());
196
102k
  EncodeFileBoundaries(dst, f, ts_sz);
197
102k
  PutVarint64Varint64(dst, f.fd.smallest_seqno, f.fd.largest_seqno);
198
  // Customized fields' format:
199
  // +-----------------------------+
200
  // | 1st field's tag (varint32)  |
201
  // +-----------------------------+
202
  // | 1st field's size (varint32) |
203
  // +-----------------------------+
204
  // |    bytes for 1st field      |
205
  // |  (based on size decoded)    |
206
  // +-----------------------------+
207
  // |                             |
208
  // |          ......             |
209
  // |                             |
210
  // +-----------------------------+
211
  // | last field's size (varint32)|
212
  // +-----------------------------+
213
  // |    bytes for last field     |
214
  // |  (based on size decoded)    |
215
  // +-----------------------------+
216
  // | terminating tag (varint32)  |
217
  // +-----------------------------+
218
  //
219
  // Customized encoding for fields:
220
  //   tag kPathId: 1 byte as path_id
221
  //   tag kNeedCompaction:
222
  //        now only can take one char value 1 indicating need-compaction
223
  //
224
102k
  PutVarint32(dst, NewFileCustomTag::kOldestAncesterTime);
225
102k
  std::string varint_oldest_ancester_time;
226
102k
  PutVarint64(&varint_oldest_ancester_time, f.oldest_ancester_time);
227
102k
  TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:VarintOldestAncesterTime",
228
102k
                           &varint_oldest_ancester_time);
229
102k
  PutLengthPrefixedSlice(dst, Slice(varint_oldest_ancester_time));
230
231
102k
  PutVarint32(dst, NewFileCustomTag::kFileCreationTime);
232
102k
  std::string varint_file_creation_time;
233
102k
  PutVarint64(&varint_file_creation_time, f.file_creation_time);
234
102k
  TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:VarintFileCreationTime",
235
102k
                           &varint_file_creation_time);
236
102k
  PutLengthPrefixedSlice(dst, Slice(varint_file_creation_time));
237
238
102k
  PutVarint32(dst, NewFileCustomTag::kEpochNumber);
239
102k
  std::string varint_epoch_number;
240
102k
  PutVarint64(&varint_epoch_number, f.epoch_number);
241
102k
  PutLengthPrefixedSlice(dst, Slice(varint_epoch_number));
242
243
102k
  if (f.file_checksum_func_name != kUnknownFileChecksumFuncName) {
244
0
    PutVarint32(dst, NewFileCustomTag::kFileChecksum);
245
0
    PutLengthPrefixedSlice(dst, Slice(f.file_checksum));
246
247
0
    PutVarint32(dst, NewFileCustomTag::kFileChecksumFuncName);
248
0
    PutLengthPrefixedSlice(dst, Slice(f.file_checksum_func_name));
249
0
  }
250
251
102k
  if (f.fd.GetPathId() != 0) {
252
0
    PutVarint32(dst, NewFileCustomTag::kPathId);
253
0
    char p = static_cast<char>(f.fd.GetPathId());
254
0
    PutLengthPrefixedSlice(dst, Slice(&p, 1));
255
0
  }
256
102k
  if (f.temperature != Temperature::kUnknown) {
257
0
    PutVarint32(dst, NewFileCustomTag::kTemperature);
258
0
    char p = static_cast<char>(f.temperature);
259
0
    PutLengthPrefixedSlice(dst, Slice(&p, 1));
260
0
  }
261
102k
  if (f.marked_for_compaction) {
262
0
    PutVarint32(dst, NewFileCustomTag::kNeedCompaction);
263
0
    char p = static_cast<char>(1);
264
0
    PutLengthPrefixedSlice(dst, Slice(&p, 1));
265
0
  }
266
102k
  if (has_min_log_number_to_keep && !min_log_num_written) {
267
25.8k
    PutVarint32(dst, NewFileCustomTag::kMinLogNumberToKeepHack);
268
25.8k
    std::string varint_log_number;
269
25.8k
    PutFixed64(&varint_log_number, min_log_number_to_keep);
270
25.8k
    PutLengthPrefixedSlice(dst, Slice(varint_log_number));
271
25.8k
    min_log_num_written = true;
272
25.8k
  }
273
102k
  if (f.oldest_blob_file_number != kInvalidBlobFileNumber) {
274
0
    PutVarint32(dst, NewFileCustomTag::kOldestBlobFileNumber);
275
0
    std::string oldest_blob_file_number;
276
0
    PutVarint64(&oldest_blob_file_number, f.oldest_blob_file_number);
277
0
    PutLengthPrefixedSlice(dst, Slice(oldest_blob_file_number));
278
0
  }
279
102k
  UniqueId64x2 unique_id = f.unique_id;
280
102k
  TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:UniqueId", &unique_id);
281
102k
  if (unique_id != kNullUniqueId64x2) {
282
102k
    PutVarint32(dst, NewFileCustomTag::kUniqueId);
283
102k
    std::string unique_id_str = EncodeUniqueIdBytes(&unique_id);
284
102k
    PutLengthPrefixedSlice(dst, Slice(unique_id_str));
285
102k
  }
286
102k
  if (f.compensated_range_deletion_size) {
287
0
    PutVarint32(dst, NewFileCustomTag::kCompensatedRangeDeletionSize);
288
0
    std::string compensated_range_deletion_size;
289
0
    PutVarint64(&compensated_range_deletion_size,
290
0
                f.compensated_range_deletion_size);
291
0
    PutLengthPrefixedSlice(dst, Slice(compensated_range_deletion_size));
292
0
  }
293
102k
  if (f.tail_size) {
294
102k
    PutVarint32(dst, NewFileCustomTag::kTailSize);
295
102k
    std::string varint_tail_size;
296
102k
    PutVarint64(&varint_tail_size, f.tail_size);
297
102k
    PutLengthPrefixedSlice(dst, Slice(varint_tail_size));
298
102k
  }
299
102k
  if (!f.user_defined_timestamps_persisted) {
300
    // The default value for the flag is true, it's only explicitly persisted
301
    // when it's false. We are putting 0 as the value here to signal false
302
    // (i.e. UDTS not persisted).
303
0
    PutVarint32(dst, NewFileCustomTag::kUserDefinedTimestampsPersisted);
304
0
    char p = static_cast<char>(0);
305
0
    PutLengthPrefixedSlice(dst, Slice(&p, 1));
306
0
  }
307
102k
  TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:NewFile4:CustomizeFields",
308
102k
                           dst);
309
310
102k
  PutVarint32(dst, NewFileCustomTag::kTerminate);
311
102k
}
312
173k
static bool GetInternalKey(Slice* input, InternalKey* dst) {
313
173k
  Slice str;
314
173k
  if (GetLengthPrefixedSlice(input, &str)) {
315
173k
    dst->DecodeFrom(str);
316
173k
    return dst->Valid();
317
173k
  } else {
318
0
    return false;
319
0
  }
320
173k
}
321
322
96.2k
bool VersionEdit::GetLevel(Slice* input, int* level, int& max_level) {
323
96.2k
  uint32_t v = 0;
324
96.2k
  if (GetVarint32(input, &v)) {
325
96.2k
    *level = v;
326
96.2k
    if (max_level < *level) {
327
14.1k
      max_level = *level;
328
14.1k
    }
329
96.2k
    return true;
330
96.2k
  } else {
331
0
    return false;
332
0
  }
333
96.2k
}
334
335
const char* VersionEdit::DecodeNewFile4From(Slice* input, int& max_level,
336
                                            uint64_t& min_log_number_to_keep,
337
                                            bool& has_min_log_number_to_keep,
338
                                            NewFiles& new_files,
339
86.5k
                                            FileMetaData& f) {
340
86.5k
  int level = 0;
341
86.5k
  uint64_t number = 0;
342
86.5k
  uint32_t path_id = 0;
343
86.5k
  uint64_t file_size = 0;
344
86.5k
  SequenceNumber smallest_seqno = 0;
345
86.5k
  SequenceNumber largest_seqno = kMaxSequenceNumber;
346
86.5k
  if (GetLevel(input, &level, max_level) && GetVarint64(input, &number) &&
347
86.5k
      GetVarint64(input, &file_size) && GetInternalKey(input, &f.smallest) &&
348
86.5k
      GetInternalKey(input, &f.largest) &&
349
86.5k
      GetVarint64(input, &smallest_seqno) &&
350
86.5k
      GetVarint64(input, &largest_seqno)) {
351
    // See comments in VersionEdit::EncodeTo() for format of customized fields
352
543k
    while (true) {
353
543k
      uint32_t custom_tag = 0;
354
543k
      Slice field;
355
543k
      if (!GetVarint32(input, &custom_tag)) {
356
0
        return "new-file4 custom field";
357
0
      }
358
543k
      if (custom_tag == kTerminate) {
359
86.5k
        break;
360
86.5k
      }
361
456k
      if (!GetLengthPrefixedSlice(input, &field)) {
362
0
        return "new-file4 custom field length prefixed slice error";
363
0
      }
364
456k
      switch (custom_tag) {
365
0
        case kPathId:
366
0
          if (field.size() != 1) {
367
0
            return "path_id field wrong size";
368
0
          }
369
0
          path_id = field[0];
370
0
          if (path_id > 3) {
371
0
            return "path_id wrong vaue";
372
0
          }
373
0
          break;
374
86.5k
        case kOldestAncesterTime:
375
86.5k
          if (!GetVarint64(&field, &f.oldest_ancester_time)) {
376
0
            return "invalid oldest ancester time";
377
0
          }
378
86.5k
          break;
379
86.5k
        case kFileCreationTime:
380
86.5k
          if (!GetVarint64(&field, &f.file_creation_time)) {
381
0
            return "invalid file creation time";
382
0
          }
383
86.5k
          break;
384
86.5k
        case kEpochNumber:
385
86.5k
          if (!GetVarint64(&field, &f.epoch_number)) {
386
0
            return "invalid epoch number";
387
0
          }
388
86.5k
          break;
389
86.5k
        case kFileChecksum:
390
0
          f.file_checksum = field.ToString();
391
0
          break;
392
0
        case kFileChecksumFuncName:
393
0
          f.file_checksum_func_name = field.ToString();
394
0
          break;
395
0
        case kNeedCompaction:
396
0
          if (field.size() != 1) {
397
0
            return "need_compaction field wrong size";
398
0
          }
399
0
          f.marked_for_compaction = (field[0] == 1);
400
0
          break;
401
23.5k
        case kMinLogNumberToKeepHack:
402
          // This is a hack to encode kMinLogNumberToKeep in a
403
          // forward-compatible fashion.
404
23.5k
          if (!GetFixed64(&field, &min_log_number_to_keep)) {
405
0
            return "deleted log number malformatted";
406
0
          }
407
23.5k
          has_min_log_number_to_keep = true;
408
23.5k
          break;
409
0
        case kOldestBlobFileNumber:
410
0
          if (!GetVarint64(&field, &f.oldest_blob_file_number)) {
411
0
            return "invalid oldest blob file number";
412
0
          }
413
0
          break;
414
0
        case kTemperature:
415
0
          if (field.size() != 1) {
416
0
            return "temperature field wrong size";
417
0
          } else {
418
0
            Temperature casted_field = static_cast<Temperature>(field[0]);
419
0
            if (casted_field < Temperature::kLastTemperature) {
420
0
              f.temperature = casted_field;
421
0
            }
422
0
          }
423
0
          break;
424
86.5k
        case kUniqueId:
425
86.5k
          if (!DecodeUniqueIdBytes(field.ToString(), &f.unique_id).ok()) {
426
0
            f.unique_id = kNullUniqueId64x2;
427
0
            return "invalid unique id";
428
0
          }
429
86.5k
          break;
430
86.5k
        case kCompensatedRangeDeletionSize:
431
0
          if (!GetVarint64(&field, &f.compensated_range_deletion_size)) {
432
0
            return "Invalid compensated range deletion size";
433
0
          }
434
0
          break;
435
86.5k
        case kTailSize:
436
86.5k
          if (!GetVarint64(&field, &f.tail_size)) {
437
0
            return "invalid tail start offset";
438
0
          }
439
86.5k
          break;
440
86.5k
        case kUserDefinedTimestampsPersisted:
441
0
          if (field.size() != 1) {
442
0
            return "user-defined timestamps persisted field wrong size";
443
0
          }
444
0
          f.user_defined_timestamps_persisted = (field[0] == 1);
445
0
          break;
446
0
        default:
447
0
          if ((custom_tag & kCustomTagNonSafeIgnoreMask) != 0) {
448
            // Should not proceed if cannot understand it
449
0
            return "new-file4 custom field not supported";
450
0
          }
451
0
          break;
452
456k
      }
453
456k
    }
454
86.5k
  } else {
455
0
    return "new-file4 entry";
456
0
  }
457
86.5k
  f.fd =
458
86.5k
      FileDescriptor(number, path_id, file_size, smallest_seqno, largest_seqno);
459
86.5k
  new_files.emplace_back(level, f);
460
86.5k
  return nullptr;
461
86.5k
}
462
463
void VersionEdit::EncodeFileBoundaries(std::string* dst,
464
102k
                                       const FileMetaData& meta, size_t ts_sz) {
465
102k
  if (ts_sz == 0 || meta.user_defined_timestamps_persisted) {
466
102k
    PutLengthPrefixedSlice(dst, meta.smallest.Encode());
467
102k
    PutLengthPrefixedSlice(dst, meta.largest.Encode());
468
102k
    return;
469
102k
  }
470
0
  std::string smallest_buf;
471
0
  std::string largest_buf;
472
0
  StripTimestampFromInternalKey(&smallest_buf, meta.smallest.Encode(), ts_sz);
473
0
  StripTimestampFromInternalKey(&largest_buf, meta.largest.Encode(), ts_sz);
474
0
  PutLengthPrefixedSlice(dst, smallest_buf);
475
0
  PutLengthPrefixedSlice(dst, largest_buf);
476
0
}
477
478
381k
Status VersionEdit::DecodeFrom(const Slice& src) {
479
381k
  Clear();
480
#ifndef NDEBUG
481
  bool ignore_ignorable_tags = false;
482
  TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:IgnoreIgnorableTags",
483
                           &ignore_ignorable_tags);
484
#endif
485
381k
  Slice input = src;
486
381k
  const char* msg = nullptr;
487
381k
  uint32_t tag = 0;
488
489
  // Temporary storage for parsing
490
381k
  int level = 0;
491
381k
  FileMetaData f;
492
381k
  Slice str;
493
381k
  InternalKey key;
494
1.64M
  while (msg == nullptr && GetVarint32(&input, &tag)) {
495
#ifndef NDEBUG
496
    if (ignore_ignorable_tags && tag > kTagSafeIgnoreMask) {
497
      tag = kTagSafeIgnoreMask;
498
    }
499
#endif
500
1.26M
    switch (tag) {
501
48.4k
      case kDbId:
502
48.4k
        if (GetLengthPrefixedSlice(&input, &str)) {
503
48.4k
          db_id_ = str.ToString();
504
48.4k
          has_db_id_ = true;
505
48.4k
        } else {
506
0
          msg = "db id";
507
0
        }
508
48.4k
        break;
509
71.7k
      case kComparator:
510
71.7k
        if (GetLengthPrefixedSlice(&input, &str)) {
511
71.7k
          comparator_ = str.ToString();
512
71.7k
          has_comparator_ = true;
513
71.7k
        } else {
514
0
          msg = "comparator name";
515
0
        }
516
71.7k
        break;
517
518
127k
      case kLogNumber:
519
127k
        if (GetVarint64(&input, &log_number_)) {
520
127k
          has_log_number_ = true;
521
127k
        } else {
522
0
          msg = "log number";
523
0
        }
524
127k
        break;
525
526
152k
      case kPrevLogNumber:
527
152k
        if (GetVarint64(&input, &prev_log_number_)) {
528
152k
          has_prev_log_number_ = true;
529
152k
        } else {
530
0
          msg = "previous log number";
531
0
        }
532
152k
        break;
533
534
193k
      case kNextFileNumber:
535
193k
        if (GetVarint64(&input, &next_file_number_)) {
536
193k
          has_next_file_number_ = true;
537
193k
        } else {
538
0
          msg = "next file number";
539
0
        }
540
193k
        break;
541
542
37.5k
      case kMaxColumnFamily:
543
37.5k
        if (GetVarint32(&input, &max_column_family_)) {
544
37.5k
          has_max_column_family_ = true;
545
37.5k
        } else {
546
0
          msg = "max column family";
547
0
        }
548
37.5k
        break;
549
550
59.3k
      case kMinLogNumberToKeep:
551
59.3k
        if (GetVarint64(&input, &min_log_number_to_keep_)) {
552
59.3k
          has_min_log_number_to_keep_ = true;
553
59.3k
        } else {
554
0
          msg = "min log number to kee";
555
0
        }
556
59.3k
        break;
557
558
248k
      case kLastSequence:
559
248k
        if (GetVarint64(&input, &last_sequence_)) {
560
248k
          has_last_sequence_ = true;
561
248k
        } else {
562
0
          msg = "last sequence number";
563
0
        }
564
248k
        break;
565
566
0
      case kCompactCursor:
567
0
        if (GetLevel(&input, &level, max_level_) &&
568
0
            GetInternalKey(&input, &key)) {
569
          // Here we re-use the output format of compact pointer in LevelDB
570
          // to persist compact_cursors_
571
0
          compact_cursors_.push_back(std::make_pair(level, key));
572
0
        } else {
573
0
          if (!msg) {
574
0
            msg = "compaction cursor";
575
0
          }
576
0
        }
577
0
        break;
578
579
9.69k
      case kDeletedFile: {
580
9.69k
        uint64_t number = 0;
581
9.69k
        if (GetLevel(&input, &level, max_level_) &&
582
9.69k
            GetVarint64(&input, &number)) {
583
9.69k
          deleted_files_.insert(std::make_pair(level, number));
584
9.69k
        } else {
585
0
          if (!msg) {
586
0
            msg = "deleted file";
587
0
          }
588
0
        }
589
9.69k
        break;
590
0
      }
591
592
0
      case kNewFile: {
593
0
        uint64_t number = 0;
594
0
        uint64_t file_size = 0;
595
0
        if (GetLevel(&input, &level, max_level_) &&
596
0
            GetVarint64(&input, &number) && GetVarint64(&input, &file_size) &&
597
0
            GetInternalKey(&input, &f.smallest) &&
598
0
            GetInternalKey(&input, &f.largest)) {
599
0
          f.fd = FileDescriptor(number, 0, file_size);
600
0
          new_files_.push_back(std::make_pair(level, f));
601
0
        } else {
602
0
          if (!msg) {
603
0
            msg = "new-file entry";
604
0
          }
605
0
        }
606
0
        break;
607
0
      }
608
0
      case kNewFile2: {
609
0
        uint64_t number = 0;
610
0
        uint64_t file_size = 0;
611
0
        SequenceNumber smallest_seqno = 0;
612
0
        SequenceNumber largest_seqno = kMaxSequenceNumber;
613
0
        if (GetLevel(&input, &level, max_level_) &&
614
0
            GetVarint64(&input, &number) && GetVarint64(&input, &file_size) &&
615
0
            GetInternalKey(&input, &f.smallest) &&
616
0
            GetInternalKey(&input, &f.largest) &&
617
0
            GetVarint64(&input, &smallest_seqno) &&
618
0
            GetVarint64(&input, &largest_seqno)) {
619
0
          f.fd = FileDescriptor(number, 0, file_size, smallest_seqno,
620
0
                                largest_seqno);
621
0
          new_files_.push_back(std::make_pair(level, f));
622
0
        } else {
623
0
          if (!msg) {
624
0
            msg = "new-file2 entry";
625
0
          }
626
0
        }
627
0
        break;
628
0
      }
629
630
0
      case kNewFile3: {
631
0
        uint64_t number = 0;
632
0
        uint32_t path_id = 0;
633
0
        uint64_t file_size = 0;
634
0
        SequenceNumber smallest_seqno = 0;
635
0
        SequenceNumber largest_seqno = kMaxSequenceNumber;
636
0
        if (GetLevel(&input, &level, max_level_) &&
637
0
            GetVarint64(&input, &number) && GetVarint32(&input, &path_id) &&
638
0
            GetVarint64(&input, &file_size) &&
639
0
            GetInternalKey(&input, &f.smallest) &&
640
0
            GetInternalKey(&input, &f.largest) &&
641
0
            GetVarint64(&input, &smallest_seqno) &&
642
0
            GetVarint64(&input, &largest_seqno)) {
643
0
          f.fd = FileDescriptor(number, path_id, file_size, smallest_seqno,
644
0
                                largest_seqno);
645
0
          new_files_.push_back(std::make_pair(level, f));
646
0
        } else {
647
0
          if (!msg) {
648
0
            msg = "new-file3 entry";
649
0
          }
650
0
        }
651
0
        break;
652
0
      }
653
654
86.5k
      case kNewFile4: {
655
86.5k
        FileMetaData ignored_file;
656
86.5k
        msg = DecodeNewFile4From(&input, max_level_, min_log_number_to_keep_,
657
86.5k
                                 has_min_log_number_to_keep_, new_files_,
658
86.5k
                                 ignored_file);
659
86.5k
        break;
660
0
      }
661
662
0
      case kBlobFileAddition:
663
0
      case kBlobFileAddition_DEPRECATED: {
664
0
        BlobFileAddition blob_file_addition;
665
0
        const Status s = blob_file_addition.DecodeFrom(&input);
666
0
        if (!s.ok()) {
667
0
          return s;
668
0
        }
669
670
0
        AddBlobFile(std::move(blob_file_addition));
671
0
        break;
672
0
      }
673
674
0
      case kBlobFileGarbage:
675
0
      case kBlobFileGarbage_DEPRECATED: {
676
0
        BlobFileGarbage blob_file_garbage;
677
0
        const Status s = blob_file_garbage.DecodeFrom(&input);
678
0
        if (!s.ok()) {
679
0
          return s;
680
0
        }
681
682
0
        AddBlobFileGarbage(std::move(blob_file_garbage));
683
0
        break;
684
0
      }
685
686
0
      case kWalAddition: {
687
0
        WalAddition wal_addition;
688
0
        const Status s = wal_addition.DecodeFrom(&input);
689
0
        if (!s.ok()) {
690
0
          return s;
691
0
        }
692
693
0
        wal_additions_.emplace_back(std::move(wal_addition));
694
0
        break;
695
0
      }
696
697
0
      case kWalAddition2: {
698
0
        Slice encoded;
699
0
        if (!GetLengthPrefixedSlice(&input, &encoded)) {
700
0
          msg = "WalAddition not prefixed by length";
701
0
          break;
702
0
        }
703
704
0
        WalAddition wal_addition;
705
0
        const Status s = wal_addition.DecodeFrom(&encoded);
706
0
        if (!s.ok()) {
707
0
          return s;
708
0
        }
709
710
0
        wal_additions_.emplace_back(std::move(wal_addition));
711
0
        break;
712
0
      }
713
714
0
      case kWalDeletion: {
715
0
        WalDeletion wal_deletion;
716
0
        const Status s = wal_deletion.DecodeFrom(&input);
717
0
        if (!s.ok()) {
718
0
          return s;
719
0
        }
720
721
0
        wal_deletion_ = std::move(wal_deletion);
722
0
        break;
723
0
      }
724
725
27.9k
      case kWalDeletion2: {
726
27.9k
        Slice encoded;
727
27.9k
        if (!GetLengthPrefixedSlice(&input, &encoded)) {
728
0
          msg = "WalDeletion not prefixed by length";
729
0
          break;
730
0
        }
731
732
27.9k
        WalDeletion wal_deletion;
733
27.9k
        const Status s = wal_deletion.DecodeFrom(&encoded);
734
27.9k
        if (!s.ok()) {
735
0
          return s;
736
0
        }
737
738
27.9k
        wal_deletion_ = std::move(wal_deletion);
739
27.9k
        break;
740
27.9k
      }
741
742
79.0k
      case kColumnFamily:
743
79.0k
        if (!GetVarint32(&input, &column_family_)) {
744
0
          if (!msg) {
745
0
            msg = "set column family id";
746
0
          }
747
0
        }
748
79.0k
        break;
749
750
32.5k
      case kColumnFamilyAdd:
751
32.5k
        if (GetLengthPrefixedSlice(&input, &str)) {
752
32.5k
          is_column_family_add_ = true;
753
32.5k
          column_family_name_ = str.ToString();
754
32.5k
        } else {
755
0
          if (!msg) {
756
0
            msg = "column family add";
757
0
          }
758
0
        }
759
32.5k
        break;
760
761
15.5k
      case kColumnFamilyDrop:
762
15.5k
        is_column_family_drop_ = true;
763
15.5k
        break;
764
765
0
      case kInAtomicGroup:
766
0
        is_in_atomic_group_ = true;
767
0
        if (!GetVarint32(&input, &remaining_entries_)) {
768
0
          if (!msg) {
769
0
            msg = "remaining entries";
770
0
          }
771
0
        }
772
0
        break;
773
774
0
      case kFullHistoryTsLow:
775
0
        if (!GetLengthPrefixedSlice(&input, &str)) {
776
0
          msg = "full_history_ts_low";
777
0
        } else if (str.empty()) {
778
0
          msg = "full_history_ts_low: empty";
779
0
        } else {
780
0
          full_history_ts_low_.assign(str.data(), str.size());
781
0
        }
782
0
        break;
783
784
71.7k
      case kPersistUserDefinedTimestamps:
785
71.7k
        if (!GetLengthPrefixedSlice(&input, &str)) {
786
0
          msg = "persist_user_defined_timestamps";
787
71.7k
        } else if (str.size() != 1) {
788
0
          msg = "persist_user_defined_timestamps field wrong size";
789
71.7k
        } else {
790
71.7k
          persist_user_defined_timestamps_ = (str[0] == 1);
791
71.7k
          has_persist_user_defined_timestamps_ = true;
792
71.7k
        }
793
71.7k
        break;
794
795
0
      case kSubcompactionProgress: {
796
0
        Slice encoded;
797
0
        if (!GetLengthPrefixedSlice(&input, &encoded)) {
798
0
          msg = "SubcompactionProgress not prefixed by length";
799
0
          break;
800
0
        }
801
802
0
        SubcompactionProgress progress;
803
0
        Status s = progress.DecodeFrom(&encoded);
804
0
        if (!s.ok()) {
805
0
          return s;
806
0
        }
807
808
0
        SetSubcompactionProgress(progress);
809
0
        break;
810
0
      }
811
812
0
      default:
813
0
        if (tag & kTagSafeIgnoreMask) {
814
          // Tag from future which can be safely ignored.
815
          // The next field must be the length of the entry.
816
0
          uint32_t field_len;
817
0
          if (!GetVarint32(&input, &field_len) ||
818
0
              static_cast<size_t>(field_len) > input.size()) {
819
0
            if (!msg) {
820
0
              msg = "safely ignoreable tag length error";
821
0
            }
822
0
          } else {
823
0
            input.remove_prefix(static_cast<size_t>(field_len));
824
0
          }
825
0
        } else {
826
0
          msg = "unknown tag";
827
0
        }
828
0
        break;
829
1.26M
    }
830
1.26M
  }
831
832
381k
  if (msg == nullptr && !input.empty()) {
833
0
    msg = "invalid tag";
834
0
  }
835
836
381k
  Status result;
837
381k
  if (msg != nullptr) {
838
0
    result = Status::Corruption("VersionEdit", msg);
839
0
  }
840
381k
  return result;
841
381k
}
842
843
0
std::string VersionEdit::DebugString(bool hex_key) const {
844
0
  std::string r;
845
0
  r.append("VersionEdit {");
846
0
  if (has_db_id_) {
847
0
    r.append("\n  DB ID: ");
848
0
    r.append(db_id_);
849
0
  }
850
0
  if (has_comparator_) {
851
0
    r.append("\n  Comparator: ");
852
0
    r.append(comparator_);
853
0
  }
854
0
  if (has_persist_user_defined_timestamps_) {
855
0
    r.append("\n  PersistUserDefinedTimestamps: ");
856
0
    r.append(persist_user_defined_timestamps_ ? "true" : "false");
857
0
  }
858
0
  if (has_log_number_) {
859
0
    r.append("\n  LogNumber: ");
860
0
    AppendNumberTo(&r, log_number_);
861
0
  }
862
0
  if (has_prev_log_number_) {
863
0
    r.append("\n  PrevLogNumber: ");
864
0
    AppendNumberTo(&r, prev_log_number_);
865
0
  }
866
0
  if (has_next_file_number_) {
867
0
    r.append("\n  NextFileNumber: ");
868
0
    AppendNumberTo(&r, next_file_number_);
869
0
  }
870
0
  if (has_max_column_family_) {
871
0
    r.append("\n  MaxColumnFamily: ");
872
0
    AppendNumberTo(&r, max_column_family_);
873
0
  }
874
0
  if (has_min_log_number_to_keep_) {
875
0
    r.append("\n  MinLogNumberToKeep: ");
876
0
    AppendNumberTo(&r, min_log_number_to_keep_);
877
0
  }
878
0
  if (has_last_sequence_) {
879
0
    r.append("\n  LastSeq: ");
880
0
    AppendNumberTo(&r, last_sequence_);
881
0
  }
882
0
  for (const auto& level_and_compact_cursor : compact_cursors_) {
883
0
    r.append("\n  CompactCursor: ");
884
0
    AppendNumberTo(&r, level_and_compact_cursor.first);
885
0
    r.append(" ");
886
0
    r.append(level_and_compact_cursor.second.DebugString(hex_key));
887
0
  }
888
0
  for (const auto& deleted_file : deleted_files_) {
889
0
    r.append("\n  DeleteFile: ");
890
0
    AppendNumberTo(&r, deleted_file.first);
891
0
    r.append(" ");
892
0
    AppendNumberTo(&r, deleted_file.second);
893
0
  }
894
0
  for (size_t i = 0; i < new_files_.size(); i++) {
895
0
    const FileMetaData& f = new_files_[i].second;
896
0
    r.append("\n  AddFile: ");
897
0
    AppendNumberTo(&r, new_files_[i].first);
898
0
    r.append(" ");
899
0
    AppendNumberTo(&r, f.fd.GetNumber());
900
0
    r.append(" ");
901
0
    AppendNumberTo(&r, f.fd.GetFileSize());
902
0
    r.append(" ");
903
0
    r.append(f.smallest.DebugString(hex_key));
904
0
    r.append(" .. ");
905
0
    r.append(f.largest.DebugString(hex_key));
906
0
    if (f.oldest_blob_file_number != kInvalidBlobFileNumber) {
907
0
      r.append(" blob_file:");
908
0
      AppendNumberTo(&r, f.oldest_blob_file_number);
909
0
    }
910
0
    r.append(" oldest_ancester_time:");
911
0
    AppendNumberTo(&r, f.oldest_ancester_time);
912
0
    r.append(" file_creation_time:");
913
0
    AppendNumberTo(&r, f.file_creation_time);
914
0
    r.append(" epoch_number:");
915
0
    AppendNumberTo(&r, f.epoch_number);
916
0
    r.append(" file_checksum:");
917
0
    r.append(Slice(f.file_checksum).ToString(true));
918
0
    r.append(" file_checksum_func_name: ");
919
0
    r.append(f.file_checksum_func_name);
920
0
    if (f.temperature != Temperature::kUnknown) {
921
0
      r.append(" temperature: ");
922
      // Maybe change to human readable format whenthe feature becomes
923
      // permanent
924
0
      r.append(std::to_string(static_cast<int>(f.temperature)));
925
0
    }
926
0
    if (f.unique_id != kNullUniqueId64x2) {
927
0
      r.append(" unique_id(internal): ");
928
0
      UniqueId64x2 id = f.unique_id;
929
0
      r.append(InternalUniqueIdToHumanString(&id));
930
0
      r.append(" public_unique_id: ");
931
0
      InternalUniqueIdToExternal(&id);
932
0
      r.append(UniqueIdToHumanString(EncodeUniqueIdBytes(&id)));
933
0
    }
934
0
    r.append(" tail size: ");
935
0
    AppendNumberTo(&r, f.tail_size);
936
0
    r.append(" User-defined timestamps persisted: ");
937
0
    r.append(f.user_defined_timestamps_persisted ? "true" : "false");
938
0
  }
939
940
0
  for (const auto& blob_file_addition : blob_file_additions_) {
941
0
    r.append("\n  BlobFileAddition: ");
942
0
    r.append(blob_file_addition.DebugString());
943
0
  }
944
945
0
  for (const auto& blob_file_garbage : blob_file_garbages_) {
946
0
    r.append("\n  BlobFileGarbage: ");
947
0
    r.append(blob_file_garbage.DebugString());
948
0
  }
949
950
0
  for (const auto& wal_addition : wal_additions_) {
951
0
    r.append("\n  WalAddition: ");
952
0
    r.append(wal_addition.DebugString());
953
0
  }
954
955
0
  if (!wal_deletion_.IsEmpty()) {
956
0
    r.append("\n  WalDeletion: ");
957
0
    r.append(wal_deletion_.DebugString());
958
0
  }
959
960
0
  r.append("\n  ColumnFamily: ");
961
0
  AppendNumberTo(&r, column_family_);
962
0
  if (is_column_family_add_) {
963
0
    r.append("\n  ColumnFamilyAdd: ");
964
0
    r.append(column_family_name_);
965
0
  }
966
0
  if (is_column_family_drop_) {
967
0
    r.append("\n  ColumnFamilyDrop");
968
0
  }
969
0
  if (is_in_atomic_group_) {
970
0
    r.append("\n  AtomicGroup: ");
971
0
    AppendNumberTo(&r, remaining_entries_);
972
0
    r.append(" entries remains");
973
0
  }
974
0
  if (HasFullHistoryTsLow()) {
975
0
    r.append("\n FullHistoryTsLow: ");
976
0
    r.append(Slice(full_history_ts_low_).ToString(hex_key));
977
0
  }
978
0
  if (HasSubcompactionProgress()) {
979
0
    r.append("\n SubcompactionProgress: ");
980
0
    r.append(subcompaction_progress_.ToString());
981
0
  }
982
0
  r.append("\n}\n");
983
0
  return r;
984
0
}
985
986
0
std::string VersionEdit::DebugJSON(int edit_num, bool hex_key) const {
987
0
  JSONWriter jw;
988
0
  jw << "EditNumber" << edit_num;
989
990
0
  if (has_db_id_) {
991
0
    jw << "DB ID" << db_id_;
992
0
  }
993
0
  if (has_comparator_) {
994
0
    jw << "Comparator" << comparator_;
995
0
  }
996
0
  if (has_log_number_) {
997
0
    jw << "LogNumber" << log_number_;
998
0
  }
999
0
  if (has_prev_log_number_) {
1000
0
    jw << "PrevLogNumber" << prev_log_number_;
1001
0
  }
1002
0
  if (has_next_file_number_) {
1003
0
    jw << "NextFileNumber" << next_file_number_;
1004
0
  }
1005
0
  if (has_max_column_family_) {
1006
0
    jw << "MaxColumnFamily" << max_column_family_;
1007
0
  }
1008
0
  if (has_min_log_number_to_keep_) {
1009
0
    jw << "MinLogNumberToKeep" << min_log_number_to_keep_;
1010
0
  }
1011
0
  if (has_last_sequence_) {
1012
0
    jw << "LastSeq" << last_sequence_;
1013
0
  }
1014
1015
0
  if (!deleted_files_.empty()) {
1016
0
    jw << "DeletedFiles";
1017
0
    jw.StartArray();
1018
1019
0
    for (const auto& deleted_file : deleted_files_) {
1020
0
      jw.StartArrayedObject();
1021
0
      jw << "Level" << deleted_file.first;
1022
0
      jw << "FileNumber" << deleted_file.second;
1023
0
      jw.EndArrayedObject();
1024
0
    }
1025
1026
0
    jw.EndArray();
1027
0
  }
1028
1029
0
  if (!new_files_.empty()) {
1030
0
    jw << "AddedFiles";
1031
0
    jw.StartArray();
1032
1033
0
    for (size_t i = 0; i < new_files_.size(); i++) {
1034
0
      jw.StartArrayedObject();
1035
0
      jw << "Level" << new_files_[i].first;
1036
0
      const FileMetaData& f = new_files_[i].second;
1037
0
      jw << "FileNumber" << f.fd.GetNumber();
1038
0
      jw << "FileSize" << f.fd.GetFileSize();
1039
0
      jw << "SmallestIKey" << f.smallest.DebugString(hex_key);
1040
0
      jw << "LargestIKey" << f.largest.DebugString(hex_key);
1041
0
      jw << "OldestAncesterTime" << f.oldest_ancester_time;
1042
0
      jw << "FileCreationTime" << f.file_creation_time;
1043
0
      jw << "EpochNumber" << f.epoch_number;
1044
0
      jw << "FileChecksum" << Slice(f.file_checksum).ToString(true);
1045
0
      jw << "FileChecksumFuncName" << f.file_checksum_func_name;
1046
0
      if (f.temperature != Temperature::kUnknown) {
1047
0
        jw << "temperature" << std::to_string(static_cast<int>(f.temperature));
1048
0
      }
1049
0
      if (f.oldest_blob_file_number != kInvalidBlobFileNumber) {
1050
0
        jw << "OldestBlobFile" << f.oldest_blob_file_number;
1051
0
      }
1052
0
      if (f.temperature != Temperature::kUnknown) {
1053
        // Maybe change to human readable format whenthe feature becomes
1054
        // permanent
1055
0
        jw << "Temperature" << static_cast<int>(f.temperature);
1056
0
      }
1057
0
      jw << "TailSize" << f.tail_size;
1058
0
      jw << "UserDefinedTimestampsPersisted"
1059
0
         << f.user_defined_timestamps_persisted;
1060
0
      jw.EndArrayedObject();
1061
0
    }
1062
1063
0
    jw.EndArray();
1064
0
  }
1065
1066
0
  if (!blob_file_additions_.empty()) {
1067
0
    jw << "BlobFileAdditions";
1068
1069
0
    jw.StartArray();
1070
1071
0
    for (const auto& blob_file_addition : blob_file_additions_) {
1072
0
      jw.StartArrayedObject();
1073
0
      jw << blob_file_addition;
1074
0
      jw.EndArrayedObject();
1075
0
    }
1076
1077
0
    jw.EndArray();
1078
0
  }
1079
1080
0
  if (!blob_file_garbages_.empty()) {
1081
0
    jw << "BlobFileGarbages";
1082
1083
0
    jw.StartArray();
1084
1085
0
    for (const auto& blob_file_garbage : blob_file_garbages_) {
1086
0
      jw.StartArrayedObject();
1087
0
      jw << blob_file_garbage;
1088
0
      jw.EndArrayedObject();
1089
0
    }
1090
1091
0
    jw.EndArray();
1092
0
  }
1093
1094
0
  if (!wal_additions_.empty()) {
1095
0
    jw << "WalAdditions";
1096
1097
0
    jw.StartArray();
1098
1099
0
    for (const auto& wal_addition : wal_additions_) {
1100
0
      jw.StartArrayedObject();
1101
0
      jw << wal_addition;
1102
0
      jw.EndArrayedObject();
1103
0
    }
1104
1105
0
    jw.EndArray();
1106
0
  }
1107
1108
0
  if (!wal_deletion_.IsEmpty()) {
1109
0
    jw << "WalDeletion";
1110
0
    jw.StartObject();
1111
0
    jw << wal_deletion_;
1112
0
    jw.EndObject();
1113
0
  }
1114
1115
0
  jw << "ColumnFamily" << column_family_;
1116
1117
0
  if (is_column_family_add_) {
1118
0
    jw << "ColumnFamilyAdd" << column_family_name_;
1119
0
  }
1120
0
  if (is_column_family_drop_) {
1121
0
    jw << "ColumnFamilyDrop" << column_family_name_;
1122
0
  }
1123
0
  if (is_in_atomic_group_) {
1124
0
    jw << "AtomicGroup" << remaining_entries_;
1125
0
  }
1126
1127
0
  if (HasFullHistoryTsLow()) {
1128
0
    jw << "FullHistoryTsLow" << Slice(full_history_ts_low_).ToString(hex_key);
1129
0
  }
1130
1131
0
  if (HasSubcompactionProgress()) {
1132
0
    jw << "SubcompactionProgress" << subcompaction_progress_.ToString();
1133
0
  }
1134
1135
0
  jw.EndObject();
1136
1137
0
  return jw.Get();
1138
0
}
1139
1140
0
void SubcompactionProgressPerLevel::EncodeTo(std::string* dst) const {
1141
0
  if (num_processed_output_records_ > 0) {
1142
0
    PutVarint32(
1143
0
        dst,
1144
0
        SubcompactionProgressPerLevelCustomTag::kNumProcessedOutputRecords);
1145
0
    std::string varint_records;
1146
0
    PutVarint64(&varint_records, num_processed_output_records_);
1147
0
    PutLengthPrefixedSlice(dst, varint_records);
1148
0
  }
1149
1150
0
  if (!output_files_.empty()) {
1151
0
    PutVarint32(dst, SubcompactionProgressPerLevelCustomTag::kOutputFilesDelta);
1152
0
    std::string files_data;
1153
0
    EncodeOutputFiles(&files_data);
1154
0
    PutLengthPrefixedSlice(dst, files_data);
1155
0
  }
1156
1157
0
  PutVarint32(dst, SubcompactionProgressPerLevelCustomTag::
1158
0
                       kSubcompactionProgressPerLevelTerminate);
1159
0
}
1160
1161
0
Status SubcompactionProgressPerLevel::DecodeFrom(Slice* input) {
1162
0
  Clear();
1163
1164
0
  while (true) {
1165
0
    uint32_t tag = 0;
1166
0
    if (!GetVarint32(input, &tag)) {
1167
0
      return Status::Corruption("SubcompactionProgressPerLevel", "tag error");
1168
0
    }
1169
1170
0
    if (tag == SubcompactionProgressPerLevelCustomTag::
1171
0
                   kSubcompactionProgressPerLevelTerminate) {
1172
0
      break;
1173
0
    }
1174
1175
0
    Slice field;
1176
0
    if (!GetLengthPrefixedSlice(input, &field)) {
1177
0
      return Status::Corruption("SubcompactionProgressPerLevel",
1178
0
                                "field length prefixed slice error");
1179
0
    }
1180
1181
0
    switch (tag) {
1182
0
      case SubcompactionProgressPerLevelCustomTag::kNumProcessedOutputRecords: {
1183
0
        if (!GetVarint64(&field, &num_processed_output_records_)) {
1184
0
          return Status::Corruption("SubcompactionProgressPerLevel",
1185
0
                                    "invalid num_processed_output_records_");
1186
0
        }
1187
0
        break;
1188
0
      }
1189
1190
0
      case SubcompactionProgressPerLevelCustomTag::kOutputFilesDelta: {
1191
0
        Status s = DecodeOutputFiles(&field, output_files_);
1192
0
        if (!s.ok()) {
1193
0
          return s;
1194
0
        }
1195
0
        break;
1196
0
      }
1197
1198
0
      default:
1199
        // Forward compatibility: Handle unknown tags
1200
0
        if ((tag & SubcompactionProgressPerLevelCustomTag::
1201
0
                       kSubcompactionProgressPerLevelCustomTagSafeIgnoreMask) !=
1202
0
            0) {
1203
0
          break;
1204
0
        } else {
1205
0
          return Status::NotSupported("SubcompactionProgress",
1206
0
                                      "unsupported critical custom field");
1207
0
        }
1208
0
    }
1209
0
  }
1210
1211
0
  return Status::OK();
1212
0
}
1213
1214
0
void SubcompactionProgressPerLevel::EncodeOutputFiles(std::string* dst) const {
1215
0
  size_t new_files_count =
1216
0
      output_files_.size() > last_persisted_output_files_count_
1217
0
          ? output_files_.size() - last_persisted_output_files_count_
1218
0
          : 0;
1219
1220
0
  assert(new_files_count > 0);
1221
1222
0
  PutVarint32(dst, static_cast<uint32_t>(new_files_count));
1223
1224
0
  for (size_t i = last_persisted_output_files_count_; i < output_files_.size();
1225
0
       ++i) {
1226
0
    std::string file_dst;
1227
0
    bool ignored_min_log_written = false;
1228
1229
0
    VersionEdit::EncodeToNewFile4(
1230
0
        output_files_[i], -1 /* level */, 0 /* ts_sz */,
1231
0
        false /* has_min_log_number_to_keep */, 0 /* min_log_number_to_keep */,
1232
0
        ignored_min_log_written, &file_dst);
1233
1234
0
    PutLengthPrefixedSlice(dst, file_dst);
1235
0
  }
1236
0
}
1237
1238
Status SubcompactionProgressPerLevel::DecodeOutputFiles(
1239
0
    Slice* input, autovector<FileMetaData>& output_files) {
1240
0
  uint32_t new_file_count = 0;
1241
0
  if (!GetVarint32(input, &new_file_count)) {
1242
0
    return Status::Corruption("SubcompactionProgressPerLevel",
1243
0
                              "new output file count");
1244
0
  }
1245
1246
0
  assert(output_files.size() == 0);
1247
1248
0
  output_files.reserve(new_file_count);
1249
1250
0
  for (uint32_t i = 0; i < new_file_count; ++i) {
1251
0
    Slice file_input;
1252
0
    if (!GetLengthPrefixedSlice(input, &file_input)) {
1253
0
      return Status::Corruption("SubcompactionProgressPerLevel",
1254
0
                                "output file metadata");
1255
0
    }
1256
1257
0
    uint32_t tag = 0;
1258
0
    if (!GetVarint32(&file_input, &tag) || tag != kNewFile4) {
1259
0
      return Status::Corruption("SubcompactionProgressPerLevel",
1260
0
                                "expected kNewFile4 tag");
1261
0
    }
1262
1263
0
    int ignored_max_level = -1;
1264
0
    uint64_t ignored_min_log_number_to_keep = 0;
1265
0
    bool ignored_has_min_log_number_to_keep = false;
1266
0
    VersionEdit::NewFiles ignored_new_files;
1267
0
    FileMetaData file;
1268
1269
0
    const char* err = VersionEdit::DecodeNewFile4From(
1270
0
        &file_input, ignored_max_level, ignored_min_log_number_to_keep,
1271
0
        ignored_has_min_log_number_to_keep, ignored_new_files, file);
1272
1273
0
    if (err != nullptr) {
1274
0
      return Status::Corruption("SubcompactionProgressPerLevel", err);
1275
0
    }
1276
1277
0
    output_files.push_back(std::move(file));
1278
0
  }
1279
1280
0
  return Status::OK();
1281
0
}
1282
1283
0
void SubcompactionProgress::EncodeTo(std::string* dst) const {
1284
0
  if (!next_internal_key_to_compact.empty()) {
1285
0
    PutVarint32(dst, SubcompactionProgressCustomTag::kNextInternalKeyToCompact);
1286
0
    PutLengthPrefixedSlice(dst, next_internal_key_to_compact);
1287
0
  }
1288
1289
0
  PutVarint32(dst, SubcompactionProgressCustomTag::kNumProcessedInputRecords);
1290
0
  std::string varint_records;
1291
0
  PutVarint64(&varint_records, num_processed_input_records);
1292
0
  PutLengthPrefixedSlice(dst, varint_records);
1293
1294
0
  if (output_level_progress.GetOutputFiles().size() >
1295
0
      output_level_progress.GetLastPersistedOutputFilesCount()) {
1296
0
    PutVarint32(dst, SubcompactionProgressCustomTag::kOutputLevelProgress);
1297
0
    std::string level_progress_data;
1298
0
    output_level_progress.EncodeTo(&level_progress_data);
1299
0
    PutLengthPrefixedSlice(dst, level_progress_data);
1300
0
  }
1301
1302
0
  if (proximal_output_level_progress.GetOutputFiles().size() >
1303
0
      proximal_output_level_progress.GetLastPersistedOutputFilesCount()) {
1304
0
    PutVarint32(dst,
1305
0
                SubcompactionProgressCustomTag::kProximalOutputLevelProgress);
1306
0
    std::string level_progress_data;
1307
0
    proximal_output_level_progress.EncodeTo(&level_progress_data);
1308
0
    PutLengthPrefixedSlice(dst, level_progress_data);
1309
0
  }
1310
0
  PutVarint32(dst,
1311
0
              SubcompactionProgressCustomTag::kSubcompactionProgressTerminate);
1312
0
}
1313
1314
0
Status SubcompactionProgress::DecodeFrom(Slice* input) {
1315
0
  Clear();
1316
1317
0
  while (true) {
1318
0
    uint32_t custom_tag = 0;
1319
0
    if (!GetVarint32(input, &custom_tag)) {
1320
0
      return Status::Corruption("SubcompactionProgress",
1321
0
                                "custom field tag error");
1322
0
    }
1323
1324
0
    if (custom_tag ==
1325
0
        SubcompactionProgressCustomTag::kSubcompactionProgressTerminate) {
1326
0
      break;
1327
0
    }
1328
1329
0
    Slice field;
1330
0
    if (!GetLengthPrefixedSlice(input, &field)) {
1331
0
      return Status::Corruption("SubcompactionProgress",
1332
0
                                "custom field length prefixed slice error");
1333
0
    }
1334
1335
0
    switch (custom_tag) {
1336
0
      case SubcompactionProgressCustomTag::kNextInternalKeyToCompact:
1337
0
        next_internal_key_to_compact = field.ToString();
1338
0
        break;
1339
1340
0
      case SubcompactionProgressCustomTag::kNumProcessedInputRecords:
1341
0
        if (!GetVarint64(&field, &num_processed_input_records)) {
1342
0
          return Status::Corruption("SubcompactionProgress",
1343
0
                                    "invalid num_processed_input_records");
1344
0
        }
1345
0
        break;
1346
1347
0
      case SubcompactionProgressCustomTag::kOutputLevelProgress: {
1348
0
        Status s = output_level_progress.DecodeFrom(&field);
1349
0
        if (!s.ok()) {
1350
0
          return s;
1351
0
        }
1352
0
        break;
1353
0
      }
1354
1355
0
      case SubcompactionProgressCustomTag::kProximalOutputLevelProgress: {
1356
0
        Status s = proximal_output_level_progress.DecodeFrom(&field);
1357
0
        if (!s.ok()) {
1358
0
          return s;
1359
0
        }
1360
0
        break;
1361
0
      }
1362
1363
0
      default:
1364
0
        if ((custom_tag & SubcompactionProgressCustomTag::
1365
0
                              kSubcompactionProgressCustomTagSafeIgnoreMask) !=
1366
0
            0) {
1367
0
          break;
1368
0
        } else {
1369
0
          return Status::NotSupported("SubcompactionProgress",
1370
0
                                      "unsupported critical custom field");
1371
0
        }
1372
0
    }
1373
0
  }
1374
1375
0
  return Status::OK();
1376
0
}
1377
1378
0
bool SubcompactionProgressBuilder::ProcessVersionEdit(const VersionEdit& edit) {
1379
0
  if (!edit.HasSubcompactionProgress()) {
1380
0
    return false;
1381
0
  }
1382
1383
0
  const SubcompactionProgress& progress = edit.GetSubcompactionProgress();
1384
1385
0
  MergeDeltaProgress(progress);
1386
1387
0
  has_subcompaction_progress_ = true;
1388
1389
0
  return true;
1390
0
}
1391
1392
void SubcompactionProgressBuilder::MergeDeltaProgress(
1393
0
    const SubcompactionProgress& delta_progress) {
1394
0
  accumulated_subcompaction_progress_.next_internal_key_to_compact =
1395
0
      delta_progress.next_internal_key_to_compact;
1396
1397
0
  accumulated_subcompaction_progress_.num_processed_input_records =
1398
0
      delta_progress.num_processed_input_records;
1399
1400
0
  MaybeMergeDeltaProgressPerLevel(
1401
0
      accumulated_subcompaction_progress_.output_level_progress,
1402
0
      delta_progress.output_level_progress);
1403
1404
0
  MaybeMergeDeltaProgressPerLevel(
1405
0
      accumulated_subcompaction_progress_.proximal_output_level_progress,
1406
0
      delta_progress.proximal_output_level_progress);
1407
0
}
1408
1409
void SubcompactionProgressBuilder::MaybeMergeDeltaProgressPerLevel(
1410
    SubcompactionProgressPerLevel& accumulated_level_progress,
1411
0
    const SubcompactionProgressPerLevel& delta_level_progress) {
1412
0
  const auto& delta_files = delta_level_progress.GetOutputFiles();
1413
0
  if (delta_files.empty()) {
1414
0
    return;
1415
0
  }
1416
0
  for (const FileMetaData& file : delta_files) {
1417
0
    accumulated_level_progress.AddToOutputFiles(file);  // Stored as copy
1418
0
  }
1419
1420
0
  accumulated_level_progress.SetNumProcessedOutputRecords(
1421
0
      delta_level_progress.GetNumProcessedOutputRecords());
1422
0
}
1423
1424
0
void SubcompactionProgressBuilder::Clear() {
1425
0
  accumulated_subcompaction_progress_.Clear();
1426
0
  has_subcompaction_progress_ = false;
1427
0
}
1428
}  // namespace ROCKSDB_NAMESPACE