Coverage Report

Created: 2026-05-16 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/table/table_properties.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
#include "rocksdb/table_properties.h"
7
8
#include "db/seqno_to_time_mapping.h"
9
#include "port/malloc.h"
10
#include "port/port.h"
11
#include "rocksdb/env.h"
12
#include "rocksdb/unique_id.h"
13
#include "rocksdb/utilities/options_type.h"
14
#include "table/table_properties_internal.h"
15
#include "table/unique_id_impl.h"
16
#include "util/compression.h"
17
#include "util/random.h"
18
#include "util/string_util.h"
19
20
namespace ROCKSDB_NAMESPACE {
21
22
const uint32_t TablePropertiesCollectorFactory::Context::kUnknownColumnFamily =
23
    std::numeric_limits<int32_t>::max();
24
25
namespace {
26
void AppendProperty(std::string& props, const std::string& key,
27
                    const std::string& value, const std::string& prop_delim,
28
0
                    const std::string& kv_delim) {
29
0
  props.append(key);
30
0
  props.append(kv_delim);
31
0
  props.append(value);
32
0
  props.append(prop_delim);
33
0
}
34
35
template <class TValue>
36
void AppendProperty(std::string& props, const std::string& key,
37
                    const TValue& value, const std::string& prop_delim,
38
0
                    const std::string& kv_delim) {
39
0
  AppendProperty(props, key, std::to_string(value), prop_delim, kv_delim);
40
0
}
Unexecuted instantiation: table_properties.cc:void rocksdb::(anonymous namespace)::AppendProperty<unsigned long>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: table_properties.cc:void rocksdb::(anonymous namespace)::AppendProperty<double>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
41
42
std::shared_ptr<CompressionManager> ResolveCompressionManagerForDisplay(
43
    Slice compatibility_name,
44
0
    const std::shared_ptr<CompressionManager>& compression_manager) {
45
0
  std::shared_ptr<CompressionManager> mgr_to_use;
46
0
  if (compression_manager) {
47
0
    mgr_to_use = compression_manager->FindCompatibleCompressionManager(
48
0
        compatibility_name);
49
0
  }
50
0
  if (mgr_to_use == nullptr) {
51
0
    ConfigOptions strict;
52
0
    strict.ignore_unknown_options = false;
53
0
    strict.ignore_unsupported_options = false;
54
0
    Status s = CompressionManager::CreateFromString(
55
0
        strict, compatibility_name.ToString(), &mgr_to_use);
56
0
    if (!s.ok()) {
57
0
      mgr_to_use.reset();
58
0
    }
59
0
  }
60
0
  return mgr_to_use;
61
0
}
62
63
std::string CompressionTypeDisplayName(
64
    CompressionType compression_type,
65
0
    const std::shared_ptr<CompressionManager>& compression_manager) {
66
0
  if (compression_manager) {
67
0
    std::string name =
68
0
        compression_manager->CompressionTypeToString(compression_type);
69
0
    if (!name.empty()) {
70
0
      return name;
71
0
    }
72
0
  }
73
0
  return CompressionTypeToString(compression_type);
74
0
}
75
}  // namespace
76
77
std::string TableProperties::ToString(const std::string& prop_delim,
78
0
                                      const std::string& kv_delim) const {
79
0
  std::string result;
80
0
  result.reserve(1024);
81
82
  // Basic Info
83
0
  AppendProperty(result, "# data blocks", num_data_blocks, prop_delim,
84
0
                 kv_delim);
85
0
  AppendProperty(result, "# data blocks compression rejected",
86
0
                 num_data_blocks_compression_rejected, prop_delim, kv_delim);
87
0
  AppendProperty(result, "# data blocks compression bypassed",
88
0
                 num_data_blocks_compression_bypassed, prop_delim, kv_delim);
89
0
  AppendProperty(result, "# uniform blocks", num_uniform_blocks, prop_delim,
90
0
                 kv_delim);
91
0
  AppendProperty(result, "# entries", num_entries, prop_delim, kv_delim);
92
0
  AppendProperty(result, "# deletions", num_deletions, prop_delim, kv_delim);
93
0
  AppendProperty(result, "# merge operands", num_merge_operands, prop_delim,
94
0
                 kv_delim);
95
0
  AppendProperty(result, "# range deletions", num_range_deletions, prop_delim,
96
0
                 kv_delim);
97
98
0
  AppendProperty(result, "raw key size", raw_key_size, prop_delim, kv_delim);
99
0
  AppendProperty(result, "raw average key size",
100
0
                 num_entries != 0 ? 1.0 * raw_key_size / num_entries : 0.0,
101
0
                 prop_delim, kv_delim);
102
0
  AppendProperty(result, "raw value size", raw_value_size, prop_delim,
103
0
                 kv_delim);
104
0
  AppendProperty(result, "raw average value size",
105
0
                 num_entries != 0 ? 1.0 * raw_value_size / num_entries : 0.0,
106
0
                 prop_delim, kv_delim);
107
108
0
  AppendProperty(result, "data block size", data_size, prop_delim, kv_delim);
109
0
  AppendProperty(result, "data uncompressed size", uncompressed_data_size,
110
0
                 prop_delim, kv_delim);
111
0
  char index_block_size_str[80];
112
0
  snprintf(index_block_size_str, sizeof(index_block_size_str),
113
0
           "index block size (user-key? %d, delta-value? %d)",
114
0
           static_cast<int>(index_key_is_user_key),
115
0
           static_cast<int>(index_value_is_delta_encoded));
116
0
  AppendProperty(result, index_block_size_str, index_size, prop_delim,
117
0
                 kv_delim);
118
0
  if (index_partitions != 0) {
119
0
    AppendProperty(result, "# index partitions", index_partitions, prop_delim,
120
0
                   kv_delim);
121
0
    AppendProperty(result, "top-level index size", top_level_index_size,
122
0
                   prop_delim, kv_delim);
123
0
  }
124
0
  AppendProperty(result, "filter block size", filter_size, prop_delim,
125
0
                 kv_delim);
126
0
  AppendProperty(result, "# entries for filter", num_filter_entries, prop_delim,
127
0
                 kv_delim);
128
0
  AppendProperty(result, "(estimated) table size",
129
0
                 data_size + index_size + filter_size, prop_delim, kv_delim);
130
131
0
  AppendProperty(
132
0
      result, "filter policy name",
133
0
      filter_policy_name.empty() ? std::string("N/A") : filter_policy_name,
134
0
      prop_delim, kv_delim);
135
136
0
  AppendProperty(result, "prefix extractor name",
137
0
                 prefix_extractor_name.empty() ? std::string("N/A")
138
0
                                               : prefix_extractor_name,
139
0
                 prop_delim, kv_delim);
140
141
0
  AppendProperty(result, "column family ID",
142
0
                 column_family_id ==
143
0
                         ROCKSDB_NAMESPACE::TablePropertiesCollectorFactory::
144
0
                             Context::kUnknownColumnFamily
145
0
                     ? std::string("N/A")
146
0
                     : std::to_string(column_family_id),
147
0
                 prop_delim, kv_delim);
148
0
  AppendProperty(
149
0
      result, "column family name",
150
0
      column_family_name.empty() ? std::string("N/A") : column_family_name,
151
0
      prop_delim, kv_delim);
152
153
0
  AppendProperty(result, "comparator name",
154
0
                 comparator_name.empty() ? std::string("N/A") : comparator_name,
155
0
                 prop_delim, kv_delim);
156
0
  AppendProperty(result, "user defined timestamps persisted",
157
0
                 user_defined_timestamps_persisted ? std::string("true")
158
0
                                                   : std::string("false"),
159
0
                 prop_delim, kv_delim);
160
0
  AppendProperty(result, "largest sequence number in file", key_largest_seqno,
161
0
                 prop_delim, kv_delim);
162
0
  AppendProperty(result, "smallest sequence number in file", key_smallest_seqno,
163
0
                 prop_delim, kv_delim);
164
165
0
  AppendProperty(
166
0
      result, "merge operator name",
167
0
      merge_operator_name.empty() ? std::string("N/A") : merge_operator_name,
168
0
      prop_delim, kv_delim);
169
170
0
  AppendProperty(result, "property collectors names",
171
0
                 property_collectors_names.empty() ? std::string("N/A")
172
0
                                                   : property_collectors_names,
173
0
                 prop_delim, kv_delim);
174
175
0
  AppendProperty(
176
0
      result, "SST file compression algo",
177
0
      compression_name.empty() ? std::string("N/A") : compression_name,
178
0
      prop_delim, kv_delim);
179
180
0
  AppendProperty(
181
0
      result, "SST file compression options",
182
0
      compression_options.empty() ? std::string("N/A") : compression_options,
183
0
      prop_delim, kv_delim);
184
185
0
  AppendProperty(result, "creation time", creation_time, prop_delim, kv_delim);
186
187
0
  AppendProperty(result, "time stamp of earliest key", oldest_key_time,
188
0
                 prop_delim, kv_delim);
189
0
  AppendProperty(result, "time stamp of newest key", newest_key_time,
190
0
                 prop_delim, kv_delim);
191
192
0
  AppendProperty(result, "file creation time", file_creation_time, prop_delim,
193
0
                 kv_delim);
194
195
0
  AppendProperty(result, "slow compression estimated data size",
196
0
                 slow_compression_estimated_data_size, prop_delim, kv_delim);
197
0
  AppendProperty(result, "fast compression estimated data size",
198
0
                 fast_compression_estimated_data_size, prop_delim, kv_delim);
199
200
  // DB identity and DB session ID
201
0
  AppendProperty(result, "DB identity", db_id, prop_delim, kv_delim);
202
0
  AppendProperty(result, "DB session identity", db_session_id, prop_delim,
203
0
                 kv_delim);
204
0
  AppendProperty(result, "DB host id", db_host_id, prop_delim, kv_delim);
205
0
  AppendProperty(result, "original file number", orig_file_number, prop_delim,
206
0
                 kv_delim);
207
208
  // Unique ID, when available
209
0
  std::string id;
210
0
  Status s = GetUniqueIdFromTableProperties(*this, &id);
211
0
  AppendProperty(result, "unique ID",
212
0
                 s.ok() ? UniqueIdToHumanString(id) : "N/A", prop_delim,
213
0
                 kv_delim);
214
215
0
  SeqnoToTimeMapping seq_time_mapping;
216
0
  s = seq_time_mapping.DecodeFrom(seqno_to_time_mapping);
217
0
  AppendProperty(result, "Sequence number to time mapping",
218
0
                 s.ok() ? seq_time_mapping.ToHumanString() : "N/A", prop_delim,
219
0
                 kv_delim);
220
221
0
  return result;
222
0
}
223
224
0
void TableProperties::Add(const TableProperties& tp) {
225
0
  data_size += tp.data_size;
226
0
  uncompressed_data_size += tp.uncompressed_data_size;
227
0
  index_size += tp.index_size;
228
0
  index_partitions += tp.index_partitions;
229
0
  top_level_index_size += tp.top_level_index_size;
230
0
  index_key_is_user_key += tp.index_key_is_user_key;
231
0
  index_value_is_delta_encoded += tp.index_value_is_delta_encoded;
232
0
  filter_size += tp.filter_size;
233
0
  raw_key_size += tp.raw_key_size;
234
0
  raw_value_size += tp.raw_value_size;
235
0
  num_data_blocks += tp.num_data_blocks;
236
0
  num_data_blocks_compression_rejected +=
237
0
      tp.num_data_blocks_compression_rejected;
238
0
  num_data_blocks_compression_bypassed +=
239
0
      tp.num_data_blocks_compression_bypassed;
240
0
  num_uniform_blocks += tp.num_uniform_blocks;
241
0
  num_entries += tp.num_entries;
242
0
  num_filter_entries += tp.num_filter_entries;
243
0
  num_deletions += tp.num_deletions;
244
0
  num_merge_operands += tp.num_merge_operands;
245
0
  num_range_deletions += tp.num_range_deletions;
246
0
  slow_compression_estimated_data_size +=
247
0
      tp.slow_compression_estimated_data_size;
248
0
  fast_compression_estimated_data_size +=
249
0
      tp.fast_compression_estimated_data_size;
250
0
}
251
252
std::map<std::string, uint64_t>
253
0
TableProperties::GetAggregatablePropertiesAsMap() const {
254
0
  std::map<std::string, uint64_t> rv;
255
0
  rv["data_size"] = data_size;
256
0
  rv["uncompressed_data_size"] = uncompressed_data_size;
257
0
  rv["index_size"] = index_size;
258
0
  rv["index_partitions"] = index_partitions;
259
0
  rv["top_level_index_size"] = top_level_index_size;
260
0
  rv["filter_size"] = filter_size;
261
0
  rv["raw_key_size"] = raw_key_size;
262
0
  rv["raw_value_size"] = raw_value_size;
263
0
  rv["num_data_blocks"] = num_data_blocks;
264
0
  rv["num_data_blocks_compression_rejected"] =
265
0
      num_data_blocks_compression_rejected;
266
0
  rv["num_data_blocks_compression_bypassed"] =
267
0
      num_data_blocks_compression_bypassed;
268
0
  rv["num_uniform_blocks"] = num_uniform_blocks;
269
0
  rv["num_entries"] = num_entries;
270
0
  rv["num_filter_entries"] = num_filter_entries;
271
0
  rv["num_deletions"] = num_deletions;
272
0
  rv["num_merge_operands"] = num_merge_operands;
273
0
  rv["num_range_deletions"] = num_range_deletions;
274
0
  rv["slow_compression_estimated_data_size"] =
275
0
      slow_compression_estimated_data_size;
276
0
  rv["fast_compression_estimated_data_size"] =
277
0
      fast_compression_estimated_data_size;
278
0
  return rv;
279
0
}
280
281
// WARNING: manual update to this function is needed
282
// whenever a new string property is added to TableProperties
283
// to reduce approximation error.
284
//
285
// TODO: eliminate the need of manually updating this function
286
// for new string properties
287
0
std::size_t TableProperties::ApproximateMemoryUsage() const {
288
0
  std::size_t usage = 0;
289
0
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
290
0
  usage += malloc_usable_size((void*)this);
291
#else
292
  usage += sizeof(*this);
293
#endif  // ROCKSDB_MALLOC_USABLE_SIZE
294
295
0
  std::size_t string_props_mem_usage =
296
0
      db_id.size() + db_session_id.size() + db_host_id.size() +
297
0
      column_family_name.size() + filter_policy_name.size() +
298
0
      comparator_name.size() + merge_operator_name.size() +
299
0
      prefix_extractor_name.size() + property_collectors_names.size() +
300
0
      compression_name.size() + compression_options.size();
301
0
  usage += string_props_mem_usage;
302
303
0
  for (auto iter = user_collected_properties.begin();
304
0
       iter != user_collected_properties.end(); ++iter) {
305
0
    usage += (iter->first.size() + iter->second.size());
306
0
  }
307
308
0
  return usage;
309
0
}
310
311
const std::string TablePropertiesNames::kDbId = "rocksdb.creating.db.identity";
312
const std::string TablePropertiesNames::kDbSessionId =
313
    "rocksdb.creating.session.identity";
314
const std::string TablePropertiesNames::kDbHostId =
315
    "rocksdb.creating.host.identity";
316
const std::string TablePropertiesNames::kOriginalFileNumber =
317
    "rocksdb.original.file.number";
318
const std::string TablePropertiesNames::kDataSize = "rocksdb.data.size";
319
const std::string TablePropertiesNames::kIndexSize = "rocksdb.index.size";
320
const std::string TablePropertiesNames::kIndexPartitions =
321
    "rocksdb.index.partitions";
322
const std::string TablePropertiesNames::kTopLevelIndexSize =
323
    "rocksdb.top-level.index.size";
324
const std::string TablePropertiesNames::kIndexKeyIsUserKey =
325
    "rocksdb.index.key.is.user.key";
326
const std::string TablePropertiesNames::kIndexValueIsDeltaEncoded =
327
    "rocksdb.index.value.is.delta.encoded";
328
const std::string TablePropertiesNames::kUDIIsPrimaryIndex =
329
    "rocksdb.udi.is.primary.index";
330
const std::string TablePropertiesNames::kFilterSize = "rocksdb.filter.size";
331
const std::string TablePropertiesNames::kRawKeySize = "rocksdb.raw.key.size";
332
const std::string TablePropertiesNames::kRawValueSize =
333
    "rocksdb.raw.value.size";
334
const std::string TablePropertiesNames::kNumDataBlocks =
335
    "rocksdb.num.data.blocks";
336
const std::string TablePropertiesNames::kNumDataBlocksCompressionRejected =
337
    "rocksdb.num.data.blocks.compression.rejected";
338
const std::string TablePropertiesNames::kNumDataBlocksCompressionBypassed =
339
    "rocksdb.num.data.blocks.compression.bypassed";
340
const std::string TablePropertiesNames::kNumUniformBlocks =
341
    "rocksdb.num.uniform.blocks";
342
const std::string TablePropertiesNames::kNumEntries = "rocksdb.num.entries";
343
const std::string TablePropertiesNames::kNumFilterEntries =
344
    "rocksdb.num.filter_entries";
345
const std::string TablePropertiesNames::kDeletedKeys = "rocksdb.deleted.keys";
346
const std::string TablePropertiesNames::kMergeOperands =
347
    "rocksdb.merge.operands";
348
const std::string TablePropertiesNames::kNumRangeDeletions =
349
    "rocksdb.num.range-deletions";
350
const std::string TablePropertiesNames::kFilterPolicy = "rocksdb.filter.policy";
351
const std::string TablePropertiesNames::kFormatVersion =
352
    "rocksdb.format.version";
353
const std::string TablePropertiesNames::kFixedKeyLen =
354
    "rocksdb.fixed.key.length";
355
const std::string TablePropertiesNames::kColumnFamilyId =
356
    "rocksdb.column.family.id";
357
const std::string TablePropertiesNames::kColumnFamilyName =
358
    "rocksdb.column.family.name";
359
const std::string TablePropertiesNames::kComparator = "rocksdb.comparator";
360
const std::string TablePropertiesNames::kMergeOperator =
361
    "rocksdb.merge.operator";
362
const std::string TablePropertiesNames::kPrefixExtractorName =
363
    "rocksdb.prefix.extractor.name";
364
const std::string TablePropertiesNames::kPropertyCollectors =
365
    "rocksdb.property.collectors";
366
const std::string TablePropertiesNames::kCompression = "rocksdb.compression";
367
const std::string TablePropertiesNames::kCompressionOptions =
368
    "rocksdb.compression_options";
369
const std::string TablePropertiesNames::kCreationTime = "rocksdb.creation.time";
370
const std::string TablePropertiesNames::kOldestKeyTime =
371
    "rocksdb.oldest.key.time";
372
const std::string TablePropertiesNames::kNewestKeyTime =
373
    "rocksdb.newest.key.time";
374
const std::string TablePropertiesNames::kFileCreationTime =
375
    "rocksdb.file.creation.time";
376
const std::string TablePropertiesNames::kSlowCompressionEstimatedDataSize =
377
    "rocksdb.sample_for_compression.slow.data.size";
378
const std::string TablePropertiesNames::kFastCompressionEstimatedDataSize =
379
    "rocksdb.sample_for_compression.fast.data.size";
380
const std::string TablePropertiesNames::kSequenceNumberTimeMapping =
381
    "rocksdb.seqno.time.map";
382
const std::string TablePropertiesNames::kTailStartOffset =
383
    "rocksdb.tail.start.offset";
384
const std::string TablePropertiesNames::kUserDefinedTimestampsPersisted =
385
    "rocksdb.user.defined.timestamps.persisted";
386
const std::string TablePropertiesNames::kKeyLargestSeqno =
387
    "rocksdb.key.largest.seqno";
388
const std::string TablePropertiesNames::kKeySmallestSeqno =
389
    "rocksdb.key.smallest.seqno";
390
const std::string TablePropertiesNames::kDataBlockRestartInterval =
391
    "rocksdb.data.block.restart.interval";
392
const std::string TablePropertiesNames::kIndexBlockRestartInterval =
393
    "rocksdb.index.block.restart.interval";
394
const std::string TablePropertiesNames::kSeparateKeyValueInDataBlock =
395
    "rocksdb.separate.key.value.in.data.block";
396
397
static std::unordered_map<std::string, OptionTypeInfo>
398
    table_properties_type_info = {
399
        {"orig_file_number",
400
         {offsetof(struct TableProperties, orig_file_number),
401
          OptionType::kUInt64T, OptionVerificationType::kNormal,
402
          OptionTypeFlags::kNone}},
403
        {"data_size",
404
         {offsetof(struct TableProperties, data_size), OptionType::kUInt64T,
405
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
406
        {"uncompressed_data_size",
407
         {offsetof(struct TableProperties, uncompressed_data_size),
408
          OptionType::kUInt64T, OptionVerificationType::kNormal,
409
          OptionTypeFlags::kNone}},
410
        {"index_size",
411
         {offsetof(struct TableProperties, index_size), OptionType::kUInt64T,
412
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
413
        {"index_partitions",
414
         {offsetof(struct TableProperties, index_partitions),
415
          OptionType::kUInt64T, OptionVerificationType::kNormal,
416
          OptionTypeFlags::kNone}},
417
        {"top_level_index_size",
418
         {offsetof(struct TableProperties, top_level_index_size),
419
          OptionType::kUInt64T, OptionVerificationType::kNormal,
420
          OptionTypeFlags::kNone}},
421
        {"index_key_is_user_key",
422
         {offsetof(struct TableProperties, index_key_is_user_key),
423
          OptionType::kUInt64T, OptionVerificationType::kNormal,
424
          OptionTypeFlags::kNone}},
425
        {"index_value_is_delta_encoded",
426
         {offsetof(struct TableProperties, index_value_is_delta_encoded),
427
          OptionType::kUInt64T, OptionVerificationType::kNormal,
428
          OptionTypeFlags::kNone}},
429
        {"udi_is_primary_index",
430
         {offsetof(struct TableProperties, udi_is_primary_index),
431
          OptionType::kUInt64T, OptionVerificationType::kNormal,
432
          OptionTypeFlags::kNone}},
433
        {"filter_size",
434
         {offsetof(struct TableProperties, filter_size), OptionType::kUInt64T,
435
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
436
        {"raw_key_size",
437
         {offsetof(struct TableProperties, raw_key_size), OptionType::kUInt64T,
438
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
439
        {"raw_value_size",
440
         {offsetof(struct TableProperties, raw_value_size),
441
          OptionType::kUInt64T, OptionVerificationType::kNormal,
442
          OptionTypeFlags::kNone}},
443
        {"num_data_blocks",
444
         {offsetof(struct TableProperties, num_data_blocks),
445
          OptionType::kUInt64T, OptionVerificationType::kNormal,
446
          OptionTypeFlags::kNone}},
447
        {"num_data_blocks_compression_rejected",
448
         {offsetof(struct TableProperties,
449
                   num_data_blocks_compression_rejected),
450
          OptionType::kUInt64T, OptionVerificationType::kNormal,
451
          OptionTypeFlags::kNone}},
452
        {"num_data_blocks_compression_bypassed",
453
         {offsetof(struct TableProperties,
454
                   num_data_blocks_compression_bypassed),
455
          OptionType::kUInt64T, OptionVerificationType::kNormal,
456
          OptionTypeFlags::kNone}},
457
        {"num_uniform_blocks",
458
         {offsetof(struct TableProperties, num_uniform_blocks),
459
          OptionType::kUInt64T, OptionVerificationType::kNormal,
460
          OptionTypeFlags::kNone}},
461
        {"num_entries",
462
         {offsetof(struct TableProperties, num_entries), OptionType::kUInt64T,
463
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
464
        {"num_filter_entries",
465
         {offsetof(struct TableProperties, num_filter_entries),
466
          OptionType::kUInt64T, OptionVerificationType::kNormal,
467
          OptionTypeFlags::kNone}},
468
        {"num_deletions",
469
         {offsetof(struct TableProperties, num_deletions), OptionType::kUInt64T,
470
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
471
        {"num_merge_operands",
472
         {offsetof(struct TableProperties, num_merge_operands),
473
          OptionType::kUInt64T, OptionVerificationType::kNormal,
474
          OptionTypeFlags::kNone}},
475
        {"num_range_deletions",
476
         {offsetof(struct TableProperties, num_range_deletions),
477
          OptionType::kUInt64T, OptionVerificationType::kNormal,
478
          OptionTypeFlags::kNone}},
479
        {"format_version",
480
         {offsetof(struct TableProperties, format_version),
481
          OptionType::kUInt64T, OptionVerificationType::kNormal,
482
          OptionTypeFlags::kNone}},
483
        {"fixed_key_len",
484
         {offsetof(struct TableProperties, fixed_key_len), OptionType::kUInt64T,
485
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
486
        {"column_family_id",
487
         {offsetof(struct TableProperties, column_family_id),
488
          OptionType::kUInt64T, OptionVerificationType::kNormal,
489
          OptionTypeFlags::kNone}},
490
        {"creation_time",
491
         {offsetof(struct TableProperties, creation_time), OptionType::kUInt64T,
492
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
493
        {"oldest_key_time",
494
         {offsetof(struct TableProperties, oldest_key_time),
495
          OptionType::kUInt64T, OptionVerificationType::kNormal,
496
          OptionTypeFlags::kNone}},
497
        {"newest_key_time",
498
         {offsetof(struct TableProperties, newest_key_time),
499
          OptionType::kUInt64T, OptionVerificationType::kNormal,
500
          OptionTypeFlags::kNone}},
501
        {"file_creation_time",
502
         {offsetof(struct TableProperties, file_creation_time),
503
          OptionType::kUInt64T, OptionVerificationType::kNormal,
504
          OptionTypeFlags::kNone}},
505
        {"slow_compression_estimated_data_size",
506
         {offsetof(struct TableProperties,
507
                   slow_compression_estimated_data_size),
508
          OptionType::kUInt64T, OptionVerificationType::kNormal,
509
          OptionTypeFlags::kNone}},
510
        {"fast_compression_estimated_data_size",
511
         {offsetof(struct TableProperties,
512
                   fast_compression_estimated_data_size),
513
          OptionType::kUInt64T, OptionVerificationType::kNormal,
514
          OptionTypeFlags::kNone}},
515
        {"external_sst_file_global_seqno_offset",
516
         {offsetof(struct TableProperties,
517
                   external_sst_file_global_seqno_offset),
518
          OptionType::kUInt64T, OptionVerificationType::kNormal,
519
          OptionTypeFlags::kNone}},
520
        {"tail_start_offset",
521
         {offsetof(struct TableProperties, tail_start_offset),
522
          OptionType::kUInt64T, OptionVerificationType::kNormal,
523
          OptionTypeFlags::kNone}},
524
        {"user_defined_timestamps_persisted",
525
         {offsetof(struct TableProperties, user_defined_timestamps_persisted),
526
          OptionType::kUInt64T, OptionVerificationType::kNormal,
527
          OptionTypeFlags::kNone}},
528
        {"key_largest_seqno",
529
         {offsetof(struct TableProperties, key_largest_seqno),
530
          OptionType::kUInt64T, OptionVerificationType::kNormal,
531
          OptionTypeFlags::kNone}},
532
        {"key_smallest_seqno",
533
         {offsetof(struct TableProperties, key_smallest_seqno),
534
          OptionType::kUInt64T, OptionVerificationType::kNormal,
535
          OptionTypeFlags::kNone}},
536
        {"data_block_restart_interval",
537
         {offsetof(struct TableProperties, data_block_restart_interval),
538
          OptionType::kUInt64T, OptionVerificationType::kNormal,
539
          OptionTypeFlags::kNone}},
540
        {"index_block_restart_interval",
541
         {offsetof(struct TableProperties, index_block_restart_interval),
542
          OptionType::kUInt64T, OptionVerificationType::kNormal,
543
          OptionTypeFlags::kNone}},
544
        {"separate_key_value_in_data_block",
545
         {offsetof(struct TableProperties, separate_key_value_in_data_block),
546
          OptionType::kUInt64T, OptionVerificationType::kNormal,
547
          OptionTypeFlags::kNone}},
548
        {"db_id",
549
         {offsetof(struct TableProperties, db_id), OptionType::kEncodedString}},
550
        {"db_session_id",
551
         {offsetof(struct TableProperties, db_session_id),
552
          OptionType::kEncodedString}},
553
        {"db_host_id",
554
         {offsetof(struct TableProperties, db_host_id),
555
          OptionType::kEncodedString}},
556
        {"column_family_name",
557
         {offsetof(struct TableProperties, column_family_name),
558
          OptionType::kEncodedString}},
559
        {"filter_policy_name",
560
         {offsetof(struct TableProperties, filter_policy_name),
561
          OptionType::kEncodedString}},
562
        {"comparator_name",
563
         {offsetof(struct TableProperties, comparator_name),
564
          OptionType::kEncodedString}},
565
        {"merge_operator_name",
566
         {offsetof(struct TableProperties, merge_operator_name),
567
          OptionType::kEncodedString}},
568
        {"prefix_extractor_name",
569
         {offsetof(struct TableProperties, prefix_extractor_name),
570
          OptionType::kEncodedString}},
571
        {"property_collectors_names",
572
         {offsetof(struct TableProperties, property_collectors_names),
573
          OptionType::kEncodedString}},
574
        {"compression_name",
575
         {offsetof(struct TableProperties, compression_name),
576
          OptionType::kEncodedString}},
577
        {"compression_options",
578
         {offsetof(struct TableProperties, compression_options),
579
          OptionType::kEncodedString}},
580
        {"seqno_to_time_mapping",
581
         {offsetof(struct TableProperties, seqno_to_time_mapping),
582
          OptionType::kEncodedString}},
583
        {"user_collected_properties",
584
         OptionTypeInfo::StringMap(
585
             offsetof(struct TableProperties, user_collected_properties),
586
             OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
587
        {"readable_properties",
588
         OptionTypeInfo::StringMap(
589
             offsetof(struct TableProperties, readable_properties),
590
             OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
591
};
592
593
Status TableProperties::Serialize(const ConfigOptions& opts,
594
0
                                  std::string* output) const {
595
0
  return OptionTypeInfo::SerializeType(opts, table_properties_type_info, this,
596
0
                                       output);
597
0
}
598
Status TableProperties::Parse(const ConfigOptions& opts,
599
                              const std::string& serialized,
600
0
                              TableProperties* table_properties) {
601
0
  return OptionTypeInfo::ParseType(opts, serialized, table_properties_type_info,
602
0
                                   table_properties);
603
0
}
604
bool TableProperties::AreEqual(const ConfigOptions& opts,
605
                               const TableProperties* other_table_properties,
606
0
                               std::string* mismatch) const {
607
0
  return OptionTypeInfo::TypesAreEqual(opts, table_properties_type_info, this,
608
0
                                       other_table_properties, mismatch);
609
0
}
610
611
#ifndef NDEBUG
612
// WARNING: TEST_SetRandomTableProperties assumes the following layout of
613
// TableProperties
614
//
615
// struct TableProperties {
616
//    int64_t orig_file_number = 0;
617
//    ...
618
//    ... int64_t properties only
619
//    ...
620
//    std::string db_id;
621
//    ...
622
//    ... std::string properties only
623
//    ...
624
//    std::string compression_options;
625
//    UserCollectedProperties user_collected_properties;
626
//    ...
627
//    ... Other extra properties: non-int64_t/non-std::string properties only
628
//    ...
629
// }
630
void TEST_SetRandomTableProperties(TableProperties* props) {
631
  Random* r = Random::GetTLSInstance();
632
  uint64_t* pu = &props->orig_file_number;
633
  assert(static_cast<void*>(pu) == static_cast<void*>(props));
634
  std::string* ps = &props->db_id;
635
  const uint64_t* const pu_end = reinterpret_cast<const uint64_t*>(ps);
636
  // Use the last string property's address instead of
637
  // the first extra property (e.g `user_collected_properties`)'s address
638
  // in the for-loop to avoid advancing pointer to pointing to
639
  // potential non-zero padding bytes between these two addresses due to
640
  // user_collected_properties's alignment requirement
641
  const std::string* const ps_end_inclusive = &props->compression_options;
642
643
  for (; pu < pu_end; ++pu) {
644
    *pu = r->Next64();
645
  }
646
  assert(static_cast<void*>(pu) == static_cast<void*>(ps));
647
  for (; ps <= ps_end_inclusive; ++ps) {
648
    *ps = r->RandomBinaryString(13);
649
  }
650
}
651
#endif
652
653
std::string ParseCompressionNameForDisplay(
654
0
    const std::string& compression_name) {
655
  // The single-argument overload intentionally consults globally registered
656
  // CompressionManagers, keyed by the encoded compatibility name, so custom
657
  // managers can contribute display names without an explicit manager handle.
658
0
  return ParseCompressionNameForDisplay(compression_name, nullptr);
659
0
}
660
661
std::string ParseCompressionNameForDisplay(
662
    const std::string& compression_name,
663
0
    std::shared_ptr<CompressionManager> compression_manager) {
664
  // Empty = no compression
665
0
  if (compression_name.empty()) {
666
0
    return "NoCompression";
667
0
  }
668
669
  // Check for format_version 7 format (contains ';')
670
0
  size_t first_semicolon = compression_name.find(';');
671
0
  if (first_semicolon == std::string::npos) {
672
    // Old format - return as-is
673
0
    return compression_name;
674
0
  }
675
676
  // New format: "<compatibility_name>;<hex_codes>;"
677
0
  size_t second_semicolon = compression_name.find(';', first_semicolon + 1);
678
0
  if (second_semicolon == std::string::npos) {
679
    // Malformed - missing second field
680
0
    return "Unknown";
681
0
  }
682
683
0
  Slice compatibility_name(compression_name.data(), first_semicolon);
684
0
  auto mgr_to_use = ResolveCompressionManagerForDisplay(compatibility_name,
685
0
                                                        compression_manager);
686
687
  // Extract hex codes
688
0
  std::string hex_codes = compression_name.substr(
689
0
      first_semicolon + 1, second_semicolon - first_semicolon - 1);
690
691
  // Validate hex string length (must be even)
692
0
  if (hex_codes.size() % 2 != 0) {
693
0
    return "Unknown";
694
0
  }
695
696
  // Parse each 2-char hex code to CompressionType.
697
  // Note: This intentionally mirrors GetDecompressor()'s decoding shape but
698
  // differs in error semantics. GetDecompressor() treats kNoCompression
699
  // (0x00) and values >= kDisableCompressionOption (0xFF) as corruption. For
700
  // display purposes, we silently filter these out and return "NoCompression"
701
  // if no valid types remain.
702
0
  std::vector<std::string> types;
703
0
  for (size_t i = 0; i < hex_codes.size(); i += 2) {
704
0
    const char* ptr = hex_codes.data() + i;
705
0
    uint64_t val = 0;
706
0
    if (!ParseBaseChars<16>(&ptr, 2, &val)) {
707
0
      return "Unknown";
708
0
    }
709
0
    auto ct = static_cast<CompressionType>(val);
710
0
    if (ct != kNoCompression && ct != kDisableCompressionOption) {
711
0
      types.push_back(CompressionTypeDisplayName(ct, mgr_to_use));
712
0
    }
713
0
  }
714
715
0
  if (types.empty()) {
716
0
    return "NoCompression";
717
0
  } else if (types.size() == 1) {
718
0
    return types[0];
719
0
  } else {
720
    // Multiple types - join with commas
721
0
    std::string result = types[0];
722
0
    for (size_t i = 1; i < types.size(); ++i) {
723
0
      result += "," + types[i];
724
0
    }
725
0
    return result;
726
0
  }
727
0
}
728
729
}  // namespace ROCKSDB_NAMESPACE