Compare commits

...
48 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
Peter Dillinger 77af042413 Fix some compression-related assertion failures (#13621)
Summary:
showing up in the crash test after https://github.com/facebook/rocksdb/issues/13540
* For an assertion `dict_samples.sample_data.size() <= opts_.max_dict_bytes` we needed to ensure that `zstd_max_train_bytes` only takes effect with kZSTD compression.
* For an assertion with `r->table_options.verify_compression == (verify_decomp != nullptr)` we needed to ensure that `data_block_verify_decompressor` is set even when dictionary compression is attempted but not used.
* Noticed along the way: finish an optimization in `CompressAndVerifyBlock` that was incomplete.

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

Test Plan:
Both failures were reproducible with hard-coding of some crash test params, and now not getting a failure.
```
--compression_type=zstd --compression_max_dict_bytes=16384 --compression_zstd_max_train_bytes=65536 --compression_max_dict_buffer_bytes=131071 --compression_use_zstd_dict_trainer=1
```
Write performance test like in https://github.com/facebook/rocksdb/issues/13540 shows essentially no change, maybe slightly faster (+0.4%) with verify_compression.

Reviewed By: virajthakur

Differential Revision: D74939103

Pulled By: pdillinger

fbshipit-source-id: 8bac8891bc08e1356eff52cc524e5bb409b0f86f
2025-05-17 14:43:29 -07:00
virajthakur acab405fc1 propagate request_id from app -> Rocks -> FS (#13616)
Summary:
[internal use] Allow the application to pass a request_id per read request to RocksDB and pass it down to the FileSystem (via IODebugContext)

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

Test Plan:
./db_test --gtest_filter=DBTest.RequestIdPlumbingTest

Validates that RocksDB Api calls with request_id set result in request_id being passed to the filesystem through IODebugContext

Reviewed By: pdillinger

Differential Revision: D74912824

Pulled By: virajthakur

fbshipit-source-id: 4f15fef3ff7b5d700563f993f9b211c991020fb6
2025-05-16 21:25:50 -07:00
Zaidoon Abd Al Hadi 9a9a403a89 add support for event listener to C API (#13601)
Summary:
mostly copied from tikv's fork of rocksdb: https://github.com/tikv/rust-rocksdb/blob/master/librocksdb_sys/crocksdb/c.cc#L2445

fixed https://github.com/facebook/rocksdb/issues/13525

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

Reviewed By: hx235

Differential Revision: D74588333

Pulled By: cbi42

fbshipit-source-id: dedfc5866cf9025f9d8b6a33a8133e432554476d
2025-05-16 17:31:19 -07:00
Peter Dillinger 83026c7db2 Fix handling of old files with compression dictionary but no compression (#13618)
Summary:
Before the fix to https://github.com/facebook/rocksdb/issues/12409 in https://github.com/facebook/rocksdb/issues/12453, SST files could have a compression dictionary but be configured for no compression. Recent PR https://github.com/facebook/rocksdb/issues/13540 regressed on handling this safely on the read side, which was caught by the format compatibile nightly test (recently expanded to cover dictionary compression in https://github.com/facebook/rocksdb/issues/13414).

This change fixes that regression.

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

Test Plan: manual and ongoing format compatibility test runs. (I don't think this case is worth introducing a back door to create a uselessly inefficient SST file, considering it's covered by nightly CI.)

Reviewed By: cbi42

Differential Revision: D74914868

Pulled By: pdillinger

fbshipit-source-id: 5a4ab058d0d6da275eefb2df1a7454d8a4b2031f
2025-05-16 17:19:15 -07:00
anand76 06d4f569a8 Fix external table ingestion workflow (#13608)
Summary:
Remove the dependency on `allow_db_generated_files` option in `IngestExternalFile` to be set for ingesting external tables. The files are created by SstFileWriter, and we should be able to ingest them. We could make it work by having the external table implementation provide the version and global sequence number related properties, but its safer to have RocksDB generate the table properties block and store it as is in the file.

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

Test Plan: Add unit test to test basic ingestion and ingestion with atomic_replace_range

Reviewed By: pdillinger

Differential Revision: D74830707

Pulled By: anand1976

fbshipit-source-id: 4a9bea4a4f38f7c24c584262095c5c98cd771ddc
2025-05-16 14:41:51 -07:00
Changyu Bi b42bf48310 Add stats for WBWI ingestion and transaction size (#13611)
Summary:
Add stats to monitor the large transaction optimization. A stat is added for how many times wbwi ingestion is used. A histogram is added to track transaction size. We could also just track write batch size for all writes but I don't want to add the overhead to all writes yet.

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

Test Plan:
ran `python3 ./tools/db_crashtest.py --txn blackbox  --txn_write_policy=0 --commit_bypass_memtable_one_in=50 --test_batches_snapshots=0 --stats_dump_period_sec=2 --dump_malloc_stats=0 --statistics=1` and manually check LOG files
```
rocksdb.number.wbwi.ingest COUNT : 57
...
rocksdb.num.op.per.transaction P50 : 1.000000 P95 : 1.000000 P99 : 1.000000 P100 : 1.000000 COUNT : 2265 SUM : 2265
```

Reviewed By: jowlyzhang

Differential Revision: D74829087

Pulled By: cbi42

fbshipit-source-id: 5a9c3ab2d4cb6071cedfc47201ce2cf65a77d3c6
2025-05-16 11:51:58 -07:00
Jay Huh 024194420c Add ColumnFamily Info to CompactionServiceJobInfo (#13615)
Summary:
Similar to https://github.com/facebook/rocksdb/pull/13555, add more info, ColumnFamily Id and name, to `CompactionServiceJobInfo`.

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

Test Plan:
Updated Unit Test
```
./compaction_service_test
```

Reviewed By: archang19

Differential Revision: D74845661

Pulled By: jaykorean

fbshipit-source-id: e2fc61006092b9febec1c6637b92cb00fb6cb73e
2025-05-15 17:19:34 -07:00
Peter Dillinger 7c9b580681 Big refactor for preliminary custom compression API (#13540)
Summary:
Adds new classes etc. in internal compression.h that are intended to become public APIs for supporting custom/pluggable compression. Some steps remain to allow for pluggable compression and to remove a lot of legacy code (e.g. now called `OLD_CompressData` and `OLD_UncompressData`), but this change refactors the key integration points of SST building and reading and compressed secondary cache over to the new APIs.

Compared with the proposed https://github.com/facebook/rocksdb/issues/7650, this fixes a number of issues including
* Making a clean divide between public and internal APIs (currently just indicated with comments)
* Enough generality that built-in compressions generally fit into the framework rather than needing special treatment
* Avoid exposing obnoxious idioms like `compress_format_version` to the user.
* Enough generality that a compressor mixing algorithms/strategies from other compressors is pretty well supported without an extra schema layer
* Explicit thread-safety contracts (carefully considered)
* Contract details around schema compatibility and extension with code changes (more detail in next PR)
* Customizable "working areas" (e.g. for ZSTD "context")
* Decompression into an arbitrary memory location (rather than involving the decompressor in memory allocation; should facilitate reducing number of objects in block cache)

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

Test Plan:
This is currently an internal refactor. More testing will come when the new API is migrated to the public API. A test in db_block_cache_test is updated to meaningfully cover a case (cache warming compression dictionary block) that was previously only covered in the crash test.

SST write performance test, like https://github.com/facebook/rocksdb/issues/13583. Compile with CLANG, run before & after simultaneously:

```
SUFFIX=`tty | sed 's|/|_|g'`; for ARGS in "-compression_parallel_threads=1 -compression_type=none" "-compression_parallel_threads=1 -compression_type=snappy" "-compression_parallel_threads=1 -compression_type=zstd" "-compression_parallel_threads=1 -compression_type=zstd -verify_compression=1" "-compression_parallel_threads=1 -compression_type=zstd -compression_max_dict_bytes=8180" "-compression_parallel_threads=4 -compression_type=snappy"; do echo $ARGS; (for I in `seq 1 20`; do ./db_bench -db=/dev/shm/dbbench$SUFFIX --benchmarks=fillseq -num=10000000 -compaction_style=2 -fifo_compaction_max_table_files_size_mb=1000 -fifo_compaction_allow_compaction=0 -disable_wal -write_buffer_size=12000000 $ARGS 2>&1 | grep micros/op; done) | awk '{n++; sum += $5;} END { print int(sum / n); }'; done
```

Before (this PR and with https://github.com/facebook/rocksdb/issues/13583 reverted):
-compression_parallel_threads=1 -compression_type=none
1908372
-compression_parallel_threads=1 -compression_type=snappy
1926093
-compression_parallel_threads=1 -compression_type=zstd
1208259
-compression_parallel_threads=1 -compression_type=zstd -verify_compression=1
997583
-compression_parallel_threads=1 -compression_type=zstd -compression_max_dict_bytes=8180
934246
-compression_parallel_threads=4 -compression_type=snappy
1644849

After:
-compression_parallel_threads=1 -compression_type=none
1956054 (+2.5%)
-compression_parallel_threads=1 -compression_type=snappy
1911433 (-0.8%)
-compression_parallel_threads=1 -compression_type=zstd
1205668 (-0.3%)
-compression_parallel_threads=1 -compression_type=zstd -verify_compression=1
999263 (+0.2%)
-compression_parallel_threads=1 -compression_type=zstd -compression_max_dict_bytes=8180
934322 (+0.0%)
-compression_parallel_threads=4 -compression_type=snappy
1642519 (-0.2%)

Pretty neutral change(s) overall.

SST read performance test (related to https://github.com/facebook/rocksdb/issues/13583). Set up:
```
for COMP in none snappy zstd; do echo $ARGS; ./db_bench -db=/dev/shm/dbbench-$COMP --benchmarks=fillseq,flush -num=10000000 -compaction_style=2 -fifo_compaction_max_table_files_size_mb=1000 -fifo_compaction_allow_compaction=0 -disable_wal -write_buffer_size=12000000 -compression_type=$COMP; done
```
Test (compile with CLANG, run before & after simultaneously):
```
for COMP in none snappy zstd; do echo $COMP; (for I in `seq 1 5`; do ./db_bench -readonly -db=/dev/shm/dbbench-$COMP --benchmarks=readrandom -num=10000000 -duration=20 -threads=8 2>&1 | grep micros/op; done) | awk '{n++; sum += $5;} END { print int(sum / n); }'; done
```

Before (this PR and with https://github.com/facebook/rocksdb/issues/13583 reverted):
none
1495646
snappy
1172443
zstd
706036
zstd (after constructing with -compression_max_dict_bytes=8180)
656182

After:
none
1494981 (-0.0%)
snappy
1171846 (-0.1%)
zstd
696363 (-1.4%)
zstd (after constructing with -compression_max_dict_bytes=8180)
667585 (+1.7%)

Pretty neutral.

Reviewed By: hx235

Differential Revision: D74626863

Pulled By: pdillinger

fbshipit-source-id: dc8ff3178da9b4eaa7c16aa1bb910c872afaf14a
2025-05-15 17:14:23 -07:00
Miroslav Kovar fc2cf7ead2 Expose optimized TransactionBaseImpl::MultiGet through JNI (#13589)
Summary:
Addresses https://github.com/facebook/rocksdb/issues/13587.

This PR exposes the optimized implementation of batched reads through a `Transaction` object to Java clients.

The latency improvement of transactional multiget on production workload achieved by switching the implementation is roughly:
```
quantile=0.2: 21%
quantile=0.5: 28%
quantile=0.8: 46%
quantile=1.0: 239%
```

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

Reviewed By: jaykorean

Differential Revision: D74660169

Pulled By: cbi42

fbshipit-source-id: d01780173e0500c96e5e431ff6645008cbf6e8b5
2025-05-14 13:19:06 -07:00
anand76 df7a3a7168 Add debug printfs in secondary cache adapter destructor (#13606)
Summary:
Add debug printfs to troubleshoot an intermittent crash test assertion failure.

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

Reviewed By: mszeszko-meta

Differential Revision: D74661545

Pulled By: anand1976

fbshipit-source-id: 1b2a30fbbea3dcea5ce1a199344e946da687ff1f
2025-05-13 14:41:28 -07:00
Till Rohrmann 2a0886b9a7 Expose pinned WriteBatchWithIndex::GetFromBatchAndDB through C bindings (#12970)
Summary:
Expose pinned WriteBatchWithIndex::GetFromBatchAndDB through C bindings so that one can read data from the `WriteBatchWithIndex` and db w/o copying the data.

This fixes https://github.com/facebook/rocksdb/issues/12969.

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

Reviewed By: cbi42

Differential Revision: D74586418

Pulled By: jaykorean

fbshipit-source-id: a5a4d2e8ce3ddf4c2371fdfdb4e9c3309966a05d
2025-05-13 14:06:28 -07:00
Yu Zhang 9c4b94b9e7 Remove flaky test for file ingestion wait time metric (#13605)
Summary:
As titled.

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

Test Plan: This is removing a test

Reviewed By: mszeszko-meta

Differential Revision: D74660230

Pulled By: jowlyzhang

fbshipit-source-id: 9c1d46b56d2f9ee43eba645563d4f954645d1ace
2025-05-13 11:19:53 -07:00
ran-openai 35e1c6c402 Add internal_merge_point_lookup_count perfstats to c interface (#13599)
Summary: Pull Request resolved: https://github.com/facebook/rocksdb/pull/13599

Reviewed By: virajthakur

Differential Revision: D74586452

Pulled By: cbi42

fbshipit-source-id: 58f31d96c040ae465afa1caba8cbb7434c72a366
2025-05-13 09:54:37 -07:00
Changyu Bi 8cb2bfa233 Fix race in accessing MANIFEST number in crash test (#13603)
Summary:
https://github.com/facebook/rocksdb/issues/13594 introduced the following data race. This PR attempts to fix it by acquiring DB mutex before accessing MANIFEST file number.
```
WARNING: ThreadSanitizer: data race (pid=9993)
  Write of size 8 at 0x7b60000014e8 by thread T50 (mutexes: write M143969571504678848):
    #0 rocksdb::ParseFileName(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long*, rocksdb::Slice const&, rocksdb::FileType*, rocksdb::WalFileType*) file/filename.cc:326 (librocksdb.so.10.3+0xaa142f)
    https://github.com/facebook/rocksdb/issues/1 rocksdb::ParseFileName(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long*, rocksdb::FileType*, rocksdb::WalFileType*) file/filename.cc:270 (librocksdb.so.10.3+0xaa1e91)
    https://github.com/facebook/rocksdb/issues/2 rocksdb::GetCurrentManifestPath(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, rocksdb::FileSystem*, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, unsigned long*) db/manifest_ops.cc:35 (librocksdb.so.10.3+0x80bd3f)
    https://github.com/facebook/rocksdb/issues/3 rocksdb::ReactiveVersionSet::MaybeSwitchManifest(rocksdb::log::Reader::Reporter*, std::unique_ptr<rocksdb::log::FragmentBufferedReader, std::default_delete<rocksdb::log::FragmentBufferedReader> >*) db/version_set.cc:7553 (librocksdb.so.10.3+0x91ca45)
    https://github.com/facebook/rocksdb/issues/4 rocksdb::ReactiveVersionSet::ReadAndApply(rocksdb::InstrumentedMutex*, std::unique_ptr<rocksdb::log::FragmentBufferedReader, std::default_delete<rocksdb::log::FragmentBufferedReader> >*, rocksdb::Status*, std::unordered_set<rocksdb::ColumnFamilyData*, std::hash<rocksdb::ColumnFamilyData*>, std::equal_to<rocksdb::ColumnFamilyData*>, std::allocator<rocksdb::ColumnFamilyData*> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*) db/version_set.cc:7531 (librocksdb.so.10.3+0x91de03)
    https://github.com/facebook/rocksdb/issues/5 rocksdb::DBImplSecondary::TryCatchUpWithPrimary() db/db_impl/db_impl_secondary.cc:709 (librocksdb.so.10.3+0x7006d5)
    https://github.com/facebook/rocksdb/issues/6 rocksdb::NonBatchedOpsStressTest::VerifyDb(rocksdb::ThreadState*) const db_stress_tool/no_batched_ops_stress.cc:235 (db_stress+0x48806b)
    https://github.com/facebook/rocksdb/issues/7 rocksdb::ThreadBody(void*) db_stress_tool/db_stress_driver.cc:23 (db_stress+0x4e5019)
    https://github.com/facebook/rocksdb/issues/8 StartThreadWrapper env/env_posix.cc:469 (librocksdb.so.10.3+0xa0977f)

  Previous read of size 8 at 0x7b60000014e8 by thread T44:
    #0 rocksdb::VersionSet::manifest_file_number() const db/version_set.h:1342 (librocksdb.so.10.3+0x69019b)
    https://github.com/facebook/rocksdb/issues/1 rocksdb::DBImpl::TEST_Current_Manifest_FileNo() db/db_impl/db_impl_debug.cc:87 (librocksdb.so.10.3+0x69019b)
    https://github.com/facebook/rocksdb/issues/2 rocksdb::NonBatchedOpsStressTest::VerifyDb(rocksdb::ThreadState*) const db_stress_tool/no_batched_ops_stress.cc:238 (db_stress+0x4880b6)
    https://github.com/facebook/rocksdb/issues/3 rocksdb::ThreadBody(void*) db_stress_tool/db_stress_driver.cc:23 (db_stress+0x4e5019)
    https://github.com/facebook/rocksdb/issues/4 StartThreadWrapper env/env_posix.cc:469 (librocksdb.so.10.3+0xa0977f)
```

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

Test Plan:
compile with TSAN, run `python3 ./tools/db_crashtest.py blackbox --test_secondary=1 --interval=10`
I could not reproduce it on main, but we can monitor if crash test fails with this race again.

Reviewed By: mszeszko-meta

Differential Revision: D74601810

Pulled By: cbi42

fbshipit-source-id: 46e13dcde9b0834053ed74c6f0937954dd36fea2
2025-05-12 15:58:33 -07:00
Changyu Bi 0e3e349369 Fix an infinite-loop bug in transaction locking (#13585)
Summary:
when a transaction reaches lock limit and times out before it attempts to wait for it (https://github.com/facebook/rocksdb/blob/9d1a071194de8093bbf3f8f57ffd176278359bf0/utilities/transactions/lock/point/point_lock_manager.cc#L320), it can busy-loop forever even though its timeout is expired. This PR fixes this bug by setting a timeout status when its timeout is reached.

This PR also updates the `LockLimit` status from `Busy` to `Aborted`, this matches the check in `Status::IsLockLimit()` and matches the customer usage (https://github.com/facebook/mysql-5.6/blob/c6e4b9f3f93dce206370105fe73ee337ece0c5e7/storage/rocksdb/ha_rocksdb.cc#L10745-L10746).

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

Test Plan: added a unit test that would infinite-loop before this fix.

Reviewed By: jaykorean

Differential Revision: D74077824

Pulled By: cbi42

fbshipit-source-id: 4993d4e4c71bb1594835e9ec6ff4a74d453a9190
2025-05-12 15:42:25 -07:00
Changyu Bi 0102b1769b Log pre-compression size written per level in compaction stats (#13596)
Summary:
Add a new field to Compaction Stats to track the pre-compression size written to each level. This logged in LOG files as column WPreComp(GB). Also improved logging of compaction_started event to include cf name.

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

Test Plan:
* Manually check LOG of db_bench runs:
With no compression
```
** Compaction Stats [default] **
Level    Files   Size     Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) WPreComp(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) CompMergeCPU(sec) Comp(cnt) Avg(sec) KeyIn KeyDrop Rblob(GB) Wblob(GB)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  L0     21/9     96.06 MB   3.0      0.0     0.0      0.0       0.4       0.4      0.4       0.0   1.0      0.0    202.0      2.22              1.27        98    0.023   3829K      0       0.0       0.0
  L1      6/6    344.89 MB   0.0      1.5     0.3      1.2       1.5       1.5      0.3       0.0   4.4    280.4    279.1      5.52              5.15        10    0.552     13M    44K       0.0       0.0
 Sum     27/15   440.95 MB   0.0      1.5     0.3      1.2       1.9       1.9      0.8       0.0   4.4    200.0    257.0      7.74              6.42       108    0.072     17M    44K       0.0       0.0
 Int      0/0      0.00 KB   0.0      0.3     0.1      0.3       0.4       0.4      0.1       0.0   6.8    219.2    255.7      1.58              1.36        14    0.113   3484K    12K       0.0       0.0

** Compaction Stats [default] **
Priority    Files   Size     Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) WPreComp(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) CompMergeCPU(sec) Comp(cnt) Avg(sec) KeyIn KeyDrop Rblob(GB) Wblob(GB)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Low      0/0      0.00 KB   0.0      1.5     0.3      1.2       1.5       1.5      0.3       0.0   0.0    280.4    279.1      5.52              5.15        10    0.552     13M    44K       0.0       0.0
High      0/0      0.00 KB   0.0      0.0     0.0      0.0       0.4       0.4      0.4       0.0   0.0      0.0    202.0      2.22              1.27        98    0.023   3829K      0       0.0       0.0
```

With expected compression ratio = 0.5
```
** Compaction Stats [default] **
Level    Files   Size     Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) WPreComp(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) CompMergeCPU(sec) Comp(cnt) Avg(sec) KeyIn KeyDrop Rblob(GB) Wblob(GB)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  L0     21/10    54.23 MB   2.8      0.0     0.0      0.0       0.2       0.4      0.2       0.0   1.0      0.0    105.2      1.96              1.29        80    0.025   3126K      0       0.0       0.0
  L1      3/3    140.18 MB   0.0      0.5     0.1      0.4       0.5       0.9      0.1       0.0   3.4    131.1    128.1      3.99              3.89         8    0.499   8324K    26K       0.0       0.0
 Sum     24/13   194.41 MB   0.0      0.5     0.1      0.4       0.7       1.3      0.3       0.0   3.5     87.9    120.5      5.96              5.17        88    0.068     11M    26K       0.0       0.0
 Int      0/0      0.00 KB   0.0      0.3     0.1      0.2       0.3       0.6      0.1       0.0   5.7    105.7    125.9      2.45              2.23        23    0.107   4973K    15K       0.0       0.0

** Compaction Stats [default] **
Priority    Files   Size     Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) WPreComp(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) CompMergeCPU(sec) Comp(cnt) Avg(sec) KeyIn KeyDrop Rblob(GB) Wblob(GB)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Low      0/0      0.00 KB   0.0      0.5     0.1      0.4       0.5       0.9      0.1       0.0   0.0    131.1    128.1      3.99              3.89         8    0.499   8324K    26K       0.0       0.0
High      0/0      0.00 KB   0.0      0.0     0.0      0.0       0.2       0.4      0.2       0.0   0.0      0.0    105.2      1.96              1.29        80    0.025   3126K      0       0.0       0.0
```

Reviewed By: hx235

Differential Revision: D74588464

Pulled By: cbi42

fbshipit-source-id: a998c0433230db4f3d7808636215b886b9ca5220
2025-05-12 11:53:16 -07:00
Changyu Bi ef67339175 Small fix in secondary DB and stress test (#13594)
Summary:
We saw some crash test failure for secondary db. It happens during crash recovery verification. This PR logs the manifest number when such failure happens. This PR also includes a small fix in `TryCatchUpWithPrimary()` that could incorrectly check WAL not found case.

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

Test Plan: monitor further secondary DB crash test failure.

Reviewed By: archang19

Differential Revision: D74488769

Pulled By: cbi42

fbshipit-source-id: 226e55b2f99a739e93abda3ee91c05b80f59bf6a
2025-05-09 12:55:40 -07:00
anand76 36600d8fa0 Pass wrapped WritableFileWriter to ExternalTableBuilder (#13591)
Summary:
This PR fixes a bug where the file checksum for an external table file was not being calculated by SstFileWriter. The checksum is calculated in WritableFileWriter, so we need to pass that the the external table builder rather than the FSWritableFile pointer directly. However, WritableFileWriter is private to RocksDB, so wrap it in an FSWritableFile and pass it.

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

Test Plan: Add a new test in table_test.cc

Reviewed By: jaykorean

Differential Revision: D74410563

Pulled By: anand1976

fbshipit-source-id: c7fa8142e20da8836589dee5fa50919951cf4046
2025-05-08 17:39:40 -07:00
Michael C Huang 13d865f6f1 Add trivial copy support when FIFO compaction reason is kChangeTemperature (#13562)
Summary:
Prior to this PR, for FIFO kChangeTemperature compaction was done by iterating and reading thru the input sst and generate the output sst. This was wasteful since for FIFO we could apply the "trivial" move by copying the input sst to the out sst without need decompress/compress and reading thru the input sst content at all. This PR added "allow_trivial_copy_when_change_temperature" to the CompactionOptionsFIFO.

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

Reviewed By: cbi42

Differential Revision: D73295404

Pulled By: mikechuangmeta

fbshipit-source-id: 02241c7389797730ecd4a3b636837cb5f912b424
2025-05-08 15:51:37 -07:00
Till Rohrmann 947a63400f Allow specifying ReadOptions for WBWI iterator (#12968)
Summary:
Allow specifying ReadOptions for WBWI iterator when creating it through the C bindings. This allows to specify upper and lower bounds for the created iterator.

This fixes https://github.com/facebook/rocksdb/issues/12963.

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

Reviewed By: pdillinger

Differential Revision: D74188049

Pulled By: jaykorean

fbshipit-source-id: 970d9910472dfedaa29a800c6d52bec14c656f3c
2025-05-06 11:42:10 -07:00
Changyu Bi f49d76b7ad Clarify that memtable_op_scan_flush_trigger does not support tailing iterator (#13586)
Summary:
clarify in comments and fix one implementation under NewIterator where option `memtable_op_scan_flush_trigger` does not work correctly with tailing iterator yet. This is because tailing iterator can rebuild iterator internally which reads from a newer memtable, and DBIter's reference to active memtable needs to be refreshed. This PR clarifies that `memtable_op_scan_flush_trigger` will have no effect on tailing iterator. We can add the support in the future if needed.

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

Test Plan: existing tests.

Reviewed By: jaykorean

Differential Revision: D74108099

Pulled By: cbi42

fbshipit-source-id: 7c6608485d57755abc44f3be0b3c5d82a7bc5ca9
2025-05-05 17:42:57 -07:00
Peter Dillinger 1428e950bd Bug fix and refactoring on parallel compression (#13583)
Summary:
While working on some compression refactoring, I noticed that `NotifyCollectTableCollectorsOnBlockAdd()` was being called from multiple threads (with `parallel_threads` > 1), meaning we were violating the promise that TablePropertiesCollectors need not be thread safe (and typically will not be, for efficiency).

Fixing this is a bit awkward or intrusive. Even though it seems weird to expose `block_compressed_bytes_fast` and `block_compressed_bytes_fast` in the public `BlockAdd()` function, and NOT the actual compressed block size used, there are some Meta-internal uses that would at least require negotiation / coordination to deprecate and remove. So it's probably easiest to just keep the awkward functionality and do the necessary modifications to call from a single thread.

The simplest solution that preserves the functionality with `parallel_threads` > 1 (provide the sampling data, expected ordering between `BlockAdd()` and `AddUserKey()`, no races) is to do the compression sampling in the thread building uncompressed blocks. Specifically, moving `NotifyCollectTableCollectorsOnBlockAdd()` and the compression sampling from `CompressAndVerifyBlock()`, which is called in parallel, to table builder `Flush()`, which is only called serially (per file). Even though this adds some compression to that single thread when sampling is enabled, that should be tolerable without complicating the code or regressing performance. Some related or nearby optimizations are included to ensure this.

* Got rid of a lot of unnecessary indirection and unnecessary fields in BlockRep, which should be a step in improving parallel compression performance (still bad IMHO).
* Restructured some `if`s etc. to streamline some logic

This satisfies my original refactoring need to moving the sampling code higher up the stack from `CompressBlock()`, to set up some other upcoming refactorings. The other caller of `CompressBlock()` (legacy BlobDB) doesn't need it, and in fact is better off calling `CompressData()` directly because it does not appear to be dealing with the various "no compression" outcomes introduced by `CompressBlock()`.

Eventual follow-up:
* Performance data below shows how the overhead of parallel compression can make it slower, with available CPUs, compared to serial compression. This infrastructure should be re-designed/re-engineered to reduce thread creation, context switches, etc. Also, more of the processing such as checksumming could be parallelized. (Things dependent on the block location in the file, such as ChecksumModifierForContext and cache warming, cannot be parallelized.)

Pull Request resolved: https://github.com/facebook/rocksdb/pull/13583
ThreadSanitizer: data race /data/users/peterd/rocksdb/./db_stress_tool/db_stress_table_properties_collector.h:36:5 in rocksdb::DbStressTablePropertiesCollector::BlockAdd(unsigned long, unsigned long, unsigned long)
```

Performance:
```
SUFFIX=`tty | sed 's|/|_|g'`; for ARGS in "-compression_parallel_threads=1 -compression_type=none" "-compression_parallel_threads=1 -compression_type=snappy" "-compression_parallel_threads=4 -compression_type=snappy"; do echo $ARGS; (for I in `seq 1 100`; do ./db_bench -db=/dev/shm/dbbench$SUFFIX --benchmarks=fillseq -num=10000000 -compaction_style=2 -fifo_compaction_max_table_files_size_mb=1000 -fifo_compaction_allow_compaction=0 -disable_wal -write_buffer_size=12000000 $ARGS 2>&1 | grep micros/op; done) | awk '{n++; sum += $5;} END { print int(sum / n); }'; done
```

Average ops/s of 100 runs, running before & after at the same time, using clang DEBUG_LEVEL=0:

-compression_parallel_threads=1 -compression_type=none
Before: 1976319
After: 1983840 (+0.3%)
-compression_parallel_threads=1 -compression_type=snappy
Before: 1945576
After: 1953473 (+0.4%)
-compression_parallel_threads=4 -compression_type=snappy
Before: 1573190
After: 1611881 (+2.4%)
-compression_parallel_threads=4 -sample_for_compression=100 (pretty high sample rate)
Before: 1577167
After: 1589704 (+0.8%)
-compression_parallel_threads=4 -sample_for_compression=10 (crazy high sample rate)
Before: 1581276
After: 1393453 (-11.9%)

As seen, you need a very very high compression sample rate to see a regression. I would expect a setting like 1000 to be more typical.

Test Plan:
Along with existing unit tests + CI, expanded crash test to make its TablePropertiesCollector non-trivial, to exercise the bug (and other potential bugs), which was confirmed with local run of whitebox_crash_test with TSAN:

```

Reviewed By: hx235

Differential Revision: D73944593

Pulled By: pdillinger

fbshipit-source-id: f1dcba4ebdc01e735251037395003945c9b34e62
2025-05-02 13:10:06 -07:00
Changyu Bi e3b7dd7b56 Add a new transaction option for large transaction optimization (#13582)
Summary:
I added `TransactionDBOptions::txn_commit_bypass_memtable_threshold` previously but per DB option is not dynamically changeable. Adding it as a per transaction option to make it easier to use. The option naming is updated to make it easier for customer to understand `large_txn_commit_optimize_threshold`. The transaction DB option `TransactionDBOptions::txn_commit_bypass_memtable_threshold` is marked as deprecated.

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

Test Plan:
- new unit test
- updated stress test to use this new transaction option

Reviewed By: jowlyzhang

Differential Revision: D73960981

Pulled By: cbi42

fbshipit-source-id: 406f6e0f5f4eb6b336976f9a93b0bc08e61a9662
2025-05-02 12:16:02 -07:00
Jay Huh 9d1a071194 Use Hex for DebugString (#13580)
Summary:
Addressing belated comment in https://github.com/facebook/rocksdb/pull/13452.

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

Test Plan:
Temp change in the Unit Test to add a null char to the key and printed

Before the fix
```
DEBUG STRING BEFORE: --- level 0 --- version# 185 ---
 287:1286[1201 .. 1210]['key000000
DEBUG STRING AFTER: --- level 0 --- version# 185 ---
 287:1286[1201 .. 1210]['key000000
```

After the fix
```
DEBUG STRING BEFORE: --- level 0 --- version# 185 ---
 287:1286[1201 .. 1210]['6B657930303030303000' seq:1201, type:1 .. '6B657930303030313800' seq:1210, type:1]
 72:1261[261 .. 270]['6B6579303030313230' seq:261, type:1 .. '6B6579303030313338' seq:270, type:1]
 67:1259[241 .. 250]['6B6579303030303830' seq:241, type:1 .. '6B6579303030303938' seq:250, type:1]
 61:1259[211 .. 220]['6B6579303030303230' seq:211, type:1 .. '6B6579303030303338' seq:220, type:1]
 --- level 1 --- version# 185 ---
 70:1353[0 .. 0]['6B6579303030303030' seq:0, type:1 .. '6B6579303030303139' seq:0, type:1]
 23:1268[21 .. 30]['6B6579303030303230' seq:21, type:1 .. '6B6579303030303239' seq:30, type:1]
 25:1268[31 .. 40]['6B6579303030303330' seq:31, type:1 .. '6B6579303030303339' seq:40, type:1]
 86:1327[0 .. 0]['6B6579303030303430' seq:0, type:1 .. '6B6579303030303539' seq:0, type:1]
 74:1326[0 .. 0]['6B6579303030303630' seq:0, type:1 .. '6B6579303030303739' seq:0, type:1]
 35:1268[81 .. 90]['6B6579303030303830' seq:81, type:1 .. '6B6579303030303839' seq:90, type:1]
 37:1268[91 .. 100]['6B6579303030303930' seq:91, type:1 .. '6B6579303030303939' seq:100, type:1]
 78:1335[0 .. 0]['6B6579303030313030' seq:0, type:1 .. '6B6579303030313139' seq:0, type:1]
 43:1270[121 .. 130]['6B6579303030313230' seq:121, type:1 .. '6B6579303030313239' seq:130, type:1]
 45:1270[131 .. 140]['6B6579303030313330' seq:131, type:1 .. '6B6579303030313339' seq:140, type:1]
 82:1332[0 .. 0]['6B6579303030313430' seq:0, type:1 .. '6B6579303030313539' seq:0, type:1]
 90:1333[0 .. 0]['6B6579303030313630' seq:0, type:1 .. '6B6579303030313739' seq:0, type:1]
 94:1332[0 .. 0]['6B6579303030313830' seq:0, type:1 .. '6B6579303030313939' seq:0, type:1]
 --- level 2 --- version# 185 ---
 --- level 3 --- version# 185 ---
 --- level 4 --- version# 185 ---
 --- level 5 --- version# 185 ---
 --- level 6 --- version# 185 ---

DEBUG STRING AFTER: --- level 0 --- version# 185 ---
 287:1286[1201 .. 1210]['6B657930303030303000' seq:1201, type:1 .. '6B657930303030313800' seq:1210, type:1]
 72:1261[261 .. 270]['6B6579303030313230' seq:261, type:1 .. '6B6579303030313338' seq:270, type:1]
 67:1259[241 .. 250]['6B6579303030303830' seq:241, type:1 .. '6B6579303030303938' seq:250, type:1]
 61:1259[211 .. 220]['6B6579303030303230' seq:211, type:1 .. '6B6579303030303338' seq:220, type:1]
 --- level 1 --- version# 185 ---
 70:1353[0 .. 0]['6B6579303030303030' seq:0, type:1 .. '6B6579303030303139' seq:0, type:1]
 23:1268[21 .. 30]['6B6579303030303230' seq:21, type:1 .. '6B6579303030303239' seq:30, type:1]
 25:1268[31 .. 40]['6B6579303030303330' seq:31, type:1 .. '6B6579303030303339' seq:40, type:1]
 86:1327[0 .. 0]['6B6579303030303430' seq:0, type:1 .. '6B6579303030303539' seq:0, type:1]
 74:1326[0 .. 0]['6B6579303030303630' seq:0, type:1 .. '6B6579303030303739' seq:0, type:1]
 35:1268[81 .. 90]['6B6579303030303830' seq:81, type:1 .. '6B6579303030303839' seq:90, type:1]
 37:1268[91 .. 100]['6B6579303030303930' seq:91, type:1 .. '6B6579303030303939' seq:100, type:1]
 78:1335[0 .. 0]['6B6579303030313030' seq:0, type:1 .. '6B6579303030313139' seq:0, type:1]
 43:1270[121 .. 130]['6B6579303030313230' seq:121, type:1 .. '6B6579303030313239' seq:130, type:1]
 45:1270[131 .. 140]['6B6579303030313330' seq:131, type:1 .. '6B6579303030313339' seq:140, type:1]
 82:1332[0 .. 0]['6B6579303030313430' seq:0, type:1 .. '6B6579303030313539' seq:0, type:1]
 90:1333[0 .. 0]['6B6579303030313630' seq:0, type:1 .. '6B6579303030313739' seq:0, type:1]
 94:1332[0 .. 0]['6B6579303030313830' seq:0, type:1 .. '6B6579303030313939' seq:0, type:1]
 --- level 2 --- version# 185 ---
 --- level 3 --- version# 185 ---
 --- level 4 --- version# 185 ---
 --- level 5 --- version# 185 ---
 --- level 6 --- version# 185 ---
```

Reviewed By: hx235

Differential Revision: D73793661

Pulled By: jaykorean

fbshipit-source-id: d553ad24489cb2eff499b1ece457c6295a1ec697
2025-04-29 11:29:22 -07:00
Jay Huh 72c3887167 Fix build (#13579)
Summary:
- [Failed CI run](https://productionresultssa17.blob.core.windows.net/actions-results/fd083599-6c98-4aec-8732-fcb280c96021/workflow-job-run-2f73efd7-c93d-53ea-a18f-1c7e17604f7e/logs/job/job-logs.txt?rsct=text%2Fplain&se=2025-04-28T17%3A15%3A01Z&sig=YJevYF5xH4RClY3klBe6Z3tnCWuYZFLlBYRHwftW9lc%3D&ske=2025-04-29T01%3A55%3A36Z&skoid=ca7593d4-ee42-46cd-af88-8b886a2f84eb&sks=b&skt=2025-04-28T13%3A55%3A36Z&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skv=2025-01-05&sp=r&spr=https&sr=b&st=2025-04-28T17%3A04%3A56Z&sv=2025-01-05)

```
2025-04-28T16:56:00.5775476Z In file included from <stdin>:1:
2025-04-28T16:56:00.5776056Z db/blob/blob_file_meta.h:28:7: error: 'uint64_t' has not been declared
2025-04-28T16:56:00.5776715Z    28 |       uint64_t blob_file_number, uint64_t total_blob_count,
2025-04-28T16:56:00.5777153Z       |       ^~~~~~~~
2025-04-28T16:56:00.5778083Z db/blob/blob_file_meta.h:15:1: note: 'uint64_t' is defined in header '<cstdint>'; this is probably fixable by adding '#include <cstdint>'
2025-04-28T16:56:00.5779293Z    14 | #include "rocksdb/rocksdb_namespace.h"
2025-04-28T16:56:00.5782126Z   +++ |+#include <cstdint>
2025-04-28T16:56:00.5782780Z    15 |
2025-04-28T16:56:00.5783204Z db/blob/blob_file_meta.h:28:34: error: 'uint64_t' has not been declared
2025-04-28T16:56:00.5783832Z    28 |       uint64_t blob_file_number, uint64_t total_blob_count,
2025-04-28T16:56:00.5784301Z       |                                  ^~~~~~~~
```

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

Test Plan: [CI](https://github.com/facebook/rocksdb/actions/runs/14713618495/job/41291839382?pr=13579)

Reviewed By: archang19, cbi42

Differential Revision: D73799590

Pulled By: jaykorean

fbshipit-source-id: 7ead97914c05958bb7146f1934c48615599bc4f8
2025-04-28 13:35:48 -07:00
Jay Huh b2815b6b46 Update folly lib (#13576)
Summary:
After some bisecting, we were able to pinpoint that https://github.com/facebook/folly/commit/7881d1e7858f35ce7176dded26162cf8f575b24c is the commit that breaks the RocksDB build-with-folly.

https://github.com/facebook/folly/commit/8e8186f67de7a23d3a07366946b1617343927d84 is the latest folly that we can update to without additional change.

Fix for the incompatible change will be followed as a separate PR.

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

Test Plan: CI

Reviewed By: hx235

Differential Revision: D73693236

Pulled By: jaykorean

fbshipit-source-id: ff94e023a361c64dea8388cb8bb9db91a2762894
2025-04-28 08:43:59 -07:00
Changyu Bi 6c0e55a2a9 Fix a bug where lock upgrade can incorrectly return deadlock status (#13575)
Summary:
AcquireLocked() returns transaction ids that currently hold the lock for deadlock detection purpose. We should not include the id of the transaction that is trying to acquire the lock, since this would lead to a false-positive deadlock detection where the deadlock is a self-loop. Note that since `wait_ids` is never cleared, there is another bug where if AcquireLocked() fails with kLockLimit, we could do deadlock detection based on `wait_ids` from a previous lock acquire attempt. This PR fixes both bugs.

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

Test Plan: added a unit test repro that shows deadlock status can be incorrectly returned.

Reviewed By: jaykorean

Differential Revision: D73617887

Pulled By: cbi42

fbshipit-source-id: a6388b3ec53db13e2c502d60199378ea95885841
2025-04-25 17:15:03 -07:00
anand76 0560544e86 Fix ExternalTableOptions initialization (#13572)
Summary: Pull Request resolved: https://github.com/facebook/rocksdb/pull/13572

Reviewed By: moakbari

Differential Revision: D73568773

Pulled By: anand1976

fbshipit-source-id: d61d76cb864e3af111bb05dc1ee51a8b3f1eaf17
2025-04-24 12:27:10 -07:00
Hui Xiao 613e1a9a38 Verify flush output file record count + minor clean up (#13556)
Summary:
**Context/Summary:**
Similar to https://github.com/facebook/rocksdb/commit/0a43d8a261b9c633c0a4e369b1ef33aa5ee32810, this is to verify flush output file contains the exact number of keys (represented by its `TableProperties::num_entries`) as added to table builder for block-based and plain table format. The implementation reuses a temporary compaction stats to record output record and existing input record (with some refactoring)

**Bonus:**
following https://github.com/facebook/rocksdb/commit/0a43d8a261b9c633c0a4e369b1ef33aa5ee32810#r154313564, limit compaction output record count check within block based table and plain table format as well as removing extra test setting; fix some typo

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

Test Plan: New test

Reviewed By: jaykorean

Differential Revision: D73229644

Pulled By: hx235

fbshipit-source-id: 2a7796450048b3bcb2d5c38f2b5fc6b53e4aae37
2025-04-23 14:52:56 -07:00
Jesson Yo bcda3bda04 add SST file manager to C api (#13404)
Summary:
we want to limit the maximum disk space used by RocksDB in one of our Go services, as it runs on a highly disk-constrained network switch.

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

Reviewed By: cbi42

Differential Revision: D73517940

Pulled By: jaykorean

fbshipit-source-id: ae91fc7a4992399e20f06cc67dad8130cf19049e
2025-04-23 10:33:06 -07:00
Peter Dillinger 9998478c64 Deflake test DBPropertiesTest.AggregatedTableProperties (#13568)
Summary:
This test was failing sporadically for me, like

```
db/db_properties_test.cc:247: Failure
Expected: (static_cast<double>(dbl_a - dbl_b) / (dbl_a + dbl_b)) <
(bias), actual: 0.113964 vs 0.1
```

I tried waiting for compaction in the test, but that made it fail consistently. Based on inspection of the test and the related test AggregatedTablePropertiesAtLevel already using `disable_auto_compactions = true`, I'm applying that to this test.

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

Test Plan: Parallel runs of the unit test, before and after

Reviewed By: jaykorean

Differential Revision: D73463685

Pulled By: pdillinger

fbshipit-source-id: 84df7cc9bdcd1caa108a7be254ffbebbe9a77de7
2025-04-22 15:31:46 -07:00
Peter Dillinger c368c6afe8 Minor compression refactoring (#13539)
Summary:
* Mostly, remove `sample_for_compression` from CompressionInfo because it's not used by the core function it serves, `CompressData()`. Confusing (and inefficient), especially in db_bench where it appears to use `FLAGS_sample_for_compression` in places where it is actually ignored.
* Various clarifying comments, clean-ups, and tiny optimizations
* Prepare some structures like `CompressionDict` for more usage
* Some TODOs and FIXMEs about some things I've noticed are amiss, confusing, or excessive
* A notable optimization opportunity that might become a "pay as you go" improvement for the potential indirection costs of customizable compression: use C++23's resize_and_overwrite() in compress functions to avoid zeroing the string buffer contents before populating it.

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

Test Plan: existing tests / CI

Reviewed By: hx235

Differential Revision: D73451273

Pulled By: pdillinger

fbshipit-source-id: 0373627466d695043d21146ce34d52f189ae9432
2025-04-22 13:02:36 -07:00
Jay Huh 1614345a52 add missing version.h change for 10.3 release (#13567)
Summary:
Follow up for https://github.com/facebook/rocksdb/pull/13566

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

Test Plan: CI

Reviewed By: pdillinger

Differential Revision: D73407482

Pulled By: jaykorean

fbshipit-source-id: 0bb7492473c0691a50d25288f0350ab097958de7
2025-04-22 09:08:36 -07:00
Jay Huh c237022831 Update for next release 10.3.0 (#13566)
Summary:
Updated version, HISTORY and compatibility script for 10.3 release (no folly hash update in this release).

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

Test Plan: CI

Reviewed By: anand1976

Differential Revision: D73391839

Pulled By: jaykorean

fbshipit-source-id: 075bb1f9f25caf96c4fcca7f4a315666acd5a288
2025-04-21 15:58:58 -07:00
149 changed files with 5793 additions and 1676 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"
+57
View File
@@ -1,6 +1,63 @@
# 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
system's prefetch) on SST file during compaction read
* A new API DB::GetNewestUserDefinedTimestamp is added to return the newest user defined timestamp seen in a column family
* Introduce API `IngestWriteBatchWithIndex()` for ingesting updates into DB while bypassing memtable writes. This improves performance when writing a large write batch to the DB.
* Add a new CF option `memtable_op_scan_flush_trigger` that triggers a flush of the memtable if an iterator's Seek()/Next() scans over a certain number of invisible entries from the memtable.
### Public API Changes
* AdvancedColumnFamilyOptions.max_write_buffer_number_to_maintain is deleted. It's deprecated since introduction of a better option max_write_buffer_size_to_maintain since RocksDB 6.5.0.
* Deprecated API `DB::MaxMemCompactionLevel()`.
* Deprecated `ReadOptions::ignore_range_deletions`.
* Deprecated API `experimental::PromoteL0()`.
* Added arbitrary string map for additional options to be overriden for remote compactions
* The fail_if_options_file_error option in DBOptions has been removed. The behavior now is to always return failure in any API that fails to persist the OPTIONS file.
### Behavior Changes
* Make stats `PREFETCH_BYTES_USEFUL`, `PREFETCH_HITS`, `PREFETCH_BYTES` only account for prefetching during user initiated scan
### Bug Fixes
* Fix a bug in Posix file system that the FSWritableFile created via `FileSystem::ReopenWritableFile` internally does not track the correct file size.
* Fix a bug where tail size of remote compaction output is not persisted in primary db's manifest
## 10.1.0 (03/24/2025)
### New Features
* Added a new `DBOptions.calculate_sst_write_lifetime_hint_set` setting that allows to customize which compaction styles SST write lifetime hint calculation is allowed on. Today RocksDB supports only two modes `kCompactionStyleLevel` and `kCompactionStyleUniversal`.
+1 -1
View File
@@ -2489,7 +2489,7 @@ checkout_folly:
fi
@# Pin to a particular version for public CI, so that PR authors don't
@# need to worry about folly breaking our integration. Update periodically
cd third-party/folly && git reset --hard 78286282478e1ae05b2e8cbcf0e2139eab283bea
cd third-party/folly && git reset --hard 8e8186f67de7a23d3a07366946b1617343927d84
@# NOTE: this hack is required for clang in some cases
perl -pi -e 's/int rv = syscall/int rv = (int)syscall/' third-party/folly/folly/detail/Futex.cpp
@# NOTE: this hack is required for gcc in some cases
+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!"
+35 -32
View File
@@ -24,7 +24,14 @@ CompressedSecondaryCache::CompressedSecondaryCache(
cache_res_mgr_(std::make_shared<ConcurrentCacheReservationManager>(
std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
cache_))),
disable_cache_(opts.capacity == 0) {}
disable_cache_(opts.capacity == 0) {
auto mgr =
GetBuiltinCompressionManager(cache_options_.compress_format_version);
compressor_ = mgr->GetCompressor(cache_options_.compression_opts,
cache_options_.compression_type);
decompressor_ =
mgr->GetDecompressorOptimizeFor(cache_options_.compression_type);
}
CompressedSecondaryCache::~CompressedSecondaryCache() = default;
@@ -97,25 +104,24 @@ std::unique_ptr<SecondaryCacheResultHandle> CompressedSecondaryCache::Lookup(
kNoCompression, CacheTier::kVolatileTier,
create_context, allocator, &value, &charge);
} else {
UncompressionContext uncompression_context(
cache_options_.compression_type);
UncompressionInfo uncompression_info(uncompression_context,
UncompressionDict::GetEmptyDict(),
cache_options_.compression_type);
size_t uncompressed_size{0};
CacheAllocationPtr uncompressed =
UncompressData(uncompression_info, (char*)data_ptr,
handle_value_charge, &uncompressed_size,
cache_options_.compress_format_version, allocator);
if (!uncompressed) {
cache_->Release(lru_handle, /*erase_if_last_ref=*/true);
return nullptr;
// TODO: can we work some magic with create_cb, which might be based on
// custom compression, to decompress without an extra copy in create_cb?
Decompressor::Args args;
args.compressed_data = Slice(data_ptr, handle_value_charge);
args.compression_type = cache_options_.compression_type;
s = decompressor_->ExtractUncompressedSize(args);
assert(s.ok());
if (s.ok()) {
auto uncompressed = std::make_unique<char[]>(args.uncompressed_size);
s = decompressor_->DecompressBlock(args, uncompressed.get());
assert(s.ok());
if (s.ok()) {
s = helper->create_cb(
Slice(uncompressed.get(), args.uncompressed_size), kNoCompression,
CacheTier::kVolatileTier, create_context, allocator, &value,
&charge);
}
}
s = helper->create_cb(Slice(uncompressed.get(), uncompressed_size),
kNoCompression, CacheTier::kVolatileTier,
create_context, allocator, &value, &charge);
}
} else {
// The item was not compressed by us. Let the helper create_cb
@@ -198,20 +204,17 @@ Status CompressedSecondaryCache::InsertInternal(
type == kNoCompression &&
!cache_options_.do_not_compress_roles.Contains(helper->role)) {
PERF_COUNTER_ADD(compressed_sec_cache_uncompressed_bytes, data_size);
CompressionContext compression_context(cache_options_.compression_type,
cache_options_.compression_opts);
uint64_t sample_for_compression{0};
CompressionInfo compression_info(
cache_options_.compression_opts, compression_context,
CompressionDict::GetEmptyDict(), cache_options_.compression_type,
sample_for_compression);
bool success =
CompressData(val, compression_info,
cache_options_.compress_format_version, &compressed_val);
if (!success) {
return Status::Corruption("Error compressing value.");
CompressionType to_type = kNoCompression;
s = compressor_->CompressBlock(val, &compressed_val, &to_type,
nullptr /*working_area*/);
if (!s.ok()) {
return s;
}
// TODO: allow values not compressed when there's no size savings?
assert(to_type == cache_options_.compression_type);
if (to_type != cache_options_.compression_type) {
return Status::Corruption("Failed to compress value.");
}
val = Slice(compressed_val);
+2
View File
@@ -145,6 +145,8 @@ class CompressedSecondaryCache : public SecondaryCache {
const Cache::CacheItemHelper* GetHelper(bool enable_custom_split_merge) const;
std::shared_ptr<Cache> cache_;
CompressedSecondaryCacheOptions cache_options_;
std::unique_ptr<Compressor> compressor_;
std::shared_ptr<Decompressor> decompressor_;
mutable port::Mutex capacity_mutex_;
std::shared_ptr<ConcurrentCacheReservationManager> cache_res_mgr_;
bool disable_cache_;
+11 -1
View File
@@ -121,7 +121,17 @@ CacheWithSecondaryAdapter::~CacheWithSecondaryAdapter() {
assert(s.ok());
assert(placeholder_usage_ == 0);
assert(reserved_usage_ == 0);
assert(pri_cache_res_->GetTotalMemoryUsed() == sec_capacity);
bool pri_cache_res_mismatch =
pri_cache_res_->GetTotalMemoryUsed() != sec_capacity;
if (pri_cache_res_mismatch) {
fprintf(stderr,
"~CacheWithSecondaryAdapter: Primary cache reservation: "
"%zu, Secondary cache capacity: %zu, "
"Secondary cache reserved: %zu\n",
pri_cache_res_->GetTotalMemoryUsed(), sec_capacity,
sec_reserved_);
assert(pri_cache_res_mismatch);
}
}
#endif // NDEBUG
}
+1 -1
View File
@@ -55,7 +55,7 @@ void ArenaWrappedDBIter::Init(
db_iter_ = DBIter::NewIter(
env, read_options_, ioptions, mutable_cf_options,
ioptions.user_comparator, /*internal_iter=*/nullptr, version, sequence,
read_callback, cfh, expose_blob_index, active_mem, &arena_);
read_callback, active_mem, cfh, expose_blob_index, &arena_);
sv_number_ = version_number;
allow_refresh_ = allow_refresh;
+3 -4
View File
@@ -267,10 +267,9 @@ Status BlobFileBuilder::CompressBlobIfNeeded(
// TODO: allow user CompressionOptions, including max_compressed_bytes_per_kb
CompressionOptions opts;
CompressionContext context(blob_compression_type_, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
blob_compression_type_, sample_for_compression);
blob_compression_type_);
constexpr uint32_t compression_format_version = 2;
@@ -279,8 +278,8 @@ Status BlobFileBuilder::CompressBlobIfNeeded(
{
StopWatch stop_watch(immutable_options_->clock, immutable_options_->stats,
BLOB_DB_COMPRESSION_MICROS);
success =
CompressData(*blob, info, compression_format_version, compressed_blob);
success = OLD_CompressData(*blob, info, compression_format_version,
compressed_blob);
}
if (!success) {
+1 -2
View File
@@ -405,10 +405,9 @@ TEST_F(BlobFileBuilderTest, Compression) {
CompressionOptions opts;
CompressionContext context(kSnappyCompression, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
kSnappyCompression, sample_for_compression);
kSnappyCompression);
std::string compressed_value;
ASSERT_TRUE(Snappy_Compress(info, uncompressed_value.data(),
+1
View File
@@ -6,6 +6,7 @@
#pragma once
#include <cassert>
#include <cstdint>
#include <iosfwd>
#include <memory>
#include <string>
+12 -9
View File
@@ -250,7 +250,8 @@ Status BlobFileReader::ReadFromFile(const RandomAccessFileReader* file_reader,
Status s;
IOOptions io_options;
s = file_reader->PrepareIOOptions(read_options, io_options);
IODebugContext dbg;
s = file_reader->PrepareIOOptions(read_options, io_options, &dbg);
if (!s.ok()) {
return s;
}
@@ -259,13 +260,13 @@ Status BlobFileReader::ReadFromFile(const RandomAccessFileReader* file_reader,
constexpr char* scratch = nullptr;
s = file_reader->Read(io_options, read_offset, read_size, slice, scratch,
aligned_buf);
aligned_buf, &dbg);
} else {
buf->reset(new char[read_size]);
constexpr AlignedBuf* aligned_scratch = nullptr;
s = file_reader->Read(io_options, read_offset, read_size, slice, buf->get(),
aligned_scratch);
aligned_scratch, &dbg);
}
if (!s.ok()) {
@@ -334,7 +335,8 @@ Status BlobFileReader::GetBlob(
constexpr bool for_compaction = true;
IOOptions io_options;
s = file_reader_->PrepareIOOptions(read_options, io_options);
IODebugContext dbg;
s = file_reader_->PrepareIOOptions(read_options, io_options, &dbg);
if (!s.ok()) {
return s;
}
@@ -463,10 +465,11 @@ void BlobFileReader::MultiGetBlob(
PERF_COUNTER_ADD(blob_read_count, num_blobs);
PERF_COUNTER_ADD(blob_read_byte, total_len);
IOOptions opts;
s = file_reader_->PrepareIOOptions(read_options, opts);
IODebugContext dbg;
s = file_reader_->PrepareIOOptions(read_options, opts, &dbg);
if (s.ok()) {
s = file_reader_->MultiRead(opts, read_reqs.data(), read_reqs.size(),
direct_io ? &aligned_buf : nullptr);
direct_io ? &aligned_buf : nullptr, &dbg);
}
if (!s.ok()) {
for (auto& req : read_reqs) {
@@ -602,9 +605,9 @@ Status BlobFileReader::UncompressBlobIfNeeded(
{
PERF_TIMER_GUARD(blob_decompress_time);
StopWatch stop_watch(clock, statistics, BLOB_DB_DECOMPRESSION_MICROS);
output = UncompressData(info, value_slice.data(), value_slice.size(),
&uncompressed_size, compression_format_version,
allocator);
output = OLD_UncompressData(info, value_slice.data(), value_slice.size(),
&uncompressed_size, compression_format_version,
allocator);
}
TEST_SYNC_POINT_CALLBACK(
+3 -4
View File
@@ -75,15 +75,14 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
} else {
CompressionOptions opts;
CompressionContext context(compression, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
compression, sample_for_compression);
compression);
constexpr uint32_t compression_format_version = 2;
for (size_t i = 0; i < num; ++i) {
ASSERT_TRUE(CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
ASSERT_TRUE(OLD_CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
blobs_to_write[i] = compressed_blobs[i];
blob_sizes[i] = compressed_blobs[i].size();
}
+3 -4
View File
@@ -77,15 +77,14 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
} else {
CompressionOptions opts;
CompressionContext context(compression, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
compression, sample_for_compression);
compression);
constexpr uint32_t compression_format_version = 2;
for (size_t i = 0; i < num; ++i) {
ASSERT_TRUE(CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
ASSERT_TRUE(OLD_CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
blobs_to_write[i] = compressed_blobs[i];
blob_sizes[i] = compressed_blobs[i].size();
}
+14 -4
View File
@@ -74,8 +74,8 @@ Status BuildTable(
EventLogger* event_logger, int job_id, TableProperties* table_properties,
Env::WriteLifeTimeHint write_hint, const std::string* full_history_ts_low,
BlobFileCompletionCallback* blob_callback, Version* version,
uint64_t* num_input_entries, uint64_t* memtable_payload_bytes,
uint64_t* memtable_garbage_bytes) {
uint64_t* memtable_payload_bytes, uint64_t* memtable_garbage_bytes,
InternalStats::CompactionStats* flush_stats) {
assert((tboptions.column_family_id ==
TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) ==
tboptions.column_family_name.empty());
@@ -253,6 +253,10 @@ Status BuildTable(
}
builder->Add(key_after_flush, value_after_flush);
if (flush_stats) {
flush_stats->num_output_records++;
}
s = meta->UpdateBoundaries(key_after_flush, value_after_flush,
ikey.sequence, ikey.type);
if (!s.ok()) {
@@ -284,6 +288,9 @@ Status BuildTable(
auto tombstone = range_del_it->Tombstone();
std::pair<InternalKey, Slice> kv = tombstone.Serialize();
builder->Add(kv.first.Encode(), kv.second);
if (flush_stats) {
flush_stats->num_output_records++;
}
InternalKey tombstone_end = tombstone.SerializeEndKey();
meta->UpdateBoundariesForRange(kv.first, tombstone_end, tombstone.seq_,
tboptions.internal_comparator);
@@ -305,9 +312,9 @@ Status BuildTable(
TEST_SYNC_POINT("BuildTable:BeforeFinishBuildTable");
const bool empty = builder->IsEmpty();
if (num_input_entries != nullptr) {
if (flush_stats) {
assert(c_iter.HasNumInputEntryScanned());
*num_input_entries =
flush_stats->num_input_records =
c_iter.NumInputEntryScanned() + num_unfragmented_tombstones;
}
if (!s.ok() || empty) {
@@ -334,6 +341,9 @@ Status BuildTable(
}
if (s.ok() && !empty) {
if (flush_stats) {
flush_stats->bytes_written_pre_comp = builder->PreCompressionSize();
}
uint64_t file_size = builder->FileSize();
meta->fd.file_size = file_size;
meta->tail_size = builder->GetTailSize();
+5 -4
View File
@@ -10,6 +10,7 @@
#include <utility>
#include <vector>
#include "db/internal_stats.h"
#include "db/range_tombstone_fragmenter.h"
#include "db/seqno_to_time_mapping.h"
#include "db/table_properties_collector.h"
@@ -34,7 +35,6 @@ class SnapshotChecker;
class TableCache;
class TableBuilder;
class WritableFileWriter;
class InternalStats;
class BlobFileCompletionCallback;
// Convenience function for NewTableBuilder on the embedded table_factory.
@@ -49,6 +49,7 @@ TableBuilder* NewTableBuilder(const TableBuilderOptions& tboptions,
//
// @param column_family_name Name of the column family that is also identified
// by column_family_id, or empty string if unknown.
// @param flush_stats treat flush as level 0 compaction in internal stats
Status BuildTable(
const std::string& dbname, VersionSet* versions,
const ImmutableDBOptions& db_options, const TableBuilderOptions& tboptions,
@@ -69,8 +70,8 @@ Status BuildTable(
Env::WriteLifeTimeHint write_hint = Env::WLTH_NOT_SET,
const std::string* full_history_ts_low = nullptr,
BlobFileCompletionCallback* blob_callback = nullptr,
Version* version = nullptr, uint64_t* num_input_entries = nullptr,
uint64_t* memtable_payload_bytes = nullptr,
uint64_t* memtable_garbage_bytes = nullptr);
Version* version = nullptr, uint64_t* memtable_payload_bytes = nullptr,
uint64_t* memtable_garbage_bytes = nullptr,
InternalStats::CompactionStats* flush_stats = nullptr);
} // namespace ROCKSDB_NAMESPACE
+506
View File
@@ -24,12 +24,14 @@
#include "rocksdb/experimental.h"
#include "rocksdb/filter_policy.h"
#include "rocksdb/iterator.h"
#include "rocksdb/listener.h"
#include "rocksdb/memtablerep.h"
#include "rocksdb/merge_operator.h"
#include "rocksdb/options.h"
#include "rocksdb/perf_context.h"
#include "rocksdb/rate_limiter.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/sst_file_manager.h"
#include "rocksdb/statistics.h"
#include "rocksdb/status.h"
#include "rocksdb/table.h"
@@ -49,6 +51,7 @@
#include "util/stderr_logger.h"
#include "utilities/merge_operators.h"
using ROCKSDB_NAMESPACE::BackgroundErrorReason;
using ROCKSDB_NAMESPACE::BackupEngine;
using ROCKSDB_NAMESPACE::BackupEngineOptions;
using ROCKSDB_NAMESPACE::BackupID;
@@ -65,7 +68,9 @@ using ROCKSDB_NAMESPACE::ColumnFamilyMetaData;
using ROCKSDB_NAMESPACE::ColumnFamilyOptions;
using ROCKSDB_NAMESPACE::CompactionFilter;
using ROCKSDB_NAMESPACE::CompactionFilterFactory;
using ROCKSDB_NAMESPACE::CompactionJobInfo;
using ROCKSDB_NAMESPACE::CompactionOptionsFIFO;
using ROCKSDB_NAMESPACE::CompactionReason;
using ROCKSDB_NAMESPACE::CompactRangeOptions;
using ROCKSDB_NAMESPACE::Comparator;
using ROCKSDB_NAMESPACE::CompressionType;
@@ -76,8 +81,11 @@ using ROCKSDB_NAMESPACE::DBOptions;
using ROCKSDB_NAMESPACE::DbPath;
using ROCKSDB_NAMESPACE::Env;
using ROCKSDB_NAMESPACE::EnvOptions;
using ROCKSDB_NAMESPACE::EventListener;
using ROCKSDB_NAMESPACE::ExternalFileIngestionInfo;
using ROCKSDB_NAMESPACE::FileLock;
using ROCKSDB_NAMESPACE::FilterPolicy;
using ROCKSDB_NAMESPACE::FlushJobInfo;
using ROCKSDB_NAMESPACE::FlushOptions;
using ROCKSDB_NAMESPACE::HistogramData;
using ROCKSDB_NAMESPACE::HyperClockCacheOptions;
@@ -90,6 +98,7 @@ using ROCKSDB_NAMESPACE::Logger;
using ROCKSDB_NAMESPACE::LRUCacheOptions;
using ROCKSDB_NAMESPACE::MemoryAllocator;
using ROCKSDB_NAMESPACE::MemoryUtil;
using ROCKSDB_NAMESPACE::MemTableInfo;
using ROCKSDB_NAMESPACE::MergeOperator;
using ROCKSDB_NAMESPACE::NewBloomFilterPolicy;
using ROCKSDB_NAMESPACE::NewCompactOnDeletionCollectorFactory;
@@ -113,10 +122,12 @@ using ROCKSDB_NAMESPACE::Slice;
using ROCKSDB_NAMESPACE::SliceParts;
using ROCKSDB_NAMESPACE::SliceTransform;
using ROCKSDB_NAMESPACE::Snapshot;
using ROCKSDB_NAMESPACE::SstFileManager;
using ROCKSDB_NAMESPACE::SstFileMetaData;
using ROCKSDB_NAMESPACE::SstFileWriter;
using ROCKSDB_NAMESPACE::Status;
using ROCKSDB_NAMESPACE::StderrLogger;
using ROCKSDB_NAMESPACE::SubcompactionJobInfo;
using ROCKSDB_NAMESPACE::TablePropertiesCollectorFactory;
using ROCKSDB_NAMESPACE::Transaction;
using ROCKSDB_NAMESPACE::TransactionDB;
@@ -130,6 +141,8 @@ using ROCKSDB_NAMESPACE::WriteBatch;
using ROCKSDB_NAMESPACE::WriteBatchWithIndex;
using ROCKSDB_NAMESPACE::WriteBufferManager;
using ROCKSDB_NAMESPACE::WriteOptions;
using ROCKSDB_NAMESPACE::WriteStallCondition;
using ROCKSDB_NAMESPACE::WriteStallInfo;
using std::unordered_set;
using std::vector;
@@ -139,6 +152,9 @@ extern "C" {
struct rocksdb_t {
DB* rep;
};
struct rocksdb_status_ptr_t {
Status* rep;
};
struct rocksdb_backup_engine_t {
BackupEngine* rep;
};
@@ -226,6 +242,9 @@ struct rocksdb_cache_t {
struct rocksdb_write_buffer_manager_t {
std::shared_ptr<WriteBufferManager> rep;
};
struct rocksdb_sst_file_manager_t {
std::shared_ptr<SstFileManager> rep;
};
struct rocksdb_livefiles_t {
std::vector<LiveFileMetaData> rep;
};
@@ -292,6 +311,28 @@ struct rocksdb_compactionfiltercontext_t {
CompactionFilter::Context rep;
};
struct rocksdb_flushjobinfo_t {
FlushJobInfo rep;
};
struct rocksdb_writestallcondition_t {
WriteStallCondition rep;
};
struct rocksdb_writestallinfo_t {
WriteStallInfo rep;
};
struct rocksdb_memtableinfo_t {
MemTableInfo rep;
};
struct rocksdb_compactionjobinfo_t {
CompactionJobInfo rep;
};
struct rocksdb_subcompactionjobinfo_t {
SubcompactionJobInfo rep;
};
struct rocksdb_externalfileingestioninfo_t {
ExternalFileIngestionInfo rep;
};
struct rocksdb_statistics_histogram_data_t {
rocksdb_statistics_histogram_data_t() : rep() {}
HistogramData rep;
@@ -2627,6 +2668,16 @@ rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base(
return result;
}
rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_readopts(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
const rocksdb_readoptions_t* options) {
rocksdb_iterator_t* result = new rocksdb_iterator_t;
result->rep =
wbwi->rep->NewIteratorWithBase(base_iterator->rep, &options->rep);
delete base_iterator;
return result;
}
rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
rocksdb_column_family_handle_t* column_family) {
@@ -2637,6 +2688,17 @@ rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_cf(
return result;
}
rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
rocksdb_column_family_handle_t* column_family,
const rocksdb_readoptions_t* options) {
rocksdb_iterator_t* result = new rocksdb_iterator_t;
result->rep = wbwi->rep->NewIteratorWithBase(
column_family->rep, base_iterator->rep, &options->rep);
delete base_iterator;
return result;
}
char* rocksdb_writebatch_wi_get_from_batch(rocksdb_writebatch_wi_t* wbwi,
const rocksdb_options_t* options,
const char* key, size_t keylen,
@@ -2696,6 +2758,23 @@ char* rocksdb_writebatch_wi_get_from_batch_and_db(
return result;
}
rocksdb_pinnableslice_t* rocksdb_writebatch_wi_get_pinned_from_batch_and_db(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options, const char* key, size_t keylen,
char** errptr) {
rocksdb_pinnableslice_t* v = new (rocksdb_pinnableslice_t);
Status s = wbwi->rep->GetFromBatchAndDB(db->rep, options->rep,
Slice(key, keylen), &v->rep);
if (!s.ok()) {
delete (v);
if (!s.IsNotFound()) {
SaveError(errptr, s);
}
return nullptr;
}
return v;
}
char* rocksdb_writebatch_wi_get_from_batch_and_db_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options,
@@ -2717,6 +2796,24 @@ char* rocksdb_writebatch_wi_get_from_batch_and_db_cf(
return result;
}
rocksdb_pinnableslice_t* rocksdb_writebatch_wi_get_pinned_from_batch_and_db_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr) {
rocksdb_pinnableslice_t* v = new (rocksdb_pinnableslice_t);
Status s = wbwi->rep->GetFromBatchAndDB(
db->rep, options->rep, column_family->rep, Slice(key, keylen), &v->rep);
if (!s.ok()) {
delete (v);
if (!s.IsNotFound()) {
SaveError(errptr, s);
}
return nullptr;
}
return v;
}
void rocksdb_write_writebatch_wi(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_writebatch_wi_t* wbwi, char** errptr) {
@@ -2930,6 +3027,352 @@ void rocksdb_block_based_options_set_unpartitioned_pinning_tier(
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
}
/* FlushJobInfo */
const char* rocksdb_flushjobinfo_cf_name(const rocksdb_flushjobinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const char* rocksdb_flushjobinfo_file_path(const rocksdb_flushjobinfo_t* info,
size_t* size) {
*size = info->rep.file_path.size();
return info->rep.file_path.data();
}
unsigned char rocksdb_flushjobinfo_triggered_writes_slowdown(
const rocksdb_flushjobinfo_t* info) {
return info->rep.triggered_writes_slowdown;
}
unsigned char rocksdb_flushjobinfo_triggered_writes_stop(
const rocksdb_flushjobinfo_t* info) {
return info->rep.triggered_writes_stop;
}
uint64_t rocksdb_flushjobinfo_largest_seqno(
const rocksdb_flushjobinfo_t* info) {
return info->rep.largest_seqno;
}
uint64_t rocksdb_flushjobinfo_smallest_seqno(
const rocksdb_flushjobinfo_t* info) {
return info->rep.smallest_seqno;
}
void rocksdb_reset_status(rocksdb_status_ptr_t* status_ptr) {
auto ptr = status_ptr->rep;
*ptr = Status::OK();
}
/* CompactionJobInfo */
void rocksdb_compactionjobinfo_status(const rocksdb_compactionjobinfo_t* info,
char** errptr) {
SaveError(errptr, info->rep.status);
}
const char* rocksdb_compactionjobinfo_cf_name(
const rocksdb_compactionjobinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
size_t rocksdb_compactionjobinfo_input_files_count(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.input_files.size();
}
const char* rocksdb_compactionjobinfo_input_file_at(
const rocksdb_compactionjobinfo_t* info, size_t pos, size_t* size) {
assert(info != nullptr);
assert(pos < info->rep.input_files.size());
const std::string& path = info->rep.input_files[pos];
*size = path.size();
return path.data();
}
size_t rocksdb_compactionjobinfo_output_files_count(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.output_files.size();
}
const char* rocksdb_compactionjobinfo_output_file_at(
const rocksdb_compactionjobinfo_t* info, size_t pos, size_t* size) {
assert(info != nullptr);
assert(pos < info->rep.output_files.size());
const std::string& path = info->rep.output_files[pos];
*size = path.size();
return path.data();
}
uint64_t rocksdb_compactionjobinfo_elapsed_micros(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.elapsed_micros;
}
uint64_t rocksdb_compactionjobinfo_num_corrupt_keys(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_corrupt_keys;
}
int rocksdb_compactionjobinfo_base_input_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.base_input_level;
}
int rocksdb_compactionjobinfo_output_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.output_level;
}
size_t rocksdb_compactionjobinfo_num_input_files(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_files;
}
size_t rocksdb_compactionjobinfo_num_input_files_at_output_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_files_at_output_level;
}
uint64_t rocksdb_compactionjobinfo_input_records(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_records;
}
uint64_t rocksdb_compactionjobinfo_output_records(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_output_records;
}
uint64_t rocksdb_compactionjobinfo_total_input_bytes(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.total_input_bytes;
}
uint64_t rocksdb_compactionjobinfo_total_output_bytes(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.total_output_bytes;
}
uint32_t rocksdb_compactionjobinfo_compaction_reason(
const rocksdb_compactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compaction_reason);
}
/* SubcompactionJobInfo */
void rocksdb_subcompactionjobinfo_status(
const rocksdb_subcompactionjobinfo_t* info, char** errptr) {
SaveError(errptr, info->rep.status);
}
const char* rocksdb_subcompactionjobinfo_cf_name(
const rocksdb_subcompactionjobinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
uint64_t rocksdb_subcompactionjobinfo_thread_id(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.thread_id;
}
int rocksdb_subcompactionjobinfo_base_input_level(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.base_input_level;
}
int rocksdb_subcompactionjobinfo_output_level(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.output_level;
}
/* ExternalFileIngestionInfo */
const char* rocksdb_externalfileingestioninfo_cf_name(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const char* rocksdb_externalfileingestioninfo_internal_file_path(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.internal_file_path.size();
return info->rep.internal_file_path.data();
}
/* External write stall info */
extern ROCKSDB_LIBRARY_API const char* rocksdb_writestallinfo_cf_name(
const rocksdb_writestallinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const rocksdb_writestallcondition_t* rocksdb_writestallinfo_cur(
const rocksdb_writestallinfo_t* info) {
return reinterpret_cast<const rocksdb_writestallcondition_t*>(
&info->rep.condition.cur);
}
const rocksdb_writestallcondition_t* rocksdb_writestallinfo_prev(
const rocksdb_writestallinfo_t* info) {
return reinterpret_cast<const rocksdb_writestallcondition_t*>(
&info->rep.condition.prev);
}
const char* rocksdb_memtableinfo_cf_name(const rocksdb_memtableinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
uint64_t rocksdb_memtableinfo_first_seqno(const rocksdb_memtableinfo_t* info) {
return info->rep.first_seqno;
}
uint64_t rocksdb_memtableinfo_earliest_seqno(
const rocksdb_memtableinfo_t* info) {
return info->rep.earliest_seqno;
}
uint64_t rocksdb_memtableinfo_num_entries(const rocksdb_memtableinfo_t* info) {
return info->rep.num_entries;
}
uint64_t rocksdb_memtableinfo_num_deletes(const rocksdb_memtableinfo_t* info) {
return info->rep.num_deletes;
}
/* event listener */
struct rocksdb_eventlistener_t : public EventListener {
void* state_{};
void (*destructor_)(void*){};
void (*on_flush_begin)(void*, rocksdb_t*, const rocksdb_flushjobinfo_t*){};
void (*on_flush_completed)(void*, rocksdb_t*,
const rocksdb_flushjobinfo_t*){};
void (*on_compaction_begin)(void*, rocksdb_t*,
const rocksdb_compactionjobinfo_t*){};
void (*on_compaction_completed)(void*, rocksdb_t*,
const rocksdb_compactionjobinfo_t*){};
void (*on_subcompaction_begin)(void*,
const rocksdb_subcompactionjobinfo_t*){};
void (*on_subcompaction_completed)(void*,
const rocksdb_subcompactionjobinfo_t*){};
void (*on_external_file_ingested)(
void*, rocksdb_t*, const rocksdb_externalfileingestioninfo_t*){};
void (*on_background_error)(void*, uint32_t, rocksdb_status_ptr_t*){};
void (*on_stall_conditions_changed)(void*, const rocksdb_writestallinfo_t*){};
void (*on_memtable_sealed)(void*, const rocksdb_memtableinfo_t*){};
rocksdb_eventlistener_t() = default;
rocksdb_eventlistener_t(const rocksdb_eventlistener_t&) = delete;
rocksdb_eventlistener_t& operator=(const rocksdb_eventlistener_t&) = delete;
rocksdb_eventlistener_t(rocksdb_eventlistener_t&&) = delete;
rocksdb_eventlistener_t& operator=(rocksdb_eventlistener_t&&) = delete;
void OnFlushBegin(DB* db, const FlushJobInfo& info) override {
rocksdb_t c_db = {db};
on_flush_begin(state_, &c_db,
reinterpret_cast<const rocksdb_flushjobinfo_t*>(&info));
}
void OnFlushCompleted(DB* db, const FlushJobInfo& info) override {
rocksdb_t c_db = {db};
on_flush_completed(state_, &c_db,
reinterpret_cast<const rocksdb_flushjobinfo_t*>(&info));
}
void OnCompactionBegin(DB* db, const CompactionJobInfo& info) override {
rocksdb_t c_db = {db};
on_compaction_begin(
state_, &c_db,
reinterpret_cast<const rocksdb_compactionjobinfo_t*>(&info));
}
void OnCompactionCompleted(DB* db, const CompactionJobInfo& info) override {
rocksdb_t c_db = {db};
on_compaction_completed(
state_, &c_db,
reinterpret_cast<const rocksdb_compactionjobinfo_t*>(&info));
}
void OnSubcompactionBegin(const SubcompactionJobInfo& info) override {
on_subcompaction_begin(
state_, reinterpret_cast<const rocksdb_subcompactionjobinfo_t*>(&info));
}
void OnSubcompactionCompleted(const SubcompactionJobInfo& info) override {
on_subcompaction_completed(
state_, reinterpret_cast<const rocksdb_subcompactionjobinfo_t*>(&info));
}
void OnExternalFileIngested(DB* db,
const ExternalFileIngestionInfo& info) override {
rocksdb_t c_db = {db};
on_external_file_ingested(
state_, &c_db,
reinterpret_cast<const rocksdb_externalfileingestioninfo_t*>(&info));
}
void OnBackgroundError(BackgroundErrorReason reason,
Status* status) override {
rocksdb_status_ptr_t* s = new rocksdb_status_ptr_t;
s->rep = status;
on_background_error(state_, static_cast<uint32_t>(reason), s);
delete s;
}
void OnStallConditionsChanged(const WriteStallInfo& info) override {
on_stall_conditions_changed(
state_, reinterpret_cast<const rocksdb_writestallinfo_t*>(&info));
}
void OnMemTableSealed(const MemTableInfo& info) override {
on_memtable_sealed(state_,
reinterpret_cast<const rocksdb_memtableinfo_t*>(&info));
}
~rocksdb_eventlistener_t() override { destructor_(state_); }
};
rocksdb_eventlistener_t* rocksdb_eventlistener_create(
void* state_, void (*destructor_)(void*), on_flush_begin_cb on_flush_begin,
on_flush_completed_cb on_flush_completed,
on_compaction_begin_cb on_compaction_begin,
on_compaction_completed_cb on_compaction_completed,
on_subcompaction_begin_cb on_subcompaction_begin,
on_subcompaction_completed_cb on_subcompaction_completed,
on_external_file_ingested_cb on_external_file_ingested,
on_background_error_cb on_background_error,
on_stall_conditions_changed_cb on_stall_conditions_changed,
on_memtable_sealed_cb on_memtable_sealed) {
rocksdb_eventlistener_t* et = new rocksdb_eventlistener_t;
et->state_ = state_;
et->destructor_ = destructor_;
et->on_flush_begin = on_flush_begin;
et->on_flush_completed = on_flush_completed;
et->on_compaction_begin = on_compaction_begin;
et->on_compaction_completed = on_compaction_completed;
et->on_subcompaction_begin = on_subcompaction_begin;
et->on_subcompaction_completed = on_subcompaction_completed;
et->on_external_file_ingested = on_external_file_ingested;
et->on_background_error = on_background_error;
et->on_stall_conditions_changed = on_stall_conditions_changed;
et->on_memtable_sealed = on_memtable_sealed;
return et;
}
void rocksdb_eventlistener_destroy(rocksdb_eventlistener_t* t) { delete t; }
void rocksdb_options_add_eventlistener(rocksdb_options_t* opt,
rocksdb_eventlistener_t* t) {
opt->rep.listeners.emplace_back(std::shared_ptr<EventListener>(t));
}
rocksdb_cuckoo_table_options_t* rocksdb_cuckoo_options_create() {
return new rocksdb_cuckoo_table_options_t;
}
@@ -4332,6 +4775,8 @@ uint64_t rocksdb_perfcontext_metric(rocksdb_perfcontext_t* context,
return rep->internal_recent_skipped_count;
case rocksdb_internal_merge_count:
return rep->internal_merge_count;
case rocksdb_internal_merge_point_lookup_count:
return rep->internal_merge_point_lookup_count;
case rocksdb_get_snapshot_time:
return rep->get_snapshot_time;
case rocksdb_get_from_memtable_time:
@@ -5239,6 +5684,67 @@ ROCKSDB_LIBRARY_API void rocksdb_write_buffer_manager_set_allow_stall(
wbm->rep->SetAllowStall(new_allow_stall);
}
rocksdb_sst_file_manager_t* rocksdb_sst_file_manager_create(
rocksdb_env_t* env) {
rocksdb_sst_file_manager_t* sfm = new rocksdb_sst_file_manager_t;
sfm->rep.reset(ROCKSDB_NAMESPACE::NewSstFileManager(env->rep));
return sfm;
}
void rocksdb_sst_file_manager_destroy(rocksdb_sst_file_manager_t* sfm) {
delete sfm;
}
void rocksdb_sst_file_manager_set_max_allowed_space_usage(
rocksdb_sst_file_manager_t* sfm, uint64_t max_allowed_space) {
sfm->rep->SetMaxAllowedSpaceUsage(max_allowed_space);
}
void rocksdb_sst_file_manager_set_compaction_buffer_size(
rocksdb_sst_file_manager_t* sfm, uint64_t compaction_buffer_size) {
sfm->rep->SetCompactionBufferSize(compaction_buffer_size);
}
bool rocksdb_sst_file_manager_is_max_allowed_space_reached(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->IsMaxAllowedSpaceReached();
}
bool rocksdb_sst_file_manager_is_max_allowed_space_reached_including_compactions(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->IsMaxAllowedSpaceReachedIncludingCompactions();
}
uint64_t rocksdb_sst_file_manager_get_total_size(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetTotalSize();
}
int64_t rocksdb_sst_file_manager_get_delete_rate_bytes_per_second(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetDeleteRateBytesPerSecond();
}
void rocksdb_sst_file_manager_set_delete_rate_bytes_per_second(
rocksdb_sst_file_manager_t* sfm, int64_t delete_rate) {
return sfm->rep->SetDeleteRateBytesPerSecond(delete_rate);
}
double rocksdb_sst_file_manager_get_max_trash_db_ratio(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetMaxTrashDBRatio();
}
void rocksdb_sst_file_manager_set_max_trash_db_ratio(
rocksdb_sst_file_manager_t* sfm, double ratio) {
return sfm->rep->SetMaxTrashDBRatio(ratio);
}
uint64_t rocksdb_sst_file_manager_get_total_trash_size(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetTotalTrashSize();
}
rocksdb_dbpath_t* rocksdb_dbpath_create(const char* path,
uint64_t target_size) {
rocksdb_dbpath_t* result = new rocksdb_dbpath_t;
+104
View File
@@ -103,6 +103,12 @@ static void CheckValue(char* err, const char* expected, char** actual,
Free(actual);
}
static void CheckPinnedValue(char* err, const char* expected,
const char** actual, size_t actual_length) {
CheckNoError(err);
CheckEqual(expected, *actual, actual_length);
}
static void CheckGet(rocksdb_t* db, const rocksdb_readoptions_t* options,
const char* key, const char* expected) {
char* err = NULL;
@@ -1245,6 +1251,8 @@ int main(int argc, char** argv) {
CheckCondition(count == 3);
size_t size;
char* value;
const char* pinned_value;
rocksdb_pinnableslice_t* p;
value = rocksdb_writebatch_wi_get_from_batch(wbi, options, "box", 3, &size,
&err);
CheckValue(err, "c", &value, size);
@@ -1254,9 +1262,19 @@ int main(int argc, char** argv) {
value = rocksdb_writebatch_wi_get_from_batch_and_db(wbi, db, roptions,
"foo", 3, &size, &err);
CheckValue(err, "hello", &value, size);
p = rocksdb_writebatch_wi_get_pinned_from_batch_and_db(wbi, db, roptions,
"foo", 3, &err);
pinned_value = rocksdb_pinnableslice_value(p, &size);
CheckPinnedValue(err, "hello", &pinned_value, size);
rocksdb_pinnableslice_destroy(p);
value = rocksdb_writebatch_wi_get_from_batch_and_db(wbi, db, roptions,
"box", 3, &size, &err);
CheckValue(err, "c", &value, size);
p = rocksdb_writebatch_wi_get_pinned_from_batch_and_db(wbi, db, roptions,
"box", 3, &err);
pinned_value = rocksdb_pinnableslice_value(p, &size);
CheckPinnedValue(err, "c", &pinned_value, size);
rocksdb_pinnableslice_destroy(p);
rocksdb_write_writebatch_wi(db, woptions, wbi, &err);
CheckNoError(err);
CheckGet(db, roptions, "foo", "hello");
@@ -1362,6 +1380,46 @@ int main(int argc, char** argv) {
rocksdb_writebatch_wi_destroy(wbi);
}
StartPhase("wbwi_iter_readoptions");
{
rocksdb_readoptions_t* iter_roptions = rocksdb_readoptions_create();
rocksdb_readoptions_set_iterate_lower_bound(iter_roptions, "boy", 3);
rocksdb_readoptions_set_iterate_upper_bound(iter_roptions, "fool", 4);
rocksdb_iterator_t* base_iter = rocksdb_create_iterator(db, iter_roptions);
rocksdb_writebatch_wi_t* wbi = rocksdb_writebatch_wi_create(0, 1);
rocksdb_writebatch_wi_put(wbi, "bar", 3, "b",
1); // should get filtered out
rocksdb_writebatch_wi_put(wbi, "cat", 3, "miau", 4);
rocksdb_writebatch_wi_put(wbi, "gnu", 3, "muh",
3); // should get filtered out
rocksdb_iterator_t* iter =
rocksdb_writebatch_wi_create_iterator_with_base_readopts(wbi, base_iter,
iter_roptions);
CheckCondition(!rocksdb_iter_valid(iter));
rocksdb_iter_seek_to_first(iter);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "cat", "miau");
rocksdb_iter_next(iter);
CheckIter(iter, "foo", "hello");
rocksdb_iter_prev(iter);
CheckIter(iter, "cat", "miau");
rocksdb_iter_prev(iter);
CheckCondition(!rocksdb_iter_valid(iter));
rocksdb_iter_seek_to_last(iter);
CheckIter(iter, "foo", "hello");
rocksdb_iter_seek(iter, "b", 1);
CheckIter(iter, "cat", "miau");
rocksdb_iter_seek_for_prev(iter, "d", 1);
CheckIter(iter, "cat", "miau");
rocksdb_iter_seek_for_prev(iter, "fool", 3);
CheckIter(iter, "foo", "hello");
rocksdb_iter_get_error(iter, &err);
CheckNoError(err);
rocksdb_iter_destroy(iter);
rocksdb_writebatch_wi_destroy(wbi);
rocksdb_readoptions_destroy(iter_roptions);
}
StartPhase("multiget");
{
const char* keys[3] = {"box", "foo", "notfound"};
@@ -1792,6 +1850,35 @@ int main(int argc, char** argv) {
rocksdb_flush_wal(db, 1, &err);
CheckNoError(err);
// Test WriteBatchWithIndex iteration with Column Family
rocksdb_writebatch_wi_t* wbwi = rocksdb_writebatch_wi_create(0, true);
rocksdb_writebatch_wi_put_cf(wbwi, handles[1], "boat", 4, "row",
3); // should be filtered out
rocksdb_writebatch_wi_put_cf(wbwi, handles[1], "buffy", 5, "charmed", 7);
rocksdb_writebatch_wi_put_cf(wbwi, handles[1], "bus", 3, "yellow",
6); // should be filtered out
rocksdb_readoptions_t* iter_roptions = rocksdb_readoptions_create();
rocksdb_readoptions_set_iterate_lower_bound(iter_roptions, "bu", 2);
rocksdb_readoptions_set_iterate_upper_bound(iter_roptions, "buffz", 5);
rocksdb_iterator_t* base_iter =
rocksdb_create_iterator_cf(db, iter_roptions, handles[1]);
rocksdb_iterator_t* wbwi_iter =
rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
wbwi, base_iter, handles[1], iter_roptions);
CheckCondition(!rocksdb_iter_valid(wbwi_iter));
rocksdb_iter_seek_to_first(wbwi_iter);
CheckCondition(rocksdb_iter_valid(wbwi_iter));
CheckIter(wbwi_iter, "buff", "rocksdb");
rocksdb_iter_next(wbwi_iter);
CheckIter(wbwi_iter, "buffy", "charmed");
rocksdb_iter_next(wbwi_iter);
CheckCondition(!rocksdb_iter_valid(wbwi_iter));
rocksdb_iter_destroy(wbwi_iter);
rocksdb_writebatch_wi_destroy(wbwi);
rocksdb_readoptions_destroy(iter_roptions);
const char* keys[3] = {"box", "box", "barfooxx"};
const rocksdb_column_family_handle_t* get_handles[3] = {
handles[0], handles[1], handles[1]};
@@ -4050,6 +4137,23 @@ int main(int argc, char** argv) {
rocksdb_cache_destroy(lru);
}
StartPhase("sst_file_manager");
{
rocksdb_sst_file_manager_t* sst_file_manager;
sst_file_manager = rocksdb_sst_file_manager_create(env);
rocksdb_sst_file_manager_set_delete_rate_bytes_per_second(sst_file_manager,
1);
rocksdb_sst_file_manager_set_max_trash_db_ratio(sst_file_manager, 0.75);
CheckCondition(1 ==
rocksdb_sst_file_manager_get_delete_rate_bytes_per_second(
sst_file_manager));
CheckCondition(0.75 == rocksdb_sst_file_manager_get_max_trash_db_ratio(
sst_file_manager));
rocksdb_sst_file_manager_destroy(sst_file_manager);
}
StartPhase("cancel_all_background_work");
rocksdb_cancel_all_background_work(db, 1);
+7
View File
@@ -283,6 +283,13 @@ class Compaction {
// are non-overlapping and can be trivially moved.
bool is_trivial_move() const { return is_trivial_move_; }
bool is_trivial_copy_compaction() const {
return immutable_options_.compaction_style == kCompactionStyleFIFO &&
compaction_reason_ == CompactionReason::kChangeTemperature &&
mutable_cf_options_.compaction_options_fifo
.allow_trivial_copy_when_change_temperature;
}
// How many total levels are there?
int number_levels() const { return number_levels_; }
+10 -3
View File
@@ -878,7 +878,14 @@ Status CompactionJob::Run() {
UpdateCompactionJobOutputStats(internal_stats_);
// Verify number of output records
if (status.ok() && db_options_.compaction_verify_record_count) {
// Only verify on table with format collects table properties
const auto& mutable_cf_options = compact_->compaction->mutable_cf_options();
if (status.ok() &&
(mutable_cf_options.table_factory->IsInstanceOf(
TableFactory::kBlockBasedTableName()) ||
mutable_cf_options.table_factory->IsInstanceOf(
TableFactory::kPlainTableName())) &&
db_options_.compaction_verify_record_count) {
uint64_t total_output_num = 0;
for (const auto& state : compact_->sub_compact_states) {
for (const auto& output : state.GetOutputs()) {
@@ -2293,8 +2300,8 @@ void CompactionJob::LogCompaction() {
cfd->GetName().c_str(), scratch);
// build event logger report
auto stream = event_logger_->Log();
stream << "job" << job_id_ << "event" << "compaction_started"
<< "compaction_reason"
stream << "job" << job_id_ << "event" << "compaction_started" << "cf_name"
<< cfd->GetName() << "compaction_reason"
<< GetCompactionReasonString(compaction->compaction_reason());
for (size_t i = 0; i < compaction->num_input_levels(); ++i) {
stream << ("files_L" + std::to_string(compaction->level(i)));
+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 -5
View File
@@ -232,11 +232,6 @@ class CompactionJobTestBase : public testing::Test {
// set default for the tests
mutable_cf_options_.target_file_size_base = 1024 * 1024;
mutable_cf_options_.max_compaction_bytes = 10 * 1024 * 1024;
// Turn off compaction_verify_record_count MockTables
if (table_type == TableTypeForTest::kMockTable) {
db_options_.compaction_verify_record_count = false;
}
}
void SetUp() override {
@@ -1674,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(
+1
View File
@@ -54,6 +54,7 @@ Status CompactionOutputs::Finish(
}
current_output().finished = true;
stats_.bytes_written += current_bytes;
stats_.bytes_written_pre_comp += builder_->PreCompressionSize();
stats_.num_output_files = static_cast<int>(outputs_.size());
return s;
+22 -5
View File
@@ -1134,10 +1134,15 @@ TEST_F(CompactionPickerTest, FIFOToCold1) {
fifo_options_.max_table_files_size = kMaxSize;
fifo_options_.file_temperature_age_thresholds = {
{Temperature::kCold, kColdThreshold}};
fifo_options_.allow_trivial_copy_when_change_temperature = true;
fifo_options_.trivial_copy_buffer_size = 16 * 1024 * 1024;
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1186,7 +1191,10 @@ TEST_F(CompactionPickerTest, FIFOToColdMaxCompactionSize) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 9;
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1253,7 +1261,10 @@ TEST_F(CompactionPickerTest, FIFOToColdWithExistingCold) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1318,7 +1329,10 @@ TEST_F(CompactionPickerTest, FIFOToColdWithHotBetweenCold) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1385,7 +1399,10 @@ TEST_F(CompactionPickerTest, FIFOToHotAndWarm) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
+36 -23
View File
@@ -74,7 +74,9 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
compaction->column_family_data()->GetName().c_str(), job_id_,
compaction_input.output_level, input_files_oss.str().c_str());
CompactionServiceJobInfo info(
dbname_, db_id_, db_session_id_, GetCompactionId(sub_compact),
dbname_, db_id_, db_session_id_,
compaction->column_family_data()->GetID(),
compaction->column_family_data()->GetName(), GetCompactionId(sub_compact),
thread_pri_, compaction->compaction_reason(),
compaction->is_full_compaction(), compaction->is_manual_compaction(),
compaction->bottommost_level(), compaction->start_level(),
@@ -113,7 +115,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
}
std::string debug_str_before_wait =
compaction->input_version()->DebugString();
compaction->input_version()->DebugString(/*hex=*/true);
ROCKS_LOG_INFO(db_options_.info_log,
"[%s] [JOB %d] Waiting for remote compaction...",
@@ -124,13 +126,14 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
&compaction_result_binary);
if (compaction_status != CompactionServiceJobStatus::kSuccess) {
ROCKS_LOG_ERROR(db_options_.info_log,
"[%s] [JOB %d] Wait() status is not kSuccess. "
"\nDebugString Before Wait():\n%s"
"\nDebugString After Wait():\n%s",
compaction->column_family_data()->GetName().c_str(),
job_id_, debug_str_before_wait.c_str(),
compaction->input_version()->DebugString().c_str());
ROCKS_LOG_ERROR(
db_options_.info_log,
"[%s] [JOB %d] Wait() status is not kSuccess. "
"\nDebugString Before Wait():\n%s"
"\nDebugString After Wait():\n%s",
compaction->column_family_data()->GetName().c_str(), job_id_,
debug_str_before_wait.c_str(),
compaction->input_version()->DebugString(/*hex=*/true).c_str());
}
if (compaction_status == CompactionServiceJobStatus::kUseLocal) {
@@ -218,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);
@@ -418,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);
}
}
@@ -525,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,
+29 -4
View File
@@ -21,10 +21,10 @@ class MyTestCompactionService : public CompactionService {
: db_path_(std::move(db_path)),
options_(options),
statistics_(statistics),
start_info_("na", "na", "na", 0, Env::TOTAL, CompactionReason::kUnknown,
false, false, false, -1, -1),
wait_info_("na", "na", "na", 0, Env::TOTAL, CompactionReason::kUnknown,
false, false, false, -1, -1),
start_info_("na", "na", "na", 0, "na", 0, Env::TOTAL,
CompactionReason::kUnknown, false, false, false, -1, -1),
wait_info_("na", "na", "na", 0, "na", 0, Env::TOTAL,
CompactionReason::kUnknown, false, false, false, -1, -1),
listeners_(listeners),
table_properties_collector_factories_(
std::move(table_properties_collector_factories)) {}
@@ -434,6 +434,30 @@ TEST_F(CompactionServiceTest, ManualCompaction) {
ASSERT_OK(result.status);
ASSERT_TRUE(result.stats.is_manual_compaction);
ASSERT_TRUE(result.stats.is_remote_compaction);
auto info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(0, info.cf_id);
ASSERT_EQ(kDefaultColumnFamilyName, info.cf_name);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(0, info.cf_id);
ASSERT_EQ(kDefaultColumnFamilyName, info.cf_name);
// Test non-default CF
ASSERT_OK(
db_->CompactRange(CompactRangeOptions(), handles_[1], nullptr, nullptr));
my_cs->GetResult(&result);
ASSERT_OK(result.status);
ASSERT_TRUE(result.stats.is_manual_compaction);
ASSERT_TRUE(result.stats.is_remote_compaction);
info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(handles_[1]->GetID(), info.cf_id);
ASSERT_EQ(handles_[1]->GetName(), info.cf_name);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(handles_[1]->GetID(), info.cf_id);
ASSERT_EQ(handles_[1]->GetName(), info.cf_name);
}
TEST_F(CompactionServiceTest, CompactionOutputFileIOError) {
@@ -1371,6 +1395,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(1, info.base_input_level);
ASSERT_EQ(2, info.output_level);
ASSERT_EQ(kDefaultColumnFamilyName, info.cf_name);
// Test priority BOTTOM
env_->SetBackgroundThreads(1, Env::BOTTOM);
+4
View File
@@ -225,6 +225,8 @@ TEST_F(TieredCompactionTest, SequenceBasedTieredStorageUniversal) {
flush_stats.micros = 1;
flush_stats.bytes_written = bytes_per_file;
flush_stats.num_output_files = 1;
flush_stats.num_input_records = kNumKeys;
flush_stats.num_output_records = kNumKeys;
expect_stats[0].Add(flush_stats);
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
@@ -1080,6 +1082,8 @@ TEST_F(TieredCompactionTest, SequenceBasedTieredStorageLevel) {
flush_stats.micros = 1;
flush_stats.bytes_written = bytes_per_file;
flush_stats.num_output_files = 1;
flush_stats.num_input_records = kNumKeys;
flush_stats.num_output_records = kNumKeys;
expect_stats[0].Add(flush_stats);
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
-3
View File
@@ -851,9 +851,6 @@ TEST_F(CorruptionTest, ParanoidFileChecksOnCompact) {
options.env = env_.get();
options.paranoid_file_checks = true;
options.create_if_missing = true;
// Skip verifying record count against TableProperties for
// MockTables
options.compaction_verify_record_count = false;
Status s;
for (const auto& mode : corruption_modes) {
delete db_;
+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(
+5
View File
@@ -506,6 +506,8 @@ TEST_P(DBBlockCacheTest1, WarmCacheWithBlocksDuringFlush) {
table_options.prepopulate_block_cache =
BlockBasedTableOptions::PrepopulateBlockCache::kFlushOnly;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
// Include a compression dictionary block
options.compression_opts.max_dict_bytes = 123;
DestroyAndReopen(options);
std::string value(kValueSize, 'a');
@@ -537,6 +539,9 @@ TEST_P(DBBlockCacheTest1, WarmCacheWithBlocksDuringFlush) {
options.statistics->getTickerCount(BLOCK_CACHE_FILTER_HIT));
}
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_FILTER_MISS));
// Including compression dict
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_MISS));
}
// Verify compaction not counted
+126 -96
View File
@@ -9434,104 +9434,134 @@ TEST_F(DBCompactionTest, CompactionWithChecksumHandoffManifest2) {
}
TEST_F(DBCompactionTest, FIFOChangeTemperature) {
for (bool write_time_default : {false, true}) {
SCOPED_TRACE("write time default? " + std::to_string(write_time_default));
for (bool should_allow_trivial_copy : {false, true}) {
for (bool write_time_default : {false, true}) {
int32_t before_compaction_calls = 0;
int32_t after_compaction_calls = 0;
if (should_allow_trivial_copy) {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBImpl::BackgroundCompaction:TriviaCopyBeforeCompaction",
[&](void*) { ++before_compaction_calls; });
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBImpl::BackgroundCompaction:TriviaCopyAfterCompaction",
[&](void*) { ++after_compaction_calls; });
} else {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBImpl::BackgroundCompaction:BeforeCompaction",
[&](void*) { ++before_compaction_calls; });
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleFIFO;
options.num_levels = 1;
options.max_open_files = -1;
options.level0_file_num_compaction_trigger = 2;
options.create_if_missing = true;
CompactionOptionsFIFO fifo_options;
fifo_options.file_temperature_age_thresholds = {{Temperature::kCold, 1000}};
fifo_options.max_table_files_size = 100000000;
options.compaction_options_fifo = fifo_options;
env_->SetMockSleep();
if (write_time_default) {
options.default_write_temperature = Temperature::kWarm;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBImpl::BackgroundCompaction:AfterCompaction",
[&](void*) { ++after_compaction_calls; });
}
SCOPED_TRACE("write time default? " + std::to_string(write_time_default));
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleFIFO;
options.num_levels = 1;
options.max_open_files = -1;
options.level0_file_num_compaction_trigger = 2;
options.create_if_missing = true;
CompactionOptionsFIFO fifo_options;
fifo_options.file_temperature_age_thresholds = {
{Temperature::kCold, 1000}};
fifo_options.max_table_files_size = 100000000;
fifo_options.allow_trivial_copy_when_change_temperature =
should_allow_trivial_copy;
fifo_options.trivial_copy_buffer_size = 4096;
options.compaction_options_fifo = fifo_options;
env_->SetMockSleep();
if (write_time_default) {
options.default_write_temperature = Temperature::kWarm;
}
// Should be ignored (TODO: fail?)
options.last_level_temperature = Temperature::kHot;
Reopen(options);
int total_cold = 0;
int total_warm = 0;
int total_hot = 0;
int total_unknown = 0;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"NewWritableFile::FileOptions.temperature", [&](void* arg) {
Temperature temperature = *(static_cast<Temperature*>(arg));
if (temperature == Temperature::kCold) {
total_cold++;
} else if (temperature == Temperature::kWarm) {
total_warm++;
} else if (temperature == Temperature::kHot) {
total_hot++;
} else {
assert(temperature == Temperature::kUnknown);
total_unknown++;
}
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
// The file system does not support checksum handoff. The check
// will be ignored.
ASSERT_OK(Put(Key(0), "value1"));
env_->MockSleepForSeconds(800);
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
ASSERT_OK(Put(Key(0), "value1"));
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
// First two L0 files both become eligible for temperature change
// compaction They should be compacted one-by-one.
ASSERT_OK(Put(Key(0), "value1"));
env_->MockSleepForSeconds(1200);
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
if (write_time_default) {
// Also test dynamic option change
ASSERT_OK(db_->SetOptions({{"default_write_temperature", "kHot"}}));
}
ASSERT_OK(Put(Key(0), "value1"));
env_->MockSleepForSeconds(800);
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
ColumnFamilyMetaData metadata;
db_->GetColumnFamilyMetaData(&metadata);
ASSERT_EQ(4, metadata.file_count);
if (write_time_default) {
ASSERT_EQ(Temperature::kHot, metadata.levels[0].files[0].temperature);
ASSERT_EQ(Temperature::kWarm, metadata.levels[0].files[1].temperature);
// Includes obsolete/deleted files moved to cold
ASSERT_EQ(total_warm, 3);
ASSERT_EQ(total_hot, 1);
// Includes non-SST DB files
ASSERT_GT(total_unknown, 0);
} else {
ASSERT_EQ(Temperature::kUnknown,
metadata.levels[0].files[0].temperature);
ASSERT_EQ(Temperature::kUnknown,
metadata.levels[0].files[1].temperature);
ASSERT_EQ(total_warm, 0);
ASSERT_EQ(total_hot, 0);
// Includes non-SST DB files
ASSERT_GT(total_unknown, 4);
}
ASSERT_EQ(Temperature::kCold, metadata.levels[0].files[2].temperature);
ASSERT_EQ(Temperature::kCold, metadata.levels[0].files[3].temperature);
ASSERT_EQ(2, total_cold);
ASSERT_EQ(2, before_compaction_calls);
ASSERT_EQ(2, after_compaction_calls);
Destroy(options);
}
// Should be ignored (TODO: fail?)
options.last_level_temperature = Temperature::kHot;
Reopen(options);
int total_cold = 0;
int total_warm = 0;
int total_hot = 0;
int total_unknown = 0;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"NewWritableFile::FileOptions.temperature", [&](void* arg) {
Temperature temperature = *(static_cast<Temperature*>(arg));
if (temperature == Temperature::kCold) {
total_cold++;
} else if (temperature == Temperature::kWarm) {
total_warm++;
} else if (temperature == Temperature::kHot) {
total_hot++;
} else {
assert(temperature == Temperature::kUnknown);
total_unknown++;
}
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
// The file system does not support checksum handoff. The check
// will be ignored.
ASSERT_OK(Put(Key(0), "value1"));
env_->MockSleepForSeconds(800);
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
ASSERT_OK(Put(Key(0), "value1"));
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
// First two L0 files both become eligible for temperature change compaction
// They should be compacted one-by-one.
ASSERT_OK(Put(Key(0), "value1"));
env_->MockSleepForSeconds(1200);
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
if (write_time_default) {
// Also test dynamic option change
ASSERT_OK(db_->SetOptions({{"default_write_temperature", "kHot"}}));
}
ASSERT_OK(Put(Key(0), "value1"));
env_->MockSleepForSeconds(800);
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
ColumnFamilyMetaData metadata;
db_->GetColumnFamilyMetaData(&metadata);
ASSERT_EQ(4, metadata.file_count);
if (write_time_default) {
ASSERT_EQ(Temperature::kHot, metadata.levels[0].files[0].temperature);
ASSERT_EQ(Temperature::kWarm, metadata.levels[0].files[1].temperature);
// Includes obsolete/deleted files moved to cold
ASSERT_EQ(total_warm, 3);
ASSERT_EQ(total_hot, 1);
// Includes non-SST DB files
ASSERT_GT(total_unknown, 0);
} else {
ASSERT_EQ(Temperature::kUnknown, metadata.levels[0].files[0].temperature);
ASSERT_EQ(Temperature::kUnknown, metadata.levels[0].files[1].temperature);
ASSERT_EQ(total_warm, 0);
ASSERT_EQ(total_hot, 0);
// Includes non-SST DB files
ASSERT_GT(total_unknown, 4);
}
ASSERT_EQ(Temperature::kCold, metadata.levels[0].files[2].temperature);
ASSERT_EQ(Temperature::kCold, metadata.levels[0].files[3].temperature);
ASSERT_EQ(2, total_cold);
Destroy(options);
}
}
+57
View File
@@ -3504,6 +3504,63 @@ TEST_F(DBFlushTest, DBStuckAfterAtomicFlushError) {
ASSERT_OK(dbfull()->TEST_WaitForBackgroundWork());
ASSERT_EQ(1, NumTableFilesAtLevel(0));
}
TEST_F(DBFlushTest, VerifyOutputRecordCount) {
for (bool use_plain_table : {false, true}) {
Options options = CurrentOptions();
options.flush_verify_memtable_count = true;
options.merge_operator = MergeOperators::CreateStringAppendOperator();
DestroyAndReopen(options);
// Verify flush output record count verification in different table
// formats
if (use_plain_table) {
options.table_factory.reset(NewPlainTableFactory());
}
// Verify that flush output record count verification does not produce false
// positives.
ASSERT_OK(Merge("k0", "v1"));
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Put("k2", "v1"));
ASSERT_OK(SingleDelete("k2"));
ASSERT_OK(Delete("k2"));
ASSERT_OK(Delete("k3"));
ASSERT_OK(db_->DeleteRange(WriteOptions(), "k1", "k3"));
ASSERT_OK(Flush());
// Verify that flush output record count verification catch corruption
DestroyAndReopen(options);
if (use_plain_table) {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"PlainTableBuilder::Add::skip",
[&](void* skip) { *(bool*)skip = true; });
} else {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"BlockBasedTableBuilder::Add::skip",
[&](void* skip) { *(bool*)skip = true; });
}
SyncPoint::GetInstance()->EnableProcessing();
const char* expect =
"Number of keys in flush output SST files does not match";
// 1. During DB open flush
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Put("k2", "v1"));
Status s = TryReopen(options);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), expect));
// 2. During regular flush
DestroyAndReopen(options);
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Put("k2", "v1"));
s = Flush();
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), expect));
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
}
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
+11 -9
View File
@@ -3886,12 +3886,14 @@ Iterator* DBImpl::NewIterator(const ReadOptions& _read_options,
auto iter = new ForwardIterator(this, read_options, cfd, sv,
/* allow_unprepared_value */ true);
// TODO(cbi): Add support for `memtable_op_scan_flush_trigger` for tailing
// iterator. This requires refreshing DBIter's pointer to active_mem when
// tailing iterator refreshes to new memtable internally.
result = DBIter::NewIter(env_, read_options, cfd->ioptions(),
sv->mutable_cf_options, cfd->user_comparator(),
iter, sv->current, kMaxSequenceNumber,
/*read_callback=*/nullptr, cfh,
/*expose_blob_index=*/false,
/*active_mem=*/sv->mem);
/*read_callback=*/nullptr, /*active_mem=*/nullptr,
cfh, /*expose_blob_index=*/false);
} else {
// Note: no need to consider the special case of
// last_seq_same_as_publish_seq_==false since NewIterator is overridden in
@@ -4095,12 +4097,12 @@ Status DBImpl::NewIterators(
auto iter = new ForwardIterator(this, read_options, cf_sv_pair.cfd,
cf_sv_pair.super_version,
/* allow_unprepared_value */ true);
iterators->push_back(
DBIter::NewIter(env_, read_options, cf_sv_pair.cfd->ioptions(),
cf_sv_pair.super_version->mutable_cf_options,
cf_sv_pair.cfd->user_comparator(), iter,
cf_sv_pair.super_version->current, kMaxSequenceNumber,
nullptr /*read_callback*/, cf_sv_pair.cfh));
iterators->push_back(DBIter::NewIter(
env_, read_options, cf_sv_pair.cfd->ioptions(),
cf_sv_pair.super_version->mutable_cf_options,
cf_sv_pair.cfd->user_comparator(), iter,
cf_sv_pair.super_version->current, kMaxSequenceNumber,
nullptr /*read_callback*/, /*active_mem=*/nullptr, cf_sv_pair.cfh));
}
} else {
for (const auto& cf_sv_pair : cf_sv_pairs) {
+1 -1
View File
@@ -2577,7 +2577,7 @@ class DBImpl : public DB {
bool ShouldntRunManualCompaction(ManualCompactionState* m);
bool HaveManualCompaction(ColumnFamilyData* cfd);
bool MCOverlap(ManualCompactionState* m, ManualCompactionState* m1);
void UpdateDeletionCompactionStats(const std::unique_ptr<Compaction>& c);
void UpdateFIFOCompactionStatus(const std::unique_ptr<Compaction>& c);
// May open and read table files for table property.
// Should not be called while holding mutex_.
+247 -3
View File
@@ -13,12 +13,14 @@
#include "db/db_impl/db_impl.h"
#include "db/error_handler.h"
#include "db/event_helpers.h"
#include "file/file_util.h"
#include "file/sst_file_manager_impl.h"
#include "logging/logging.h"
#include "monitoring/iostats_context_imp.h"
#include "monitoring/perf_context_imp.h"
#include "monitoring/thread_status_updater.h"
#include "monitoring/thread_status_util.h"
#include "options/options_helper.h"
#include "rocksdb/file_system.h"
#include "rocksdb/io_status.h"
#include "rocksdb/options.h"
@@ -3786,11 +3788,251 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
c->column_family_data()->GetName().c_str(),
c->num_input_files(0));
if (status.ok() && io_s.ok()) {
UpdateDeletionCompactionStats(c);
UpdateFIFOCompactionStatus(c);
}
*made_progress = true;
TEST_SYNC_POINT_CALLBACK("DBImpl::BackgroundCompaction:AfterCompaction",
c->column_family_data());
} else if (c->is_trivial_copy_compaction()) {
TEST_SYNC_POINT_CALLBACK(
"DBImpl::BackgroundCompaction:TriviaCopyBeforeCompaction",
c->column_family_data());
assert(c->num_input_files(1) == 0);
assert(c->column_family_data()->ioptions().compaction_style ==
kCompactionStyleFIFO);
assert(c->compaction_reason() == CompactionReason::kChangeTemperature);
compaction_job_stats.num_input_files = c->num_input_files(0);
NotifyOnCompactionBegin(c->column_family_data(), c.get(), status,
compaction_job_stats, job_context->job_id);
std::vector<FileMetaData> out_files;
for (const auto& in_file : *c->inputs(0)) {
const uint64_t out_file_number = versions_->NewFileNumber();
const std::string in_fname =
TableFileName(c->immutable_options().cf_paths,
in_file->fd.GetNumber(), in_file->fd.GetPathId());
const std::string out_fname =
TableFileName(c->immutable_options().cf_paths, out_file_number,
c->output_path_id());
// TODO (mikechuang): Currently skip calling
// EventHelpers::NotifyTableFileCreationStarted for the trivial copy.
// Since it's a trivial copy we should ideally use the exact
// TableProperties from the input file but that will break some existing
// stress tests. For now skip the listener call for the FIFO
// kChangeTemperature trivial copy move.
int64_t tmp_current_time = 0;
auto get_time_status =
immutable_db_options_.clock->GetCurrentTime(&tmp_current_time);
if (!get_time_status.ok()) {
ROCKS_LOG_BUFFER(log_buffer,
"[%s] WARNING: Failed to get current time %s "
"status=%s",
c->column_family_data()->GetName().c_str(),
get_time_status.ToString().c_str());
}
uint64_t out_file_creation_time = static_cast<uint64_t>(tmp_current_time);
FileOptions copied_file_options = file_options_;
copied_file_options.temperature = c->output_temperature();
std::unique_ptr<WritableFileWriter> dest_writer;
{
std::unique_ptr<FSWritableFile> dest_file;
IOStatus writable_file_io_status =
immutable_db_options_.fs.get()->NewWritableFile(
out_fname, copied_file_options, &dest_file, nullptr /* dbg */);
TEST_SYNC_POINT_CALLBACK(
"NewWritableFile::FileOptions.temperature",
const_cast<Temperature*>(&copied_file_options.temperature));
if (!writable_file_io_status.ok()) {
io_s = writable_file_io_status;
ROCKS_LOG_BUFFER(
log_buffer,
"[%s] Error: Abort trivial copy compaction, failed to open "
"NewWritableFile %s\n"
" out_fname=%s, temperature=%s, io_status=%s",
c->column_family_data()->GetName().c_str(), out_fname.c_str(),
temperature_to_string[c->output_temperature()].c_str(),
io_s.ToString().c_str());
break;
}
FileTypeSet tmp_set = immutable_db_options_.checksum_handoff_file_types;
dest_writer.reset(new WritableFileWriter(
std::move(dest_file), out_fname, copied_file_options,
immutable_db_options_.clock, io_tracer_,
immutable_db_options_.stats, Histograms::SST_WRITE_MICROS,
c->immutable_options().listeners,
immutable_db_options_.file_checksum_gen_factory.get(),
tmp_set.Contains(FileType::kTableFile), false));
}
ROCKS_LOG_BUFFER(
log_buffer,
"[%s] Started copying from: %s\n"
" temperature=%s, to: %s, temperature=%s, buffer_size=%" PRIu64,
c->column_family_data()->GetName().c_str(), in_fname.c_str(),
temperature_to_string[in_file->temperature].c_str(),
out_fname.c_str(),
temperature_to_string[c->output_temperature()].c_str(),
c->mutable_cf_options()
.compaction_options_fifo.trivial_copy_buffer_size);
// Add IO_LOW HINT for compaction
IOOptions copy_files_compaction_io_options;
copy_files_compaction_io_options.rate_limiter_priority =
Env::IOPriority::IO_LOW;
copy_files_compaction_io_options.type = IOType::kData;
copy_files_compaction_io_options.io_activity =
Env::IOActivity::kCompaction;
IOStatus copy_file_io_status = CopyFile(
immutable_db_options_.fs.get() /* fileSystem */,
in_fname /* source */, in_file->temperature /* src_temp_hint */,
dest_writer /* dest_writer */, 0 /* size */, true /* use_fsync */,
io_tracer_ /* io_tracer*/,
c->mutable_cf_options()
.compaction_options_fifo
.trivial_copy_buffer_size /* max_read_buffer_size
*/
,
copy_files_compaction_io_options /* readIOOptions */,
copy_files_compaction_io_options /* writeIOOptions */);
if (dest_writer) {
IOOptions close_files_compaction_io_options;
close_files_compaction_io_options.rate_limiter_priority =
Env::IOPriority::IO_LOW;
close_files_compaction_io_options.type = IOType::kData;
close_files_compaction_io_options.io_activity =
Env::IOActivity::kCompaction;
// Close the dest_write
io_s = dest_writer->Close(close_files_compaction_io_options);
if (!io_s.ok()) {
ROCKS_LOG_BUFFER(
log_buffer,
"[%s] Failed to close the writer. Failed to copy from: %s\n"
" temperature=%s, to=%s, temperature=%s, io_status=%s",
c->column_family_data()->GetName().c_str(), in_fname.c_str(),
temperature_to_string[in_file->temperature].c_str(),
out_fname.c_str(),
temperature_to_string[c->output_temperature()].c_str(),
io_s.ToString().c_str());
break;
}
}
io_s = copy_file_io_status;
if (!io_s.ok()) {
ROCKS_LOG_BUFFER(log_buffer,
"[%s] Failed to copy from: %s\n"
" temperature=%s, to=%s, temperature=%s, io_status=%s",
c->column_family_data()->GetName().c_str(),
in_fname.c_str(),
temperature_to_string[in_file->temperature].c_str(),
out_fname.c_str(),
temperature_to_string[c->output_temperature()].c_str(),
io_s.ToString().c_str());
break;
}
ROCKS_LOG_BUFFER(log_buffer,
"[%s] Successfully copying from: %s\n"
" temperature=%s, to=%s, temperature=%s, io_status=%s",
c->column_family_data()->GetName().c_str(),
in_fname.c_str(),
temperature_to_string[in_file->temperature].c_str(),
out_fname.c_str(),
temperature_to_string[c->output_temperature()].c_str(),
io_s.ToString().c_str());
FileMetaData out_file_metadata{
out_file_number,
c->output_path_id(),
in_file->fd.GetFileSize(),
in_file->smallest,
in_file->largest,
in_file->fd.smallest_seqno,
in_file->fd.largest_seqno,
false /* marked_for_compact */,
c->output_temperature() /* temperature */,
in_file->oldest_blob_file_number,
in_file->oldest_ancester_time,
out_file_creation_time,
c->MinInputFileEpochNumber(),
dest_writer->GetFileChecksum(),
dest_writer->GetFileChecksumFuncName(),
in_file->unique_id,
in_file->compensated_range_deletion_size,
in_file->tail_size,
in_file->user_defined_timestamps_persisted};
out_files.push_back(std::move(out_file_metadata));
}
// Update version set
if (status.ok() && io_s.ok()) {
// NOTE: ChangeTemperature should only copy one file at one file
// hence *c->inputs(0) == out_files.size() == 1 if copy succeeded
assert(c->inputs(0)->size() == 1);
assert(out_files.size() == 1);
auto out_file_metadata_it = out_files.begin();
for (const auto& in_file : *c->inputs(0)) {
if (out_file_metadata_it == out_files.end()) {
break;
}
c->edit()->DeleteFile(c->level(), in_file->fd.GetNumber());
c->edit()->AddFile(c->level(), *out_file_metadata_it);
++out_file_metadata_it;
}
status = versions_->LogAndApply(
c->column_family_data(), read_options, write_options, c->edit(),
&mutex_, directories_.GetDbDir(),
/*new_descriptor_log=*/false, /*column_family_options=*/nullptr,
[&c, &compaction_released](const Status& s) {
c->ReleaseCompactionFiles(s);
compaction_released = true;
});
}
// TODO (mikechuang): Currently skip calling
// EventHelper::LogAndNotifyTableFileCreationFinished for the trivial copy.
// Since it's a trivial copy we should ideally use the exact TableProperties
// from the input file but that will break some existing stress tests. For
// now skip the listener call for the FIFO kChangeTemperature trivial copy
// move.
if (io_s.ok()) {
io_s = versions_->io_status();
}
InstallSuperVersionAndScheduleWork(
c->column_family_data(), job_context->superversion_contexts.data());
if (status.ok() && io_s.ok()) {
UpdateFIFOCompactionStatus(c);
} else {
for (const auto& in_file : *c->inputs(0)) {
const std::string in_fname =
TableFileName(c->immutable_options().cf_paths,
in_file->fd.GetNumber(), in_file->fd.GetPathId());
ROCKS_LOG_BUFFER(
log_buffer,
"[%s] Failed to do trvial copy compaction: %s"
" temperature=%s, to temperature=%s, status=%s, io_status=%s",
c->column_family_data()->GetName().c_str(), in_fname.c_str(),
temperature_to_string[in_file->temperature].c_str(),
temperature_to_string[c->output_temperature()].c_str(),
status.ToString().c_str(), io_s.ToString().c_str());
}
}
*made_progress = true;
TEST_SYNC_POINT_CALLBACK(
"DBImpl::BackgroundCompaction:TriviaCopyAfterCompaction",
c->column_family_data());
} else if (!trivial_move_disallowed && c->IsTrivialMove()) {
TEST_SYNC_POINT("DBImpl::BackgroundCompaction:TrivialMove");
TEST_SYNC_POINT_CALLBACK("DBImpl::BackgroundCompaction:BeforeCompaction",
@@ -4176,8 +4418,7 @@ bool DBImpl::MCOverlap(ManualCompactionState* m, ManualCompactionState* m1) {
return false;
}
void DBImpl::UpdateDeletionCompactionStats(
const std::unique_ptr<Compaction>& c) {
void DBImpl::UpdateFIFOCompactionStatus(const std::unique_ptr<Compaction>& c) {
if (c == nullptr) {
return;
}
@@ -4191,6 +4432,9 @@ void DBImpl::UpdateDeletionCompactionStats(
case CompactionReason::kFIFOTtl:
RecordTick(stats_, FIFO_TTL_COMPACTIONS);
break;
case CompactionReason::kChangeTemperature:
RecordTick(stats_, FIFO_CHANGE_TEMPERATURE_COMPACTIONS);
break;
default:
assert(false);
break;
+1
View File
@@ -84,6 +84,7 @@ void DBImpl::TEST_GetFilesMetaData(
}
uint64_t DBImpl::TEST_Current_Manifest_FileNo() {
InstrumentedMutexLock l(&mutex_);
return versions_->manifest_file_number();
}
+48 -23
View File
@@ -2000,6 +2000,9 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
const size_t ts_sz = ucmp->timestamp_size();
const bool logical_strip_timestamp =
ts_sz > 0 && !cfd->ioptions().persist_user_defined_timestamps;
// Note that here we treat flush as level 0 compaction in internal stats
InternalStats::CompactionStats flush_stats(CompactionReason::kFlush,
1 /* count */);
{
ScopedArenaPtr<InternalIterator> iter(
logical_strip_timestamp
@@ -2072,19 +2075,20 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
kMaxSequenceNumber);
Version* version = cfd->current();
version->Ref();
uint64_t num_input_entries = 0;
s = BuildTable(dbname_, versions_.get(), immutable_db_options_, tboptions,
file_options_for_compaction_, cfd->table_cache(),
iter.get(), std::move(range_del_iters), &meta,
&blob_file_additions, snapshot_seqs, earliest_snapshot,
earliest_write_conflict_snapshot, kMaxSequenceNumber,
snapshot_checker, paranoid_file_checks,
cfd->internal_stats(), &io_s, io_tracer_,
BlobFileCreationReason::kRecovery,
nullptr /* seqno_to_time_mapping */, &event_logger_,
job_id, nullptr /* table_properties */, write_hint,
nullptr /*full_history_ts_low*/, &blob_callback_, version,
&num_input_entries);
TableProperties temp_table_proerties;
s = BuildTable(
dbname_, versions_.get(), immutable_db_options_, tboptions,
file_options_for_compaction_, cfd->table_cache(), iter.get(),
std::move(range_del_iters), &meta, &blob_file_additions,
snapshot_seqs, earliest_snapshot, earliest_write_conflict_snapshot,
kMaxSequenceNumber, snapshot_checker, paranoid_file_checks,
cfd->internal_stats(), &io_s, io_tracer_,
BlobFileCreationReason::kRecovery,
nullptr /* seqno_to_time_mapping */, &event_logger_, job_id,
&temp_table_proerties /* table_properties */, write_hint,
nullptr /*full_history_ts_low*/, &blob_callback_, version,
nullptr /* memtable_payload_bytes */,
nullptr /* memtable_garbage_bytes */, &flush_stats);
version->Unref();
LogFlush(immutable_db_options_.info_log);
ROCKS_LOG_DEBUG(immutable_db_options_.info_log,
@@ -2100,10 +2104,31 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
}
uint64_t total_num_entries = mem->NumEntries();
if (s.ok() && total_num_entries != num_input_entries) {
if (s.ok() && total_num_entries != flush_stats.num_input_records) {
std::string msg = "Expected " + std::to_string(total_num_entries) +
" entries in memtable, but read " +
std::to_string(num_input_entries);
std::to_string(flush_stats.num_input_records);
ROCKS_LOG_WARN(immutable_db_options_.info_log,
"[%s] [JOB %d] Level-0 flush during recover: %s",
cfd->GetName().c_str(), job_id, msg.c_str());
if (immutable_db_options_.flush_verify_memtable_count) {
s = Status::Corruption(msg);
}
}
// Only verify on table with format collects table properties
const auto& mutable_cf_options = cfd->GetLatestMutableCFOptions();
if (s.ok() &&
(mutable_cf_options.table_factory->IsInstanceOf(
TableFactory::kBlockBasedTableName()) ||
mutable_cf_options.table_factory->IsInstanceOf(
TableFactory::kPlainTableName())) &&
flush_stats.num_output_records != temp_table_proerties.num_entries) {
std::string msg =
"Number of keys in flush output SST files does not match "
"number of keys added to the table. Expected " +
std::to_string(flush_stats.num_output_records) + " but there are " +
std::to_string(temp_table_proerties.num_entries) +
" in output SST files";
ROCKS_LOG_WARN(immutable_db_options_.info_log,
"[%s] [JOB %d] Level-0 flush during recover: %s",
cfd->GetName().c_str(), job_id, msg.c_str());
@@ -2151,25 +2176,25 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
}
}
InternalStats::CompactionStats stats(CompactionReason::kFlush, 1);
stats.micros = immutable_db_options_.clock->NowMicros() - start_micros;
flush_stats.micros = immutable_db_options_.clock->NowMicros() - start_micros;
if (has_output) {
stats.bytes_written = meta.fd.GetFileSize();
stats.num_output_files = 1;
flush_stats.bytes_written = meta.fd.GetFileSize();
flush_stats.num_output_files = 1;
}
const auto& blobs = edit->GetBlobFileAdditions();
for (const auto& blob : blobs) {
stats.bytes_written_blob += blob.GetTotalBlobBytes();
flush_stats.bytes_written_blob += blob.GetTotalBlobBytes();
}
stats.num_output_files_blob = static_cast<int>(blobs.size());
flush_stats.num_output_files_blob = static_cast<int>(blobs.size());
cfd->internal_stats()->AddCompactionStats(level, Env::Priority::USER, stats);
cfd->internal_stats()->AddCompactionStats(level, Env::Priority::USER,
flush_stats);
cfd->internal_stats()->AddCFStats(
InternalStats::BYTES_FLUSHED,
stats.bytes_written + stats.bytes_written_blob);
flush_stats.bytes_written + flush_stats.bytes_written_blob);
RecordTick(stats_, COMPACT_WRITE_BYTES, meta.fd.GetFileSize());
return s;
}
+8 -8
View File
@@ -728,13 +728,13 @@ Status DBImplSecondary::TryCatchUpWithPrimary() {
// instance
if (s.ok()) {
s = FindAndRecoverLogFiles(&cfds_changed, &job_context);
}
if (s.IsPathNotFound()) {
ROCKS_LOG_INFO(
immutable_db_options_.info_log,
"Secondary tries to read WAL, but WAL file(s) have already "
"been purged by primary.");
s = Status::OK();
if (s.IsPathNotFound()) {
ROCKS_LOG_INFO(
immutable_db_options_.info_log,
"Secondary tries to read WAL, but WAL file(s) have already "
"been purged by primary.");
s = Status::OK();
}
}
if (s.ok()) {
for (auto cfd : cfds_changed) {
@@ -909,7 +909,7 @@ Status DBImplSecondary::CompactWithoutInstallation(
ROCKS_LOG_ERROR(
immutable_db_options_.info_log,
"GetCompactionInputsFromFileNumbers() failed - %s.\n DebugString: %s",
s.ToString().c_str(), version->DebugString().c_str());
s.ToString().c_str(), version->DebugString(/*hex=*/true).c_str());
return s;
}
+1
View File
@@ -929,6 +929,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
/*min_prep_log=*/log_ref, last_sequence,
/*memtable_updated=*/memtable_update_count > 0,
write_options.ignore_missing_column_families);
RecordTick(stats_, NUMBER_WBWI_INGEST);
}
}
+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"
+4 -4
View File
@@ -71,9 +71,9 @@ class DBIter final : public Iterator {
InternalIterator* internal_iter,
const Version* version, const SequenceNumber& sequence,
ReadCallback* read_callback,
ReadOnlyMemTable* active_mem,
ColumnFamilyHandleImpl* cfh = nullptr,
bool expose_blob_index = false,
ReadOnlyMemTable* active_mem = nullptr,
Arena* arena = nullptr) {
void* mem = arena ? arena->AllocateAligned(sizeof(DBIter))
: operator new(sizeof(DBIter));
@@ -475,9 +475,9 @@ class DBIter final : public Iterator {
const size_t timestamp_size_;
std::string saved_timestamp_;
std::optional<std::vector<ScanOptions>> scan_opts_;
ReadOnlyMemTable* active_mem_;
SequenceNumber memtable_seqno_lb_;
uint32_t memtable_op_scan_flush_trigger_;
ReadOnlyMemTable* const active_mem_;
const SequenceNumber memtable_seqno_lb_;
const uint32_t memtable_op_scan_flush_trigger_;
Direction direction_;
bool valid_;
bool current_entry_is_merged_;
+1 -1
View File
@@ -532,7 +532,7 @@ TEST_F(DBIteratorStressTest, StressTest) {
env_, ropt, ImmutableOptions(options),
MutableCFOptions(options), BytewiseComparator(),
internal_iter, /*version=*/nullptr, sequence,
nullptr /*read_callback*/));
nullptr /*read_callback*/, /*active_mem=*/nullptr));
}
// Do a random operation. It's important to do it on ref_it
+84 -82
View File
@@ -262,7 +262,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -296,7 +296,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -323,7 +323,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -356,7 +356,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -392,7 +392,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
@@ -423,7 +423,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 7 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
SetPerfLevel(kEnableCount);
ASSERT_TRUE(GetPerfLevel() == kEnableCount);
@@ -462,7 +462,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -488,7 +488,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
@@ -512,7 +512,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -548,7 +548,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 7 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
SetPerfLevel(kEnableCount);
ASSERT_TRUE(GetPerfLevel() == kEnableCount);
@@ -579,7 +579,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -623,7 +623,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -655,7 +655,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -686,7 +686,7 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
ASSERT_OK(db_iter->status());
@@ -699,7 +699,7 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(!db_iter->Valid());
ASSERT_OK(db_iter->status());
@@ -723,7 +723,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkipCountSkips) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
2 /* sequence */, nullptr /* read_callback */));
2 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -770,7 +770,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -808,7 +808,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -838,8 +838,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 202 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -874,7 +873,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
ASSERT_OK(db_iter->status());
@@ -893,7 +892,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 200 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -931,7 +930,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -968,7 +967,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1019,7 +1018,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1066,7 +1065,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1111,7 +1110,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1150,7 +1149,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1186,7 +1185,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1217,7 +1216,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1255,7 +1254,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1294,7 +1293,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 * i + 1 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1348,7 +1347,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, MutableCFOptions(options), BytewiseComparator(),
internal_iter, nullptr /* version */, 2 * i + 1 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
@@ -1391,7 +1390,7 @@ TEST_F(DBIteratorTest, DBIteratorTimedPutBasic) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
7 /* sequence */, nullptr /* read_callback */));
7 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1441,7 +1440,7 @@ TEST_F(DBIteratorTest, DBIterator1) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
1 /* sequence */, nullptr /* read_callback */));
1 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1470,7 +1469,7 @@ TEST_F(DBIteratorTest, DBIterator2) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
0 /* sequence */, nullptr /* read_callback */));
0 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1495,7 +1494,7 @@ TEST_F(DBIteratorTest, DBIterator3) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
2 /* sequence */, nullptr /* read_callback */));
2 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1520,7 +1519,7 @@ TEST_F(DBIteratorTest, DBIterator4) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
4 /* sequence */, nullptr /* read_callback */));
4 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1554,7 +1553,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1578,7 +1577,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 1 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1602,7 +1601,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1626,7 +1625,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 3 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1650,7 +1649,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1674,7 +1673,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 5 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1698,7 +1697,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 6 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1720,7 +1719,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -1751,7 +1750,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1775,7 +1774,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 1 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1799,7 +1798,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1823,7 +1822,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 3 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
ASSERT_OK(db_iter->status());
@@ -1843,7 +1842,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1867,7 +1866,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 5 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1891,7 +1890,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 6 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1935,7 +1934,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1971,7 +1970,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2013,7 +2012,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2055,7 +2054,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 5 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2102,7 +2101,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 6 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2150,7 +2149,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 7 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2192,7 +2191,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 9 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2240,7 +2239,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 13 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2289,7 +2288,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 14 /* sequence */,
nullptr /* read_callback */));
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2321,7 +2320,7 @@ TEST_F(DBIteratorTest, DBIterator8) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -2349,10 +2348,11 @@ TEST_F(DBIteratorTest, DBIterator9) {
internal_iter->AddMerge("d", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
std::unique_ptr<Iterator> db_iter(
DBIter::NewIter(env_, ro, ImmutableOptions(options),
MutableCFOptions(options), BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2419,7 +2419,7 @@ TEST_F(DBIteratorTest, DBIterator10) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->Seek("c");
ASSERT_TRUE(db_iter->Valid());
@@ -2459,7 +2459,7 @@ TEST_F(DBIteratorTest, SeekToLastOccurrenceSeq0) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, 0 /* force seek */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -2489,7 +2489,7 @@ TEST_F(DBIteratorTest, DBIterator11) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
1 /* sequence */, nullptr /* read_callback */));
1 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -2517,7 +2517,7 @@ TEST_F(DBIteratorTest, DBIterator12) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, 0 /* force seek */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -2557,7 +2557,7 @@ TEST_F(DBIteratorTest, DBIterator13) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
2 /* sequence */, nullptr /* read_callback */));
2 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), key);
@@ -2587,7 +2587,7 @@ TEST_F(DBIteratorTest, DBIterator14) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
4 /* sequence */, nullptr /* read_callback */));
4 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -2627,7 +2627,8 @@ class DBIterWithMergeIterTest : public testing::Test {
db_iter_.reset(DBIter::NewIter(
env_, ro_, ImmutableOptions(options_), MutableCFOptions(options_),
BytewiseComparator(), merge_iter, nullptr /* version */,
8 /* read data earlier than seqId 8 */, nullptr /* read_callback */));
8 /* read data earlier than seqId 8 */, nullptr /* read_callback */,
/*active_mem=*/nullptr));
}
Env* env_;
@@ -3066,7 +3067,7 @@ TEST_F(DBIteratorTest, SeekPrefixTombstones) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
int skipped_keys = 0;
@@ -3099,10 +3100,11 @@ TEST_F(DBIteratorTest, SeekToFirstLowerBound) {
Slice lower_bound(lower_bound_str);
ro.iterate_lower_bound = &lower_bound;
Options options;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
std::unique_ptr<Iterator> db_iter(
DBIter::NewIter(env_, ro, ImmutableOptions(options),
MutableCFOptions(options), BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToFirst();
if (i == kNumKeys + 1) {
@@ -3141,7 +3143,7 @@ TEST_F(DBIteratorTest, PrevLowerBound) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekToLast();
for (int i = kNumKeys; i >= kLowerBound; --i) {
@@ -3169,7 +3171,7 @@ TEST_F(DBIteratorTest, SeekLessLowerBound) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
auto before_lower_bound_str = std::to_string(kLowerBound - 1);
Slice before_lower_bound(lower_bound_str);
@@ -3194,7 +3196,7 @@ TEST_F(DBIteratorTest, ReverseToForwardWithDisappearingKeys) {
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ReadOptions(), ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, nullptr /* read_callback */, /*active_mem=*/nullptr));
db_iter->SeekForPrev("a");
ASSERT_TRUE(db_iter->Valid());
+3 -1
View File
@@ -377,6 +377,8 @@ TEST_F(DBPropertiesTest, AggregatedTableProperties) {
NewBloomFilterPolicy(kBloomBitsPerKey, false));
table_options.block_size = 1024;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
// The checks assume kTableCount number of files
options.disable_auto_compactions = true;
DestroyAndReopen(options);
@@ -567,7 +569,7 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
options.target_file_size_base = 8192;
options.max_bytes_for_level_base = 10000;
options.max_bytes_for_level_multiplier = 2;
// This ensures there no compaction happening when we call GetProperty().
// The checks assume kTableCount number of files
options.disable_auto_compactions = true;
options.merge_operator.reset(new TestPutOperator());
+97 -1
View File
@@ -144,6 +144,103 @@ TEST_F(DBTest, MockEnvTest) {
delete db;
}
TEST_F(DBTest, RequestIdPlumbingTest) {
// test that request_id is passed to the filesystem, from
// ReadOptions to IODebugContext
Options options = CurrentOptions();
options.env = env_;
// Create a mock environment to capture IODebugContext during reads
const std::string* captured_request_id_dbg;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"RandomAccessFileReader::Read:IODebugContext", [&](void* arg) {
IODebugContext* dbg = static_cast<IODebugContext*>(arg);
if (dbg == nullptr) {
captured_request_id_dbg = nullptr;
} else {
captured_request_id_dbg = dbg->request_id;
}
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Flush());
// test request_id plumbing during a get
{
const std::string test_request_id = "test_request_id_123";
ReadOptions read_opts;
read_opts.request_id = &test_request_id;
std::string value;
ASSERT_OK(db_->Get(read_opts, "k1", &value));
// Verify the request_id was propagated to the file system
ASSERT_NE(captured_request_id_dbg, nullptr);
ASSERT_EQ(*captured_request_id_dbg, test_request_id);
}
captured_request_id_dbg = nullptr;
// test request_id plumbing during iterator seek
ASSERT_OK(Put("k2", "v2"));
ASSERT_OK(Flush());
{
ReadOptions read_opts;
const std::string request_id = "test_request_id_456";
read_opts.request_id = &request_id;
std::unique_ptr<Iterator> iter(db_->NewIterator(read_opts));
iter->Seek("k2");
ASSERT_TRUE(iter->Valid());
// Verify the request_id was propagated to the file system
ASSERT_NE(captured_request_id_dbg, nullptr);
ASSERT_EQ(*captured_request_id_dbg, request_id);
}
// test request_id plumbing during multiget
captured_request_id_dbg = nullptr;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"RandomAccessFileReader::MultiRead:IODebugContext", [&](void* arg) {
IODebugContext* dbg = static_cast<IODebugContext*>(arg);
if (dbg == nullptr) {
captured_request_id_dbg = nullptr;
} else {
captured_request_id_dbg = dbg->request_id;
}
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
ASSERT_OK(Put("k3", "v3"));
ASSERT_OK(Put("k4", "v4"));
ASSERT_OK(Flush());
{
ReadOptions read_opts;
const std::string multiget_request_id = "test_request_id_789";
read_opts.request_id = &multiget_request_id;
std::vector<std::string> values;
std::vector<Slice> keys = {Slice("k3"), Slice("k4")};
values.resize(keys.size());
std::vector<ColumnFamilyHandle*> cfhs(keys.size(),
db_->DefaultColumnFamily());
db_->MultiGet(read_opts, cfhs, keys, &values);
ASSERT_NE(captured_request_id_dbg, nullptr);
ASSERT_EQ(*captured_request_id_dbg, multiget_request_id);
}
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_F(DBTest, MemEnvTest) {
std::unique_ptr<Env> env{NewMemEnv(Env::Default())};
Options options;
@@ -5463,7 +5560,6 @@ TEST_F(DBTest, DynamicLevelCompressionPerLevel2) {
options.max_bytes_for_level_multiplier = 8;
options.max_background_compactions = 1;
options.num_levels = 5;
options.compaction_verify_record_count = false;
std::shared_ptr<mock::MockTableFactory> mtf(new mock::MockTableFactory);
options.table_factory = mtf;
+2 -4
View File
@@ -1722,16 +1722,14 @@ TEST_P(CompressionFailuresTest, CompressionFailures) {
});
} else if (compression_failure_type_ == kTestDecompressionFail) {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"UncompressBlockData:TamperWithReturnValue", [](void* arg) {
"DecompressBlockData:TamperWithReturnValue", [](void* arg) {
Status* ret = static_cast<Status*>(arg);
ASSERT_OK(*ret);
*ret = Status::Corruption("kTestDecompressionFail");
});
} else if (compression_failure_type_ == kTestDecompressionCorruption) {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"UncompressBlockData:"
"TamperWithDecompressionOutput",
[](void* arg) {
"DecompressBlockData:TamperWithDecompressionOutput", [](void* arg) {
BlockContents* contents = static_cast<BlockContents*>(arg);
// Ensure uncompressed data != original data
const size_t len = contents->data.size() + 1;
-49
View File
@@ -260,55 +260,6 @@ TEST_F(ExternalSSTFileBasicTest, Basic) {
s = sst_file_writer.DeleteRange(Key(100), Key(200));
ASSERT_NOK(s) << s.ToString();
DestroyAndReopen(options);
SyncPoint::GetInstance()->LoadDependency({
{"DBImpl::IngestExternalFile:AfterIncIngestFileCounter",
"ExternalSSTFileBasicTest.LiveWriteStart"},
{"WriteThread::JoinBatchGroup:Wait",
"DBImpl::IngestExternalFile:AfterIncIngestFileCounter:2"},
});
SyncPoint::GetInstance()->EnableProcessing();
PerfContext* write_thread_perf_context;
std::thread write_thread([&] {
TEST_SYNC_POINT("ExternalSSTFileBasicTest.LiveWriteStart");
SetPerfLevel(kEnableWait);
write_thread_perf_context = get_perf_context();
write_thread_perf_context->Reset();
ASSERT_OK(db_->Put(WriteOptions(), "bar", "v2"));
ASSERT_GT(write_thread_perf_context->write_thread_wait_nanos, 0);
// Test sync points were used to make sure this live write enter write
// thread after the file ingestion entered write thread. So by the time this
// live write finishes, the latest seqno is 1 means file ingestion used
// seqno 0.
ASSERT_EQ(db_->GetLatestSequenceNumber(), 1U);
});
// Add file using file path
SetPerfLevel(kEnableTimeExceptForMutex);
PerfContext* perf_ctx = get_perf_context();
perf_ctx->Reset();
s = DeprecatedAddFile({file1});
ASSERT_GT(perf_context.file_ingestion_nanos, 0);
ASSERT_GT(perf_context.file_ingestion_blocking_live_writes_nanos, 0);
ASSERT_OK(s) << s.ToString();
for (int k = 0; k < 100; k++) {
ASSERT_EQ(Get(Key(k)), Key(k) + "_val");
}
write_thread.join();
SyncPoint::GetInstance()->DisableProcessing();
// Re-ingest the file just to check the perf context not enabled at and below
// kEnableWait.
SetPerfLevel(kEnableWait);
perf_ctx->Reset();
IngestExternalFileOptions opts;
opts.allow_global_seqno = true;
opts.allow_blocking_flush = true;
ASSERT_OK(db_->IngestExternalFile({file1}, opts));
ASSERT_EQ(perf_context.file_ingestion_nanos, 0);
ASSERT_EQ(perf_context.file_ingestion_blocking_live_writes_nanos, 0);
DestroyAndRecreateExternalSSTFilesDir();
}
+48 -25
View File
@@ -868,7 +868,9 @@ Status FlushJob::WriteLevel0Table() {
ts_sz > 0 && !cfd_->ioptions().persist_user_defined_timestamps;
std::vector<BlobFileAddition> blob_file_additions;
// Note that here we treat flush as level 0 compaction in internal stats
InternalStats::CompactionStats flush_stats(CompactionReason::kFlush,
1 /* count**/);
{
auto write_hint = base_->storage_info()->CalculateSSTWriteHint(
/*level=*/0, db_options_.calculate_sst_write_lifetime_hint_set);
@@ -887,7 +889,7 @@ Status FlushJob::WriteLevel0Table() {
ro.total_order_seek = true;
ro.io_activity = Env::IOActivity::kFlush;
Arena arena;
uint64_t total_num_entries = 0, total_num_deletes = 0;
uint64_t total_num_input_entries = 0, total_num_deletes = 0;
uint64_t total_data_size = 0;
size_t total_memory_usage = 0;
uint64_t total_num_range_deletes = 0;
@@ -922,7 +924,7 @@ Status FlushJob::WriteLevel0Table() {
if (range_del_iter != nullptr) {
range_del_iters.emplace_back(range_del_iter);
}
total_num_entries += m->NumEntries();
total_num_input_entries += m->NumEntries();
total_num_deletes += m->NumDeletion();
total_data_size += m->GetDataSize();
total_memory_usage += m->ApproximateMemoryUsage();
@@ -934,11 +936,12 @@ Status FlushJob::WriteLevel0Table() {
// "Write Buffer Full", should make update flush_reason_ accordingly.
event_logger_->Log() << "job" << job_context_->job_id << "event"
<< "flush_started" << "num_memtables" << mems_.size()
<< "num_entries" << total_num_entries << "num_deletes"
<< total_num_deletes << "total_data_size"
<< total_data_size << "memory_usage"
<< total_memory_usage << "num_range_deletes"
<< total_num_range_deletes << "flush_reason"
<< "total_num_input_entries" << total_num_input_entries
<< "num_deletes" << total_num_deletes
<< "total_data_size" << total_data_size
<< "memory_usage" << total_memory_usage
<< "num_range_deletes" << total_num_range_deletes
<< "flush_reason"
<< GetFlushReasonString(flush_reason_);
{
@@ -976,7 +979,6 @@ Status FlushJob::WriteLevel0Table() {
meta_.oldest_ancester_time = oldest_ancester_time;
meta_.file_creation_time = current_time;
uint64_t num_input_entries = 0;
uint64_t memtable_payload_bytes = 0;
uint64_t memtable_garbage_bytes = 0;
IOStatus io_s;
@@ -1010,16 +1012,38 @@ Status FlushJob::WriteLevel0Table() {
cfd_->internal_stats(), &io_s, io_tracer_,
BlobFileCreationReason::kFlush, seqno_to_time_mapping_.get(),
event_logger_, job_context_->job_id, &table_properties_, write_hint,
full_history_ts_low, blob_callback_, base_, &num_input_entries,
&memtable_payload_bytes, &memtable_garbage_bytes);
full_history_ts_low, blob_callback_, base_, &memtable_payload_bytes,
&memtable_garbage_bytes, &flush_stats);
TEST_SYNC_POINT_CALLBACK("FlushJob::WriteLevel0Table:s", &s);
// TODO: Cleanup io_status in BuildTable and table builders
assert(!s.ok() || io_s.ok());
io_s.PermitUncheckedError();
if (num_input_entries != total_num_entries && s.ok()) {
std::string msg = "Expected " + std::to_string(total_num_entries) +
if (s.ok() && total_num_input_entries != flush_stats.num_input_records) {
std::string msg = "Expected " +
std::to_string(total_num_input_entries) +
" entries in memtables, but read " +
std::to_string(num_input_entries);
std::to_string(flush_stats.num_input_records);
ROCKS_LOG_WARN(db_options_.info_log, "[%s] [JOB %d] Level-0 flush %s",
cfd_->GetName().c_str(), job_context_->job_id,
msg.c_str());
if (db_options_.flush_verify_memtable_count) {
s = Status::Corruption(msg);
}
}
// Only verify on table with format collects table properties
if (s.ok() &&
(mutable_cf_options_.table_factory->IsInstanceOf(
TableFactory::kBlockBasedTableName()) ||
mutable_cf_options_.table_factory->IsInstanceOf(
TableFactory::kPlainTableName())) &&
flush_stats.num_output_records != table_properties_.num_entries) {
std::string msg =
"Number of keys in flush output SST files does not match "
"number of keys added to the table. Expected " +
std::to_string(flush_stats.num_output_records) + " but there are " +
std::to_string(table_properties_.num_entries) +
" in output SST files";
ROCKS_LOG_WARN(db_options_.info_log, "[%s] [JOB %d] Level-0 flush %s",
cfd_->GetName().c_str(), job_context_->job_id,
msg.c_str());
@@ -1085,12 +1109,10 @@ Status FlushJob::WriteLevel0Table() {
// Piggyback FlushJobInfo on the first first flushed memtable.
mems_[0]->SetFlushJobInfo(GetFlushJobInfo());
// Note that here we treat flush as level 0 compaction in internal stats
InternalStats::CompactionStats stats(CompactionReason::kFlush, 1);
const uint64_t micros = clock_->NowMicros() - start_micros;
const uint64_t cpu_micros = clock_->CPUMicros() - start_cpu_micros;
stats.micros = micros;
stats.cpu_micros = cpu_micros;
flush_stats.micros = micros;
flush_stats.cpu_micros = cpu_micros;
ROCKS_LOG_INFO(db_options_.info_log,
"[%s] [JOB %d] Flush lasted %" PRIu64
@@ -1099,22 +1121,23 @@ Status FlushJob::WriteLevel0Table() {
cpu_micros);
if (has_output) {
stats.bytes_written = meta_.fd.GetFileSize();
stats.num_output_files = 1;
flush_stats.bytes_written = meta_.fd.GetFileSize();
flush_stats.num_output_files = 1;
}
const auto& blobs = edit_->GetBlobFileAdditions();
for (const auto& blob : blobs) {
stats.bytes_written_blob += blob.GetTotalBlobBytes();
flush_stats.bytes_written_blob += blob.GetTotalBlobBytes();
}
stats.num_output_files_blob = static_cast<int>(blobs.size());
flush_stats.num_output_files_blob = static_cast<int>(blobs.size());
RecordTimeToHistogram(stats_, FLUSH_TIME, stats.micros);
cfd_->internal_stats()->AddCompactionStats(0 /* level */, thread_pri_, stats);
RecordTimeToHistogram(stats_, FLUSH_TIME, flush_stats.micros);
cfd_->internal_stats()->AddCompactionStats(0 /* level */, thread_pri_,
flush_stats);
cfd_->internal_stats()->AddCFStats(
InternalStats::BYTES_FLUSHED,
stats.bytes_written + stats.bytes_written_blob);
flush_stats.bytes_written + flush_stats.bytes_written_blob);
RecordFlushIOStats();
return s;
+1
View File
@@ -42,6 +42,7 @@ using MinIterHeap =
std::priority_queue<InternalIterator*, std::vector<InternalIterator*>,
MinIterComparator>;
// TODO: name to TailingIterator
/**
* ForwardIterator is a special type of iterator that only supports Seek()
* and Next(). It is expected to perform better than TailingIterator by
+15 -8
View File
@@ -45,6 +45,8 @@ const std::map<LevelStatType, LevelStat> InternalStats::compaction_level_stats =
{LevelStatType::RN_GB, LevelStat{"RnGB", "Rn(GB)"}},
{LevelStatType::RNP1_GB, LevelStat{"Rnp1GB", "Rnp1(GB)"}},
{LevelStatType::WRITE_GB, LevelStat{"WriteGB", "Write(GB)"}},
{LevelStatType::WRITE_PRE_COMP_GB,
LevelStat{"WPreCompGB", "WPreComp(GB)"}},
{LevelStatType::W_NEW_GB, LevelStat{"WnewGB", "Wnew(GB)"}},
{LevelStatType::MOVED_GB, LevelStat{"MovedGB", "Moved(GB)"}},
{LevelStatType::WRITE_AMP, LevelStat{"WriteAmp", "W-Amp"}},
@@ -100,19 +102,20 @@ void PrintLevelStatsHeader(char* buf, size_t len, const std::string& cf_name,
int line_size = snprintf(
buf + written_size, len - written_size,
"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s "
"%s "
"%s\n",
// Note that we skip COMPACTED_FILES and merge it with Files column
group_by.c_str(), hdr(LevelStatType::NUM_FILES),
hdr(LevelStatType::SIZE_BYTES), hdr(LevelStatType::SCORE),
hdr(LevelStatType::READ_GB), hdr(LevelStatType::RN_GB),
hdr(LevelStatType::RNP1_GB), hdr(LevelStatType::WRITE_GB),
hdr(LevelStatType::W_NEW_GB), hdr(LevelStatType::MOVED_GB),
hdr(LevelStatType::WRITE_AMP), hdr(LevelStatType::READ_MBPS),
hdr(LevelStatType::WRITE_MBPS), hdr(LevelStatType::COMP_SEC),
hdr(LevelStatType::COMP_CPU_SEC), hdr(LevelStatType::COMP_COUNT),
hdr(LevelStatType::AVG_SEC), hdr(LevelStatType::KEY_IN),
hdr(LevelStatType::KEY_DROP), hdr(LevelStatType::R_BLOB_GB),
hdr(LevelStatType::W_BLOB_GB));
hdr(LevelStatType::WRITE_PRE_COMP_GB), hdr(LevelStatType::W_NEW_GB),
hdr(LevelStatType::MOVED_GB), hdr(LevelStatType::WRITE_AMP),
hdr(LevelStatType::READ_MBPS), hdr(LevelStatType::WRITE_MBPS),
hdr(LevelStatType::COMP_SEC), hdr(LevelStatType::COMP_CPU_SEC),
hdr(LevelStatType::COMP_COUNT), hdr(LevelStatType::AVG_SEC),
hdr(LevelStatType::KEY_IN), hdr(LevelStatType::KEY_DROP),
hdr(LevelStatType::R_BLOB_GB), hdr(LevelStatType::W_BLOB_GB));
written_size += line_size;
written_size = std::min(written_size, static_cast<int>(len));
@@ -140,6 +143,8 @@ void PrepareLevelStats(std::map<LevelStatType, double>* level_stats,
stats.bytes_read_non_output_levels / kGB;
(*level_stats)[LevelStatType::RNP1_GB] = stats.bytes_read_output_level / kGB;
(*level_stats)[LevelStatType::WRITE_GB] = stats.bytes_written / kGB;
(*level_stats)[LevelStatType::WRITE_PRE_COMP_GB] =
stats.bytes_written_pre_comp / kGB;
(*level_stats)[LevelStatType::W_NEW_GB] = bytes_new / kGB;
(*level_stats)[LevelStatType::MOVED_GB] = stats.bytes_moved / kGB;
(*level_stats)[LevelStatType::WRITE_AMP] = w_amp;
@@ -164,12 +169,13 @@ void PrintLevelStats(char* buf, size_t len, const std::string& name,
buf, len,
"%4s " /* Level */
"%6d/%-3d " /* Files */
"%8s " /* Size */
"%10s " /* Size */
"%5.1f " /* Score */
"%8.1f " /* Read(GB) */
"%7.1f " /* Rn(GB) */
"%8.1f " /* Rnp1(GB) */
"%9.1f " /* Write(GB) */
"%9.1f " /* WPreComp(GB) */
"%8.1f " /* Wnew(GB) */
"%9.1f " /* Moved(GB) */
"%5.1f " /* W-Amp */
@@ -193,6 +199,7 @@ void PrintLevelStats(char* buf, size_t len, const std::string& name,
stat_value.at(LevelStatType::RN_GB),
stat_value.at(LevelStatType::RNP1_GB),
stat_value.at(LevelStatType::WRITE_GB),
stat_value.at(LevelStatType::WRITE_PRE_COMP_GB),
stat_value.at(LevelStatType::W_NEW_GB),
stat_value.at(LevelStatType::MOVED_GB),
stat_value.at(LevelStatType::WRITE_AMP),
+15 -1
View File
@@ -71,6 +71,7 @@ enum class LevelStatType {
RN_GB,
RNP1_GB,
WRITE_GB,
WRITE_PRE_COMP_GB,
W_NEW_GB,
MOVED_GB,
WRITE_AMP,
@@ -179,6 +180,9 @@ class InternalStats {
// Total number of bytes written to table files during compaction
uint64_t bytes_written;
// Total number of bytes written pre-compression during compaction
uint64_t bytes_written_pre_comp;
// Total number of bytes written to blob files during compaction
uint64_t bytes_written_blob;
@@ -231,6 +235,7 @@ class InternalStats {
bytes_skipped_output_level(0),
bytes_read_blob(0),
bytes_written(0),
bytes_written_pre_comp(0),
bytes_written_blob(0),
bytes_moved(0),
num_input_files_in_non_output_levels(0),
@@ -258,6 +263,7 @@ class InternalStats {
bytes_skipped_output_level(0),
bytes_read_blob(0),
bytes_written(0),
bytes_written_pre_comp(0),
bytes_written_blob(0),
bytes_moved(0),
num_input_files_in_non_output_levels(0),
@@ -291,6 +297,7 @@ class InternalStats {
bytes_skipped_output_level(c.bytes_skipped_output_level),
bytes_read_blob(c.bytes_read_blob),
bytes_written(c.bytes_written),
bytes_written_pre_comp(c.bytes_written_pre_comp),
bytes_written_blob(c.bytes_written_blob),
bytes_moved(c.bytes_moved),
num_input_files_in_non_output_levels(
@@ -321,6 +328,7 @@ class InternalStats {
bytes_skipped_output_level = c.bytes_skipped_output_level;
bytes_read_blob = c.bytes_read_blob;
bytes_written = c.bytes_written;
bytes_written_pre_comp = c.bytes_written_pre_comp;
bytes_written_blob = c.bytes_written_blob;
bytes_moved = c.bytes_moved;
num_input_files_in_non_output_levels =
@@ -353,6 +361,7 @@ class InternalStats {
this->bytes_skipped_output_level = 0;
this->bytes_read_blob = 0;
this->bytes_written = 0;
this->bytes_written_pre_comp = 0;
this->bytes_written_blob = 0;
this->bytes_moved = 0;
this->num_input_files_in_non_output_levels = 0;
@@ -381,6 +390,7 @@ class InternalStats {
this->bytes_skipped_output_level += c.bytes_skipped_output_level;
this->bytes_read_blob += c.bytes_read_blob;
this->bytes_written += c.bytes_written;
this->bytes_written_pre_comp += c.bytes_written_pre_comp;
this->bytes_written_blob += c.bytes_written_blob;
this->bytes_moved += c.bytes_moved;
this->num_input_files_in_non_output_levels +=
@@ -413,6 +423,7 @@ class InternalStats {
this->bytes_skipped_output_level -= c.bytes_skipped_output_level;
this->bytes_read_blob -= c.bytes_read_blob;
this->bytes_written -= c.bytes_written;
this->bytes_written_pre_comp -= c.bytes_written_pre_comp;
this->bytes_written_blob -= c.bytes_written_blob;
this->bytes_moved -= c.bytes_moved;
this->num_input_files_in_non_output_levels -=
@@ -697,7 +708,10 @@ class InternalStats {
// a full cache, which would force a re-scan on the next GetStats.
std::shared_ptr<CacheEntryStatsCollector<CacheEntryRoleStats>>
cache_entry_stats_collector_;
// Per-ColumnFamily/level compaction stats
// Per-column family and level compaction statistics, including flush and file
// ingestion. These are treated as compactions to L0 or the level where the
// file was ingested.
std::vector<CompactionStats> comp_stats_;
std::vector<CompactionStats> comp_stats_by_pri_;
CompactionStats per_key_placement_comp_stats_;
+1
View File
@@ -418,6 +418,7 @@ DECLARE_uint32(uncache_aggressiveness);
DECLARE_int32(test_ingest_standalone_range_deletion_one_in);
DECLARE_bool(allow_unprepared_value);
DECLARE_string(file_temperature_age_thresholds);
DECLARE_bool(allow_trivial_copy_when_change_temperature);
DECLARE_uint32(commit_bypass_memtable_one_in);
DECLARE_bool(track_and_verify_wals);
DECLARE_bool(enable_remote_compaction);
+3
View File
@@ -536,6 +536,9 @@ DEFINE_string(file_temperature_age_thresholds, "",
"See CompactionOptionsFIFO::file_temperature_age_thresholds. "
"empty == unset");
DEFINE_bool(allow_trivial_copy_when_change_temperature, true,
"Allow kChangeTemperature to do trivial copy");
static const bool FLAGS_subcompactions_dummy __attribute__((__unused__)) =
RegisterFlagValidator(&FLAGS_subcompactions, &ValidateUint32Range);
@@ -26,25 +26,50 @@ class DbStressTablePropertiesCollector : public TablePropertiesCollector {
Status AddUserKey(const Slice& /* key */, const Slice& /* value */,
EntryType /*type*/, SequenceNumber /*seq*/,
uint64_t /*file_size*/) override {
++keys_added;
++all_calls;
return Status::OK();
}
Status Finish(UserCollectedProperties* /* properties */) override {
void BlockAdd(uint64_t /* block_uncomp_bytes */,
uint64_t /* block_compressed_bytes_fast */,
uint64_t /* block_compressed_bytes_slow */) override {
++blocks_added;
++all_calls;
}
Status Finish(UserCollectedProperties* properties) override {
++all_calls;
(*properties)["db_stress_collector_property"] =
std::to_string(keys_added) + ";" + std::to_string(blocks_added) + ";" +
std::to_string(all_calls);
return Status::OK();
}
UserCollectedProperties GetReadableProperties() const override {
return UserCollectedProperties{};
UserCollectedProperties props;
const_cast<DbStressTablePropertiesCollector*>(this)->Finish(&props);
return props;
}
const char* Name() const override {
return "DbStressTablePropertiesCollector";
}
bool NeedCompact() const override { return need_compact_; }
bool NeedCompact() const override {
++all_calls;
return need_compact_;
}
private:
const bool need_compact_;
// These are tracked to detect race conditions that would arise from RocksDB
// invoking TablePropertiesCollector functions in an unsynchronized way, as
// TablePropertiesCollectors are allowed (encouraged) not to be thread safe.
size_t keys_added = 0;
size_t blocks_added = 0;
// Including race between BlockAdd and AddUserKey (etc.)
mutable size_t all_calls = 0;
};
// A `DbStressTablePropertiesCollectorFactory` creates
+23 -4
View File
@@ -427,6 +427,11 @@ bool StressTest::BuildOptionsTable() {
std::vector<std::string>{
"{{temperature=kWarm;age=30}:{temperature=kCold;age=300}}",
"{{temperature=kCold;age=100}}", "{}"});
options_tbl.emplace(
"allow_trivial_copy_when_change_temperature",
std::vector<std::string>{
FLAGS_allow_trivial_copy_when_change_temperature ? "true"
: "false"});
}
// NOTE: allow -1 to mean starting disabled but dynamically changing
@@ -838,11 +843,21 @@ Status StressTest::NewTxn(WriteOptions& write_opts, ThreadState* thread,
FLAGS_use_only_the_last_commit_time_batch_for_recovery;
txn_options.lock_timeout = 600000; // 10 min
txn_options.deadlock_detect = true;
if (FLAGS_commit_bypass_memtable_one_in > 0) {
if (FLAGS_commit_bypass_memtable_one_in > 0 &&
thread->rand.OneIn(FLAGS_commit_bypass_memtable_one_in)) {
assert(FLAGS_txn_write_policy == 0);
assert(FLAGS_user_timestamp_size == 0);
txn_options.commit_bypass_memtable =
thread->rand.OneIn(FLAGS_commit_bypass_memtable_one_in);
if (thread->rand.OneIn(2)) {
txn_options.commit_bypass_memtable = true;
}
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;
}
@@ -4216,10 +4231,14 @@ void InitializeOptionsFromFlags(
StringToTemperature(FLAGS_default_temperature.c_str());
if (!FLAGS_file_temperature_age_thresholds.empty()) {
const std::string allowTrivialCopyBoolStr =
FLAGS_allow_trivial_copy_when_change_temperature ? "true" : "false";
Status s = GetColumnFamilyOptionsFromString(
{}, options,
"compaction_options_fifo={file_temperature_age_thresholds=" +
FLAGS_file_temperature_age_thresholds + "}",
FLAGS_file_temperature_age_thresholds +
";allow_trivial_copy_when_change_temperature=" +
allowTrivialCopyBoolStr + "}",
&options);
if (!s.ok()) {
fprintf(stderr, "While setting file_temperature_age_thresholds: %s\n",
+12 -3
View File
@@ -233,6 +233,13 @@ class NonBatchedOpsStressTest : public StressTest {
}
Status s = secondary_db_->TryCatchUpWithPrimary();
#ifndef NDEBUG
uint64_t manifest_num = static_cast_with_check<DBImpl>(secondary_db_)
->TEST_Current_Manifest_FileNo();
#else
uint64_t manifest_num = 0;
#endif
if (!s.ok()) {
VerificationAbort(shared,
"Secondary failed to catch up to the primary");
@@ -267,9 +274,11 @@ class NonBatchedOpsStressTest : public StressTest {
assert(!pre_read_expected_values.empty() &&
static_cast<size_t>(i - start) <
pre_read_expected_values.size());
VerifyValueRange(static_cast<int>(cf), i, options, shared, from_db,
/* msg_prefix */ "Secondary get verification", s,
pre_read_expected_values[i - start]);
VerifyValueRange(
static_cast<int>(cf), i, options, shared, from_db,
/* msg_prefix */ "Secondary get verification, manifest: " +
std::to_string(manifest_num),
s, pre_read_expected_values[i - start]);
}
}
} else if (method == VerificationMethod::kGetEntity) {
+32 -14
View File
@@ -22,7 +22,10 @@ IOStatus CopyFile(FileSystem* fs, const std::string& source,
Temperature src_temp_hint,
std::unique_ptr<WritableFileWriter>& dest_writer,
uint64_t size, bool use_fsync,
const std::shared_ptr<IOTracer>& io_tracer) {
const std::shared_ptr<IOTracer>& io_tracer,
uint64_t max_read_buffer_size,
const std::optional<IOOptions>& readIOOptions,
const std::optional<IOOptions>& writeIOOptions) {
FileOptions soptions;
IOStatus io_s;
std::unique_ptr<SequentialFileReader> src_reader;
@@ -38,7 +41,8 @@ IOStatus CopyFile(FileSystem* fs, const std::string& source,
if (size == 0) {
// default argument means copy everything
io_s = fs->GetFileSize(source, opts, &size, nullptr);
io_s =
fs->GetFileSize(source, readIOOptions.value_or(opts), &size, nullptr);
if (!io_s.ok()) {
return io_s;
}
@@ -47,14 +51,23 @@ IOStatus CopyFile(FileSystem* fs, const std::string& source,
new SequentialFileReader(std::move(srcfile), source, io_tracer));
}
char buffer[4096];
const size_t read_buffer_size = std::max(
static_cast<size_t>(4096), static_cast<size_t>(max_read_buffer_size));
std::unique_ptr<char[]> buffer;
buffer.reset(new char[read_buffer_size]);
Env::IOPriority read_rate_limiter_priority = Env::IO_TOTAL;
if (readIOOptions.has_value()) {
read_rate_limiter_priority = readIOOptions.value().rate_limiter_priority;
}
Slice slice;
while (size > 0) {
size_t bytes_to_read = std::min(sizeof(buffer), static_cast<size_t>(size));
size_t bytes_to_read = std::min(static_cast<size_t>(read_buffer_size),
static_cast<size_t>(size));
// TODO: rate limit copy file
io_s = status_to_io_status(
src_reader->Read(bytes_to_read, &slice, buffer,
Env::IO_TOTAL /* rate_limiter_priority */));
io_s = status_to_io_status(src_reader->Read(
bytes_to_read, &slice, buffer.get(),
read_rate_limiter_priority /* rate_limiter_priority */));
if (!io_s.ok()) {
return io_s;
}
@@ -65,19 +78,22 @@ IOStatus CopyFile(FileSystem* fs, const std::string& source,
std::to_string(dest_writer->GetFileSize()));
}
io_s = dest_writer->Append(opts, slice);
io_s = dest_writer->Append(writeIOOptions.value_or(opts), slice);
if (!io_s.ok()) {
return io_s;
}
size -= slice.size();
}
return dest_writer->Sync(opts, use_fsync);
return dest_writer->Sync(writeIOOptions.value_or(opts), use_fsync);
}
IOStatus CopyFile(FileSystem* fs, const std::string& source,
Temperature src_temp_hint, const std::string& destination,
Temperature dst_temp, uint64_t size, bool use_fsync,
const std::shared_ptr<IOTracer>& io_tracer) {
const std::shared_ptr<IOTracer>& io_tracer,
uint64_t max_read_buffer_size,
const std::optional<IOOptions>& readIOOptions,
const std::optional<IOOptions>& writeIOOptions) {
FileOptions options;
IOStatus io_s;
std::unique_ptr<WritableFileWriter> dest_writer;
@@ -96,7 +112,8 @@ IOStatus CopyFile(FileSystem* fs, const std::string& source,
}
return CopyFile(fs, source, src_temp_hint, dest_writer, size, use_fsync,
io_tracer);
io_tracer, max_read_buffer_size, readIOOptions,
writeIOOptions);
}
// Utility function to create a file with the provided contents
@@ -230,15 +247,16 @@ IOStatus GenerateOneFileChecksum(
Slice slice;
uint64_t offset = 0;
IOOptions opts;
io_s = reader->PrepareIOOptions(read_options, opts);
IODebugContext dbg;
io_s = reader->PrepareIOOptions(read_options, opts, &dbg);
if (!io_s.ok()) {
return io_s;
}
while (size > 0) {
size_t bytes_to_read =
static_cast<size_t>(std::min(uint64_t{readahead_size}, size));
io_s =
reader->Read(opts, offset, bytes_to_read, &slice, buf.get(), nullptr);
io_s = reader->Read(opts, offset, bytes_to_read, &slice, buf.get(), nullptr,
&dbg);
if (!io_s.ok()) {
return IOStatus::Corruption("file read failed with error: " +
io_s.ToString());
+22 -5
View File
@@ -24,18 +24,28 @@ IOStatus CopyFile(FileSystem* fs, const std::string& source,
Temperature src_temp_hint,
std::unique_ptr<WritableFileWriter>& dest_writer,
uint64_t size, bool use_fsync,
const std::shared_ptr<IOTracer>& io_tracer);
const std::shared_ptr<IOTracer>& io_tracer,
uint64_t max_read_buffer_size = 4096,
const std::optional<IOOptions>& readIOOptions = {},
const std::optional<IOOptions>& writeIOOptions = {});
IOStatus CopyFile(FileSystem* fs, const std::string& source,
Temperature src_temp_hint, const std::string& destination,
Temperature dst_temp, uint64_t size, bool use_fsync,
const std::shared_ptr<IOTracer>& io_tracer);
const std::shared_ptr<IOTracer>& io_tracer,
uint64_t max_read_buffer_size = 4096,
const std::optional<IOOptions>& readIOOptions = {},
const std::optional<IOOptions>& writeIOOptions = {});
inline IOStatus CopyFile(const std::shared_ptr<FileSystem>& fs,
const std::string& source, Temperature src_temp_hint,
const std::string& destination, Temperature dst_temp,
uint64_t size, bool use_fsync,
const std::shared_ptr<IOTracer>& io_tracer) {
const std::shared_ptr<IOTracer>& io_tracer,
uint64_t max_read_buffer_size = 4096,
const std::optional<IOOptions>& readIOOptions = {},
const std::optional<IOOptions>& writeIOOptions = {}) {
return CopyFile(fs.get(), source, src_temp_hint, destination, dst_temp, size,
use_fsync, io_tracer);
use_fsync, io_tracer, max_read_buffer_size, readIOOptions,
writeIOOptions);
}
IOStatus CreateFile(FileSystem* fs, const std::string& destination,
const std::string& contents, bool use_fsync);
@@ -76,7 +86,14 @@ IOStatus GenerateOneFileChecksum(
const ReadOptions& read_options, Statistics* stats, SystemClock* clock);
inline IOStatus PrepareIOFromReadOptions(const ReadOptions& ro,
SystemClock* clock, IOOptions& opts) {
SystemClock* clock, IOOptions& opts,
IODebugContext* dbg = nullptr) {
if (ro.request_id != nullptr) {
if (dbg != nullptr && dbg->request_id == nullptr) {
dbg->SetRequestId(ro.request_id);
}
}
if (ro.deadline.count()) {
std::chrono::microseconds now =
std::chrono::microseconds(clock->NowMicros());
+21 -12
View File
@@ -106,11 +106,14 @@ IOStatus RandomAccessFileReader::Create(
IOStatus RandomAccessFileReader::Read(const IOOptions& opts, uint64_t offset,
size_t n, Slice* result, char* scratch,
AlignedBuf* aligned_buf) const {
AlignedBuf* aligned_buf,
IODebugContext* dbg) const {
(void)aligned_buf;
const Env::IOPriority rate_limiter_priority = opts.rate_limiter_priority;
TEST_SYNC_POINT_CALLBACK("RandomAccessFileReader::Read", nullptr);
TEST_SYNC_POINT_CALLBACK("RandomAccessFileReader::Read:IODebugContext",
const_cast<void*>(static_cast<void*>(dbg)));
// To be paranoid: modify scratch a little bit, so in case underlying
// FileSystem doesn't fill the buffer but return success and `scratch` returns
@@ -175,7 +178,7 @@ IOStatus RandomAccessFileReader::Read(const IOOptions& opts, uint64_t offset,
// the opts.timeout before calling file_->Read
assert(!opts.timeout.count() || allowed == read_size);
io_s = file_->Read(aligned_offset + buf.CurrentSize(), allowed, opts,
&tmp, buf.Destination(), nullptr);
&tmp, buf.Destination(), dbg);
}
if (ShouldNotifyListeners()) {
auto finish_ts = FileOperationInfo::FinishNow();
@@ -237,7 +240,7 @@ IOStatus RandomAccessFileReader::Read(const IOOptions& opts, uint64_t offset,
// the opts.timeout before calling file_->Read
assert(!opts.timeout.count() || allowed == n);
io_s = file_->Read(offset + pos, allowed, opts, &tmp_result,
scratch + pos, nullptr);
scratch + pos, dbg);
}
if (ShouldNotifyListeners()) {
auto finish_ts = FileOperationInfo::FinishNow();
@@ -311,7 +314,8 @@ bool TryMerge(FSReadRequest* dest, const FSReadRequest& src) {
IOStatus RandomAccessFileReader::MultiRead(const IOOptions& opts,
FSReadRequest* read_reqs,
size_t num_reqs,
AlignedBuf* aligned_buf) const {
AlignedBuf* aligned_buf,
IODebugContext* dbg) const {
(void)aligned_buf; // suppress warning of unused variable in LITE mode
assert(num_reqs > 0);
@@ -420,8 +424,10 @@ IOStatus RandomAccessFileReader::MultiRead(const IOOptions& opts,
remaining_bytes -= request_bytes;
}
}
io_s = file_->MultiRead(fs_reqs, num_fs_reqs, opts,
/*IODebugContext*=*/nullptr);
TEST_SYNC_POINT_CALLBACK(
"RandomAccessFileReader::MultiRead:IODebugContext",
const_cast<void*>(static_cast<void*>(dbg)));
io_s = file_->MultiRead(fs_reqs, num_fs_reqs, opts, dbg);
RecordInHistogram(stats_, MULTIGET_IO_BATCH_SIZE, num_fs_reqs);
}
@@ -475,18 +481,21 @@ IOStatus RandomAccessFileReader::MultiRead(const IOOptions& opts,
}
IOStatus RandomAccessFileReader::PrepareIOOptions(const ReadOptions& ro,
IOOptions& opts) const {
IOOptions& opts,
IODebugContext* dbg) const {
if (clock_ != nullptr) {
return PrepareIOFromReadOptions(ro, clock_, opts);
return PrepareIOFromReadOptions(ro, clock_, opts, dbg);
} else {
return PrepareIOFromReadOptions(ro, SystemClock::Default().get(), opts);
return PrepareIOFromReadOptions(ro, SystemClock::Default().get(), opts,
dbg);
}
}
IOStatus RandomAccessFileReader::ReadAsync(
FSReadRequest& req, const IOOptions& opts,
std::function<void(FSReadRequest&, void*)> cb, void* cb_arg,
void** io_handle, IOHandleDeleter* del_fn, AlignedBuf* aligned_buf) {
void** io_handle, IOHandleDeleter* del_fn, AlignedBuf* aligned_buf,
IODebugContext* dbg) {
IOStatus s;
// Create a callback and populate info.
auto read_async_callback =
@@ -532,14 +541,14 @@ IOStatus RandomAccessFileReader::ReadAsync(
(stats_ != nullptr) ? &elapsed : nullptr, true /*overwrite*/,
true /*delay_enabled*/);
s = file_->ReadAsync(aligned_req, opts, read_async_callback,
read_async_info, io_handle, del_fn, nullptr /*dbg*/);
read_async_info, io_handle, del_fn, dbg);
} else {
StopWatch sw(clock_, stats_, hist_type_,
GetFileReadHistograms(stats_, opts.io_activity),
(stats_ != nullptr) ? &elapsed : nullptr, true /*overwrite*/,
true /*delay_enabled*/);
s = file_->ReadAsync(req, opts, read_async_callback, read_async_info,
io_handle, del_fn, nullptr /*dbg*/);
io_handle, del_fn, dbg);
}
RecordTick(stats_, READ_ASYNC_MICROS, elapsed);
+10 -6
View File
@@ -164,7 +164,8 @@ class RandomAccessFileReader {
// the internally allocated buffer on return, and the result refers to a
// region in aligned_buf.
IOStatus Read(const IOOptions& opts, uint64_t offset, size_t n, Slice* result,
char* scratch, AlignedBuf* aligned_buf) const;
char* scratch, AlignedBuf* aligned_buf,
IODebugContext* dbg = nullptr) const;
// REQUIRES:
// num_reqs > 0, reqs do not overlap, and offsets in reqs are increasing.
@@ -172,10 +173,12 @@ class RandomAccessFileReader {
// In direct IO mode, aligned_buf stores the aligned buffer allocated inside
// MultiRead, the result Slices in reqs refer to aligned_buf.
IOStatus MultiRead(const IOOptions& opts, FSReadRequest* reqs,
size_t num_reqs, AlignedBuf* aligned_buf) const;
size_t num_reqs, AlignedBuf* aligned_buf,
IODebugContext* dbg = nullptr) const;
IOStatus Prefetch(const IOOptions& opts, uint64_t offset, size_t n) const {
return file_->Prefetch(offset, n, opts, nullptr);
IOStatus Prefetch(const IOOptions& opts, uint64_t offset, size_t n,
IODebugContext* dbg = nullptr) const {
return file_->Prefetch(offset, n, opts, dbg);
}
FSRandomAccessFile* file() { return file_.get(); }
@@ -184,12 +187,13 @@ class RandomAccessFileReader {
bool use_direct_io() const { return file_->use_direct_io(); }
IOStatus PrepareIOOptions(const ReadOptions& ro, IOOptions& opts) const;
IOStatus PrepareIOOptions(const ReadOptions& ro, IOOptions& opts,
IODebugContext* dbg = nullptr) const;
IOStatus ReadAsync(FSReadRequest& req, const IOOptions& opts,
std::function<void(FSReadRequest&, void*)> cb,
void* cb_arg, void** io_handle, IOHandleDeleter* del_fn,
AlignedBuf* aligned_buf);
AlignedBuf* aligned_buf, IODebugContext* dbg = nullptr);
void ReadAsyncCallback(FSReadRequest& req, void* cb_arg);
};
+12 -8
View File
@@ -147,8 +147,9 @@ TEST_F(RandomAccessFileReaderTest, MultiReadDirectIO) {
reqs.push_back(std::move(r0));
reqs.push_back(std::move(r1));
AlignedBuf aligned_buf;
ASSERT_OK(
r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf));
IODebugContext dbg;
ASSERT_OK(r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf,
&dbg));
AssertResult(content, reqs);
@@ -192,8 +193,9 @@ TEST_F(RandomAccessFileReaderTest, MultiReadDirectIO) {
reqs.push_back(std::move(r1));
reqs.push_back(std::move(r2));
AlignedBuf aligned_buf;
ASSERT_OK(
r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf));
IODebugContext dbg;
ASSERT_OK(r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf,
&dbg));
AssertResult(content, reqs);
@@ -237,8 +239,9 @@ TEST_F(RandomAccessFileReaderTest, MultiReadDirectIO) {
reqs.push_back(std::move(r1));
reqs.push_back(std::move(r2));
AlignedBuf aligned_buf;
ASSERT_OK(
r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf));
IODebugContext dbg;
ASSERT_OK(r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf,
&dbg));
AssertResult(content, reqs);
@@ -274,8 +277,9 @@ TEST_F(RandomAccessFileReaderTest, MultiReadDirectIO) {
reqs.push_back(std::move(r0));
reqs.push_back(std::move(r1));
AlignedBuf aligned_buf;
ASSERT_OK(
r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf));
IODebugContext dbg;
ASSERT_OK(r->MultiRead(IOOptions(), reqs.data(), reqs.size(), &aligned_buf,
&dbg));
AssertResult(content, reqs);
+17
View File
@@ -115,6 +115,21 @@ struct CompactionOptionsFIFO {
// Default: empty
std::vector<FileTemperatureAge> file_temperature_age_thresholds{};
// EXPERIMENTAL
// If true, when compaction is picked for kChangeTemperature reason,
// allow the trivia copy of the sst file from source FileSystem to
// destination FileSystem. If false, the changeTemperature will be
// the non-trivial copy by iterating/appending blocks by blocks of the
// sst file.
bool allow_trivial_copy_when_change_temperature = false;
// EXPERIMENTAL
// If 'allow_trivia_copy_op_when_change_temperature=true', the tmp buffer size
// to copy the file from the source FileSystem to the destnation FileSystem.
// If 'allow_trivia_copy_op_when_change_temperature=false', this field will
// not be used. The minmum buffer size must be at least 4KiB
uint64_t trivial_copy_buffer_size = 4096;
CompactionOptionsFIFO() : max_table_files_size(1 * 1024 * 1024 * 1024) {}
CompactionOptionsFIFO(uint64_t _max_table_files_size, bool _allow_compaction)
: max_table_files_size(_max_table_files_size),
@@ -1106,6 +1121,8 @@ struct AdvancedColumnFamilyOptions {
// CompactOnDeletionCollectorFactory) together with this option to compact
// away tombstones after the memtable is flushed.
//
// Note that this option has no effect on tailing iterators yet.
//
// Default: 0 (disabled)
// Dynamically changeable through the SetOptions() API.
uint32_t memtable_op_scan_flush_trigger = 0;
+208 -2
View File
@@ -69,6 +69,7 @@ extern "C" {
/* Exported types */
typedef struct rocksdb_t rocksdb_t;
typedef struct rocksdb_status_ptr_t rocksdb_status_ptr_t;
typedef struct rocksdb_backup_engine_t rocksdb_backup_engine_t;
typedef struct rocksdb_backup_engine_info_t rocksdb_backup_engine_info_t;
typedef struct rocksdb_backup_engine_options_t rocksdb_backup_engine_options_t;
@@ -79,6 +80,7 @@ typedef struct rocksdb_hyper_clock_cache_options_t
rocksdb_hyper_clock_cache_options_t;
typedef struct rocksdb_cache_t rocksdb_cache_t;
typedef struct rocksdb_write_buffer_manager_t rocksdb_write_buffer_manager_t;
typedef struct rocksdb_sst_file_manager_t rocksdb_sst_file_manager_t;
typedef struct rocksdb_compactionfilter_t rocksdb_compactionfilter_t;
typedef struct rocksdb_compactionfiltercontext_t
rocksdb_compactionfiltercontext_t;
@@ -141,6 +143,15 @@ typedef struct rocksdb_statistics_histogram_data_t
rocksdb_statistics_histogram_data_t;
typedef struct rocksdb_wait_for_compact_options_t
rocksdb_wait_for_compact_options_t;
typedef struct rocksdb_flushjobinfo_t rocksdb_flushjobinfo_t;
typedef struct rocksdb_compactionjobinfo_t rocksdb_compactionjobinfo_t;
typedef struct rocksdb_subcompactionjobinfo_t rocksdb_subcompactionjobinfo_t;
typedef struct rocksdb_externalfileingestioninfo_t
rocksdb_externalfileingestioninfo_t;
typedef struct rocksdb_eventlistener_t rocksdb_eventlistener_t;
typedef struct rocksdb_writestallinfo_t rocksdb_writestallinfo_t;
typedef struct rocksdb_writestallcondition_t rocksdb_writestallcondition_t;
typedef struct rocksdb_memtableinfo_t rocksdb_memtableinfo_t;
/* DB operations */
@@ -986,11 +997,22 @@ extern ROCKSDB_LIBRARY_API char* rocksdb_writebatch_wi_get_from_batch_and_db(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options, const char* key, size_t keylen,
size_t* vallen, char** errptr);
extern ROCKSDB_LIBRARY_API rocksdb_pinnableslice_t*
rocksdb_writebatch_wi_get_pinned_from_batch_and_db(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options, const char* key, size_t keylen,
char** errptr);
extern ROCKSDB_LIBRARY_API char* rocksdb_writebatch_wi_get_from_batch_and_db_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, size_t* vallen, char** errptr);
extern ROCKSDB_LIBRARY_API rocksdb_pinnableslice_t*
rocksdb_writebatch_wi_get_pinned_from_batch_and_db_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_write_writebatch_wi(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_wi_t* wbwi, char** errptr);
@@ -998,13 +1020,20 @@ extern ROCKSDB_LIBRARY_API rocksdb_iterator_t*
rocksdb_writebatch_wi_create_iterator_with_base(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator);
extern ROCKSDB_LIBRARY_API rocksdb_iterator_t*
rocksdb_writebatch_wi_create_iterator_with_base_readopts(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
const rocksdb_readoptions_t* options);
extern ROCKSDB_LIBRARY_API rocksdb_iterator_t*
rocksdb_writebatch_wi_create_iterator_with_base_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
rocksdb_column_family_handle_t* cf);
extern ROCKSDB_LIBRARY_API rocksdb_iterator_t*
rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
rocksdb_column_family_handle_t* cf, const rocksdb_readoptions_t* options);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_wi_update_timestamps(
rocksdb_writebatch_wi_t* wbwi, const char* ts, size_t tslen, void* state,
size_t (*get_ts_size)(void*, uint32_t), char** errptr);
/* Options utils */
// Load the latest rocksdb options from the specified db_path.
@@ -1126,6 +1155,137 @@ rocksdb_block_based_options_set_unpartitioned_pinning_tier(
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_write_buffer_manager(
rocksdb_options_t* opt, rocksdb_write_buffer_manager_t* wbm);
/* Flush job info */
extern ROCKSDB_LIBRARY_API const char* rocksdb_flushjobinfo_cf_name(
const rocksdb_flushjobinfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API const char* rocksdb_flushjobinfo_file_path(
const rocksdb_flushjobinfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_flushjobinfo_triggered_writes_slowdown(const rocksdb_flushjobinfo_t*);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_flushjobinfo_triggered_writes_stop(const rocksdb_flushjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_largest_seqno(const rocksdb_flushjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_smallest_seqno(const rocksdb_flushjobinfo_t*);
extern ROCKSDB_LIBRARY_API void rocksdb_reset_status(
rocksdb_status_ptr_t* status_ptr);
/* Compaction job info */
extern ROCKSDB_LIBRARY_API void rocksdb_compactionjobinfo_status(
const rocksdb_compactionjobinfo_t* info, char** errptr);
extern ROCKSDB_LIBRARY_API const char* rocksdb_compactionjobinfo_cf_name(
const rocksdb_compactionjobinfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compactionjobinfo_input_files_count(const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API const char* rocksdb_compactionjobinfo_input_file_at(
const rocksdb_compactionjobinfo_t*, size_t pos, size_t*);
extern ROCKSDB_LIBRARY_API size_t rocksdb_compactionjobinfo_output_files_count(
const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API const char* rocksdb_compactionjobinfo_output_file_at(
const rocksdb_compactionjobinfo_t*, size_t pos, size_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_elapsed_micros(const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_num_corrupt_keys(const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API int rocksdb_compactionjobinfo_base_input_level(
const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API int rocksdb_compactionjobinfo_output_level(
const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_input_records(const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_output_records(const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_total_input_bytes(const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_total_output_bytes(
const rocksdb_compactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API uint32_t rocksdb_compactionjobinfo_compaction_reason(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API size_t rocksdb_compactionjobinfo_num_input_files(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compactionjobinfo_num_input_files_at_output_level(
const rocksdb_compactionjobinfo_t* info);
/* Subcompaction job info */
extern ROCKSDB_LIBRARY_API void rocksdb_subcompactionjobinfo_status(
const rocksdb_subcompactionjobinfo_t*, char**);
extern ROCKSDB_LIBRARY_API const char* rocksdb_subcompactionjobinfo_cf_name(
const rocksdb_subcompactionjobinfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_subcompactionjobinfo_thread_id(const rocksdb_subcompactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API int rocksdb_subcompactionjobinfo_base_input_level(
const rocksdb_subcompactionjobinfo_t*);
extern ROCKSDB_LIBRARY_API int rocksdb_subcompactionjobinfo_output_level(
const rocksdb_subcompactionjobinfo_t*);
/* External file ingestion info */
extern ROCKSDB_LIBRARY_API const char*
rocksdb_externalfileingestioninfo_cf_name(
const rocksdb_externalfileingestioninfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_externalfileingestioninfo_internal_file_path(
const rocksdb_externalfileingestioninfo_t*, size_t*);
/* External write stall info */
extern ROCKSDB_LIBRARY_API const char* rocksdb_writestallinfo_cf_name(
const rocksdb_writestallinfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API const rocksdb_writestallcondition_t*
rocksdb_writestallinfo_cur(const rocksdb_writestallinfo_t*);
extern ROCKSDB_LIBRARY_API const rocksdb_writestallcondition_t*
rocksdb_writestallinfo_prev(const rocksdb_writestallinfo_t*);
extern ROCKSDB_LIBRARY_API const char* rocksdb_memtableinfo_cf_name(
const rocksdb_memtableinfo_t*, size_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_first_seqno(const rocksdb_memtableinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_earliest_seqno(const rocksdb_memtableinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_num_entries(const rocksdb_memtableinfo_t*);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_num_deletes(const rocksdb_memtableinfo_t*);
/* Event listener */
typedef void (*on_flush_begin_cb)(void*, rocksdb_t*,
const rocksdb_flushjobinfo_t*);
typedef void (*on_flush_completed_cb)(void*, rocksdb_t*,
const rocksdb_flushjobinfo_t*);
typedef void (*on_compaction_begin_cb)(void*, rocksdb_t*,
const rocksdb_compactionjobinfo_t*);
typedef void (*on_compaction_completed_cb)(void*, rocksdb_t*,
const rocksdb_compactionjobinfo_t*);
typedef void (*on_subcompaction_begin_cb)(
void*, const rocksdb_subcompactionjobinfo_t*);
typedef void (*on_subcompaction_completed_cb)(
void*, const rocksdb_subcompactionjobinfo_t*);
typedef void (*on_external_file_ingested_cb)(
void*, rocksdb_t*, const rocksdb_externalfileingestioninfo_t*);
typedef void (*on_background_error_cb)(void*, uint32_t, rocksdb_status_ptr_t*);
typedef void (*on_stall_conditions_changed_cb)(void*,
const rocksdb_writestallinfo_t*);
typedef void (*rocksdb_logger_logv_cb)(void*, uint32_t log_level, const char*);
typedef void (*on_memtable_sealed_cb)(void*, const rocksdb_memtableinfo_t*);
extern ROCKSDB_LIBRARY_API rocksdb_eventlistener_t*
rocksdb_eventlistener_create(
void* state_, void (*destructor_)(void*), on_flush_begin_cb on_flush_begin,
on_flush_completed_cb on_flush_completed,
on_compaction_begin_cb on_compaction_begin,
on_compaction_completed_cb on_compaction_completed,
on_subcompaction_begin_cb on_subcompaction_begin,
on_subcompaction_completed_cb on_subcompaction_completed,
on_external_file_ingested_cb on_external_file_ingested,
on_background_error_cb on_background_error,
on_stall_conditions_changed_cb on_stall_conditions_changed,
on_memtable_sealed_cb on_memtable_sealed);
extern ROCKSDB_LIBRARY_API void rocksdb_eventlistener_destroy(
rocksdb_eventlistener_t*);
extern ROCKSDB_LIBRARY_API void rocksdb_options_add_eventlistener(
rocksdb_options_t*, rocksdb_eventlistener_t*);
/* Cuckoo table options */
extern ROCKSDB_LIBRARY_API rocksdb_cuckoo_table_options_t*
@@ -1875,7 +2035,8 @@ enum {
rocksdb_blob_decompress_time,
rocksdb_internal_range_del_reseek_count,
rocksdb_block_read_cpu_time,
rocksdb_total_metric_count = 79
rocksdb_internal_merge_point_lookup_count,
rocksdb_total_metric_count = 80
};
extern ROCKSDB_LIBRARY_API void rocksdb_set_perf_level(int);
@@ -2225,6 +2386,51 @@ extern ROCKSDB_LIBRARY_API void rocksdb_write_buffer_manager_set_buffer_size(
extern ROCKSDB_LIBRARY_API void rocksdb_write_buffer_manager_set_allow_stall(
rocksdb_write_buffer_manager_t* wbm, bool new_allow_stall);
/* SstFileManager */
extern ROCKSDB_LIBRARY_API rocksdb_sst_file_manager_t*
rocksdb_sst_file_manager_create(rocksdb_env_t* env);
extern ROCKSDB_LIBRARY_API void rocksdb_sst_file_manager_destroy(
rocksdb_sst_file_manager_t* sfm);
extern ROCKSDB_LIBRARY_API void
rocksdb_sst_file_manager_set_max_allowed_space_usage(
rocksdb_sst_file_manager_t* sfm, uint64_t max_allowed_space);
extern ROCKSDB_LIBRARY_API void
rocksdb_sst_file_manager_set_compaction_buffer_size(
rocksdb_sst_file_manager_t* sfm, uint64_t compaction_buffer_size);
extern ROCKSDB_LIBRARY_API bool
rocksdb_sst_file_manager_is_max_allowed_space_reached(
rocksdb_sst_file_manager_t* sfm);
extern ROCKSDB_LIBRARY_API bool
rocksdb_sst_file_manager_is_max_allowed_space_reached_including_compactions(
rocksdb_sst_file_manager_t* sfm);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_sst_file_manager_get_total_size(rocksdb_sst_file_manager_t* sfm);
extern ROCKSDB_LIBRARY_API int64_t
rocksdb_sst_file_manager_get_delete_rate_bytes_per_second(
rocksdb_sst_file_manager_t* sfm);
extern ROCKSDB_LIBRARY_API void
rocksdb_sst_file_manager_set_delete_rate_bytes_per_second(
rocksdb_sst_file_manager_t* sfm, int64_t delete_rate);
extern ROCKSDB_LIBRARY_API double
rocksdb_sst_file_manager_get_max_trash_db_ratio(
rocksdb_sst_file_manager_t* sfm);
extern ROCKSDB_LIBRARY_API void rocksdb_sst_file_manager_set_max_trash_db_ratio(
rocksdb_sst_file_manager_t* sfm, double ratio);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_sst_file_manager_get_total_trash_size(rocksdb_sst_file_manager_t* sfm);
/* HyperClockCache */
extern ROCKSDB_LIBRARY_API rocksdb_hyper_clock_cache_options_t*
+2
View File
@@ -27,6 +27,8 @@ enum CompressionType : unsigned char {
kXpressCompression = 0x6,
kZSTD = 0x7,
// TODO: add enum values for user custom compression types
// kDisableCompressionOption is used to disable some compression options.
kDisableCompressionOption = 0xff,
};
+17 -1
View File
@@ -125,6 +125,17 @@ class ExternalTableReader {
std::vector<std::string>* values,
std::vector<Status>* statuses) = 0;
// Allocate and return the contents of the properties block. If the builder
// supports PutPropertiesBlock(), then this must be supported. The
// properties block should be written to the table file as is (no
// compression or mutation of any kind), and its offset in the file
// should be returned in file_offset.
virtual Status GetPropertiesBlock(std::unique_ptr<char[]>* /*property_block*/,
uint64_t* /*size*/,
uint64_t* /*file_offset*/) {
return Status::NotSupported();
}
// Return TableProperties for the file. At a minimum, the following
// properties need to be returned -
// comparator_name
@@ -179,6 +190,11 @@ class ExternalTableBuilder {
// Finish().
virtual uint64_t FileSize() const = 0;
// Write the raw properties block as is in the table file
virtual Status PutPropertiesBlock(const Slice& /*property_block*/) {
return Status::NotSupported();
}
// As mentioned in earlier comments, the following table properties must be
// returned at a minimum -
// comparator_name
@@ -253,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
+6 -3
View File
@@ -220,6 +220,8 @@ struct FileOptions : EnvOptions {
// A structure to pass back some debugging information from the FileSystem
// implementation to RocksDB in case of an IO error
// TODO(virajthakur): Update all calls to FS APIs for writes to pass in
// IODebugContext
struct IODebugContext {
// file_path to be filled in by RocksDB in case of an error
std::string file_path;
@@ -230,8 +232,9 @@ struct IODebugContext {
// To be set by the FileSystem implementation
std::string msg;
// To be set by the underlying FileSystem implementation.
std::string request_id;
// To be set by the application, to allow tracing logs/metrics from user ->
// RocksDB -> FS.
const std::string* request_id = nullptr;
// In order to log required information in IO tracing for different
// operations, Each bit in trace_data stores which corresponding info from
@@ -255,7 +258,7 @@ struct IODebugContext {
// Called by underlying file system to set request_id and log request_id in
// IOTracing.
void SetRequestId(const std::string& _request_id) {
void SetRequestId(const std::string* _request_id) {
request_id = _request_id;
trace_data |= (1 << TraceData::kRequestID);
}
+25 -2
View File
@@ -464,6 +464,12 @@ struct CompactionServiceJobInfo {
std::string db_name;
std::string db_id;
std::string db_session_id;
// the id of the column family where the compaction happened.
uint32_t cf_id;
// the name of the column family where the compaction happened.
std::string cf_name;
uint64_t job_id; // job_id is only unique within the current DB and session,
// restart DB will reset the job_id. `db_id` and
// `db_session_id` could help you build unique id across
@@ -484,7 +490,8 @@ struct CompactionServiceJobInfo {
int output_level;
CompactionServiceJobInfo(std::string db_name_, std::string db_id_,
std::string db_session_id_, uint64_t job_id_,
std::string db_session_id_, uint32_t cf_id_,
std::string cf_name_, uint64_t job_id_,
Env::Priority priority_,
CompactionReason compaction_reason_,
bool is_full_compaction_, bool is_manual_compaction_,
@@ -493,6 +500,8 @@ struct CompactionServiceJobInfo {
: db_name(std::move(db_name_)),
db_id(std::move(db_id_)),
db_session_id(std::move(db_session_id_)),
cf_id(cf_id_),
cf_name(std::move(cf_name_)),
job_id(job_id_),
priority(priority_),
compaction_reason(compaction_reason_),
@@ -605,7 +614,8 @@ struct DBOptions {
// DEPRECATED: This option might be removed in a future release.
//
// If true, during memtable flush, RocksDB will validate total entries
// read in flush, and compare with counter inserted into it.
// read in flush, total entries written in the SST and compare them with
// counter of keys added.
//
// The option is here to turn the feature off in case this new validation
// feature has a bug. The option may be removed in the future once the
@@ -2052,6 +2062,19 @@ struct ReadOptions {
// *** END options for RocksDB internal use only ***
// *** BEGIN per-request settings for internal team use only ***
// TODO: create a new struct for per-request options, potentially including
// timestamps in point lookups/scans
// request_id is a unique id assigned by the application. It is used to allow
// us to link file system metrics/logs to rocksDB and application logs. This
// request_id may not be unique to each RocksDB api call - it could refer to
// an application level request that results in multiple RocksDB api calls
const std::string* request_id = nullptr;
// *** END per-request settings for internal team use only ***
ReadOptions() {}
ReadOptions(bool _verify_checksums, bool _fill_cache);
explicit ReadOptions(Env::IOActivity _io_activity);
+10
View File
@@ -516,6 +516,7 @@ enum Tickers : uint32_t {
// Number of FIFO compactions that drop files based on different reasons
FIFO_MAX_SIZE_COMPACTIONS,
FIFO_TTL_COMPACTIONS,
FIFO_CHANGE_TEMPERATURE_COMPACTIONS,
// Number of bytes prefetched during user initiated scan
PREFETCH_BYTES,
@@ -535,6 +536,12 @@ enum Tickers : uint32_t {
FILE_READ_CORRUPTION_RETRY_COUNT,
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT,
// Counter for the number of times a WBWI is ingested into the DB. This
// happens when IngestWriteBatchWithIndex() is used and when large
// transaction optimization is enabled through
// TransactionOptions::large_txn_commit_optimize_threshold.
NUMBER_WBWI_INGEST,
TICKER_ENUM_MAX
};
@@ -672,6 +679,9 @@ enum Histograms : uint32_t {
// system's prefetch) from the end of SST table during block based table open
TABLE_OPEN_PREFETCH_TAIL_READ_BYTES,
// Number of operations per transaction.
NUM_OP_PER_TRANSACTION,
HISTOGRAM_ENUM_MAX
};
+2
View File
@@ -316,6 +316,8 @@ class Status {
return Status(kInvalidArgument, kTxnNotPrepared, msg, msg2);
}
static Status LockLimit() { return Status(kAborted, kLockLimit); }
// Returns true iff the status indicates success.
bool ok() const {
MarkChecked();
+37 -3
View File
@@ -254,10 +254,12 @@ struct TransactionDBOptions {
// for more details.
std::vector<std::shared_ptr<SecondaryIndex>> secondary_indices;
// EXPERIMENTAL, SUBJECT TO CHANGE
// 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
// a transaction exceeds this threshold, then the transaction commit will skip
// insertions into memtable as an optimization to reduce commit latency.
// a transaction is at least this threshold, then the transaction commit will
// skip insertions into memtable as an optimization to reduce commit latency.
// See comment for TransactionOptions::commit_bypass_memtable for more detail.
// Setting TransactionOptions::commit_bypass_memtable to true takes precedence
// over this option.
@@ -364,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
@@ -387,6 +405,22 @@ struct TransactionOptions {
// can cause flush/compaction to report `num_single_del_mismatch` due to
// consecutive SingleDeletes.
bool commit_bypass_memtable = false;
// EXPERIMENTAL, SUBJECT TO CHANGE
// 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.
//
// 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
@@ -236,7 +236,8 @@ class WriteBatchWithIndex : public WriteBatchBase {
Iterator* base_iterator,
const ReadOptions* opts = nullptr);
// default column family
Iterator* NewIteratorWithBase(Iterator* base_iterator);
Iterator* NewIteratorWithBase(Iterator* base_iterator,
const ReadOptions* opts = nullptr);
// Similar to DB::Get() but will only read the key from this batch.
// If the batch does not have enough data to resolve Merge operations,
+2 -2
View File
@@ -12,8 +12,8 @@
// NOTE: in 'main' development branch, this should be the *next*
// minor or major version number planned for release.
#define ROCKSDB_MAJOR 10
#define ROCKSDB_MINOR 2
#define ROCKSDB_PATCH 0
#define ROCKSDB_MINOR 3
#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
+4
View File
@@ -5273,6 +5273,8 @@ class TickerTypeJni {
return -0x56;
case ROCKSDB_NAMESPACE::Tickers::FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT:
return -0x57;
case ROCKSDB_NAMESPACE::Tickers::FIFO_CHANGE_TEMPERATURE_COMPACTIONS:
return -0x58;
case ROCKSDB_NAMESPACE::Tickers::TICKER_ENUM_MAX:
// -0x54 is the max value at this time. Since these values are exposed
// directly to Java clients, we'll keep the value the same till the next
@@ -5735,6 +5737,8 @@ class TickerTypeJni {
case -0x57:
return ROCKSDB_NAMESPACE::Tickers::
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT;
case -0x58:
return ROCKSDB_NAMESPACE::Tickers::FIFO_CHANGE_TEMPERATURE_COMPACTIONS;
case -0x54:
// -0x54 is the max value at this time. Since these values are exposed
// directly to Java clients, we'll keep the value the same till the next
+30
View File
@@ -341,6 +341,36 @@ jobjectArray Java_org_rocksdb_Transaction_multiGet__JJ_3_3B(
statuses);
}
/*
* Class: org_rocksdb_Transaction
* Method: multiGet
* Signature: (JJJ[[B)[[B
*/
jobjectArray Java_org_rocksdb_Transaction_multiGet__JJJ_3_3B(
JNIEnv* env, jclass /*jobj*/, jlong jhandle, jlong jread_options_handle,
jlong jcf_handle, jobjectArray jkeys) {
ROCKSDB_NAMESPACE::MultiGetJNIKeys keys;
if (!keys.fromByteArrays(env, jkeys)) {
return nullptr;
}
auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
auto* cf_handle =
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(jcf_handle);
size_t num_keys = keys.size();
std::vector<ROCKSDB_NAMESPACE::PinnableSlice> values(num_keys);
std::vector<ROCKSDB_NAMESPACE::Status> statuses(num_keys);
txn->MultiGet(
*reinterpret_cast<ROCKSDB_NAMESPACE::ReadOptions*>(jread_options_handle),
cf_handle, num_keys, keys.slices().data(), values.data(), statuses.data(),
/*sorted_input=*/false);
return ROCKSDB_NAMESPACE::MultiGetJNIValues::byteArrays<
ROCKSDB_NAMESPACE::PinnableSlice>(env, values, statuses);
}
/*
* Class: org_rocksdb_Transaction
* Method: getForUpdate
@@ -661,6 +661,46 @@ public class Transaction extends RocksObject {
return Arrays.asList(multiGet(nativeHandle_, readOptions.nativeHandle_, keysArray));
}
/**
* This function is similar to
* {@link RocksDB#multiGetAsList} except it will
* also read pending changes in this transaction.
* Currently, this function will return Status::MergeInProgress if the most
* recent write to the queried key in this batch is a Merge.
* <p>
* If {@link ReadOptions#snapshot()} is not set, the current version of the
* key will be read. Calling {@link #setSnapshot()} does not affect the
* version of the data returned.
* <p>
* Note that setting {@link ReadOptions#setSnapshot(Snapshot)} will affect
* what is read from the DB but will NOT change which keys are read from this
* transaction (the keys in this transaction do not yet belong to any snapshot
* and will be fetched regardless).
* <p>
* This method uses the optimized path with support for batched reads.
*
* @param readOptions Read options.=
* {@link org.rocksdb.ColumnFamilyHandle} instances.
* @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
* instance
* @param keys of keys for which values need to be retrieved.
*
* @return Array of values, one for each key
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public List<byte[]> multiGetAsList(final ReadOptions readOptions,
final ColumnFamilyHandle columnFamilyHandle, final List<byte[]> keys)
throws RocksDBException {
if (keys.isEmpty()) {
return new ArrayList<>(0);
}
final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
return Arrays.asList(multiGet(
nativeHandle_, readOptions.nativeHandle_, columnFamilyHandle.nativeHandle_, keysArray));
}
/**
* Read this key and ensure that this transaction will only
* be able to be committed if this key is not written outside this
@@ -2877,6 +2917,8 @@ public class Transaction extends RocksObject {
final byte[][] keys, final long[] columnFamilyHandles) throws RocksDBException;
private static native byte[][] multiGet(
final long handle, final long readOptionsHandle, final byte[][] keys) throws RocksDBException;
private static native byte[][] multiGet(final long nativeHandle, final long readOptionsHandle,
final long cfHandle, final byte[][] keys) throws RocksDBException;
private static native byte[] getForUpdate(final long handle, final long readOptionsHandle,
final byte[] key, final int keyOffset, final int keyLength, final long columnFamilyHandle,
final boolean exclusive, final boolean doValidate) throws RocksDBException;
@@ -345,6 +345,32 @@ public class TransactionTest extends AbstractTransactionTest {
}
}
@Test
public void multiGetAsList() throws RocksDBException {
final byte[] k1 = "k1".getBytes(UTF_8);
final byte[] k2 = "k2".getBytes(UTF_8);
final byte[] k3 = "k3".getBytes(UTF_8);
final byte[] v1 = "v1".getBytes(UTF_8);
final byte[] v2 = "v2".getBytes(UTF_8);
try (final DBContainer dbContainer = startDb();
final ReadOptions readOptions = new ReadOptions()) {
final ColumnFamilyHandle testCf = dbContainer.getTestColumnFamily();
try (final Transaction txn = dbContainer.beginTransaction()) {
txn.put(testCf, k1, v1);
txn.put(testCf, k2, v2);
txn.commit();
}
try (final Transaction txn = dbContainer.beginTransaction()) {
final List<byte[]> result =
txn.multiGetAsList(readOptions, testCf, Arrays.asList(k1, k2, k3));
assertThat(result).containsExactly(v1, v2, null);
}
}
}
@Test
public void name() throws RocksDBException {
try(final DBContainer dbContainer = startDb();
+1 -1
View File
@@ -31,7 +31,7 @@ using CacheAllocationPtr = std::unique_ptr<char[], CustomDeleter>;
inline CacheAllocationPtr AllocateBlock(size_t size,
MemoryAllocator* allocator) {
if (allocator) {
auto block = reinterpret_cast<char*>(allocator->Allocate(size));
auto block = static_cast<char*>(allocator->Allocate(size));
return CacheAllocationPtr(block, allocator);
}
return CacheAllocationPtr(new char[size]);
+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*/) {
+4
View File
@@ -262,6 +262,8 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
{READAHEAD_TRIMMED, "rocksdb.readahead.trimmed"},
{FIFO_MAX_SIZE_COMPACTIONS, "rocksdb.fifo.max.size.compactions"},
{FIFO_TTL_COMPACTIONS, "rocksdb.fifo.ttl.compactions"},
{FIFO_CHANGE_TEMPERATURE_COMPACTIONS,
"rocksdb.fifo.change_temperature.compactions"},
{PREFETCH_BYTES, "rocksdb.prefetch.bytes"},
{PREFETCH_BYTES_USEFUL, "rocksdb.prefetch.bytes.useful"},
{PREFETCH_HITS, "rocksdb.prefetch.hits"},
@@ -270,6 +272,7 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
"rocksdb.file.read.corruption.retry.count"},
{FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT,
"rocksdb.file.read.corruption.retry.success.count"},
{NUMBER_WBWI_INGEST, "rocksdb.number.wbwi.ingest"},
};
const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
@@ -341,6 +344,7 @@ const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
{ASYNC_PREFETCH_ABORT_MICROS, "rocksdb.async.prefetch.abort.micros"},
{TABLE_OPEN_PREFETCH_TAIL_READ_BYTES,
"rocksdb.table.open.prefetch.tail.read.bytes"},
{NUM_OP_PER_TRANSACTION, "rocksdb.num.op.per.transaction"},
};
std::shared_ptr<Statistics> CreateDBStatistics() {
+10 -1
View File
@@ -301,7 +301,16 @@ static std::unordered_map<std::string, OptionTypeInfo>
OptionTypeInfo::Struct("file_temperature_age_thresholds",
&file_temperature_age_type_info, 0,
OptionVerificationType::kNormal,
OptionTypeFlags::kMutable))}};
OptionTypeFlags::kMutable))},
{"allow_trivial_copy_when_change_temperature",
{offsetof(struct CompactionOptionsFIFO,
allow_trivial_copy_when_change_temperature),
OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
{"trivial_copy_buffer_size",
{offsetof(struct CompactionOptionsFIFO, trivial_copy_buffer_size),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}}};
static std::unordered_map<std::string, OptionTypeInfo>
universal_compaction_options_type_info = {
+99 -1
View File
@@ -151,7 +151,7 @@ char* Decompress(const char* input_data, size_t input_length,
return nullptr;
}
std::unique_ptr<void, decltype(CloseDecompressorFun)> compressorGuard(
std::unique_ptr<void, decltype(CloseDecompressorFun)> decompressorGuard(
decompressor, CloseDecompressorFun);
SIZE_T decompressedBufferSize = 0;
@@ -201,6 +201,104 @@ char* Decompress(const char* input_data, size_t input_length,
// Return the raw buffer to the caller supporting the tradition
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 =
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 decompressedDataSize = 0;
success = ::Decompress(decompressor, const_cast<char*>(input), input_length,
output, output_length, &decompressedDataSize);
if (!success) {
#ifdef _DEBUG
std::cerr << "XPRESS: Failed to decompress LastError " << GetLastError()
<< std::endl;
#endif
return -1;
}
return static_cast<int64_t>(decompressedDataSize);
}
} // namespace xpress
} // namespace port
} // namespace ROCKSDB_NAMESPACE
+6
View File
@@ -21,6 +21,12 @@ 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);
} // namespace xpress
} // namespace port
} // namespace ROCKSDB_NAMESPACE
File diff suppressed because it is too large. Load diff
+5 -25
View File
@@ -83,6 +83,8 @@ class BlockBasedTableBuilder : public TableBuilder {
bool IsEmpty() const override;
uint64_t PreCompressionSize() const override;
// Size of the file generated so far. If invoked after a successful
// Finish() call, returns the size of the final generated file.
uint64_t FileSize() const override;
@@ -118,12 +120,6 @@ class BlockBasedTableBuilder : public TableBuilder {
// REQUIRES: `rep_->state == kBuffered`
void EnterUnbuffered();
// Call block's Finish() method and then
// - in buffered mode, buffer the uncompressed block contents.
// - in unbuffered mode, write the compressed block contents to file.
void WriteBlock(BlockBuilder* block, BlockHandle* handle,
BlockType blocktype);
// Compress and write block content to the file.
void WriteBlock(const Slice& block_contents, BlockHandle* handle,
BlockType block_type);
@@ -159,7 +155,7 @@ class BlockBasedTableBuilder : public TableBuilder {
class BlockBasedTablePropertiesCollectorFactory;
class BlockBasedTablePropertiesCollector;
Rep* rep_;
struct WorkingAreaPair;
struct ParallelCompressionRep;
// Advanced operation: flush any buffered key/value pairs to file.
@@ -175,17 +171,13 @@ class BlockBasedTableBuilder : public TableBuilder {
// Get blocks from mem-table walking thread, compress them and
// pass them to the write thread. Used in parallel compression mode only
void BGWorkCompression(const CompressionContext& compression_ctx,
UncompressionContext* verify_ctx);
void BGWorkCompression(WorkingAreaPair& working_area);
// Given uncompressed block content, try to compress it and return result and
// compression type
void CompressAndVerifyBlock(const Slice& uncompressed_block_data,
bool is_data_block,
const CompressionContext& compression_ctx,
UncompressionContext* verify_ctx,
bool is_data_block, WorkingAreaPair& working_area,
std::string* compressed_output,
Slice* result_block_contents,
CompressionType* result_compression_type,
Status* out_status);
@@ -200,16 +192,4 @@ class BlockBasedTableBuilder : public TableBuilder {
void StopParallelCompression();
};
Slice CompressBlock(const Slice& uncompressed_data, const CompressionInfo& info,
CompressionType* type, uint32_t format_version,
bool do_sample, std::string* compressed_output,
std::string* sampled_output_fast,
std::string* sampled_output_slow);
#ifndef NDEBUG
// 0 == disable the hack
// > 0 => counter for rotating through compression types
extern RelaxedAtomic<uint64_t> g_hack_mixed_compression_in_block_based_table;
#endif
} // namespace ROCKSDB_NAMESPACE
+104 -69
View File
@@ -91,13 +91,13 @@ CacheAllocationPtr CopyBufferToHeap(MemoryAllocator* allocator, Slice& buf) {
#define INSTANTIATE_BLOCKLIKE_TEMPLATES(T) \
template Status BlockBasedTable::RetrieveBlock<T>( \
FilePrefetchBuffer * prefetch_buffer, const ReadOptions& ro, \
const BlockHandle& handle, const UncompressionDict& uncompression_dict, \
const BlockHandle& handle, UnownedPtr<Decompressor> decomp, \
CachableEntry<T>* out_parsed_block, GetContext* get_context, \
BlockCacheLookupContext* lookup_context, bool for_compaction, \
bool use_cache, bool async_read, bool use_block_cache_for_lookup) const; \
template Status BlockBasedTable::MaybeReadBlockAndLoadToCache<T>( \
FilePrefetchBuffer * prefetch_buffer, const ReadOptions& ro, \
const BlockHandle& handle, const UncompressionDict& uncompression_dict, \
const BlockHandle& handle, UnownedPtr<Decompressor> decomp, \
bool for_compaction, CachableEntry<T>* block_entry, \
GetContext* get_context, BlockCacheLookupContext* lookup_context, \
BlockContents* contents, bool async_read, \
@@ -107,7 +107,7 @@ CacheAllocationPtr CopyBufferToHeap(MemoryAllocator* allocator, Slice& buf) {
CachableEntry<T>* out_parsed_block) const;
INSTANTIATE_BLOCKLIKE_TEMPLATES(ParsedFullFilterBlock);
INSTANTIATE_BLOCKLIKE_TEMPLATES(UncompressionDict);
INSTANTIATE_BLOCKLIKE_TEMPLATES(DecompressorDict);
INSTANTIATE_BLOCKLIKE_TEMPLATES(Block_kData);
INSTANTIATE_BLOCKLIKE_TEMPLATES(Block_kIndex);
INSTANTIATE_BLOCKLIKE_TEMPLATES(Block_kFilterPartitionIndex);
@@ -195,7 +195,7 @@ Status ReadAndParseBlockFromFile(
const Footer& footer, const ReadOptions& options, const BlockHandle& handle,
std::unique_ptr<TBlocklike>* result, const ImmutableOptions& ioptions,
BlockCreateContext& create_context, bool maybe_compressed,
const UncompressionDict& uncompression_dict,
UnownedPtr<Decompressor> decomp,
const PersistentCacheOptions& cache_options,
MemoryAllocator* memory_allocator, bool for_compaction, bool async_read) {
assert(result);
@@ -204,8 +204,8 @@ Status ReadAndParseBlockFromFile(
BlockFetcher block_fetcher(
file, prefetch_buffer, footer, options, handle, &contents, ioptions,
/*do_uncompress*/ maybe_compressed, maybe_compressed,
TBlocklike::kBlockType, uncompression_dict, cache_options,
memory_allocator, nullptr, for_compaction);
TBlocklike::kBlockType, decomp, cache_options, memory_allocator, nullptr,
for_compaction);
Status s;
// If prefetch_buffer is not allocated, it will fallback to synchronous
// reading of block contents.
@@ -683,7 +683,8 @@ Status BlockBasedTable::Open(
// 6. [meta block: index]
// 7. [meta block: filter]
IOOptions opts;
s = file->PrepareIOOptions(ro, opts);
IODebugContext dbg;
s = file->PrepareIOOptions(ro, opts, &dbg);
if (s.ok()) {
s = ReadFooterFromFile(opts, file.get(), *ioptions.fs,
prefetch_buffer.get(), file_size, &footer,
@@ -708,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.
@@ -738,13 +746,23 @@ Status BlockBasedTable::Open(
return s;
}
CompressionType saved_comp_type = CompressionTypeFromString(
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()));
rep->decompressor = mgr->GetDecompressorOptimizeFor(saved_comp_type);
}
// Populate BlockCreateContext
bool blocks_definitely_zstd_compressed =
rep->table_properties && (rep->table_properties->compression_name ==
CompressionTypeToString(kZSTD));
rep->create_context = BlockCreateContext(
&rep->table_options, &rep->ioptions, rep->ioptions.stats,
blocks_definitely_zstd_compressed, block_protection_bytes_per_key,
rep->decompressor.get(), block_protection_bytes_per_key,
rep->internal_comparator.user_comparator(), rep->index_value_is_full,
rep->index_has_first_key);
@@ -934,7 +952,8 @@ Status BlockBasedTable::PrefetchTail(
#endif // NDEBUG
IOOptions opts;
Status s = file->PrepareIOOptions(ro, opts);
IODebugContext dbg;
Status s = file->PrepareIOOptions(ro, opts, &dbg);
// Try file system prefetch
if (s.ok() && !file->use_direct_io() && !force_direct_prefetch) {
if (!file->Prefetch(opts, prefetch_off, prefetch_len).IsNotSupported()) {
@@ -997,9 +1016,6 @@ Status BlockBasedTable::ReadPropertiesBlock(
"Problem reading or processing seqno-to-time mapping: %s",
s.ToString().c_str());
}
rep_->blocks_maybe_compressed =
rep_->table_properties->compression_name !=
CompressionTypeToString(kNoCompression);
}
} else {
ROCKS_LOG_ERROR(rep_->ioptions.logger,
@@ -1239,7 +1255,10 @@ Status BlockBasedTable::PrefetchIndexAndFilterBlocks(
}
}
if (!rep_->compression_dict_handle.IsNull()) {
// NOTE: before the fix to https://github.com/facebook/rocksdb/issues/12409, a
// file could have a (de)compression dictionary block without a configured
// compression, so we need to ignore the dictionary in that case.
if (!rep_->compression_dict_handle.IsNull() && rep_->decompressor) {
std::unique_ptr<UncompressionDictReader> uncompression_dict_reader;
s = UncompressionDictReader::Create(
this, ro, prefetch_buffer, use_cache, prefetch_all || pin_unpartitioned,
@@ -1301,10 +1320,9 @@ Status BlockBasedTable::ReadMetaIndexBlock(
Status s = ReadAndParseBlockFromFile(
rep_->file.get(), prefetch_buffer, rep_->footer, ro,
rep_->footer.metaindex_handle(), &metaindex, rep_->ioptions,
rep_->create_context, true /*maybe_compressed*/,
UncompressionDict::GetEmptyDict(), rep_->persistent_cache_options,
GetMemoryAllocator(rep_->table_options), false /* for_compaction */,
false /* async_read */);
rep_->create_context, true /*maybe_compressed*/, rep_->decompressor.get(),
rep_->persistent_cache_options, GetMemoryAllocator(rep_->table_options),
false /* for_compaction */, false /* async_read */);
if (!s.ok()) {
ROCKS_LOG_ERROR(rep_->ioptions.logger,
@@ -1343,7 +1361,7 @@ template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::GetDataBlockFromCache(
const Slice& cache_key, BlockCacheInterface<TBlocklike> block_cache,
CachableEntry<TBlocklike>* out_parsed_block, GetContext* get_context,
const UncompressionDict* dict) const {
UnownedPtr<Decompressor> decomp) const {
assert(out_parsed_block);
assert(out_parsed_block->IsEmpty());
@@ -1352,12 +1370,24 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::GetDataBlockFromCache(
// Lookup uncompressed cache first
if (block_cache) {
BlockCreateContext create_ctx = rep_->create_context;
create_ctx.dict = dict;
assert(!cache_key.empty());
auto cache_handle = block_cache.LookupFull(
cache_key, &create_ctx, GetCachePriority<TBlocklike>(), statistics,
rep_->ioptions.lowest_used_cache_tier);
typename BlockCacheInterface<TBlocklike>::TypedHandle* cache_handle;
if (decomp.get() != rep_->decompressor.get() && decomp) {
// `decomp` must be a dictionary-aware decompressor, which is only
// available in the block cache (so that dictionaries can be evicted
// from memory) and can't live in the table reader.
// NOTE: inefficient BlockCreateContext copy for dict-aware decompressor
// (see TODO in block_cache.h)
BlockCreateContext create_ctx = rep_->create_context;
create_ctx.decompressor = decomp.get();
cache_handle = block_cache.LookupFull(
cache_key, &create_ctx, GetCachePriority<TBlocklike>(), statistics,
rep_->ioptions.lowest_used_cache_tier);
} else {
cache_handle = block_cache.LookupFull(
cache_key, &rep_->create_context, GetCachePriority<TBlocklike>(),
statistics, rep_->ioptions.lowest_used_cache_tier);
}
// Avoid updating metrics here if the handle is not complete yet. This
// happens with MultiGet and secondary cache. So update the metrics only
@@ -1387,10 +1417,9 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::PutDataBlockToCache(
CachableEntry<TBlocklike>* out_parsed_block,
BlockContents&& uncompressed_block_contents,
BlockContents&& compressed_block_contents, CompressionType block_comp_type,
const UncompressionDict& uncompression_dict,
MemoryAllocator* memory_allocator, GetContext* get_context) const {
UnownedPtr<Decompressor> decomp, MemoryAllocator* memory_allocator,
GetContext* get_context) const {
const ImmutableOptions& ioptions = rep_->ioptions;
const uint32_t format_version = rep_->table_options.format_version;
assert(out_parsed_block);
assert(out_parsed_block->IsEmpty());
@@ -1402,12 +1431,10 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::PutDataBlockToCache(
uncompressed_block_contents.data.empty()) {
assert(compressed_block_contents.data.data());
// Retrieve the uncompressed contents into a new buffer
UncompressionContext context(block_comp_type);
UncompressionInfo info(context, uncompression_dict, block_comp_type);
s = UncompressBlockData(info, compressed_block_contents.data.data(),
compressed_block_contents.data.size(),
&uncompressed_block_contents, format_version,
ioptions, memory_allocator);
s = DecompressBlockData(
compressed_block_contents.data.data(),
compressed_block_contents.data.size(), block_comp_type, *decomp,
&uncompressed_block_contents, ioptions, memory_allocator);
if (!s.ok()) {
return s;
}
@@ -1520,15 +1547,18 @@ Status BlockBasedTable::LookupAndPinBlocksInCache(
assert(block_cache);
Status s;
CachableEntry<UncompressionDict> uncompression_dict;
CachableEntry<DecompressorDict> cached_dict;
if (rep_->uncompression_dict_reader) {
s = rep_->uncompression_dict_reader->GetOrReadUncompressionDictionary(
/* prefetch_buffer= */ nullptr, ro,
/* get_context= */ nullptr, /* lookup_context= */ nullptr,
&uncompression_dict);
&cached_dict);
if (!s.ok()) {
return s;
}
if (!cached_dict.GetValue()) {
return Status::Corruption("Success but no dictionary read");
}
}
// Do the lookup.
@@ -1537,14 +1567,20 @@ Status BlockBasedTable::LookupAndPinBlocksInCache(
Statistics* statistics = rep_->ioptions.statistics.get();
BlockCreateContext create_ctx = rep_->create_context;
create_ctx.dict = uncompression_dict.GetValue()
? uncompression_dict.GetValue()
: &UncompressionDict::GetEmptyDict();
auto cache_handle =
block_cache.LookupFull(key, &create_ctx, GetCachePriority<TBlocklike>(),
statistics, rep_->ioptions.lowest_used_cache_tier);
typename BlockCacheInterface<TBlocklike>::TypedHandle* cache_handle;
if (cached_dict.GetValue()) {
// NOTE: inefficient BlockCreateContext copy for dict-aware decompressor
// (see TODO in block_cache.h)
BlockCreateContext create_ctx = rep_->create_context;
create_ctx.decompressor = cached_dict.GetValue()->decompressor_.get();
cache_handle = block_cache.LookupFull(
key, &create_ctx, GetCachePriority<TBlocklike>(), statistics,
rep_->ioptions.lowest_used_cache_tier);
} else {
cache_handle = block_cache.LookupFull(
key, &rep_->create_context, GetCachePriority<TBlocklike>(), statistics,
rep_->ioptions.lowest_used_cache_tier);
}
if (!cache_handle) {
UpdateCacheMissMetrics(TBlocklike::kBlockType, /* get_context = */ nullptr);
@@ -1573,7 +1609,7 @@ template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike>
BlockBasedTable::MaybeReadBlockAndLoadToCache(
FilePrefetchBuffer* prefetch_buffer, const ReadOptions& ro,
const BlockHandle& handle, const UncompressionDict& uncompression_dict,
const BlockHandle& handle, UnownedPtr<Decompressor> decomp,
bool for_compaction, CachableEntry<TBlocklike>* out_parsed_block,
GetContext* get_context, BlockCacheLookupContext* lookup_context,
BlockContents* contents, bool async_read,
@@ -1597,7 +1633,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
if (!contents) {
if (use_block_cache_for_lookup) {
s = GetDataBlockFromCache(key, block_cache, out_parsed_block,
get_context, &uncompression_dict);
get_context, decomp);
// Value could still be null at this point, so check the cache handle
// and update the read pattern for prefetching
if (out_parsed_block->GetValue() ||
@@ -1627,7 +1663,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
const bool maybe_compressed =
TBlocklike::kBlockType != BlockType::kFilter &&
TBlocklike::kBlockType != BlockType::kCompressionDictionary &&
rep_->blocks_maybe_compressed;
rep_->decompressor;
// This flag, if true, tells BlockFetcher to return the uncompressed
// block when ReadBlockContents() is called.
const bool do_uncompress = maybe_compressed;
@@ -1651,8 +1687,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
BlockFetcher block_fetcher(
rep_->file.get(), prefetch_buffer, rep_->footer, ro, handle,
&tmp_contents, rep_->ioptions, do_uncompress, maybe_compressed,
TBlocklike::kBlockType, uncompression_dict,
rep_->persistent_cache_options,
TBlocklike::kBlockType, decomp, rep_->persistent_cache_options,
GetMemoryAllocator(rep_->table_options),
/*allocator=*/nullptr);
@@ -1667,7 +1702,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
s = block_fetcher.ReadBlockContents();
}
contents_comp_type = block_fetcher.get_compression_type();
contents_comp_type = block_fetcher.compression_type();
if (get_context) {
switch (TBlocklike::kBlockType) {
case BlockType::kIndex:
@@ -1699,7 +1734,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
// block in block_fetcher
s = PutDataBlockToCache(
key, block_cache, out_parsed_block, std::move(uncomp_contents),
std::move(comp_contents), contents_comp_type, uncompression_dict,
std::move(comp_contents), contents_comp_type, decomp,
GetMemoryAllocator(rep_->table_options), get_context);
}
} else {
@@ -1715,7 +1750,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
// the block to the cache.
s = PutDataBlockToCache(
key, block_cache, out_parsed_block, std::move(uncomp_contents),
std::move(comp_contents), contents_comp_type, uncompression_dict,
std::move(comp_contents), contents_comp_type, decomp,
GetMemoryAllocator(rep_->table_options), get_context);
}
}
@@ -1830,7 +1865,7 @@ void BlockBasedTable::FinishTraceRecord(
template <typename TBlocklike /*, auto*/>
WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::RetrieveBlock(
FilePrefetchBuffer* prefetch_buffer, const ReadOptions& ro,
const BlockHandle& handle, const UncompressionDict& uncompression_dict,
const BlockHandle& handle, UnownedPtr<Decompressor> decomp,
CachableEntry<TBlocklike>* out_parsed_block, GetContext* get_context,
BlockCacheLookupContext* lookup_context, bool for_compaction,
bool use_cache, bool async_read, bool use_block_cache_for_lookup) const {
@@ -1840,8 +1875,8 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::RetrieveBlock(
Status s;
if (use_cache) {
s = MaybeReadBlockAndLoadToCache(
prefetch_buffer, ro, handle, uncompression_dict, for_compaction,
out_parsed_block, get_context, lookup_context,
prefetch_buffer, ro, handle, decomp, for_compaction, out_parsed_block,
get_context, lookup_context,
/*contents=*/nullptr, async_read, use_block_cache_for_lookup);
if (!s.ok()) {
@@ -1865,7 +1900,7 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::RetrieveBlock(
const bool maybe_compressed =
TBlocklike::kBlockType != BlockType::kFilter &&
TBlocklike::kBlockType != BlockType::kCompressionDictionary &&
rep_->blocks_maybe_compressed;
rep_->decompressor;
std::unique_ptr<TBlocklike> block;
{
@@ -1874,9 +1909,9 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::RetrieveBlock(
StopWatch sw(rep_->ioptions.clock, rep_->ioptions.stats, histogram);
s = ReadAndParseBlockFromFile(
rep_->file.get(), prefetch_buffer, rep_->footer, ro, handle, &block,
rep_->ioptions, rep_->create_context, maybe_compressed,
uncompression_dict, rep_->persistent_cache_options,
GetMemoryAllocator(rep_->table_options), for_compaction, async_read);
rep_->ioptions, rep_->create_context, maybe_compressed, decomp,
rep_->persistent_cache_options, GetMemoryAllocator(rep_->table_options),
for_compaction, async_read);
if (get_context) {
switch (TBlocklike::kBlockType) {
@@ -2558,8 +2593,8 @@ Status BlockBasedTable::VerifyChecksumInBlocks(
BlockFetcher block_fetcher(
rep_->file.get(), &prefetch_buffer, rep_->footer, read_options, handle,
&contents, rep_->ioptions, false /* decompress */,
false /*maybe_compressed*/, BlockType::kData,
UncompressionDict::GetEmptyDict(), rep_->persistent_cache_options);
false /*maybe_compressed*/, BlockType::kData, nullptr /*decompressor*/,
rep_->persistent_cache_options);
s = block_fetcher.ReadBlockContents();
if (!s.ok()) {
break;
@@ -2648,12 +2683,12 @@ Status BlockBasedTable::VerifyChecksumInMetaBlocks(
// if it was checked on open.
} else {
// FIXME? Need to verify checksums of index and filter partitions?
s = BlockFetcher(
rep_->file.get(), nullptr /* prefetch buffer */, rep_->footer,
read_options, handle, &contents, rep_->ioptions,
false /* decompress */, false /*maybe_compressed*/,
GetBlockTypeForMetaBlockByName(meta_block_name),
UncompressionDict::GetEmptyDict(), rep_->persistent_cache_options)
s = BlockFetcher(rep_->file.get(), nullptr /* prefetch buffer */,
rep_->footer, read_options, handle, &contents,
rep_->ioptions, false /* decompress */,
false /*maybe_compressed*/,
GetBlockTypeForMetaBlockByName(meta_block_name),
nullptr /*decompressor*/, rep_->persistent_cache_options)
.ReadBlockContents();
}
if (!s.ok()) {
@@ -3033,7 +3068,7 @@ Status BlockBasedTable::DumpTable(WritableFile* out_file) {
// Output compression dictionary
if (rep_->uncompression_dict_reader) {
CachableEntry<UncompressionDict> uncompression_dict;
CachableEntry<DecompressorDict> uncompression_dict;
s = rep_->uncompression_dict_reader->GetOrReadUncompressionDictionary(
nullptr /* prefetch_buffer */, ro, nullptr /* get_context */,
nullptr /* lookup_context */, &uncompression_dict);
+10 -9
View File
@@ -364,7 +364,7 @@ class BlockBasedTable : public TableReader {
template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> MaybeReadBlockAndLoadToCache(
FilePrefetchBuffer* prefetch_buffer, const ReadOptions& ro,
const BlockHandle& handle, const UncompressionDict& uncompression_dict,
const BlockHandle& handle, UnownedPtr<Decompressor> decomp,
bool for_compaction, CachableEntry<TBlocklike>* block_entry,
GetContext* get_context, BlockCacheLookupContext* lookup_context,
BlockContents* contents, bool async_read,
@@ -376,7 +376,7 @@ class BlockBasedTable : public TableReader {
template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> RetrieveBlock(
FilePrefetchBuffer* prefetch_buffer, const ReadOptions& ro,
const BlockHandle& handle, const UncompressionDict& uncompression_dict,
const BlockHandle& handle, UnownedPtr<Decompressor> decomp,
CachableEntry<TBlocklike>* block_entry, GetContext* get_context,
BlockCacheLookupContext* lookup_context, bool for_compaction,
bool use_cache, bool async_read, bool use_block_cache_for_lookup) const;
@@ -397,7 +397,7 @@ class BlockBasedTable : public TableReader {
const MultiGetRange* batch,
const autovector<BlockHandle, MultiGetContext::MAX_BATCH_SIZE>* handles,
Status* statuses, CachableEntry<Block_kData>* results, char* scratch,
const UncompressionDict& uncompression_dict, bool use_fs_scratch);
UnownedPtr<Decompressor> decomp, bool use_fs_scratch);
// Get the iterator from the index reader.
//
@@ -429,7 +429,7 @@ class BlockBasedTable : public TableReader {
WithBlocklikeCheck<Status, TBlocklike> GetDataBlockFromCache(
const Slice& cache_key, BlockCacheInterface<TBlocklike> block_cache,
CachableEntry<TBlocklike>* block, GetContext* get_context,
const UncompressionDict* dict) const;
UnownedPtr<Decompressor> decomp) const;
// Put a maybe compressed block to the corresponding block caches.
// This method will perform decompression against block_contents if needed
@@ -447,8 +447,7 @@ class BlockBasedTable : public TableReader {
CachableEntry<TBlocklike>* cached_block,
BlockContents&& uncompressed_block_contents,
BlockContents&& compressed_block_contents,
CompressionType block_comp_type,
const UncompressionDict& uncompression_dict,
CompressionType block_comp_type, UnownedPtr<Decompressor> decomp,
MemoryAllocator* memory_allocator, GetContext* get_context) const;
// Calls (*handle_result)(arg, ...) repeatedly, starting with the entry found
@@ -650,9 +649,11 @@ struct BlockBasedTable::Rep {
Slice min_timestamp;
Slice max_timestamp;
// If false, blocks in this file are definitely all uncompressed. Knowing this
// before reading individual blocks enables certain optimizations.
bool blocks_maybe_compressed = true;
// If blocks might be compressed, refers to a decompressor that can decompress
// them. (nullptr -> no blocks compressed) However, if (data) blocks are
// dictionary compressed, a dictionary-aware decompressor is needed, which
// might live in the block cache.
std::shared_ptr<Decompressor> decompressor;
// These describe how index is encoded.
bool index_has_first_key = false;
@@ -60,34 +60,33 @@ TBlockIter* BlockBasedTable::NewDataBlockIterator(
}
CachableEntry<Block> block;
if (rep_->uncompression_dict_reader && block_type == BlockType::kData) {
CachableEntry<UncompressionDict> uncompression_dict;
// For async scans, don't use the prefetch buffer since an async prefetch
// might already be under way and this would invalidate it. Also, the
// uncompression dict is typically at the end of the file and would
// most likely break the sequentiality of the access pattern.
// Same is with auto_readahead_size. It iterates over index to lookup for
// data blocks. And this could break the the sequentiality of the access
// pattern.
s = rep_->uncompression_dict_reader->GetOrReadUncompressionDictionary(
((ro.async_io || ro.auto_readahead_size) ? nullptr : prefetch_buffer),
ro, get_context, lookup_context, &uncompression_dict);
if (!s.ok()) {
iter->Invalidate(s);
return iter;
{
CachableEntry<DecompressorDict> dict;
Decompressor* decomp = rep_->decompressor.get();
if (rep_->uncompression_dict_reader && block_type == BlockType::kData) {
// For async scans, don't use the prefetch buffer since an async prefetch
// might already be under way and this would invalidate it. Also, the
// uncompression dict is typically at the end of the file and would
// most likely break the sequentiality of the access pattern.
// Same is with auto_readahead_size. It iterates over index to lookup for
// data blocks. And this could break the the sequentiality of the access
// pattern.
s = rep_->uncompression_dict_reader->GetOrReadUncompressionDictionary(
((ro.async_io || ro.auto_readahead_size) ? nullptr : prefetch_buffer),
ro, get_context, lookup_context, &dict);
if (!s.ok()) {
iter->Invalidate(s);
return iter;
}
assert(dict.GetValue());
if (dict.GetValue()) {
decomp = dict.GetValue()->decompressor_.get();
}
}
const UncompressionDict& dict = uncompression_dict.GetValue()
? *uncompression_dict.GetValue()
: UncompressionDict::GetEmptyDict();
s = RetrieveBlock(
prefetch_buffer, ro, handle, dict, &block.As<IterBlocklike>(),
prefetch_buffer, ro, handle, decomp, &block.As<IterBlocklike>(),
get_context, lookup_context, for_compaction,
/* use_cache */ true, async_read, use_block_cache_for_lookup);
} else {
s = RetrieveBlock(
prefetch_buffer, ro, handle, UncompressionDict::GetEmptyDict(),
&block.As<IterBlocklike>(), get_context, lookup_context, for_compaction,
/* use_cache */ true, async_read, use_block_cache_for_lookup);
}
if (s.IsTryAgain() && async_read) {
@@ -33,7 +33,7 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
(const ReadOptions& options, const MultiGetRange* batch,
const autovector<BlockHandle, MultiGetContext::MAX_BATCH_SIZE>* handles,
Status* statuses, CachableEntry<Block_kData>* results, char* scratch,
const UncompressionDict& uncompression_dict, bool use_fs_scratch) const {
UnownedPtr<Decompressor> decomp, bool use_fs_scratch) const {
RandomAccessFileReader* file = rep_->file.get();
const Footer& footer = rep_->footer;
const ImmutableOptions& ioptions = rep_->ioptions;
@@ -51,7 +51,7 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
// XXX: use_cache=true means double cache query?
statuses[idx_in_batch] = RetrieveBlock(
nullptr, options, handle, uncompression_dict,
nullptr, options, handle, decomp,
&results[idx_in_batch].As<Block_kData>(), mget_iter->get_context,
/* lookup_context */ nullptr,
/* for_compaction */ false, /* use_cache */ true,
@@ -138,17 +138,18 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
AlignedBuf direct_io_buf;
{
IOOptions opts;
IOStatus s = file->PrepareIOOptions(options, opts);
IODebugContext dbg;
IOStatus s = file->PrepareIOOptions(options, opts, &dbg);
if (s.ok()) {
#if defined(WITH_COROUTINES)
if (file->use_direct_io()) {
#endif // WITH_COROUTINES
s = file->MultiRead(opts, &read_reqs[0], read_reqs.size(),
&direct_io_buf);
&direct_io_buf, &dbg);
#if defined(WITH_COROUTINES)
} else {
co_await batch->context()->reader().MultiReadAsync(
file, opts, &read_reqs[0], read_reqs.size(), &direct_io_buf);
file, opts, &read_reqs[0], read_reqs.size(), &direct_io_buf, &dbg);
}
#endif // WITH_COROUTINES
}
@@ -240,10 +241,11 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
// its not a memory mapped file
Slice result;
IOOptions opts;
IOStatus io_s = file->PrepareIOOptions(options, opts);
IODebugContext dbg;
IOStatus io_s = file->PrepareIOOptions(options, opts, &dbg);
opts.verify_and_reconstruct_read = true;
io_s = file->Read(opts, handle.offset(), BlockSizeWithTrailer(handle),
&result, const_cast<char*>(data), nullptr);
&result, const_cast<char*>(data), nullptr, &dbg);
if (io_s.ok()) {
assert(result.data() == data);
assert(result.size() == BlockSizeWithTrailer(handle));
@@ -298,7 +300,7 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
// necessary. Since we're passing the serialized block contents, it
// will avoid looking up the block cache
s = MaybeReadBlockAndLoadToCache(
nullptr, options, handle, uncompression_dict,
nullptr, options, handle, decomp,
/*for_compaction=*/false, block_entry, mget_iter->get_context,
/*lookup_context=*/nullptr, &serialized_block,
/*async_read=*/false, /*use_block_cache_for_lookup=*/true);
@@ -320,11 +322,9 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
GetBlockCompressionType(serialized_block);
BlockContents contents;
if (compression_type != kNoCompression) {
UncompressionContext context(compression_type);
UncompressionInfo info(context, uncompression_dict, compression_type);
s = UncompressSerializedBlock(
info, req.result.data() + req_offset, handle.size(), &contents,
footer.format_version(), rep_->ioptions, memory_allocator);
s = DecompressSerializedBlock(
req.result.data() + req_offset, handle.size(), compression_type,
*decomp, &contents, rep_->ioptions, memory_allocator);
} else {
// There are two cases here:
// 1) caller uses the shared buffer (scratch or direct io buffer);
@@ -421,10 +421,10 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::MultiGet)
{
MultiGetRange data_block_range(sst_file_range, sst_file_range.begin(),
sst_file_range.end());
CachableEntry<UncompressionDict> uncompression_dict;
Status uncompression_dict_status;
uncompression_dict_status.PermitUncheckedError();
bool uncompression_dict_inited = false;
CachableEntry<DecompressorDict> dict;
Status dict_status;
dict_status.PermitUncheckedError();
bool dict_inited = false;
size_t total_len = 0;
// GetContext for any key will do, as the stats will be aggregated
@@ -466,26 +466,26 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::MultiGet)
continue;
}
if (!uncompression_dict_inited && rep_->uncompression_dict_reader) {
uncompression_dict_status =
rep_->uncompression_dict_reader
->GetOrReadUncompressionDictionary(
nullptr /* prefetch_buffer */, read_options,
get_context, &metadata_lookup_context,
&uncompression_dict);
uncompression_dict_inited = true;
if (!dict_inited && rep_->uncompression_dict_reader) {
dict_status = rep_->uncompression_dict_reader
->GetOrReadUncompressionDictionary(
nullptr /* prefetch_buffer */, read_options,
get_context, &metadata_lookup_context, &dict);
dict_inited = true;
}
if (!uncompression_dict_status.ok()) {
assert(!uncompression_dict_status.IsNotFound());
*(miter->s) = uncompression_dict_status;
if (!dict_status.ok()) {
assert(!dict_status.IsNotFound());
*(miter->s) = dict_status;
data_block_range.SkipKey(miter);
sst_file_range.SkipKey(miter);
continue;
} else {
assert(!dict_inited || dict.GetValue() != nullptr);
}
if (dict.GetValue()) {
create_ctx.decompressor = dict.GetValue()->decompressor_.get();
}
create_ctx.dict = uncompression_dict.GetValue()
? uncompression_dict.GetValue()
: &UncompressionDict::GetEmptyDict();
if (v.handle.offset() == prev_offset) {
// This key can reuse the previous block (later on).
@@ -565,11 +565,8 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::MultiGet)
if (total_len) {
char* scratch = nullptr;
bool use_fs_scratch = false;
const UncompressionDict& dict = uncompression_dict.GetValue()
? *uncompression_dict.GetValue()
: UncompressionDict::GetEmptyDict();
assert(uncompression_dict_inited || !rep_->uncompression_dict_reader);
assert(uncompression_dict_status.ok());
assert(dict_inited || !rep_->uncompression_dict_reader);
assert(dict_status.ok());
if (!rep_->file->use_direct_io()) {
if (CheckFSFeatureSupport(rep_->ioptions.fs.get(),
@@ -589,7 +586,7 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::MultiGet)
// 3. If blocks are compressed and no compressed block cache, use
// stack buf
if (!use_fs_scratch && !rep_->file->use_direct_io() &&
rep_->blocks_maybe_compressed) {
rep_->decompressor) {
if (total_len <= kMultiGetReadStackBufSize) {
scratch = stack_buf;
} else {
@@ -599,7 +596,10 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::MultiGet)
}
CO_AWAIT(RetrieveMultipleBlocks)
(read_options, &data_block_range, &block_handles, &statuses[0],
&results[0], scratch, dict, use_fs_scratch);
&results[0], scratch,
dict.GetValue() ? dict.GetValue()->decompressor_.get()
: rep_->decompressor.get(),
use_fs_scratch);
if (get_context) {
++(get_context->get_context_stats_.num_sst_read);
}
@@ -190,6 +190,8 @@ class BlockBasedTableReaderBaseTest : public testing::Test {
if (status) {
*status = s;
} else {
ASSERT_OK(s);
}
}
+5 -5
View File
@@ -52,10 +52,10 @@ void BlockCreateContext::Create(
table_options->filter_policy.get(), std::move(block)));
}
void BlockCreateContext::Create(std::unique_ptr<UncompressionDict>* parsed_out,
void BlockCreateContext::Create(std::unique_ptr<DecompressorDict>* parsed_out,
BlockContents&& block) {
parsed_out->reset(new UncompressionDict(
block.data, std::move(block.allocation), using_zstd));
parsed_out->reset(new DecompressorDict(
block.data, std::move(block.allocation), *decompressor));
}
namespace {
@@ -69,7 +69,7 @@ const std::array<const Cache::CacheItemHelper*,
BlockCacheInterface<ParsedFullFilterBlock>::GetFullHelper(),
BlockCacheInterface<Block_kFilterPartitionIndex>::GetFullHelper(),
nullptr, // kProperties
BlockCacheInterface<UncompressionDict>::GetFullHelper(),
BlockCacheInterface<DecompressorDict>::GetFullHelper(),
BlockCacheInterface<Block_kRangeDeletion>::GetFullHelper(),
nullptr, // kHashIndexPrefixes
nullptr, // kHashIndexMetadata
@@ -86,7 +86,7 @@ const std::array<const Cache::CacheItemHelper*,
BlockCacheInterface<ParsedFullFilterBlock>::GetBasicHelper(),
BlockCacheInterface<Block_kFilterPartitionIndex>::GetBasicHelper(),
nullptr, // kProperties
BlockCacheInterface<UncompressionDict>::GetBasicHelper(),
BlockCacheInterface<DecompressorDict>::GetBasicHelper(),
BlockCacheInterface<Block_kRangeDeletion>::GetBasicHelper(),
nullptr, // kHashIndexPrefixes
nullptr, // kHashIndexMetadata
+10 -12
View File
@@ -71,15 +71,16 @@ struct BlockCreateContext : public Cache::CreateContext {
BlockCreateContext() {}
BlockCreateContext(const BlockBasedTableOptions* _table_options,
const ImmutableOptions* _ioptions, Statistics* _statistics,
bool _using_zstd, uint8_t _protection_bytes_per_key,
Decompressor* _decompressor,
uint8_t _protection_bytes_per_key,
const Comparator* _raw_ucmp,
bool _index_value_is_full = false,
bool _index_has_first_key = false)
: table_options(_table_options),
ioptions(_ioptions),
statistics(_statistics),
decompressor(_decompressor),
raw_ucmp(_raw_ucmp),
using_zstd(_using_zstd),
protection_bytes_per_key(_protection_bytes_per_key),
index_value_is_full(_index_value_is_full),
index_has_first_key(_index_has_first_key) {}
@@ -87,10 +88,9 @@ struct BlockCreateContext : public Cache::CreateContext {
const BlockBasedTableOptions* table_options = nullptr;
const ImmutableOptions* ioptions = nullptr;
Statistics* statistics = nullptr;
// TODO: refactor to avoid copying BlockCreateContext for dict in block cache
Decompressor* decompressor = nullptr;
const Comparator* raw_ucmp = nullptr;
const UncompressionDict* dict = nullptr;
uint32_t format_version;
bool using_zstd = false;
uint8_t protection_bytes_per_key = 0;
bool index_value_is_full;
bool index_has_first_key;
@@ -102,12 +102,10 @@ struct BlockCreateContext : public Cache::CreateContext {
CompressionType type, MemoryAllocator* alloc) {
BlockContents uncompressed_block_contents;
if (type != CompressionType::kNoCompression) {
assert(dict != nullptr);
UncompressionContext context(type);
UncompressionInfo info(context, *dict, type);
Status s = UncompressBlockData(
info, data.data(), data.size(), &uncompressed_block_contents,
table_options->format_version, *ioptions, alloc);
assert(decompressor != nullptr);
Status s =
DecompressBlockData(data.data(), data.size(), type, *decompressor,
&uncompressed_block_contents, *ioptions, alloc);
if (!s.ok()) {
parsed_out->reset();
return;
@@ -130,7 +128,7 @@ struct BlockCreateContext : public Cache::CreateContext {
BlockContents&& block);
void Create(std::unique_ptr<ParsedFullFilterBlock>* parsed_out,
BlockContents&& block);
void Create(std::unique_ptr<UncompressionDict>* parsed_out,
void Create(std::unique_ptr<DecompressorDict>* parsed_out,
BlockContents&& block);
};
+2 -1
View File
@@ -39,7 +39,8 @@ void BlockPrefetcher::PrefetchIfNeeded(
return;
}
IOOptions opts;
Status s = rep->file->PrepareIOOptions(read_options, opts);
IODebugContext dbg;
Status s = rep->file->PrepareIOOptions(read_options, opts, &dbg);
if (!s.ok()) {
return;
}
+35 -43
View File
@@ -833,6 +833,19 @@ class BlockPerKVChecksumTest : public DBTestBase {
}
};
namespace {
const BlockBasedTableOptions *kTableOptions() {
static BlockBasedTableOptions opts{};
return &opts;
}
Decompressor *kDecompressor() {
static auto mgr = GetBuiltinCompressionManager(
GetCompressFormatForVersion(kTableOptions()->format_version));
static auto decomp = mgr->GetDecompressor();
return decomp.get();
}
} // namespace
TEST_F(BlockPerKVChecksumTest, EmptyBlock) {
// Tests that empty block code path is not broken by per kv checksum.
BlockBuilder builder(
@@ -845,14 +858,11 @@ TEST_F(BlockPerKVChecksumTest, EmptyBlock) {
std::unique_ptr<Block_kData> data_block;
Options options = Options();
BlockBasedTableOptions tbo;
uint8_t protection_bytes_per_key = 8;
BlockCreateContext create_context{&tbo,
nullptr,
nullptr /* statistics */,
false /* using_zstd */,
protection_bytes_per_key,
options.comparator};
BlockCreateContext create_context{
kTableOptions(), nullptr,
nullptr /* statistics */, kDecompressor(),
protection_bytes_per_key, options.comparator};
create_context.Create(&data_block, std::move(contents));
std::unique_ptr<DataBlockIter> biter{data_block->NewDataIterator(
options.comparator, kDisableGlobalSequenceNumber)};
@@ -885,14 +895,10 @@ TEST_F(BlockPerKVChecksumTest, InitializeProtectionInfo) {
// Make sure that the checksum construction code path does not break
// when the block is itself already corrupted.
Options options = Options();
BlockBasedTableOptions tbo;
uint8_t protection_bytes_per_key = 8;
BlockCreateContext create_context{&tbo,
nullptr /* ioptions */,
nullptr /* statistics */,
false /* using_zstd */,
protection_bytes_per_key,
options.comparator};
BlockCreateContext create_context{
kTableOptions(), nullptr /* ioptions */, nullptr /* statistics */,
kDecompressor(), protection_bytes_per_key, options.comparator};
{
std::string invalid_content = "1";
@@ -950,20 +956,19 @@ TEST_F(BlockPerKVChecksumTest, ApproximateMemory) {
};
Options options = Options();
BlockBasedTableOptions tbo;
uint8_t protection_bytes_per_key = 8;
BlockCreateContext with_checksum_create_context{
&tbo,
kTableOptions(),
nullptr /* ioptions */,
nullptr /* statistics */,
false /* using_zstd */,
kDecompressor(),
protection_bytes_per_key,
options.comparator,
true /* index_value_is_full */};
BlockCreateContext create_context{&tbo,
BlockCreateContext create_context{kTableOptions(),
nullptr /* ioptions */,
nullptr /* statistics */,
false /* using_zstd */,
kDecompressor(),
0,
options.comparator,
true /* index_value_is_full */};
@@ -1054,13 +1059,9 @@ class DataBlockKVChecksumTest
std::unique_ptr<Block_kData> GenerateDataBlock(
std::vector<std::string> &keys, std::vector<std::string> &values,
int num_record) {
BlockBasedTableOptions tbo;
BlockCreateContext create_context{&tbo,
nullptr /* statistics */,
nullptr /* ioptions */,
false /* using_zstd */,
GetChecksumLen(),
Options().comparator};
BlockCreateContext create_context{
kTableOptions(), nullptr /* statistics */, nullptr /* ioptions */,
kDecompressor(), GetChecksumLen(), Options().comparator};
builder_ = std::make_unique<BlockBuilder>(
static_cast<int>(GetRestartInterval()),
GetUseDeltaEncoding() /* use_delta_encoding */,
@@ -1181,13 +1182,12 @@ class IndexBlockKVChecksumTest
std::vector<BlockHandle> &block_handles,
std::vector<std::string> &first_keys, int num_record) {
Options options = Options();
BlockBasedTableOptions tbo;
uint8_t protection_bytes_per_key = GetChecksumLen();
BlockCreateContext create_context{
&tbo,
kTableOptions(),
nullptr /* ioptions */,
nullptr /* statistics */,
false /* _using_zstd */,
kDecompressor(),
protection_bytes_per_key,
options.comparator,
!UseValueDeltaEncoding() /* value_is_full */,
@@ -1324,14 +1324,10 @@ class MetaIndexBlockKVChecksumTest
std::vector<std::string> &keys, std::vector<std::string> &values,
int num_record) {
Options options = Options();
BlockBasedTableOptions tbo;
uint8_t protection_bytes_per_key = GetChecksumLen();
BlockCreateContext create_context{&tbo,
nullptr /* ioptions */,
nullptr /* statistics */,
false /* using_zstd */,
protection_bytes_per_key,
options.comparator};
BlockCreateContext create_context{
kTableOptions(), nullptr /* ioptions */, nullptr /* statistics */,
kDecompressor(), protection_bytes_per_key, options.comparator};
builder_ =
std::make_unique<BlockBuilder>(static_cast<int>(GetRestartInterval()));
// add a bunch of records to a block
@@ -1359,14 +1355,10 @@ INSTANTIATE_TEST_CASE_P(P, MetaIndexBlockKVChecksumTest,
TEST_P(MetaIndexBlockKVChecksumTest, ChecksumConstructionAndVerification) {
Options options = Options();
BlockBasedTableOptions tbo;
uint8_t protection_bytes_per_key = GetChecksumLen();
BlockCreateContext create_context{&tbo,
nullptr /* ioptions */,
nullptr /* statistics */,
false /* using_zstd */,
protection_bytes_per_key,
options.comparator};
BlockCreateContext create_context{
kTableOptions(), nullptr /* ioptions */, nullptr /* statistics */,
kDecompressor(), protection_bytes_per_key, options.comparator};
std::vector<int> num_restart_intervals = {1, 16};
for (const auto num_restart_interval : num_restart_intervals) {
const int kNumRecords = num_restart_interval * GetRestartInterval();
@@ -30,8 +30,7 @@ Status FilterBlockReaderCommon<TBlocklike>::ReadFilterBlock(
const Status s = table->RetrieveBlock(
prefetch_buffer, read_options, rep->filter_handle,
UncompressionDict::GetEmptyDict(), filter_block, get_context,
lookup_context,
/* decomp */ nullptr, filter_block, get_context, lookup_context,
/* for_compaction */ false, use_cache,
/* async_read */ false, /* use_block_cache_for_lookup */ true);
+3 -3
View File
@@ -76,8 +76,8 @@ Status HashIndexReader::Create(const BlockBasedTable* table,
BlockFetcher prefixes_block_fetcher(
file, prefetch_buffer, footer, ro, prefixes_handle, &prefixes_contents,
ioptions, true /*decompress*/, true /*maybe_compressed*/,
BlockType::kHashIndexPrefixes, UncompressionDict::GetEmptyDict(),
cache_options, memory_allocator);
BlockType::kHashIndexPrefixes, rep->decompressor.get(), cache_options,
memory_allocator);
s = prefixes_block_fetcher.ReadBlockContents();
if (!s.ok()) {
return s;
@@ -87,7 +87,7 @@ Status HashIndexReader::Create(const BlockBasedTable* table,
file, prefetch_buffer, footer, ro, prefixes_meta_handle,
&prefixes_meta_contents, ioptions, true /*decompress*/,
true /*maybe_compressed*/, BlockType::kHashIndexMetadata,
UncompressionDict::GetEmptyDict(), cache_options, memory_allocator);
rep->decompressor.get(), cache_options, memory_allocator);
s = prefixes_meta_block_fetcher.ReadBlockContents();
if (!s.ok()) {
// TODO: log error
+3 -3
View File
@@ -26,9 +26,9 @@ Status BlockBasedTable::IndexReaderCommon::ReadIndexBlock(
assert(rep != nullptr);
const Status s = table->RetrieveBlock(
prefetch_buffer, read_options, rep->index_handle,
UncompressionDict::GetEmptyDict(), &index_block->As<Block_kIndex>(),
get_context, lookup_context, /* for_compaction */ false, use_cache,
prefetch_buffer, read_options, rep->index_handle, rep->decompressor.get(),
&index_block->As<Block_kIndex>(), get_context, lookup_context,
/* for_compaction */ false, use_cache,
/* async_read */ false, /* use_block_cache_for_lookup */ true);
return s;
@@ -413,8 +413,7 @@ Status PartitionedFilterBlockReader::GetFilterPartitionBlock(
const Status s = table()->RetrieveBlock(
prefetch_buffer, read_options, fltr_blk_handle,
UncompressionDict::GetEmptyDict(), filter_block, get_context,
lookup_context,
/* decomp */ nullptr, filter_block, get_context, lookup_context,
/* for_compaction */ false, /* use_cache */ true,
/* async_read */ false, /* use_block_cache_for_lookup */ true);
@@ -592,7 +591,8 @@ Status PartitionedFilterBlockReader::CacheDependencies(
/*usage=*/FilePrefetchBufferUsage::kUnknown);
IOOptions opts;
s = rep->file->PrepareIOOptions(ro, opts);
IODebugContext dbg;
s = rep->file->PrepareIOOptions(ro, opts, &dbg);
if (s.ok()) {
s = prefetch_buffer->Prefetch(opts, rep->file.get(), prefetch_off,
static_cast<size_t>(prefetch_len));
@@ -610,7 +610,7 @@ Status PartitionedFilterBlockReader::CacheDependencies(
// filter blocks
s = table()->MaybeReadBlockAndLoadToCache(
prefetch_buffer ? prefetch_buffer.get() : tail_prefetch_buffer, ro,
handle, UncompressionDict::GetEmptyDict(),
handle, /* dict */ nullptr,
/* for_compaction */ false, &block, nullptr /* get_context */,
&lookup_context, nullptr /* contents */, false,
/* use_block_cache_for_lookup */ true);
@@ -190,7 +190,7 @@ Status PartitionIndexReader::CacheDependencies(
// filter blocks
Status s = table()->MaybeReadBlockAndLoadToCache(
prefetch_buffer ? prefetch_buffer.get() : tail_prefetch_buffer, ro,
handle, UncompressionDict::GetEmptyDict(),
handle, rep->decompressor.get(),
/*for_compaction=*/false, &block.As<Block_kIndex>(),
/*get_context=*/nullptr, &lookup_context, /*contents=*/nullptr,
/*async_read=*/false, /*use_block_cache_for_lookup=*/true);
@@ -23,7 +23,7 @@ Status UncompressionDictReader::Create(
assert(!pin || prefetch);
assert(uncompression_dict_reader);
CachableEntry<UncompressionDict> uncompression_dict;
CachableEntry<DecompressorDict> uncompression_dict;
if (prefetch || !use_cache) {
const Status s = ReadUncompressionDictionary(
table, prefetch_buffer, ro, use_cache, nullptr /* get_context */,
@@ -47,7 +47,7 @@ Status UncompressionDictReader::ReadUncompressionDictionary(
const BlockBasedTable* table, FilePrefetchBuffer* prefetch_buffer,
const ReadOptions& read_options, bool use_cache, GetContext* get_context,
BlockCacheLookupContext* lookup_context,
CachableEntry<UncompressionDict>* uncompression_dict) {
CachableEntry<DecompressorDict>* uncompression_dict) {
// TODO: add perf counter for compression dictionary read time
assert(table);
@@ -60,8 +60,7 @@ Status UncompressionDictReader::ReadUncompressionDictionary(
const Status s = table->RetrieveBlock(
prefetch_buffer, read_options, rep->compression_dict_handle,
UncompressionDict::GetEmptyDict(), uncompression_dict, get_context,
lookup_context,
/* decomp */ nullptr, uncompression_dict, get_context, lookup_context,
/* for_compaction */ false, use_cache,
/* async_read */ false, /* use_block_cache_for_lookup */ true);
@@ -79,7 +78,7 @@ Status UncompressionDictReader::ReadUncompressionDictionary(
Status UncompressionDictReader::GetOrReadUncompressionDictionary(
FilePrefetchBuffer* prefetch_buffer, const ReadOptions& ro,
GetContext* get_context, BlockCacheLookupContext* lookup_context,
CachableEntry<UncompressionDict>* uncompression_dict) const {
CachableEntry<DecompressorDict>* uncompression_dict) const {
assert(uncompression_dict);
if (!uncompression_dict_.IsEmpty()) {
@@ -34,13 +34,13 @@ class UncompressionDictReader {
Status GetOrReadUncompressionDictionary(
FilePrefetchBuffer* prefetch_buffer, const ReadOptions& ro,
GetContext* get_context, BlockCacheLookupContext* lookup_context,
CachableEntry<UncompressionDict>* uncompression_dict) const;
CachableEntry<DecompressorDict>* uncompression_dict) const;
size_t ApproximateMemoryUsage() const;
private:
UncompressionDictReader(const BlockBasedTable* t,
CachableEntry<UncompressionDict>&& uncompression_dict)
CachableEntry<DecompressorDict>&& uncompression_dict)
: table_(t), uncompression_dict_(std::move(uncompression_dict)) {
assert(table_);
}
@@ -51,10 +51,10 @@ class UncompressionDictReader {
const BlockBasedTable* table, FilePrefetchBuffer* prefetch_buffer,
const ReadOptions& read_options, bool use_cache, GetContext* get_context,
BlockCacheLookupContext* lookup_context,
CachableEntry<UncompressionDict>* uncompression_dict);
CachableEntry<DecompressorDict>* uncompression_dict);
const BlockBasedTable* table_;
CachableEntry<UncompressionDict> uncompression_dict_;
CachableEntry<DecompressorDict> uncompression_dict_;
};
} // namespace ROCKSDB_NAMESPACE
Loaded 100 of 149 files, more files were not shown because too many files have changed in this diff. Show more