mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-06 02:52:35 -05:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8b5e4a6b7 | ||
|
|
a59ca8d5da | ||
|
|
740240e3b1 | ||
|
|
633631ac79 | ||
|
|
e7d28965ce | ||
|
|
c1b29dfe70 | ||
|
|
a116092ee6 | ||
|
|
f90d89ea52 | ||
|
|
cf149842a2 | ||
|
|
f2d64341f5 | ||
|
|
9c7f4946bb | ||
|
|
9885ced363 | ||
|
|
cda1e40498 | ||
|
|
0c3f08008a |
No files matched your search
@@ -38,7 +38,7 @@ runs:
|
||||
$env:Path = $env:JAVA_HOME + ";" + $env:Path
|
||||
mkdir build
|
||||
cd build
|
||||
& cmake -G "$Env:CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE="$Env:CMAKE_PORTABLE" -DSNAPPY=1 -DJNI=1 ..
|
||||
& cmake -G "$Env:CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE="$Env:CMAKE_PORTABLE" -DSNAPPY=1 -DXPRESS=1 -DJNI=1 ..
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
cd ..
|
||||
echo "Building with VS version: $Env:CMAKE_GENERATOR"
|
||||
|
||||
+34
@@ -1,6 +1,40 @@
|
||||
# Rocksdb Change Log
|
||||
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
|
||||
|
||||
## 10.3.4 (06/17/2025)
|
||||
### Public API Changes
|
||||
* Change NewExternalTableFactory to return a unique_ptr instead of shared_ptr.
|
||||
|
||||
## 10.3.3 (06/04/2025)
|
||||
### Bug Fixes
|
||||
* Fix iterator operations returning NotImplemented status if disallow_memtable_writes and paranoid_memory_checks CF options are both set.
|
||||
* Fix Windows-only XPRESS compression
|
||||
* Fix newer gtest compatibility
|
||||
|
||||
## 10.3.2 (05/30/2025)
|
||||
### Behavior Changes
|
||||
* In Remote Compactions, instead of using FileSystem::GetFileSize() for each CompactionOutputFile, use the file size that is being tracked internally as part of the output file's metadata. FileSize is now part of CompactionServiceOutputFile and serialized in the CompactionServiceResult
|
||||
|
||||
## 10.3.1 (05/22/2025)
|
||||
### New Features
|
||||
* Add new experimental `TransactionOptions::large_txn_commit_optimize_byte_threshold` to enable optimizations for large transaction commit by transaction batch data size.
|
||||
|
||||
### Behavior Changes
|
||||
* `TransactionOptions::large_txn_commit_optimize_threshold` now has default value 0 for disabled. `TransactionDBOptions::txn_commit_bypass_memtable_threshold` now has no effect on transactions.
|
||||
|
||||
## 10.3.0 (05/17/2025)
|
||||
### New Features
|
||||
* Add new experimental `CompactionOptionsFIFO::allow_trivial_copy_when_change_temperature` along with `CompactionOptionsFIFO::trivial_copy_buffer_size` to allow optimizing FIFO compactions with tiering when kChangeTemperature to move files from source tier FileSystem to another tier FileSystem via trivial and direct copying raw sst file instead of reading thru the content of the SST file then rebuilding the table files.
|
||||
* Add a new field to Compaction Stats in LOG files for the pre-compression size written to each level.
|
||||
* Add new experimental `TransactionOptions::large_txn_commit_optimize_threshold` to enable optimizations for large transaction commit with per transaction threshold. `TransactionDBOptions::txn_commit_bypass_memtable_threshold` is deprecated in favor of this transaction option.
|
||||
* [internal team use only] Allow an application-defined `request_id` to be passed to RocksDB and propagated to the filesystem via IODebugContext
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a bug where transaction lock upgrade can incorrectly fail with a Deadlock status. This happens when a transaction has a non-zero timeout and tries to upgrade a shared lock that is also held by another transaction.
|
||||
* Pass wrapped WritableFileWriter pointer to ExternalTableBuilder so that the file checksum can be correctly calculated and returned by SstFileWriter for external table files.
|
||||
* Fix an infinite-loop bug in transaction locking. This can happen if a transaction reaches lock limit and its time out expires before it attempts to wait for it.
|
||||
* Fixed a potential data race with `CompressionOptions::parallel_threads > 1` and a `TablePropertiesCollector` overriding `BlockAdd()`.
|
||||
|
||||
## 10.2.0 (04/21/2025)
|
||||
### New Features
|
||||
* Provide histogram stats `COMPACTION_PREFETCH_BYTES` to measure number of bytes for RocksDB's prefetching (as opposed to file
|
||||
|
||||
@@ -118,6 +118,9 @@ fi
|
||||
# fi
|
||||
set -e
|
||||
|
||||
# Exclude third-party from formatting
|
||||
EXCLUDE=':!third-party/'
|
||||
|
||||
uncommitted_code=`git diff HEAD`
|
||||
|
||||
# If there's no uncommitted changes, we assume user are doing post-commit
|
||||
@@ -137,11 +140,11 @@ then
|
||||
# should be relevant for formatting fixes.
|
||||
FORMAT_UPSTREAM_MERGE_BASE="$(git merge-base "$FORMAT_UPSTREAM" HEAD)"
|
||||
# Get the differences
|
||||
diffs=$(git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -p 1) || true
|
||||
diffs=$(git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" -- $EXCLUDE | $CLANG_FORMAT_DIFF -p 1) || true
|
||||
echo "Checking format of changes not yet in $FORMAT_UPSTREAM..."
|
||||
else
|
||||
# Check the format of uncommitted lines,
|
||||
diffs=$(git diff -U0 HEAD | $CLANG_FORMAT_DIFF -p 1) || true
|
||||
diffs=$(git diff -U0 HEAD -- $EXCLUDE | $CLANG_FORMAT_DIFF -p 1) || true
|
||||
echo "Checking format of uncommitted changes..."
|
||||
fi
|
||||
|
||||
@@ -187,9 +190,9 @@ fi
|
||||
# Do in-place format adjustment.
|
||||
if [ -z "$uncommitted_code" ]
|
||||
then
|
||||
git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -i -p 1
|
||||
git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" -- $EXCLUDE | $CLANG_FORMAT_DIFF -i -p 1
|
||||
else
|
||||
git diff -U0 HEAD | $CLANG_FORMAT_DIFF -i -p 1
|
||||
git diff -U0 HEAD -- $EXCLUDE | $CLANG_FORMAT_DIFF -i -p 1
|
||||
fi
|
||||
echo "Files reformatted!"
|
||||
|
||||
|
||||
@@ -427,8 +427,9 @@ struct CompactionServiceInput {
|
||||
// CompactionServiceOutputFile is the metadata for the output SST file
|
||||
struct CompactionServiceOutputFile {
|
||||
std::string file_name;
|
||||
SequenceNumber smallest_seqno;
|
||||
SequenceNumber largest_seqno;
|
||||
uint64_t file_size{};
|
||||
SequenceNumber smallest_seqno{};
|
||||
SequenceNumber largest_seqno{};
|
||||
std::string smallest_internal_key;
|
||||
std::string largest_internal_key;
|
||||
uint64_t oldest_ancester_time = kUnknownOldestAncesterTime;
|
||||
@@ -436,24 +437,26 @@ struct CompactionServiceOutputFile {
|
||||
uint64_t epoch_number = kUnknownEpochNumber;
|
||||
std::string file_checksum = kUnknownFileChecksum;
|
||||
std::string file_checksum_func_name = kUnknownFileChecksumFuncName;
|
||||
uint64_t paranoid_hash;
|
||||
uint64_t paranoid_hash{};
|
||||
bool marked_for_compaction;
|
||||
UniqueId64x2 unique_id{};
|
||||
TableProperties table_properties;
|
||||
bool is_proximal_level_output;
|
||||
Temperature file_temperature;
|
||||
Temperature file_temperature = Temperature::kUnknown;
|
||||
|
||||
CompactionServiceOutputFile() = default;
|
||||
CompactionServiceOutputFile(
|
||||
const std::string& name, SequenceNumber smallest, SequenceNumber largest,
|
||||
std::string _smallest_internal_key, std::string _largest_internal_key,
|
||||
uint64_t _oldest_ancester_time, uint64_t _file_creation_time,
|
||||
uint64_t _epoch_number, const std::string& _file_checksum,
|
||||
const std::string& name, uint64_t size, SequenceNumber smallest,
|
||||
SequenceNumber largest, std::string _smallest_internal_key,
|
||||
std::string _largest_internal_key, uint64_t _oldest_ancester_time,
|
||||
uint64_t _file_creation_time, uint64_t _epoch_number,
|
||||
const std::string& _file_checksum,
|
||||
const std::string& _file_checksum_func_name, uint64_t _paranoid_hash,
|
||||
bool _marked_for_compaction, UniqueId64x2 _unique_id,
|
||||
const TableProperties& _table_properties, bool _is_proximal_level_output,
|
||||
Temperature _file_temperature)
|
||||
: file_name(name),
|
||||
file_size(size),
|
||||
smallest_seqno(smallest),
|
||||
largest_seqno(largest),
|
||||
smallest_internal_key(std::move(_smallest_internal_key)),
|
||||
|
||||
@@ -1669,6 +1669,7 @@ TEST_F(CompactionJobTest, ResultSerialization) {
|
||||
UniqueId64x2 id{rnd64.Uniform(UINT64_MAX), rnd64.Uniform(UINT64_MAX)};
|
||||
result.output_files.emplace_back(
|
||||
rnd.RandomString(rnd.Uniform(kStrMaxLen)) /* file_name */,
|
||||
rnd64.Uniform(UINT64_MAX) /* file_size */,
|
||||
rnd64.Uniform(UINT64_MAX) /* smallest_seqno */,
|
||||
rnd64.Uniform(UINT64_MAX) /* largest_seqno */,
|
||||
rnd.RandomBinaryString(
|
||||
|
||||
@@ -221,18 +221,24 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
}
|
||||
|
||||
FileMetaData meta;
|
||||
uint64_t file_size;
|
||||
// FIXME: file_size should be part of CompactionServiceOutputFile so that
|
||||
// we don't get DB corruption if the full file size has not been propagated
|
||||
// back to the caller through the file system (which could have metadata
|
||||
// lag or caching bugs).
|
||||
s = fs_->GetFileSize(tgt_file, IOOptions(), &file_size, nullptr);
|
||||
uint64_t file_size = file.file_size;
|
||||
|
||||
// TODO - Clean this up in the next release.
|
||||
// For backward compatibility - in case the remote worker does not populate
|
||||
// the file_size yet. If missing, continue to populate this from the file
|
||||
// system.
|
||||
if (file_size == 0) {
|
||||
s = fs_->GetFileSize(tgt_file, IOOptions(), &file_size, nullptr);
|
||||
}
|
||||
|
||||
if (!s.ok()) {
|
||||
sub_compact->status = s;
|
||||
db_options_.compaction_service->OnInstallation(
|
||||
response.scheduled_job_id, CompactionServiceJobStatus::kFailure);
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
}
|
||||
assert(file_size > 0);
|
||||
|
||||
meta.fd = FileDescriptor(file_num, compaction->output_path_id(), file_size,
|
||||
file.smallest_seqno, file.largest_seqno);
|
||||
meta.smallest.DecodeFrom(file.smallest_internal_key);
|
||||
@@ -421,14 +427,14 @@ Status CompactionServiceCompactionJob::Run() {
|
||||
for (const auto& output_file : sub_compact->GetOutputs()) {
|
||||
auto& meta = output_file.meta;
|
||||
compaction_result_->output_files.emplace_back(
|
||||
MakeTableFileName(meta.fd.GetNumber()), meta.fd.smallest_seqno,
|
||||
meta.fd.largest_seqno, meta.smallest.Encode().ToString(),
|
||||
meta.largest.Encode().ToString(), meta.oldest_ancester_time,
|
||||
meta.file_creation_time, meta.epoch_number, meta.file_checksum,
|
||||
meta.file_checksum_func_name, output_file.validator.GetHash(),
|
||||
meta.marked_for_compaction, meta.unique_id,
|
||||
*output_file.table_properties, output_file.is_proximal_level,
|
||||
meta.temperature);
|
||||
MakeTableFileName(meta.fd.GetNumber()), meta.fd.GetFileSize(),
|
||||
meta.fd.smallest_seqno, meta.fd.largest_seqno,
|
||||
meta.smallest.Encode().ToString(), meta.largest.Encode().ToString(),
|
||||
meta.oldest_ancester_time, meta.file_creation_time, meta.epoch_number,
|
||||
meta.file_checksum, meta.file_checksum_func_name,
|
||||
output_file.validator.GetHash(), meta.marked_for_compaction,
|
||||
meta.unique_id, *output_file.table_properties,
|
||||
output_file.is_proximal_level, meta.temperature);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,6 +534,10 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
{offsetof(struct CompactionServiceOutputFile, file_name),
|
||||
OptionType::kEncodedString, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"file_size",
|
||||
{offsetof(struct CompactionServiceOutputFile, file_size),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"smallest_seqno",
|
||||
{offsetof(struct CompactionServiceOutputFile, smallest_seqno),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
||||
|
||||
@@ -5086,6 +5086,7 @@ TEST_F(DBBasicTest, DisallowMemtableWrite) {
|
||||
options_allow.create_if_missing = true;
|
||||
Options options_disallow = options_allow;
|
||||
options_disallow.disallow_memtable_writes = true;
|
||||
options_disallow.paranoid_memory_checks = true;
|
||||
|
||||
DestroyAndReopen(options_allow);
|
||||
// CFs allowing and disallowing memtable write
|
||||
@@ -5125,6 +5126,11 @@ TEST_F(DBBasicTest, DisallowMemtableWrite) {
|
||||
EXPECT_EQ(Get(2, "b2"), "2");
|
||||
EXPECT_EQ(Get(3, "b3"), "NOT_FOUND");
|
||||
|
||||
std::unique_ptr<Iterator> iter(
|
||||
dbfull()->NewIterator(ReadOptions(), handles_[3]));
|
||||
iter->Seek("a3");
|
||||
ASSERT_OK(iter->status());
|
||||
iter.reset();
|
||||
// When the DB is re-opened with WAL entries for a CF that is newly setting
|
||||
// disallow_memtable_writes, we detect that and fail the open gracefully.
|
||||
ASSERT_EQ(TryReopenWithColumnFamilies(
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/testutil.h"
|
||||
|
||||
@@ -849,9 +849,15 @@ Status StressTest::NewTxn(WriteOptions& write_opts, ThreadState* thread,
|
||||
assert(FLAGS_user_timestamp_size == 0);
|
||||
if (thread->rand.OneIn(2)) {
|
||||
txn_options.commit_bypass_memtable = true;
|
||||
} else {
|
||||
}
|
||||
if (thread->rand.OneIn(2)) {
|
||||
txn_options.large_txn_commit_optimize_threshold = 1;
|
||||
}
|
||||
if (thread->rand.OneIn(2) ||
|
||||
(!txn_options.commit_bypass_memtable &&
|
||||
txn_options.large_txn_commit_optimize_threshold != 1)) {
|
||||
txn_options.large_txn_commit_optimize_byte_threshold = 1;
|
||||
}
|
||||
if (commit_bypass_memtable) {
|
||||
*commit_bypass_memtable = txn_options.commit_bypass_memtable;
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ class ExternalTableFactory : public Customizable {
|
||||
|
||||
// Allocate a TableFactory that wraps around an ExternalTableFactory. Use this
|
||||
// to allocate and set in ColumnFamilyOptions::table_factory.
|
||||
std::shared_ptr<TableFactory> NewExternalTableFactory(
|
||||
std::unique_ptr<TableFactory> NewExternalTableFactory(
|
||||
std::shared_ptr<ExternalTableFactory> inner_factory);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -254,7 +254,7 @@ struct TransactionDBOptions {
|
||||
// for more details.
|
||||
std::vector<std::shared_ptr<SecondaryIndex>> secondary_indices;
|
||||
|
||||
// Deprecated, this option may be removed in the future.
|
||||
// Deprecated, this option has no effect and may be removed in the future.
|
||||
// Use TransactionOptions::large_txn_commit_optimize_threshold instead.
|
||||
//
|
||||
// This option is only valid for write committed. If the number of updates in
|
||||
@@ -366,6 +366,22 @@ struct TransactionOptions {
|
||||
// DeleteRange, SingleDelete.
|
||||
bool write_batch_track_timestamp_size = false;
|
||||
|
||||
// The following three options enable optimizations for large transaction
|
||||
// commit to bypass memtable write.
|
||||
// - If any transaction's commit should bybass memtable write,
|
||||
// set commit_bypass_memtable to true.
|
||||
// - If only bypass memtable write for transactions with >= n operations,
|
||||
// set commit_bypass_memtable to false,
|
||||
// large_txn_commit_optimize_threshold to n, and
|
||||
// large_txn_commit_optimize_byte_threshold to 0.
|
||||
// Similarly for only optimize when a transaction's write batch size is >= n.
|
||||
// - If bypass memtable write for transactions with >= n operations or >= x
|
||||
// bytes,
|
||||
// set commit_bypass_memtable to false,
|
||||
// large_txn_commit_optimize_threshold to n, and
|
||||
// large_txn_commit_optimize_byte_threshold to x.
|
||||
//
|
||||
//
|
||||
// EXPERIMENTAL, SUBJECT TO CHANGE
|
||||
// Only supports write-committed policy. If set to true, the transaction will
|
||||
// skip memtable write and ingest into the DB directly during Commit(). This
|
||||
@@ -394,8 +410,17 @@ struct TransactionOptions {
|
||||
// When the number of updates in a transaction is at least this threshold,
|
||||
// we will enable optimizations for commiting a large transaction. See
|
||||
// comment for `commit_bypass_memtable` for more optimization detail.
|
||||
uint32_t large_txn_commit_optimize_threshold =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
//
|
||||
// Default: 0 (disabled).
|
||||
uint32_t large_txn_commit_optimize_threshold = 0;
|
||||
|
||||
// EXPERIMENTAL, SUBJECT TO CHANGE
|
||||
// When the size of a transaction's write batch is at least this threshold,
|
||||
// we will enable optimizations for commiting a large transaction. See
|
||||
// comment for `commit_bypass_memtable` for more optimization detail.
|
||||
//
|
||||
// Default: 0 (disabled).
|
||||
uint64_t large_txn_commit_optimize_byte_threshold = 0;
|
||||
};
|
||||
|
||||
// The per-write optimizations that do not involve transactions. TransactionDB
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// minor or major version number planned for release.
|
||||
#define ROCKSDB_MAJOR 10
|
||||
#define ROCKSDB_MINOR 3
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_PATCH 4
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
@@ -79,6 +79,10 @@ class VectorRep : public MemTableRep {
|
||||
// Advance to the first entry with a key >= target
|
||||
void Seek(const Slice& user_key, const char* memtable_key) override;
|
||||
|
||||
// Seek and do some memory validation
|
||||
Status SeekAndValidate(const Slice& internal_key, const char* memtable_key,
|
||||
bool allow_data_in_errors) override;
|
||||
|
||||
// Advance to the first entry with a key <= target
|
||||
void SeekForPrev(const Slice& user_key, const char* memtable_key) override;
|
||||
|
||||
@@ -221,6 +225,22 @@ void VectorRep::Iterator::Seek(const Slice& user_key,
|
||||
.first;
|
||||
}
|
||||
|
||||
Status VectorRep::Iterator::SeekAndValidate(const Slice& /* internal_key */,
|
||||
const char* /* memtable_key */,
|
||||
bool /* allow_data_in_errors */) {
|
||||
if (vrep_) {
|
||||
WriteLock l(&vrep_->rwlock_);
|
||||
if (bucket_->begin() == bucket_->end()) {
|
||||
// Memtable is empty
|
||||
return Status::OK();
|
||||
} else {
|
||||
return Status::NotSupported("SeekAndValidate() not implemented");
|
||||
}
|
||||
} else {
|
||||
return Status::NotSupported("SeekAndValidate() not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
// Advance to the first entry with a key <= target
|
||||
void VectorRep::Iterator::SeekForPrev(const Slice& /*user_key*/,
|
||||
const char* /*memtable_key*/) {
|
||||
|
||||
@@ -202,11 +202,69 @@ char* Decompress(const char* input_data, size_t input_length,
|
||||
return outputBuffer.release();
|
||||
}
|
||||
|
||||
int64_t GetDecompressedSize(const char* input_data, size_t input_length) {
|
||||
assert(input_data != nullptr);
|
||||
|
||||
if (input_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
|
||||
|
||||
DECOMPRESSOR_HANDLE decompressor = NULL;
|
||||
|
||||
BOOL success =
|
||||
CreateDecompressor(COMPRESS_ALGORITHM_XPRESS, // Compression Algorithm
|
||||
allocRoutinesPtr, // Optional allocation routine
|
||||
&decompressor); // Handle
|
||||
|
||||
if (!success) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "XPRESS: Failed to create Decompressor LastError "
|
||||
<< GetLastError() << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::unique_ptr<void, decltype(CloseDecompressorFun)> decompressorGuard(
|
||||
decompressor, CloseDecompressorFun);
|
||||
|
||||
SIZE_T decompressedBufferSize = 0;
|
||||
|
||||
success = ::Decompress(decompressor, // Compressor Handle
|
||||
const_cast<char*>(input_data), // Compressed data
|
||||
input_length, // Compressed data size
|
||||
NULL, // Buffer set to NULL
|
||||
0, // Buffer size set to 0
|
||||
&decompressedBufferSize); // Decompressed Data size
|
||||
|
||||
assert(!success);
|
||||
auto lastError = GetLastError();
|
||||
|
||||
if (lastError != ERROR_INSUFFICIENT_BUFFER) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr
|
||||
<< "XPRESS: Failed to estimate decompressed buffer size LastError "
|
||||
<< lastError << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(decompressedBufferSize > 0);
|
||||
return static_cast<int64_t>(decompressedBufferSize);
|
||||
}
|
||||
|
||||
int64_t DecompressToBuffer(const char* input, size_t input_length, char* output,
|
||||
size_t output_length) {
|
||||
assert(input != nullptr);
|
||||
assert(output != nullptr);
|
||||
|
||||
if (input_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPRESS_ALLOCATION_ROUTINES* allocRoutinesPtr = nullptr;
|
||||
|
||||
DECOMPRESSOR_HANDLE decompressor = NULL;
|
||||
|
||||
BOOL success =
|
||||
|
||||
@@ -22,6 +22,8 @@ bool Compress(const char* input, size_t length, std::string* output);
|
||||
char* Decompress(const char* input_data, size_t input_length,
|
||||
size_t* uncompressed_size);
|
||||
|
||||
int64_t GetDecompressedSize(const char* input, size_t input_length);
|
||||
|
||||
int64_t DecompressToBuffer(const char* input, size_t input_length, char* output,
|
||||
size_t output_length);
|
||||
|
||||
|
||||
@@ -709,6 +709,13 @@ Status BlockBasedTable::Open(
|
||||
rep->file = std::move(file);
|
||||
rep->footer = footer;
|
||||
|
||||
// Some ancient versions (~2.5 - 2.7, format_version=1) could compress the
|
||||
// metaindex block, so we need to allow for that
|
||||
if (footer.format_version() < 2) {
|
||||
auto mgr = GetBuiltinCompressionManager(/*compression_format_version=*/1);
|
||||
rep->decompressor = mgr->GetDecompressor();
|
||||
}
|
||||
|
||||
// For fully portable/stable cache keys, we need to read the properties
|
||||
// block before setting up cache keys. TODO: consider setting up a bootstrap
|
||||
// cache key for PersistentCache to use for metaindex and properties blocks.
|
||||
@@ -743,6 +750,9 @@ Status BlockBasedTable::Open(
|
||||
rep->table_properties ? rep->table_properties->compression_name
|
||||
: std::string{});
|
||||
if (saved_comp_type != kNoCompression) {
|
||||
// Includes "unrecognized" or "unspecified" case, including some old files
|
||||
// before the compression_name table property was introduced in
|
||||
// version 4.9.0
|
||||
// TODO: custom CompressionManager
|
||||
auto mgr = GetBuiltinCompressionManager(
|
||||
GetCompressFormatForVersion(footer.format_version()));
|
||||
|
||||
@@ -473,10 +473,10 @@ class ExternalTableFactoryAdapter : public TableFactory {
|
||||
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<TableFactory> NewExternalTableFactory(
|
||||
std::unique_ptr<TableFactory> NewExternalTableFactory(
|
||||
std::shared_ptr<ExternalTableFactory> inner_factory) {
|
||||
std::shared_ptr<TableFactory> res;
|
||||
res.reset(new ExternalTableFactoryAdapter(std::move(inner_factory)));
|
||||
std::unique_ptr<TableFactory> res;
|
||||
res = std::make_unique<ExternalTableFactoryAdapter>(std::move(inner_factory));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
@@ -477,6 +477,38 @@ GTEST_DECLARE_bool_(death_test_use_fork);
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename RawType>
|
||||
AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
|
||||
const char* rhs_expression,
|
||||
RawType lhs_value, RawType rhs_value) {
|
||||
const FloatingPoint<RawType> lhs(lhs_value), rhs(rhs_value);
|
||||
|
||||
if (lhs.AlmostEquals(rhs)) {
|
||||
return AssertionSuccess();
|
||||
}
|
||||
|
||||
::std::stringstream lhs_ss;
|
||||
lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
|
||||
<< lhs_value;
|
||||
|
||||
::std::stringstream rhs_ss;
|
||||
rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
|
||||
<< rhs_value;
|
||||
|
||||
return EqFailure(lhs_expression, rhs_expression,
|
||||
StringStreamToString(&lhs_ss), StringStreamToString(&rhs_ss),
|
||||
false);
|
||||
}
|
||||
|
||||
template
|
||||
AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
|
||||
const char* rhs_expression,
|
||||
float lhs_value, float rhs_value);
|
||||
template
|
||||
AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
|
||||
const char* rhs_expression,
|
||||
double lhs_value, double rhs_value);
|
||||
|
||||
// The value of GetTestTypeId() as seen from within the Google Test
|
||||
// library. This is solely for testing GetTestTypeId().
|
||||
GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
|
||||
|
||||
+2
-22
@@ -3973,7 +3973,7 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val);
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include <iomanip>
|
||||
// #include <iomanip> // Not included in newer versions of gtest
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -21451,27 +21451,7 @@ template <typename RawType>
|
||||
AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
|
||||
const char* rhs_expression,
|
||||
RawType lhs_value,
|
||||
RawType rhs_value) {
|
||||
const FloatingPoint<RawType> lhs(lhs_value), rhs(rhs_value);
|
||||
|
||||
if (lhs.AlmostEquals(rhs)) {
|
||||
return AssertionSuccess();
|
||||
}
|
||||
|
||||
::std::stringstream lhs_ss;
|
||||
lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
|
||||
<< lhs_value;
|
||||
|
||||
::std::stringstream rhs_ss;
|
||||
rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
|
||||
<< rhs_value;
|
||||
|
||||
return EqFailure(lhs_expression,
|
||||
rhs_expression,
|
||||
StringStreamToString(&lhs_ss),
|
||||
StringStreamToString(&rhs_ss),
|
||||
false);
|
||||
}
|
||||
RawType rhs_value);
|
||||
|
||||
// Helper function for implementing ASSERT_NEAR.
|
||||
//
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "rocksdb/utilities/ldb_cmd.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <iomanip>
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "db/version_edit.h"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
* Fix a bug where transaction lock upgrade can incorrectly fail with a Deadlock status. This happens when a transaction has a non-zero timeout and tries to upgrade a shared lock that is also held by another transaction.
|
||||
@@ -1 +0,0 @@
|
||||
Pass wrapped WritableFileWriter pointer to ExternalTableBuilder so that the file checksum can be correctly calculated and returned by SstFileWriter for external table files.
|
||||
@@ -1 +0,0 @@
|
||||
* Fix an infinite-loop bug in transaction locking. This can happen if a transaction reaches lock limit and its time out expires before it attempts to wait for it.
|
||||
@@ -1 +0,0 @@
|
||||
* Fixed a potential data race with `CompressionOptions::parallel_threads > 1` and a `TablePropertiesCollector` overriding `BlockAdd()`.
|
||||
@@ -1 +0,0 @@
|
||||
* Add new experimental `CompactionOptionsFIFO::allow_trivial_copy_when_change_temperature` along with `CompactionOptionsFIFO::trivial_copy_buffer_size` to allow optimizing FIFO compactions with tiering when kChangeTemperature to move files from source tier FileSystem to another tier FileSystem via trivial and direct copying raw sst file instead of reading thru the content of the SST file then rebuilding the table files.
|
||||
@@ -1 +0,0 @@
|
||||
* Add a new field to Compaction Stats in LOG files for the pre-compression size written to each level.
|
||||
@@ -1 +0,0 @@
|
||||
* Add new experimental `TransactionOptions::large_txn_commit_optimize_threshold` to enable optimizations for large transaction commit with per transaction threshold. `TransactionDBOptions::txn_commit_bypass_memtable_threshold` is deprecated in favor of this transaction option.
|
||||
@@ -1,2 +0,0 @@
|
||||
[internal team use only]
|
||||
allow an application-defined request_id to be passed to RocksDB and propagated to the filesystem via IODebugContext
|
||||
+15
-1
@@ -590,7 +590,7 @@ class BuiltinDecompressorV2 : public Decompressor {
|
||||
Status ExtractUncompressedSize(Args& args) override {
|
||||
assert(args.compression_type != kNoCompression);
|
||||
if (args.compression_type == kSnappyCompression) {
|
||||
// Exception to encoding of uncompressed size
|
||||
// 1st exception to encoding of uncompressed size
|
||||
#ifdef SNAPPY
|
||||
size_t uncompressed_length = 0;
|
||||
if (!snappy::GetUncompressedLength(args.compressed_data.data(),
|
||||
@@ -603,6 +603,20 @@ class BuiltinDecompressorV2 : public Decompressor {
|
||||
#else
|
||||
return Status::NotSupported("Snappy not supported in this build");
|
||||
#endif
|
||||
} else if (args.compression_type == kXpressCompression) {
|
||||
// 2nd exception to encoding of uncompressed size
|
||||
#ifdef XPRESS
|
||||
int64_t result = port::xpress::GetDecompressedSize(
|
||||
args.compressed_data.data(), args.compressed_data.size());
|
||||
if (result < 0) {
|
||||
return Status::Corruption("Error reading XPRESS compressed length");
|
||||
}
|
||||
args.uncompressed_size = static_cast<size_t>(result);
|
||||
return Status::OK();
|
||||
#else
|
||||
return Status::NotSupported("XPRESS not supported in this build");
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// Extract encoded uncompressed size
|
||||
return Decompressor::ExtractUncompressedSize(args);
|
||||
|
||||
+2
-1
@@ -1260,7 +1260,8 @@ inline std::string CompressionOptionsToString(
|
||||
// block. Also, decompressed sizes for LZ4 are encoded in platform-dependent
|
||||
// way.
|
||||
// 2 -- Zlib, BZip2 and LZ4 encode decompressed size as Varint32 just before the
|
||||
// start of compressed block. Snappy format is the same as version 1.
|
||||
// start of compressed block. Snappy and XPRESS instead extract the decompressed
|
||||
// size from the compressed block itself, same as version 1.
|
||||
|
||||
inline bool Snappy_Compress(const CompressionInfo& /*info*/, const char* input,
|
||||
size_t length, ::std::string* output) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
|
||||
@@ -107,14 +107,13 @@ void PessimisticTransaction::Initialize(const TransactionOptions& txn_options) {
|
||||
if (txn_options.commit_bypass_memtable) {
|
||||
// No need to optimize for empty transction
|
||||
commit_bypass_memtable_threshold_ = 1;
|
||||
} else if (txn_options.large_txn_commit_optimize_threshold !=
|
||||
std::numeric_limits<uint32_t>::max()) {
|
||||
commit_bypass_memtable_threshold_ =
|
||||
txn_options.large_txn_commit_optimize_threshold;
|
||||
} else {
|
||||
commit_bypass_memtable_threshold_ =
|
||||
db_options.txn_commit_bypass_memtable_threshold;
|
||||
txn_options.large_txn_commit_optimize_threshold;
|
||||
}
|
||||
|
||||
commit_bypass_memtable_byte_threshold_ =
|
||||
txn_options.large_txn_commit_optimize_byte_threshold;
|
||||
}
|
||||
|
||||
PessimisticTransaction::~PessimisticTransaction() {
|
||||
@@ -855,8 +854,8 @@ Status WriteCommittedTxn::CommitInternal() {
|
||||
if (!needs_ts) {
|
||||
s = WriteBatchInternal::MarkCommit(working_batch, name_);
|
||||
} else {
|
||||
assert(commit_bypass_memtable_threshold_ ==
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
assert(!commit_bypass_memtable_threshold_);
|
||||
assert(!commit_bypass_memtable_byte_threshold_);
|
||||
assert(commit_timestamp_ != kMaxTxnTimestamp);
|
||||
char commit_ts_buf[sizeof(kMaxTxnTimestamp)];
|
||||
EncodeFixed64(commit_ts_buf, commit_timestamp_);
|
||||
@@ -895,7 +894,16 @@ Status WriteCommittedTxn::CommitInternal() {
|
||||
uint32_t wb_count = wb->Count();
|
||||
RecordInHistogram(db_impl_->immutable_db_options_.stats,
|
||||
NUM_OP_PER_TRANSACTION, wb_count);
|
||||
bool bypass_memtable = wb_count >= commit_bypass_memtable_threshold_;
|
||||
bool bypass_memtable = false;
|
||||
if (!needs_ts) {
|
||||
if (commit_bypass_memtable_threshold_ &&
|
||||
wb_count >= commit_bypass_memtable_threshold_) {
|
||||
bypass_memtable = true;
|
||||
} else if (commit_bypass_memtable_byte_threshold_ &&
|
||||
wb->GetDataSize() >= commit_bypass_memtable_byte_threshold_) {
|
||||
bypass_memtable = true;
|
||||
}
|
||||
}
|
||||
if (!bypass_memtable) {
|
||||
// insert prepared batch into Memtable only skipping WAL.
|
||||
// Memtable will ignore BeginPrepare/EndPrepare markers
|
||||
|
||||
@@ -166,10 +166,11 @@ class PessimisticTransaction : public TransactionBaseImpl {
|
||||
// Refer to
|
||||
// TransactionOptions::skip_prepare
|
||||
bool skip_prepare_ = false;
|
||||
// Refer to
|
||||
// TransactionOptions::commit_bypass_memtable
|
||||
// Refer to TransactionOptions::commit_bypass_memtable
|
||||
uint32_t commit_bypass_memtable_threshold_ =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
uint64_t commit_bypass_memtable_byte_threshold_ =
|
||||
std::numeric_limits<uint64_t>::max();
|
||||
|
||||
private:
|
||||
friend class TransactionTest_ValidateSnapshotTest_Test;
|
||||
|
||||
@@ -8959,7 +8959,6 @@ class CommitBypassMemtableTest : public DBTestBase,
|
||||
TransactionDBOptions txn_db_opts;
|
||||
|
||||
void SetUpTransactionDB(
|
||||
uint32_t threshold = std::numeric_limits<uint32_t>::max(),
|
||||
bool atomic_flush = false) {
|
||||
options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -8973,7 +8972,6 @@ class CommitBypassMemtableTest : public DBTestBase,
|
||||
Destroy(options, true);
|
||||
|
||||
txn_db_opts.write_policy = TxnDBWritePolicy::WRITE_COMMITTED;
|
||||
txn_db_opts.txn_commit_bypass_memtable_threshold = threshold;
|
||||
ASSERT_OK(TransactionDB::Open(options, txn_db_opts, dbname_, &txn_db));
|
||||
ASSERT_NE(txn_db, nullptr);
|
||||
db_ = txn_db;
|
||||
@@ -9429,10 +9427,10 @@ TEST_P(CommitBypassMemtableTest, Recovery) {
|
||||
VerifyDBFromMap(expected);
|
||||
}
|
||||
|
||||
TEST_P(CommitBypassMemtableTest, ThresholdTxnDBOption) {
|
||||
// Tests TransactionDBOptions::txn_commit_bypass_memtable_threshold
|
||||
TEST_P(CommitBypassMemtableTest, OptimizeLargeTxnCommitThreshold) {
|
||||
// Tests TransactionOptions::large_txn_commit_optimize_threshold
|
||||
const uint32_t threshold = 10;
|
||||
SetUpTransactionDB(/*threshold=*/threshold);
|
||||
SetUpTransactionDB();
|
||||
bool commit_bypass_memtable = false;
|
||||
// TODO: add and use stats for this
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
@@ -9440,73 +9438,25 @@ TEST_P(CommitBypassMemtableTest, ThresholdTxnDBOption) {
|
||||
[&](void* arg) { commit_bypass_memtable = *(static_cast<bool*>(arg)); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// TransactionOptions::commit_bypass_memtable takes precedence
|
||||
WriteOptions wopts;
|
||||
// Test default (disabled)
|
||||
TransactionOptions txn_opts;
|
||||
txn_opts.commit_bypass_memtable = true;
|
||||
Transaction* txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn1->SetName("xid1"));
|
||||
ASSERT_OK(txn1->Put("k2", "v2"));
|
||||
ASSERT_OK(txn1->Put("k1", "v1"));
|
||||
auto txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn1->SetName("xid0"));
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
ASSERT_OK(
|
||||
txn1->Put("key" + std::to_string(i), "value" + std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(txn1->Prepare());
|
||||
ASSERT_OK(txn1->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
// Test threshold behavior
|
||||
for (auto num_ops : {threshold - 1, threshold}) {
|
||||
commit_bypass_memtable = false;
|
||||
txn_opts.commit_bypass_memtable = false;
|
||||
auto txn = txn_db->BeginTransaction(wopts, txn_opts, txn1);
|
||||
txn1 = nullptr;
|
||||
ASSERT_OK(txn->SetName("xid" + std::to_string(num_ops)));
|
||||
for (uint32_t i = 0; i < num_ops; ++i) {
|
||||
ASSERT_OK(
|
||||
txn->Put("key" + std::to_string(i), "value" + std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_EQ(commit_bypass_memtable, num_ops >= threshold);
|
||||
delete txn;
|
||||
}
|
||||
|
||||
// Repeat the same test with updates to two CFs
|
||||
std::vector<std::string> cfs = {"pk", "sk"};
|
||||
CreateColumnFamilies(cfs, options);
|
||||
|
||||
// Test threshold behavior with CFs
|
||||
for (auto num_ops : {threshold - 1, threshold}) {
|
||||
commit_bypass_memtable = false;
|
||||
txn_opts.commit_bypass_memtable = false;
|
||||
auto txn_cf = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn_cf->SetName("xid_cf" + std::to_string(num_ops)));
|
||||
for (uint32_t i = 0; i < num_ops; ++i) {
|
||||
ASSERT_OK(txn_cf->Put(handles_[i % 2], "key" + std::to_string(i),
|
||||
"value" + std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(txn_cf->Prepare());
|
||||
ASSERT_OK(txn_cf->Commit());
|
||||
ASSERT_EQ(commit_bypass_memtable, num_ops >= threshold);
|
||||
delete txn_cf;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(CommitBypassMemtableTest, OptimizeLargeTxnCommitThreshold) {
|
||||
// Tests TransactionOptions::large_txn_commit_optimize_threshold
|
||||
const uint32_t threshold = 10;
|
||||
SetUpTransactionDB();
|
||||
bool commit_bypass_memtable = false;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteCommittedTxn::CommitInternal:bypass_memtable",
|
||||
[&](void* arg) { commit_bypass_memtable = *(static_cast<bool*>(arg)); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
delete txn1;
|
||||
|
||||
// Test with transaction option only
|
||||
WriteOptions wopts;
|
||||
TransactionOptions txn_opts;
|
||||
txn_opts.large_txn_commit_optimize_threshold = threshold;
|
||||
|
||||
// Test with transaction below threshold
|
||||
auto txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn1->SetName("xid1"));
|
||||
ASSERT_OK(txn1->Put("k1", "v1"));
|
||||
ASSERT_OK(txn1->Prepare());
|
||||
@@ -9526,38 +9476,6 @@ TEST_P(CommitBypassMemtableTest, OptimizeLargeTxnCommitThreshold) {
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
delete txn1;
|
||||
|
||||
// Test with both DB option and transaction option - transaction option should
|
||||
// take precedence
|
||||
SetUpTransactionDB(/*threshold=*/threshold * 2);
|
||||
|
||||
// Transaction option is lower than DB option, should use transaction option
|
||||
txn_opts.large_txn_commit_optimize_threshold = threshold;
|
||||
txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn1->SetName("xid3"));
|
||||
for (uint32_t i = 0; i < threshold; ++i) {
|
||||
ASSERT_OK(
|
||||
txn1->Put("key" + std::to_string(i), "value" + std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(txn1->Prepare());
|
||||
commit_bypass_memtable = false;
|
||||
ASSERT_OK(txn1->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
delete txn1;
|
||||
|
||||
// Transaction option is higher than DB option, should use transaction option
|
||||
txn_opts.large_txn_commit_optimize_threshold = threshold * 3;
|
||||
txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn1->SetName("xid4"));
|
||||
for (uint32_t i = 0; i < threshold * 3 - 1; ++i) {
|
||||
ASSERT_OK(
|
||||
txn1->Put("key" + std::to_string(i), "value" + std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(txn1->Prepare());
|
||||
commit_bypass_memtable = false;
|
||||
ASSERT_OK(txn1->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
delete txn1;
|
||||
|
||||
SetUpTransactionDB();
|
||||
// Test with multiple column families
|
||||
std::vector<std::string> cfs = {"pk", "sk"};
|
||||
@@ -9610,7 +9528,7 @@ TEST_P(CommitBypassMemtableTest, OptimizeLargeTxnCommitThreshold) {
|
||||
|
||||
TEST_P(CommitBypassMemtableTest, AtomicFlushTest) {
|
||||
const uint32_t threshold = 10;
|
||||
SetUpTransactionDB(/*threshold=*/threshold, /*atomic_flush=*/true);
|
||||
SetUpTransactionDB(/*atomic_flush=*/true);
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::vector<std::string> cfs = {"cf0", "cf1", "cf2"};
|
||||
@@ -9621,7 +9539,9 @@ TEST_P(CommitBypassMemtableTest, AtomicFlushTest) {
|
||||
ASSERT_OK(db_->Put({}, handles_[2], "key2", "val2"));
|
||||
|
||||
// Write to cf 0, should see cf1 and cf2 flushed too
|
||||
auto txn = txn_db->BeginTransaction({}, {}, nullptr);
|
||||
TransactionOptions txn_opts;
|
||||
txn_opts.large_txn_commit_optimize_threshold = threshold;
|
||||
auto txn = txn_db->BeginTransaction({}, txn_opts, nullptr);
|
||||
for (uint32_t i = 0; i <= threshold; ++i) {
|
||||
ASSERT_OK(txn->Put(handles_[0], "key" + std::to_string(i),
|
||||
"cf0" + std::to_string(i)));
|
||||
@@ -9889,6 +9809,126 @@ TEST_F(TransactionDBTest, SelfDeadlockBug) {
|
||||
delete txn1;
|
||||
delete txn2;
|
||||
}
|
||||
|
||||
TEST_P(CommitBypassMemtableTest,
|
||||
OptimizeLargeTxnCommitWriteBatchSizeThreshold) {
|
||||
// Tests TransactionOptions::large_txn_commit_optimize_byte_threshold
|
||||
const uint64_t threshold = 100;
|
||||
SetUpTransactionDB();
|
||||
bool commit_bypass_memtable = false;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteCommittedTxn::CommitInternal:bypass_memtable",
|
||||
[&](void* arg) { commit_bypass_memtable = *(static_cast<bool*>(arg)); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Random rnd(301);
|
||||
|
||||
WriteOptions wopts;
|
||||
TransactionOptions txn_opts;
|
||||
// Test default
|
||||
auto txn = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn->SetName("xid0"));
|
||||
ASSERT_OK(txn->Put("k1", rnd.RandomString(1000)));
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
|
||||
// Test with transaction option only
|
||||
txn_opts.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
// Above threshold
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts, txn);
|
||||
ASSERT_OK(txn->SetName("xid1"));
|
||||
ASSERT_OK(txn->Put("k1", rnd.RandomString(threshold)));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() >= threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
// Below threshold
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts, txn);
|
||||
ASSERT_OK(txn->SetName("xid2"));
|
||||
ASSERT_OK(txn->Put("k2", "v2"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
delete txn;
|
||||
|
||||
// With commit_bypass_memtbale
|
||||
TransactionOptions txn_opts2;
|
||||
txn_opts2.commit_bypass_memtable = true;
|
||||
txn_opts2.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts2, nullptr);
|
||||
ASSERT_OK(txn->SetName("xid3"));
|
||||
ASSERT_OK(txn->Put("k3", "v3"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
delete txn;
|
||||
|
||||
// With count based threshold `large_txn_commit_optimize_threshold`
|
||||
TransactionOptions txn_opts3;
|
||||
txn_opts3.commit_bypass_memtable = false;
|
||||
txn_opts3.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
txn_opts3.large_txn_commit_optimize_threshold = 3;
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts3, nullptr);
|
||||
ASSERT_OK(txn->SetName("xid4"));
|
||||
ASSERT_OK(txn->Put("k3", "v3"));
|
||||
ASSERT_OK(txn->Delete("k2"));
|
||||
ASSERT_OK(txn->Delete("k1"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts3, txn);
|
||||
ASSERT_OK(txn->SetName("xid4"));
|
||||
ASSERT_OK(txn->Put("k3", "v3"));
|
||||
ASSERT_OK(txn->Delete("k2"));
|
||||
ASSERT_OK(txn->Delete("k1"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts3, txn);
|
||||
ASSERT_OK(txn->SetName("xid5"));
|
||||
ASSERT_OK(txn->Put("k5", "v5"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
delete txn;
|
||||
|
||||
// Test with multiple column families
|
||||
std::vector<std::string> cfs = {"pk", "sk"};
|
||||
CreateColumnFamilies(cfs, options);
|
||||
TransactionOptions txn_opts_cf;
|
||||
|
||||
txn_opts_cf.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
|
||||
// Below threshold
|
||||
auto txn_cf = txn_db->BeginTransaction(wopts, txn_opts_cf, nullptr);
|
||||
ASSERT_OK(txn_cf->SetName("xid_cf_above"));
|
||||
ASSERT_OK(txn_cf->Put(handles_[0], "k1", rnd.RandomString(threshold / 2)));
|
||||
ASSERT_OK(txn_cf->Put(handles_[1], "k2", rnd.RandomString(threshold / 2)));
|
||||
ASSERT_TRUE(txn_cf->GetWriteBatch()->GetDataSize() >= threshold);
|
||||
ASSERT_OK(txn_cf->Prepare());
|
||||
ASSERT_OK(txn_cf->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
txn_cf = txn_db->BeginTransaction(wopts, txn_opts_cf, txn_cf);
|
||||
ASSERT_OK(txn_cf->SetName("xid_cf_below"));
|
||||
ASSERT_OK(txn_cf->Put(handles_[0], "k1", rnd.RandomString(10)));
|
||||
ASSERT_OK(txn_cf->Put(handles_[1], "k2", rnd.RandomString(10)));
|
||||
ASSERT_TRUE(txn_cf->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn_cf->Prepare());
|
||||
ASSERT_OK(txn_cf->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
|
||||
delete txn_cf;
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
Reference in new issue
Block a user