Compare commits

...
Author SHA1 Message Date
anand76 a8b5e4a6b7 Update HISTORY and version for 10.3.4 2025-06-17 16:36:32 -07:00
anand76 a59ca8d5da Change NewExternalTableFactory to return unique_ptr (#13705)
Summary:
Change NewExternalTableFactory API to return unique_ptr for use with the object registry.

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

Reviewed By: jaykorean

Differential Revision: D76827580

Pulled By: anand1976

fbshipit-source-id: 251ad0e498b62059b8417ff967ca74146de43e2f
2025-06-17 16:22:16 -07:00
Peter Dillinger 740240e3b1 Update version and HISTORY for 10.3.3 2025-06-04 19:14:23 -07:00
anand76 633631ac79 Fix iterator errors for CFs with disallow_memtable_writes (#13663)
Summary:
Iterator seek returns "SeekAndValidate() not implemented" error if the disallow_memtable_writes CF option is set along with paranoid_memory_checks. The fix is to sanitize the paranoid_memory_checks option to false, which should be safe since the memtable is guaranteed to be empty.

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

Test Plan: Update unit test in db_basic_test.cc

Reviewed By: pdillinger

Differential Revision: D75973515

Pulled By: anand1976

fbshipit-source-id: 3f381f19dcda72e3b78ee375f755fb4809c6b99c
2025-06-04 19:12:49 -07:00
Peter Dillinger e7d28965ce Clean up stale unreleased_history (not sure what happened) 2025-06-04 12:02:40 -07:00
Peter Dillinger c1b29dfe70 Fix tests broken by gtest upgrade (#13661)
Summary:
Some tests were failing due to apparent missing include of iomanip. I suspect this was from a gtest upgrade, because in open source, the include iomanip comes from gtest.h. To ensure we maintain compatibility with older gtest as well as the newer one, I pulled the include iomanip out of the in-repo gtest.h. Note that other places in gtest code only instantiate floating-point related templates with `float` and `double` types.

Also, to avoid `make format` being insanely slow on gtest.h, I've excluded third-party from the formatting check.

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

Test Plan: make check, internal CI, manually ensure formatting check works outside of third-party/

Reviewed By: jaykorean

Differential Revision: D75963897

Pulled By: pdillinger

fbshipit-source-id: ed5737dd456e74068185f1ac5d57046d7509df7a
2025-06-04 10:53:41 -07:00
Peter Dillinger a116092ee6 Fix XPRESS compression and enable in CI (#13649)
Summary:
Somehow this was previously not being tested in our Windows CI jobs so was accidentally broken in https://github.com/facebook/rocksdb/pull/13540  This fix will need to be backported to 10.3.

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

Test Plan: CI

Reviewed By: hx235

Differential Revision: D75655418

Pulled By: pdillinger

fbshipit-source-id: a56bb213270904a1b7a13b905c2cc1919116df1c
2025-05-30 09:31:36 -07:00
Jay Huh f90d89ea52 Update HISTORY and version for 10.3.2 2025-05-30 07:18:13 -07:00
Jay Huh cf149842a2 Include file_size in CompactionServiceOutputFile (#13620)
Summary:
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`

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

Test Plan:
Tested with logging Meta's internal offload Infra

```
./compaction_job_test
```

Reviewed By: jowlyzhang

Differential Revision: D75006961

Pulled By: jaykorean

fbshipit-source-id: 008f9dc22bd672746ac180380ada4188713a6b85
2025-05-30 07:12:47 -07:00
Changyu Bi f2d64341f5 Update HISTORY and version for 10.3.1 2025-05-22 20:34:07 -07:00
Changyu Bi 9c7f4946bb Update default value for large txn options (#13636)
Summary:
to make it easier to use 0 for disabled. And deprecate the use of txn db option `txn_commit_bypass_memtable_threshold`.

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

Test Plan: updated unit tests.

Reviewed By: jowlyzhang

Differential Revision: D75262136

Pulled By: cbi42

fbshipit-source-id: 9040e5a9c918c1d0906a2db4600cc012d2436b22
2025-05-22 20:27:57 -07:00
Changyu Bi 9885ced363 Enable large txn optimization by transaction write batch size (#13634)
Summary:
Larger key/values can cause memtable write to take longer time. Add new option `TransactionOptions::large_txn_commit_optimize_byte_threshold` that enables the optimization by transaction write batch size.

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

Test Plan:
- new unit test
- added option to stress test and ran stress test for some time: `python3 ./tools/db_crashtest.py --txn blackbox  --txn_write_policy=0 --commit_bypass_memtable_one_in=50 --test_batches_snapshots=0`

Reviewed By: jowlyzhang

Differential Revision: D75248126

Pulled By: cbi42

fbshipit-source-id: 9522db93457729ba60e4176f7d47f7c2c7778567
2025-05-22 20:27:49 -07:00
Peter Dillinger cda1e40498 Fix another format compatibility failure (#13628)
Summary:
Some specific old versions around RocksDB 2.5 would compress the metaindex and properties blocks. This hasn't been done since, probably because it interferes with the properties block indicating how to set up for decompression (so the reader can read those blocks before doing any decompression).

To fix backward compatibility, we establish a decompressor early if format_version indicates the file could come from a sufficiently old version.

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

Test Plan: local and CI runs of tools/check_format_compatible.sh. (I don't believe we need special code to set up a unit test for this case.)

Reviewed By: jowlyzhang

Differential Revision: D75107623

Pulled By: pdillinger

fbshipit-source-id: 97132b8c5e0602e8e27254a11386d866b23cb4f5
2025-05-21 09:29:12 -07:00
Peter Dillinger 0c3f08008a Update HISTORY for 10.3.0 release 2025-05-17 16:25:23 -07:00
35 changed files with 426 additions and 176 deletions

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
View File
@@ -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
+7 -4
View 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!"
+11 -8
View File
@@ -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)),
+1
View File
@@ -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(
+24 -14
View File
@@ -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,
+6
View File
@@ -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(
+2
View File
@@ -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"
+7 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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
+28 -3
View File
@@ -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
+1 -1
View File
@@ -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
+20
View File
@@ -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*/) {
+58
View File
@@ -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 =
+2
View File
@@ -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()));
+3 -3
View File
@@ -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;
}
+1
View File
@@ -14,6 +14,7 @@
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
+32
View File
@@ -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
View File
@@ -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.
//
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+137 -97
View File
@@ -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) {