Coverage Report

Created: 2026-02-14 06:58

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