Replace TableProperties::properties_offsets map with external_sst_file_global_seqno_offset (#9212)

Summary:
**Context:**
Searching `TableProperties::properties_offsets` across the codebase reveals that internally it is only used to find the external SST file's global seqno offeset. Therefore we can narrow it down and replace this map property with a uint64_t property `external_sst_file_global_seqno_offset` to save memory usage related to table properties.

Note:
- See PR comments for discussion about potential impact on existing external usage of `TableProperties::properties_offsets`
- See PR comments for discussion on keeping external SST file global seqno's offset VS using a simple flag indicating seqno's existence.

**Summary:**
- Replaced `TableProperties::properties_offsets` with `TableProperties::external_sst_file_global_seqno_offset`

Pull Request resolved: https://github.com/facebook/rocksdb/pull/9212

Test Plan: - Relied on existing tests should be sufficient since `TableProperties::properties_offsets` existed before and should already be tested.

Reviewed By: ajkr

Differential Revision: D32665941

Pulled By: hx235

fbshipit-source-id: 718e44617346dc4f3b1276ee953e61c196277795
main
Hui Xiao 3 years ago committed by Facebook GitHub Bot
parent 44ac714808
commit 9daf07305c
  1. 3
      HISTORY.md
  2. 8
      db/external_sst_file_ingestion_job.cc
  3. 7
      include/rocksdb/table_properties.h
  4. 25
      java/rocksjni/portal.h
  5. 2
      java/rocksjni/testable_event_listener.cc
  6. 33
      java/src/main/java/org/rocksdb/TableProperties.java
  7. 10
      java/src/test/java/org/rocksdb/EventListenerTest.java
  8. 14
      table/meta_blocks.cc
  9. 3
      table/table_test.cc

@ -8,6 +8,9 @@
### Public API change ### Public API change
* Extend WriteBatch::AssignTimestamp and AssignTimestamps API so that both functions can accept an optional `checker` argument that performs additional checking on timestamp sizes. * Extend WriteBatch::AssignTimestamp and AssignTimestamps API so that both functions can accept an optional `checker` argument that performs additional checking on timestamp sizes.
### Performance Improvements
* Replaced map property `TableProperties::properties_offsets` with uint64_t property `external_sst_file_global_seqno_offset` to save table properties's memory.
## 6.27.0 (2021-11-19) ## 6.27.0 (2021-11-19)
### New Features ### New Features
* Added new ChecksumType kXXH3 which is faster than kCRC32c on almost all x86\_64 hardware. * Added new ChecksumType kXXH3 which is faster than kCRC32c on almost all x86\_64 hardware.

@ -609,14 +609,12 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
// Set the global sequence number // Set the global sequence number
file_to_ingest->original_seqno = DecodeFixed64(seqno_iter->second.c_str()); file_to_ingest->original_seqno = DecodeFixed64(seqno_iter->second.c_str());
auto offsets_iter = props->properties_offsets.find( if (props->external_sst_file_global_seqno_offset == 0) {
ExternalSstFilePropertyNames::kGlobalSeqno);
if (offsets_iter == props->properties_offsets.end() ||
offsets_iter->second == 0) {
file_to_ingest->global_seqno_offset = 0; file_to_ingest->global_seqno_offset = 0;
return Status::Corruption("Was not able to find file global seqno field"); return Status::Corruption("Was not able to find file global seqno field");
} }
file_to_ingest->global_seqno_offset = static_cast<size_t>(offsets_iter->second); file_to_ingest->global_seqno_offset =
static_cast<size_t>(props->external_sst_file_global_seqno_offset);
} else if (file_to_ingest->version == 1) { } else if (file_to_ingest->version == 1) {
// SST file V1 should not have global seqno field // SST file V1 should not have global seqno field
assert(seqno_iter == uprops.end()); assert(seqno_iter == uprops.end());

@ -232,6 +232,10 @@ struct TableProperties {
// compression algorithm (see `ColumnFamilyOptions::sample_for_compression`). // compression algorithm (see `ColumnFamilyOptions::sample_for_compression`).
// 0 means unknown. // 0 means unknown.
uint64_t fast_compression_estimated_data_size = 0; uint64_t fast_compression_estimated_data_size = 0;
// Offset of the value of the property "external sst file global seqno" in the
// file if the property exists.
// 0 means not exists.
uint64_t external_sst_file_global_seqno_offset = 0;
// DB identity // DB identity
// db_id is an identifier generated the first time the DB is created // db_id is an identifier generated the first time the DB is created
@ -284,9 +288,6 @@ struct TableProperties {
UserCollectedProperties user_collected_properties; UserCollectedProperties user_collected_properties;
UserCollectedProperties readable_properties; UserCollectedProperties readable_properties;
// The offset of the value of each property in the file.
std::map<std::string, uint64_t> properties_offsets;
// convert this object to a human readable form // convert this object to a human readable form
// @prop_delim: delimiter for each property. // @prop_delim: delimiter for each property.
std::string ToString(const std::string& prop_delim = "; ", std::string ToString(const std::string& prop_delim = "; ",

@ -6147,9 +6147,9 @@ class TablePropertiesJni : public JavaClass {
jmethodID mid = env->GetMethodID( jmethodID mid = env->GetMethodID(
jclazz, "<init>", jclazz, "<init>",
"(JJJJJJJJJJJJJJJJJJJJJ[BLjava/lang/String;Ljava/lang/String;Ljava/" "(JJJJJJJJJJJJJJJJJJJJJJ[BLjava/lang/String;Ljava/lang/String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/" "lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V"); "String;Ljava/util/Map;Ljava/util/Map;)V");
if (mid == nullptr) { if (mid == nullptr) {
// exception thrown: NoSuchMethodException or OutOfMemoryError // exception thrown: NoSuchMethodException or OutOfMemoryError
return nullptr; return nullptr;
@ -6258,23 +6258,6 @@ class TablePropertiesJni : public JavaClass {
return nullptr; return nullptr;
} }
// Map<String, Long>
jobject jproperties_offsets = ROCKSDB_NAMESPACE::HashMapJni::fromCppMap(
env, &table_properties.properties_offsets);
if (env->ExceptionCheck()) {
// exception occurred creating java map
env->DeleteLocalRef(jcolumn_family_name);
env->DeleteLocalRef(jfilter_policy_name);
env->DeleteLocalRef(jcomparator_name);
env->DeleteLocalRef(jmerge_operator_name);
env->DeleteLocalRef(jprefix_extractor_name);
env->DeleteLocalRef(jproperty_collectors_names);
env->DeleteLocalRef(jcompression_name);
env->DeleteLocalRef(juser_collected_properties);
env->DeleteLocalRef(jreadable_properties);
return nullptr;
}
jobject jtable_properties = env->NewObject( jobject jtable_properties = env->NewObject(
jclazz, mid, static_cast<jlong>(table_properties.data_size), jclazz, mid, static_cast<jlong>(table_properties.data_size),
static_cast<jlong>(table_properties.index_size), static_cast<jlong>(table_properties.index_size),
@ -6299,10 +6282,12 @@ class TablePropertiesJni : public JavaClass {
table_properties.slow_compression_estimated_data_size), table_properties.slow_compression_estimated_data_size),
static_cast<jlong>( static_cast<jlong>(
table_properties.fast_compression_estimated_data_size), table_properties.fast_compression_estimated_data_size),
static_cast<jlong>(
table_properties.external_sst_file_global_seqno_offset),
jcolumn_family_name, jfilter_policy_name, jcomparator_name, jcolumn_family_name, jfilter_policy_name, jcomparator_name,
jmerge_operator_name, jprefix_extractor_name, jmerge_operator_name, jprefix_extractor_name,
jproperty_collectors_names, jcompression_name, jproperty_collectors_names, jcompression_name,
juser_collected_properties, jreadable_properties, jproperties_offsets); juser_collected_properties, jreadable_properties);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
return nullptr; return nullptr;

@ -37,6 +37,7 @@ static TableProperties newTablePropertiesForTest() {
table_properties.file_creation_time = UINT64_MAX; table_properties.file_creation_time = UINT64_MAX;
table_properties.slow_compression_estimated_data_size = UINT64_MAX; table_properties.slow_compression_estimated_data_size = UINT64_MAX;
table_properties.fast_compression_estimated_data_size = UINT64_MAX; table_properties.fast_compression_estimated_data_size = UINT64_MAX;
table_properties.external_sst_file_global_seqno_offset = UINT64_MAX;
table_properties.db_id = "dbId"; table_properties.db_id = "dbId";
table_properties.db_session_id = "sessionId"; table_properties.db_session_id = "sessionId";
table_properties.column_family_name = "columnFamilyName"; table_properties.column_family_name = "columnFamilyName";
@ -49,7 +50,6 @@ static TableProperties newTablePropertiesForTest() {
table_properties.compression_options = "compressionOptions"; table_properties.compression_options = "compressionOptions";
table_properties.user_collected_properties = {{"key", "value"}}; table_properties.user_collected_properties = {{"key", "value"}};
table_properties.readable_properties = {{"key", "value"}}; table_properties.readable_properties = {{"key", "value"}};
table_properties.properties_offsets = {{"key", UINT64_MAX}};
return table_properties; return table_properties;
} }

@ -31,6 +31,7 @@ public class TableProperties {
private final long oldestKeyTime; private final long oldestKeyTime;
private final long slowCompressionEstimatedDataSize; private final long slowCompressionEstimatedDataSize;
private final long fastCompressionEstimatedDataSize; private final long fastCompressionEstimatedDataSize;
private final long externalSstFileGlobalSeqnoOffset;
private final byte[] columnFamilyName; private final byte[] columnFamilyName;
private final String filterPolicyName; private final String filterPolicyName;
private final String comparatorName; private final String comparatorName;
@ -40,7 +41,6 @@ public class TableProperties {
private final String compressionName; private final String compressionName;
private final Map<String, String> userCollectedProperties; private final Map<String, String> userCollectedProperties;
private final Map<String, String> readableProperties; private final Map<String, String> readableProperties;
private final Map<String, Long> propertiesOffsets;
/** /**
* Access is package private as this will only be constructed from * Access is package private as this will only be constructed from
@ -54,11 +54,11 @@ public class TableProperties {
final long formatVersion, final long fixedKeyLen, final long columnFamilyId, final long formatVersion, final long fixedKeyLen, final long columnFamilyId,
final long creationTime, final long oldestKeyTime, final long creationTime, final long oldestKeyTime,
final long slowCompressionEstimatedDataSize, final long fastCompressionEstimatedDataSize, final long slowCompressionEstimatedDataSize, final long fastCompressionEstimatedDataSize,
final byte[] columnFamilyName, final String filterPolicyName, final String comparatorName, final long externalSstFileGlobalSeqnoOffset, final byte[] columnFamilyName,
final String mergeOperatorName, final String prefixExtractorName, final String filterPolicyName, final String comparatorName, final String mergeOperatorName,
final String propertyCollectorsNames, final String compressionName, final String prefixExtractorName, final String propertyCollectorsNames,
final Map<String, String> userCollectedProperties, final String compressionName, final Map<String, String> userCollectedProperties,
final Map<String, String> readableProperties, final Map<String, Long> propertiesOffsets) { final Map<String, String> readableProperties) {
this.dataSize = dataSize; this.dataSize = dataSize;
this.indexSize = indexSize; this.indexSize = indexSize;
this.indexPartitions = indexPartitions; this.indexPartitions = indexPartitions;
@ -80,6 +80,7 @@ public class TableProperties {
this.oldestKeyTime = oldestKeyTime; this.oldestKeyTime = oldestKeyTime;
this.slowCompressionEstimatedDataSize = slowCompressionEstimatedDataSize; this.slowCompressionEstimatedDataSize = slowCompressionEstimatedDataSize;
this.fastCompressionEstimatedDataSize = fastCompressionEstimatedDataSize; this.fastCompressionEstimatedDataSize = fastCompressionEstimatedDataSize;
this.externalSstFileGlobalSeqnoOffset = externalSstFileGlobalSeqnoOffset;
this.columnFamilyName = columnFamilyName; this.columnFamilyName = columnFamilyName;
this.filterPolicyName = filterPolicyName; this.filterPolicyName = filterPolicyName;
this.comparatorName = comparatorName; this.comparatorName = comparatorName;
@ -89,7 +90,6 @@ public class TableProperties {
this.compressionName = compressionName; this.compressionName = compressionName;
this.userCollectedProperties = userCollectedProperties; this.userCollectedProperties = userCollectedProperties;
this.readableProperties = readableProperties; this.readableProperties = readableProperties;
this.propertiesOffsets = propertiesOffsets;
} }
/** /**
@ -379,15 +379,6 @@ public class TableProperties {
return readableProperties; return readableProperties;
} }
/**
* The offset of the value of each property in the file.
*
* @return the offset of each property.
*/
public Map<String, Long> getPropertiesOffsets() {
return propertiesOffsets;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) if (this == o)
@ -408,6 +399,7 @@ public class TableProperties {
&& oldestKeyTime == that.oldestKeyTime && oldestKeyTime == that.oldestKeyTime
&& slowCompressionEstimatedDataSize == that.slowCompressionEstimatedDataSize && slowCompressionEstimatedDataSize == that.slowCompressionEstimatedDataSize
&& fastCompressionEstimatedDataSize == that.fastCompressionEstimatedDataSize && fastCompressionEstimatedDataSize == that.fastCompressionEstimatedDataSize
&& externalSstFileGlobalSeqnoOffset == that.externalSstFileGlobalSeqnoOffset
&& Arrays.equals(columnFamilyName, that.columnFamilyName) && Arrays.equals(columnFamilyName, that.columnFamilyName)
&& Objects.equals(filterPolicyName, that.filterPolicyName) && Objects.equals(filterPolicyName, that.filterPolicyName)
&& Objects.equals(comparatorName, that.comparatorName) && Objects.equals(comparatorName, that.comparatorName)
@ -416,8 +408,7 @@ public class TableProperties {
&& Objects.equals(propertyCollectorsNames, that.propertyCollectorsNames) && Objects.equals(propertyCollectorsNames, that.propertyCollectorsNames)
&& Objects.equals(compressionName, that.compressionName) && Objects.equals(compressionName, that.compressionName)
&& Objects.equals(userCollectedProperties, that.userCollectedProperties) && Objects.equals(userCollectedProperties, that.userCollectedProperties)
&& Objects.equals(readableProperties, that.readableProperties) && Objects.equals(readableProperties, that.readableProperties);
&& Objects.equals(propertiesOffsets, that.propertiesOffsets);
} }
@Override @Override
@ -426,9 +417,9 @@ public class TableProperties {
indexKeyIsUserKey, indexValueIsDeltaEncoded, filterSize, rawKeySize, rawValueSize, indexKeyIsUserKey, indexValueIsDeltaEncoded, filterSize, rawKeySize, rawValueSize,
numDataBlocks, numEntries, numDeletions, numMergeOperands, numRangeDeletions, formatVersion, numDataBlocks, numEntries, numDeletions, numMergeOperands, numRangeDeletions, formatVersion,
fixedKeyLen, columnFamilyId, creationTime, oldestKeyTime, slowCompressionEstimatedDataSize, fixedKeyLen, columnFamilyId, creationTime, oldestKeyTime, slowCompressionEstimatedDataSize,
fastCompressionEstimatedDataSize, filterPolicyName, comparatorName, mergeOperatorName, fastCompressionEstimatedDataSize, externalSstFileGlobalSeqnoOffset, filterPolicyName,
prefixExtractorName, propertyCollectorsNames, compressionName, userCollectedProperties, comparatorName, mergeOperatorName, prefixExtractorName, propertyCollectorsNames,
readableProperties, propertiesOffsets); compressionName, userCollectedProperties, readableProperties);
result = 31 * result + Arrays.hashCode(columnFamilyName); result = 31 * result + Arrays.hashCode(columnFamilyName);
return result; return result;
} }

@ -238,16 +238,14 @@ public class EventListenerTest {
final Map<String, String> userCollectedPropertiesTestData = final Map<String, String> userCollectedPropertiesTestData =
Collections.singletonMap("key", "value"); Collections.singletonMap("key", "value");
final Map<String, String> readablePropertiesTestData = Collections.singletonMap("key", "value"); final Map<String, String> readablePropertiesTestData = Collections.singletonMap("key", "value");
final Map<String, Long> propertiesOffsetsTestData =
Collections.singletonMap("key", TEST_LONG_VAL);
final TableProperties tablePropertiesTestData = new TableProperties(TEST_LONG_VAL, final TableProperties tablePropertiesTestData = new TableProperties(TEST_LONG_VAL,
TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL,
TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL,
TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL,
TEST_LONG_VAL, TEST_LONG_VAL, "columnFamilyName".getBytes(), "filterPolicyName", TEST_LONG_VAL, TEST_LONG_VAL, TEST_LONG_VAL, "columnFamilyName".getBytes(),
"comparatorName", "mergeOperatorName", "prefixExtractorName", "propertyCollectorsNames", "filterPolicyName", "comparatorName", "mergeOperatorName", "prefixExtractorName",
"compressionName", userCollectedPropertiesTestData, readablePropertiesTestData, "propertyCollectorsNames", "compressionName", userCollectedPropertiesTestData,
propertiesOffsetsTestData); readablePropertiesTestData);
final FlushJobInfo flushJobInfoTestData = new FlushJobInfo(Integer.MAX_VALUE, final FlushJobInfo flushJobInfoTestData = new FlushJobInfo(Integer.MAX_VALUE,
"testColumnFamily", "/file/path", TEST_LONG_VAL, Integer.MAX_VALUE, true, true, "testColumnFamily", "/file/path", TEST_LONG_VAL, Integer.MAX_VALUE, true, true,
TEST_LONG_VAL, TEST_LONG_VAL, tablePropertiesTestData, (byte) 0x0a); TEST_LONG_VAL, TEST_LONG_VAL, tablePropertiesTestData, (byte) 0x0a);

@ -326,8 +326,10 @@ Status ReadTablePropertiesHelper(
auto raw_val = iter.value(); auto raw_val = iter.value();
auto pos = predefined_uint64_properties.find(key); auto pos = predefined_uint64_properties.find(key);
new_table_properties->properties_offsets.insert( if (key == ExternalSstFilePropertyNames::kGlobalSeqno) {
{key, handle.offset() + iter.ValueOffset()}); new_table_properties->external_sst_file_global_seqno_offset =
handle.offset() + iter.ValueOffset();
}
if (pos != predefined_uint64_properties.end()) { if (pos != predefined_uint64_properties.end()) {
if (key == TablePropertiesNames::kDeletedKeys || if (key == TablePropertiesNames::kDeletedKeys ||
@ -382,12 +384,12 @@ Status ReadTablePropertiesHelper(
s = VerifyBlockChecksum(footer.checksum(), properties_block.data(), s = VerifyBlockChecksum(footer.checksum(), properties_block.data(),
block_size, file->file_name(), handle.offset()); block_size, file->file_name(), handle.offset());
if (s.IsCorruption()) { if (s.IsCorruption()) {
const auto seqno_pos_iter = new_table_properties->properties_offsets.find( if (new_table_properties->external_sst_file_global_seqno_offset != 0) {
ExternalSstFilePropertyNames::kGlobalSeqno);
if (seqno_pos_iter != new_table_properties->properties_offsets.end()) {
std::string tmp_buf(properties_block.data(), std::string tmp_buf(properties_block.data(),
block_fetcher.GetBlockSizeWithTrailer()); block_fetcher.GetBlockSizeWithTrailer());
uint64_t global_seqno_offset = seqno_pos_iter->second - handle.offset(); uint64_t global_seqno_offset =
new_table_properties->external_sst_file_global_seqno_offset -
handle.offset();
EncodeFixed64(&tmp_buf[static_cast<size_t>(global_seqno_offset)], 0); EncodeFixed64(&tmp_buf[static_cast<size_t>(global_seqno_offset)], 0);
s = VerifyBlockChecksum(footer.checksum(), tmp_buf.data(), block_size, s = VerifyBlockChecksum(footer.checksum(), tmp_buf.data(), block_size,
file->file_name(), handle.offset()); file->file_name(), handle.offset());

@ -4490,8 +4490,7 @@ TEST_P(BlockBasedTableTest, DISABLED_TableWithGlobalSeqno) {
user_props[ExternalSstFilePropertyNames::kVersion].c_str()); user_props[ExternalSstFilePropertyNames::kVersion].c_str());
global_seqno = DecodeFixed64( global_seqno = DecodeFixed64(
user_props[ExternalSstFilePropertyNames::kGlobalSeqno].c_str()); user_props[ExternalSstFilePropertyNames::kGlobalSeqno].c_str());
global_seqno_offset = global_seqno_offset = props->external_sst_file_global_seqno_offset;
props->properties_offsets[ExternalSstFilePropertyNames::kGlobalSeqno];
}; };
// Helper function to update the value of the global seqno in the file // Helper function to update the value of the global seqno in the file

Loading…
Cancel
Save