2016-02-09 23:12:00 +00:00
|
|
|
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
2017-07-15 23:03:42 +00:00
|
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
|
|
// (found in the LICENSE.Apache file in the root directory).
|
2013-10-16 21:59:46 +00:00
|
|
|
//
|
2011-03-18 22:37:00 +00:00
|
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
|
|
// 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.
|
|
|
|
|
2013-08-23 15:38:13 +00:00
|
|
|
#include "rocksdb/options.h"
|
2011-03-18 22:37:00 +00:00
|
|
|
|
2019-06-06 20:52:39 +00:00
|
|
|
#include <cinttypes>
|
2013-01-11 01:18:50 +00:00
|
|
|
#include <limits>
|
|
|
|
|
2021-09-29 11:01:57 +00:00
|
|
|
#include "logging/logging.h"
|
2023-05-17 18:27:09 +00:00
|
|
|
#include "monitoring/statistics_impl.h"
|
2017-04-06 02:02:00 +00:00
|
|
|
#include "options/db_options.h"
|
|
|
|
#include "options/options_helper.h"
|
2013-08-23 15:38:13 +00:00
|
|
|
#include "rocksdb/cache.h"
|
|
|
|
#include "rocksdb/compaction_filter.h"
|
|
|
|
#include "rocksdb/comparator.h"
|
|
|
|
#include "rocksdb/env.h"
|
2021-09-29 11:01:57 +00:00
|
|
|
#include "rocksdb/filter_policy.h"
|
2014-01-25 00:15:05 +00:00
|
|
|
#include "rocksdb/memtablerep.h"
|
2014-01-28 05:58:46 +00:00
|
|
|
#include "rocksdb/merge_operator.h"
|
2014-01-25 00:15:05 +00:00
|
|
|
#include "rocksdb/slice.h"
|
|
|
|
#include "rocksdb/slice_transform.h"
|
2017-02-01 01:30:20 +00:00
|
|
|
#include "rocksdb/sst_file_manager.h"
|
2020-07-24 20:43:14 +00:00
|
|
|
#include "rocksdb/sst_partitioner.h"
|
2014-01-28 05:58:46 +00:00
|
|
|
#include "rocksdb/table.h"
|
2014-01-25 00:15:05 +00:00
|
|
|
#include "rocksdb/table_properties.h"
|
2015-10-13 00:03:03 +00:00
|
|
|
#include "rocksdb/wal_filter.h"
|
2019-05-30 21:47:29 +00:00
|
|
|
#include "table/block_based/block_based_table_factory.h"
|
2015-04-06 19:50:44 +00:00
|
|
|
#include "util/compression.h"
|
2011-03-18 22:37:00 +00:00
|
|
|
|
2020-02-20 20:07:53 +00:00
|
|
|
namespace ROCKSDB_NAMESPACE {
|
2011-03-18 22:37:00 +00:00
|
|
|
|
2017-02-28 01:36:06 +00:00
|
|
|
AdvancedColumnFamilyOptions::AdvancedColumnFamilyOptions() {
|
[RocksDB] [Column Family] Interface proposal
Summary:
<This diff is for Column Family branch>
Sharing some of the work I've done so far. This diff compiles and passes the tests.
The biggest change is in options.h - I broke down Options into two parts - DBOptions and ColumnFamilyOptions. DBOptions is DB-specific (env, create_if_missing, block_cache, etc.) and ColumnFamilyOptions is column family-specific (all compaction options, compresion options, etc.). Note that this does not break backwards compatibility at all.
Further, I created DBWithColumnFamily which inherits DB interface and adds new functions with column family support. Clients can transparently switch to DBWithColumnFamily and it will not break their backwards compatibility.
There are few methods worth checking out: ListColumnFamilies(), MultiNewIterator(), MultiGet() and GetSnapshot(). [GetSnapshot() returns the snapshot across all column families for now - I think that's what we agreed on]
Finally, I made small changes to WriteBatch so we are able to atomically insert data across column families.
Please provide feedback.
Test Plan: make check works, the code is backward compatible
Reviewers: dhruba, haobo, sdong, kailiu, emayanke
CC: leveldb
Differential Revision: https://reviews.facebook.net/D14445
2013-12-03 19:14:09 +00:00
|
|
|
assert(memtable_factory.get() != nullptr);
|
|
|
|
}
|
|
|
|
|
2017-02-28 01:36:06 +00:00
|
|
|
AdvancedColumnFamilyOptions::AdvancedColumnFamilyOptions(const Options& options)
|
|
|
|
: max_write_buffer_number(options.max_write_buffer_number),
|
2014-01-06 21:31:06 +00:00
|
|
|
min_write_buffer_number_to_merge(
|
|
|
|
options.min_write_buffer_number_to_merge),
|
Support saving history in memtable_list
Summary:
For transactions, we are using the memtables to validate that there are no write conflicts. But after flushing, we don't have any memtables, and transactions could fail to commit. So we want to someone keep around some extra history to use for conflict checking. In addition, we want to provide a way to increase the size of this history if too many transactions fail to commit.
After chatting with people, it seems like everyone prefers just using Memtables to store this history (instead of a separate history structure). It seems like the best place for this is abstracted inside the memtable_list. I decide to create a separate list in MemtableListVersion as using the same list complicated the flush/installalflushresults logic too much.
This diff adds a new parameter to control how much memtable history to keep around after flushing. However, it sounds like people aren't too fond of adding new parameters. So I am making the default size of flushed+not-flushed memtables be set to max_write_buffers. This should not change the maximum amount of memory used, but make it more likely we're using closer the the limit. (We are now postponing deleting flushed memtables until the max_write_buffer limit is reached). So while we might use more memory on average, we are still obeying the limit set (and you could argue it's better to go ahead and use up memory now instead of waiting for a write stall to happen to test this limit).
However, if people are opposed to this default behavior, we can easily set it to 0 and require this parameter be set in order to use transactions.
Test Plan: Added a xfunc test to play around with setting different values of this parameter in all tests. Added testing in memtablelist_test and planning on adding more testing here.
Reviewers: sdong, rven, igor
Reviewed By: igor
Subscribers: dhruba, leveldb
Differential Revision: https://reviews.facebook.net/D37443
2015-05-28 23:34:24 +00:00
|
|
|
max_write_buffer_number_to_maintain(
|
|
|
|
options.max_write_buffer_number_to_maintain),
|
Refactor trimming logic for immutable memtables (#5022)
Summary:
MyRocks currently sets `max_write_buffer_number_to_maintain` in order to maintain enough history for transaction conflict checking. The effectiveness of this approach depends on the size of memtables. When memtables are small, it may not keep enough history; when memtables are large, this may consume too much memory.
We are proposing a new way to configure memtable list history: by limiting the memory usage of immutable memtables. The new option is `max_write_buffer_size_to_maintain` and it will take precedence over the old `max_write_buffer_number_to_maintain` if they are both set to non-zero values. The new option accounts for the total memory usage of flushed immutable memtables and mutable memtable. When the total usage exceeds the limit, RocksDB may start dropping immutable memtables (which is also called trimming history), starting from the oldest one.
The semantics of the old option actually works both as an upper bound and lower bound. History trimming will start if number of immutable memtables exceeds the limit, but it will never go below (limit-1) due to history trimming.
In order the mimic the behavior with the new option, history trimming will stop if dropping the next immutable memtable causes the total memory usage go below the size limit. For example, assuming the size limit is set to 64MB, and there are 3 immutable memtables with sizes of 20, 30, 30. Although the total memory usage is 80MB > 64MB, dropping the oldest memtable will reduce the memory usage to 60MB < 64MB, so in this case no memtable will be dropped.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5022
Differential Revision: D14394062
Pulled By: miasantreble
fbshipit-source-id: 60457a509c6af89d0993f988c9b5c2aa9e45f5c5
2019-08-23 20:54:09 +00:00
|
|
|
max_write_buffer_size_to_maintain(
|
|
|
|
options.max_write_buffer_size_to_maintain),
|
2017-02-28 01:36:06 +00:00
|
|
|
inplace_update_support(options.inplace_update_support),
|
|
|
|
inplace_update_num_locks(options.inplace_update_num_locks),
|
2022-06-23 16:42:18 +00:00
|
|
|
experimental_mempurge_threshold(options.experimental_mempurge_threshold),
|
2017-02-28 01:36:06 +00:00
|
|
|
inplace_callback(options.inplace_callback),
|
|
|
|
memtable_prefix_bloom_size_ratio(
|
|
|
|
options.memtable_prefix_bloom_size_ratio),
|
2019-02-19 20:12:25 +00:00
|
|
|
memtable_whole_key_filtering(options.memtable_whole_key_filtering),
|
2017-02-28 01:36:06 +00:00
|
|
|
memtable_huge_page_size(options.memtable_huge_page_size),
|
|
|
|
memtable_insert_with_hint_prefix_extractor(
|
|
|
|
options.memtable_insert_with_hint_prefix_extractor),
|
|
|
|
bloom_locality(options.bloom_locality),
|
|
|
|
arena_block_size(options.arena_block_size),
|
2014-01-06 21:31:06 +00:00
|
|
|
compression_per_level(options.compression_per_level),
|
|
|
|
num_levels(options.num_levels),
|
|
|
|
level0_slowdown_writes_trigger(options.level0_slowdown_writes_trigger),
|
|
|
|
level0_stop_writes_trigger(options.level0_stop_writes_trigger),
|
|
|
|
target_file_size_base(options.target_file_size_base),
|
|
|
|
target_file_size_multiplier(options.target_file_size_multiplier),
|
options.level_compaction_dynamic_level_bytes to allow RocksDB to pick size bases of levels dynamically.
Summary:
When having fixed max_bytes_for_level_base, the ratio of size of largest level and the second one can range from 0 to the multiplier. This makes LSM tree frequently irregular and unpredictable. It can also cause poor space amplification in some cases.
In this improvement (proposed by Igor Kabiljo), we introduce a parameter option.level_compaction_use_dynamic_max_bytes. When turning it on, RocksDB is free to pick a level base in the range of (options.max_bytes_for_level_base/options.max_bytes_for_level_multiplier, options.max_bytes_for_level_base] so that real level ratios are close to options.max_bytes_for_level_multiplier.
Test Plan: New unit tests and pass tests suites including valgrind.
Reviewers: MarkCallaghan, rven, yhchiang, igor, ikabiljo
Reviewed By: ikabiljo
Subscribers: yoshinorim, ikabiljo, dhruba, leveldb
Differential Revision: https://reviews.facebook.net/D31437
2015-02-05 19:44:17 +00:00
|
|
|
level_compaction_dynamic_level_bytes(
|
|
|
|
options.level_compaction_dynamic_level_bytes),
|
2014-01-06 21:31:06 +00:00
|
|
|
max_bytes_for_level_multiplier(options.max_bytes_for_level_multiplier),
|
|
|
|
max_bytes_for_level_multiplier_additional(
|
|
|
|
options.max_bytes_for_level_multiplier_additional),
|
2016-06-16 23:02:52 +00:00
|
|
|
max_compaction_bytes(options.max_compaction_bytes),
|
2015-11-19 02:10:20 +00:00
|
|
|
soft_pending_compaction_bytes_limit(
|
|
|
|
options.soft_pending_compaction_bytes_limit),
|
2015-09-11 21:31:23 +00:00
|
|
|
hard_pending_compaction_bytes_limit(
|
|
|
|
options.hard_pending_compaction_bytes_limit),
|
2014-01-06 21:31:06 +00:00
|
|
|
compaction_style(options.compaction_style),
|
2015-09-22 00:16:31 +00:00
|
|
|
compaction_pri(options.compaction_pri),
|
2014-01-06 21:31:06 +00:00
|
|
|
compaction_options_universal(options.compaction_options_universal),
|
2014-05-21 18:43:35 +00:00
|
|
|
compaction_options_fifo(options.compaction_options_fifo),
|
2014-01-06 21:31:06 +00:00
|
|
|
max_sequential_skip_in_iterations(
|
|
|
|
options.max_sequential_skip_in_iterations),
|
|
|
|
memtable_factory(options.memtable_factory),
|
TablePropertiesCollectorFactory
Summary:
This diff addresses task #4296714 and rethinks how users provide us with TablePropertiesCollectors as part of Options.
Here's description of task #4296714:
I'm debugging #4295529 and noticed that our count of user properties kDeletedKeys is wrong. We're sharing one single InternalKeyPropertiesCollector with all Table Builders. In LOG Files, we're outputting number of kDeletedKeys as connected with a single table, while it's actually the total count of deleted keys since creation of the DB.
For example, this table has 3155 entries and 1391828 deleted keys.
The problem with current approach that we call methods on a single TablePropertiesCollector for all the tables we create. Even worse, we could do it from multiple threads at the same time and TablePropertiesCollector has no way of knowing which table we're calling it for.
Good part: Looks like nobody inside Facebook is using Options::table_properties_collectors. This means we should be able to painfully change the API.
In this change, I introduce TablePropertiesCollectorFactory. For every table we create, we call `CreateTablePropertiesCollector`, which creates a TablePropertiesCollector for a single table. We then use it sequentially from a single thread, which means it doesn't have to be thread-safe.
Test Plan:
Added a test in table_properties_collector_test that fails on master (build two tables, assert that kDeletedKeys count is correct for the second one).
Also, all other tests
Reviewers: sdong, dhruba, haobo, kailiu
Reviewed By: kailiu
CC: leveldb
Differential Revision: https://reviews.facebook.net/D18579
2014-05-13 19:30:55 +00:00
|
|
|
table_properties_collector_factories(
|
|
|
|
options.table_properties_collector_factories),
|
2014-03-25 18:09:40 +00:00
|
|
|
max_successive_merges(options.max_successive_merges),
|
2024-02-21 21:15:27 +00:00
|
|
|
strict_max_successive_merges(options.strict_max_successive_merges),
|
2015-04-17 22:26:50 +00:00
|
|
|
optimize_filters_for_hits(options.optimize_filters_for_hits),
|
Add options.compaction_measure_io_stats to print write I/O stats in compactions
Summary:
Add options.compaction_measure_io_stats to print out / pass to listener accumulated time spent on write calls. Example outputs in info logs:
2015/08/12-16:27:59.463944 7fd428bff700 (Original Log Time 2015/08/12-16:27:59.463922) EVENT_LOG_v1 {"time_micros": 1439422079463897, "job": 6, "event": "compaction_finished", "output_level": 1, "num_output_files": 4, "total_output_size": 6900525, "num_input_records": 111483, "num_output_records": 106877, "file_write_nanos": 15663206, "file_range_sync_nanos": 649588, "file_fsync_nanos": 349614797, "file_prepare_write_nanos": 1505812, "lsm_state": [2, 4, 0, 0, 0, 0, 0]}
Add two more counters in iostats_context.
Also add a parameter of db_bench.
Test Plan: Add a unit test. Also manually verify LOG outputs in db_bench
Subscribers: leveldb, dhruba
Differential Revision: https://reviews.facebook.net/D44115
2015-08-13 00:24:45 +00:00
|
|
|
paranoid_file_checks(options.paranoid_file_checks),
|
2016-10-08 00:21:45 +00:00
|
|
|
force_consistency_checks(options.force_consistency_checks),
|
2018-04-03 04:57:28 +00:00
|
|
|
report_bg_io_stats(options.report_bg_io_stats),
|
2019-03-18 19:07:35 +00:00
|
|
|
ttl(options.ttl),
|
Periodic Compactions (#5166)
Summary:
Introducing Periodic Compactions.
This feature allows all the files in a CF to be periodically compacted. It could help in catching any corruptions that could creep into the DB proactively as every file is constantly getting re-compacted. And also, of course, it helps to cleanup data older than certain threshold.
- Introduced a new option `periodic_compaction_time` to control how long a file can live without being compacted in a CF.
- This works across all levels.
- The files are put in the same level after going through the compaction. (Related files in the same level are picked up as `ExpandInputstoCleanCut` is used).
- Compaction filters, if any, are invoked as usual.
- A new table property, `file_creation_time`, is introduced to implement this feature. This property is set to the time at which the SST file was created (and that time is given by the underlying Env/OS).
This feature can be enabled on its own, or in conjunction with `ttl`. It is possible to set a different time threshold for the bottom level when used in conjunction with ttl. Since `ttl` works only on 0 to last but one levels, you could set `ttl` to, say, 1 day, and `periodic_compaction_time` to, say, 7 days. Since `ttl < periodic_compaction_time` all files in last but one levels keep getting picked up based on ttl, and almost never based on periodic_compaction_time. The files in the bottom level get picked up for compaction based on `periodic_compaction_time`.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5166
Differential Revision: D14884441
Pulled By: sagar0
fbshipit-source-id: 408426cbacb409c06386a98632dcf90bfa1bda47
2019-04-11 02:24:25 +00:00
|
|
|
periodic_compaction_seconds(options.periodic_compaction_seconds),
|
2020-08-19 01:31:31 +00:00
|
|
|
sample_for_compression(options.sample_for_compression),
|
2024-02-28 22:36:13 +00:00
|
|
|
last_level_temperature(options.last_level_temperature),
|
|
|
|
default_write_temperature(options.default_write_temperature),
|
2023-08-18 00:06:57 +00:00
|
|
|
default_temperature(options.default_temperature),
|
2022-07-15 04:49:34 +00:00
|
|
|
preclude_last_level_data_seconds(
|
|
|
|
options.preclude_last_level_data_seconds),
|
2022-10-08 01:49:40 +00:00
|
|
|
preserve_internal_time_seconds(options.preserve_internal_time_seconds),
|
2020-08-19 01:31:31 +00:00
|
|
|
enable_blob_files(options.enable_blob_files),
|
|
|
|
min_blob_size(options.min_blob_size),
|
|
|
|
blob_file_size(options.blob_file_size),
|
2020-11-13 02:57:20 +00:00
|
|
|
blob_compression_type(options.blob_compression_type),
|
|
|
|
enable_blob_garbage_collection(options.enable_blob_garbage_collection),
|
|
|
|
blob_garbage_collection_age_cutoff(
|
Make it possible to force the garbage collection of the oldest blob files (#8994)
Summary:
The current BlobDB garbage collection logic works by relocating the valid
blobs from the oldest blob files as they are encountered during compaction,
and cleaning up blob files once they contain nothing but garbage. However,
with sufficiently skewed workloads, it is theoretically possible to end up in a
situation when few or no compactions get scheduled for the SST files that contain
references to the oldest blob files, which can lead to increased space amp due
to the lack of GC.
In order to efficiently handle such workloads, the patch adds a new BlobDB
configuration option called `blob_garbage_collection_force_threshold`,
which signals to BlobDB to schedule targeted compactions for the SST files
that keep alive the oldest batch of blob files if the overall ratio of garbage in
the given blob files meets the threshold *and* all the given blob files are
eligible for GC based on `blob_garbage_collection_age_cutoff`. (For example,
if the new option is set to 0.9, targeted compactions will get scheduled if the
sum of garbage bytes meets or exceeds 90% of the sum of total bytes in the
oldest blob files, assuming all affected blob files are below the age-based cutoff.)
The net result of these targeted compactions is that the valid blobs in the oldest
blob files are relocated and the oldest blob files themselves cleaned up (since
*all* SST files that rely on them get compacted away).
These targeted compactions are similar to periodic compactions in the sense
that they force certain SST files that otherwise would not get picked up to undergo
compaction and also in the sense that instead of merging files from multiple levels,
they target a single file. (Note: such compactions might still include neighboring files
from the same level due to the need of having a "clean cut" boundary but they never
include any files from any other level.)
This functionality is currently only supported with the leveled compaction style
and is inactive by default (since the default value is set to 1.0, i.e. 100%).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8994
Test Plan: Ran `make check` and tested using `db_bench` and the stress/crash tests.
Reviewed By: riversand963
Differential Revision: D31489850
Pulled By: ltamasi
fbshipit-source-id: 44057d511726a0e2a03c5d9313d7511b3f0c4eab
2021-10-12 01:00:44 +00:00
|
|
|
options.blob_garbage_collection_age_cutoff),
|
|
|
|
blob_garbage_collection_force_threshold(
|
2021-11-20 01:52:42 +00:00
|
|
|
options.blob_garbage_collection_force_threshold),
|
2022-06-03 03:04:33 +00:00
|
|
|
blob_compaction_readahead_size(options.blob_compaction_readahead_size),
|
2022-06-14 21:19:26 +00:00
|
|
|
blob_file_starting_level(options.blob_file_starting_level),
|
2022-07-17 14:13:59 +00:00
|
|
|
blob_cache(options.blob_cache),
|
2023-04-12 00:50:34 +00:00
|
|
|
prepopulate_blob_cache(options.prepopulate_blob_cache),
|
|
|
|
persist_user_defined_timestamps(options.persist_user_defined_timestamps) {
|
2014-01-06 21:31:06 +00:00
|
|
|
assert(memtable_factory.get() != nullptr);
|
2014-06-25 21:31:30 +00:00
|
|
|
if (max_bytes_for_level_multiplier_additional.size() <
|
|
|
|
static_cast<unsigned int>(num_levels)) {
|
2014-06-25 20:11:12 +00:00
|
|
|
max_bytes_for_level_multiplier_additional.resize(num_levels, 1);
|
|
|
|
}
|
2014-01-06 21:31:06 +00:00
|
|
|
}
|
|
|
|
|
2017-02-28 01:36:06 +00:00
|
|
|
ColumnFamilyOptions::ColumnFamilyOptions()
|
|
|
|
: compression(Snappy_Supported() ? kSnappyCompression : kNoCompression),
|
|
|
|
table_factory(
|
|
|
|
std::shared_ptr<TableFactory>(new BlockBasedTableFactory())) {}
|
|
|
|
|
|
|
|
ColumnFamilyOptions::ColumnFamilyOptions(const Options& options)
|
2017-09-16 00:09:48 +00:00
|
|
|
: ColumnFamilyOptions(*static_cast<const ColumnFamilyOptions*>(&options)) {}
|
2017-02-28 01:36:06 +00:00
|
|
|
|
2023-12-01 19:10:30 +00:00
|
|
|
DBOptions::DBOptions() = default;
|
2014-01-06 21:31:06 +00:00
|
|
|
DBOptions::DBOptions(const Options& options)
|
2017-09-16 00:09:48 +00:00
|
|
|
: DBOptions(*static_cast<const DBOptions*>(&options)) {}
|
2014-01-06 21:31:06 +00:00
|
|
|
|
2014-02-07 05:39:20 +00:00
|
|
|
void DBOptions::Dump(Logger* log) const {
|
2017-02-01 01:30:20 +00:00
|
|
|
ImmutableDBOptions(*this).Dump(log);
|
|
|
|
MutableDBOptions(*this).Dump(log);
|
2014-02-07 05:39:20 +00:00
|
|
|
} // DBOptions::Dump
|
|
|
|
|
|
|
|
void ColumnFamilyOptions::Dump(Logger* log) const {
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.comparator: %s",
|
|
|
|
comparator->Name());
|
2023-04-12 00:50:34 +00:00
|
|
|
if (comparator->timestamp_size() > 0) {
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.persist_user_defined_timestamps: %s",
|
|
|
|
persist_user_defined_timestamps ? "true" : "false");
|
|
|
|
}
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.merge_operator: %s",
|
|
|
|
merge_operator ? merge_operator->Name() : "None");
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.compaction_filter: %s",
|
|
|
|
compaction_filter ? compaction_filter->Name() : "None");
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.compaction_filter_factory: %s",
|
2015-06-08 23:34:26 +00:00
|
|
|
compaction_filter_factory ? compaction_filter_factory->Name() : "None");
|
2020-07-24 20:43:14 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.sst_partitioner_factory: %s",
|
|
|
|
sst_partitioner_factory ? sst_partitioner_factory->Name() : "None");
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.memtable_factory: %s",
|
|
|
|
memtable_factory->Name());
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.table_factory: %s",
|
|
|
|
table_factory->Name());
|
|
|
|
ROCKS_LOG_HEADER(log, " table_factory options: %s",
|
2020-09-14 23:59:00 +00:00
|
|
|
table_factory->GetPrintableOptions().c_str());
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.write_buffer_size: %" ROCKSDB_PRIszt,
|
|
|
|
write_buffer_size);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.max_write_buffer_number: %d",
|
|
|
|
max_write_buffer_number);
|
|
|
|
if (!compression_per_level.empty()) {
|
|
|
|
for (unsigned int i = 0; i < compression_per_level.size(); i++) {
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.compression[%d]: %s", i,
|
|
|
|
CompressionTypeToString(compression_per_level[i]).c_str());
|
|
|
|
}
|
2012-10-28 06:13:17 +00:00
|
|
|
} else {
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.compression: %s",
|
|
|
|
CompressionTypeToString(compression).c_str());
|
2012-10-28 06:13:17 +00:00
|
|
|
}
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.bottommost_compression: %s",
|
|
|
|
bottommost_compression == kDisableCompressionOption
|
|
|
|
? "Disabled"
|
|
|
|
: CompressionTypeToString(bottommost_compression).c_str());
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.prefix_extractor: %s",
|
2013-08-14 16:06:10 +00:00
|
|
|
prefix_extractor == nullptr ? "nullptr" : prefix_extractor->Name());
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.memtable_insert_with_hint_prefix_extractor: %s",
|
|
|
|
memtable_insert_with_hint_prefix_extractor == nullptr
|
|
|
|
? "nullptr"
|
|
|
|
: memtable_insert_with_hint_prefix_extractor->Name());
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.num_levels: %d", num_levels);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.min_write_buffer_number_to_merge: %d",
|
|
|
|
min_write_buffer_number_to_merge);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.max_write_buffer_number_to_maintain: %d",
|
|
|
|
max_write_buffer_number_to_maintain);
|
Refactor trimming logic for immutable memtables (#5022)
Summary:
MyRocks currently sets `max_write_buffer_number_to_maintain` in order to maintain enough history for transaction conflict checking. The effectiveness of this approach depends on the size of memtables. When memtables are small, it may not keep enough history; when memtables are large, this may consume too much memory.
We are proposing a new way to configure memtable list history: by limiting the memory usage of immutable memtables. The new option is `max_write_buffer_size_to_maintain` and it will take precedence over the old `max_write_buffer_number_to_maintain` if they are both set to non-zero values. The new option accounts for the total memory usage of flushed immutable memtables and mutable memtable. When the total usage exceeds the limit, RocksDB may start dropping immutable memtables (which is also called trimming history), starting from the oldest one.
The semantics of the old option actually works both as an upper bound and lower bound. History trimming will start if number of immutable memtables exceeds the limit, but it will never go below (limit-1) due to history trimming.
In order the mimic the behavior with the new option, history trimming will stop if dropping the next immutable memtable causes the total memory usage go below the size limit. For example, assuming the size limit is set to 64MB, and there are 3 immutable memtables with sizes of 20, 30, 30. Although the total memory usage is 80MB > 64MB, dropping the oldest memtable will reduce the memory usage to 60MB < 64MB, so in this case no memtable will be dropped.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5022
Differential Revision: D14394062
Pulled By: miasantreble
fbshipit-source-id: 60457a509c6af89d0993f988c9b5c2aa9e45f5c5
2019-08-23 20:54:09 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.max_write_buffer_size_to_maintain: %" PRIu64,
|
|
|
|
max_write_buffer_size_to_maintain);
|
2018-06-28 00:34:07 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.bottommost_compression_opts.window_bits: %d",
|
|
|
|
bottommost_compression_opts.window_bits);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.bottommost_compression_opts.level: %d",
|
|
|
|
bottommost_compression_opts.level);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.bottommost_compression_opts.strategy: %d",
|
|
|
|
bottommost_compression_opts.strategy);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.bottommost_compression_opts.max_dict_bytes: "
|
2019-04-04 19:05:42 +00:00
|
|
|
"%" PRIu32,
|
2018-06-28 00:34:07 +00:00
|
|
|
bottommost_compression_opts.max_dict_bytes);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.bottommost_compression_opts.zstd_max_train_bytes: "
|
2019-04-04 19:05:42 +00:00
|
|
|
"%" PRIu32,
|
2018-06-28 00:34:07 +00:00
|
|
|
bottommost_compression_opts.zstd_max_train_bytes);
|
2020-04-01 23:37:54 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.bottommost_compression_opts.parallel_threads: "
|
|
|
|
"%" PRIu32,
|
|
|
|
bottommost_compression_opts.parallel_threads);
|
2018-06-28 00:34:07 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.bottommost_compression_opts.enabled: %s",
|
|
|
|
bottommost_compression_opts.enabled ? "true" : "false");
|
Limit buffering for collecting samples for compression dictionary (#7970)
Summary:
For dictionary compression, we need to collect some representative samples of the data to be compressed, which we use to either generate or train (when `CompressionOptions::zstd_max_train_bytes > 0`) a dictionary. Previously, the strategy was to buffer all the data blocks during flush, and up to the target file size during compaction. That strategy allowed us to randomly pick samples from as wide a range as possible that'd be guaranteed to land in a single output file.
However, some users try to make huge files in memory-constrained environments, where this strategy can cause OOM. This PR introduces an option, `CompressionOptions::max_dict_buffer_bytes`, that limits how much data blocks are buffered before we switch to unbuffered mode (which means creating the per-SST dictionary, writing out the buffered data, and compressing/writing new blocks as soon as they are built). It is not strict as we currently buffer more than just data blocks -- also keys are buffered. But it does make a step towards giving users predictable memory usage.
Related changes include:
- Changed sampling for dictionary compression to select unique data blocks when there is limited availability of data blocks
- Made use of `BlockBuilder::SwapAndReset()` to save an allocation+memcpy when buffering data blocks for building a dictionary
- Changed `ParseBoolean()` to accept an input containing characters after the boolean. This is necessary since, with this PR, a value for `CompressionOptions::enabled` is no longer necessarily the final component in the `CompressionOptions` string.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/7970
Test Plan:
- updated `CompressionOptions` unit tests to verify limit is respected (to the extent expected in the current implementation) in various scenarios of flush/compaction to bottommost/non-bottommost level
- looked at jemalloc heap profiles right before and after switching to unbuffered mode during flush/compaction. Verified memory usage in buffering is proportional to the limit set.
Reviewed By: pdillinger
Differential Revision: D26467994
Pulled By: ajkr
fbshipit-source-id: 3da4ef9fba59974e4ef40e40c01611002c861465
2021-02-19 22:06:59 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.bottommost_compression_opts.max_dict_buffer_bytes: "
|
|
|
|
"%" PRIu64,
|
|
|
|
bottommost_compression_opts.max_dict_buffer_bytes);
|
Support using ZDICT_finalizeDictionary to generate zstd dictionary (#9857)
Summary:
An untrained dictionary is currently simply the concatenation of several samples. The ZSTD API, ZDICT_finalizeDictionary(), can improve such a dictionary's effectiveness at low cost. This PR changes how dictionary is created by calling the ZSTD ZDICT_finalizeDictionary() API instead of creating raw content dictionary (when max_dict_buffer_bytes > 0), and pass in all buffered uncompressed data blocks as samples.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/9857
Test Plan:
#### db_bench test for cpu/memory of compression+decompression and space saving on synthetic data:
Set up: change the parameter [here](https://github.com/facebook/rocksdb/blob/fb9a167a55e0970b1ef6f67c1600c8d9c4c6114f/tools/db_bench_tool.cc#L1766) to 16384 to make synthetic data more compressible.
```
# linked local ZSTD with version 1.5.2
# DEBUG_LEVEL=0 ROCKSDB_NO_FBCODE=1 ROCKSDB_DISABLE_ZSTD=1 EXTRA_CXXFLAGS="-DZSTD_STATIC_LINKING_ONLY -DZSTD -I/data/users/changyubi/install/include/" EXTRA_LDFLAGS="-L/data/users/changyubi/install/lib/ -l:libzstd.a" make -j32 db_bench
dict_bytes=16384
train_bytes=1048576
echo "========== No Dictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=0 -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=0 -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
echo "========== Raw Content Dictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench_main -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench_main -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
echo "========== FinalizeDictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
echo "========== TrainDictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
# Result: TrainDictionary is much better on space saving, but FinalizeDictionary seems to use less memory.
# before compression data size: 1.2GB
dict_bytes=16384
max_dict_buffer_bytes = 1048576
space cpu/memory
No Dictionary 468M 14.93user 1.00system 0:15.92elapsed 100%CPU (0avgtext+0avgdata 23904maxresident)k
Raw Dictionary 251M 15.81user 0.80system 0:16.56elapsed 100%CPU (0avgtext+0avgdata 156808maxresident)k
FinalizeDictionary 236M 11.93user 0.64system 0:12.56elapsed 100%CPU (0avgtext+0avgdata 89548maxresident)k
TrainDictionary 84M 7.29user 0.45system 0:07.75elapsed 100%CPU (0avgtext+0avgdata 97288maxresident)k
```
#### Benchmark on 10 sample SST files for spacing saving and CPU time on compression:
FinalizeDictionary is comparable to TrainDictionary in terms of space saving, and takes less time in compression.
```
dict_bytes=16384
train_bytes=1048576
for sst_file in `ls ../temp/myrock-sst/`
do
echo "********** $sst_file **********"
echo "========== No Dictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD
echo "========== Raw Content Dictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD --compression_max_dict_bytes=$dict_bytes
echo "========== FinalizeDictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD --compression_max_dict_bytes=$dict_bytes --compression_zstd_max_train_bytes=$train_bytes --compression_use_zstd_finalize_dict
echo "========== TrainDictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD --compression_max_dict_bytes=$dict_bytes --compression_zstd_max_train_bytes=$train_bytes
done
010240.sst (Size/Time) 011029.sst 013184.sst 021552.sst 185054.sst 185137.sst 191666.sst 7560381.sst 7604174.sst 7635312.sst
No Dictionary 28165569 / 2614419 32899411 / 2976832 32977848 / 3055542 31966329 / 2004590 33614351 / 1755877 33429029 / 1717042 33611933 / 1776936 33634045 / 2771417 33789721 / 2205414 33592194 / 388254
Raw Content Dictionary 28019950 / 2697961 33748665 / 3572422 33896373 / 3534701 26418431 / 2259658 28560825 / 1839168 28455030 / 1846039 28494319 / 1861349 32391599 / 3095649 33772142 / 2407843 33592230 / 474523
FinalizeDictionary 27896012 / 2650029 33763886 / 3719427 33904283 / 3552793 26008225 / 2198033 28111872 / 1869530 28014374 / 1789771 28047706 / 1848300 32296254 / 3204027 33698698 / 2381468 33592344 / 517433
TrainDictionary 28046089 / 2740037 33706480 / 3679019 33885741 / 3629351 25087123 / 2204558 27194353 / 1970207 27234229 / 1896811 27166710 / 1903119 32011041 / 3322315 32730692 / 2406146 33608631 / 570593
```
#### Decompression/Read test:
With FinalizeDictionary/TrainDictionary, some data structure used for decompression are in stored in dictionary, so they are expected to be faster in terms of decompression/reads.
```
dict_bytes=16384
train_bytes=1048576
echo "No Dictionary"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=0 > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=0 2>&1 | grep MB/s
echo "Raw Dictionary"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes 2>&1 | grep MB/s
echo "FinalizeDict"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false 2>&1 | grep MB/s
echo "Train Dictionary"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes 2>&1 | grep MB/s
No Dictionary
readrandom : 12.183 micros/op 82082 ops/sec 12.183 seconds 1000000 operations; 9.1 MB/s (1000000 of 1000000 found)
Raw Dictionary
readrandom : 12.314 micros/op 81205 ops/sec 12.314 seconds 1000000 operations; 9.0 MB/s (1000000 of 1000000 found)
FinalizeDict
readrandom : 9.787 micros/op 102180 ops/sec 9.787 seconds 1000000 operations; 11.3 MB/s (1000000 of 1000000 found)
Train Dictionary
readrandom : 9.698 micros/op 103108 ops/sec 9.699 seconds 1000000 operations; 11.4 MB/s (1000000 of 1000000 found)
```
Reviewed By: ajkr
Differential Revision: D35720026
Pulled By: cbi42
fbshipit-source-id: 24d230fdff0fd28a1bb650658798f00dfcfb2a1f
2022-05-20 19:09:09 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.bottommost_compression_opts.use_zstd_dict_trainer: %s",
|
|
|
|
bottommost_compression_opts.use_zstd_dict_trainer ? "true" : "false");
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.compression_opts.window_bits: %d",
|
|
|
|
compression_opts.window_bits);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.compression_opts.level: %d",
|
|
|
|
compression_opts.level);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.compression_opts.strategy: %d",
|
|
|
|
compression_opts.strategy);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
2019-04-04 19:05:42 +00:00
|
|
|
" Options.compression_opts.max_dict_bytes: %" PRIu32,
|
Shared dictionary compression using reference block
Summary:
This adds a new metablock containing a shared dictionary that is used
to compress all data blocks in the SST file. The size of the shared dictionary
is configurable in CompressionOptions and defaults to 0. It's currently only
used for zlib/lz4/lz4hc, but the block will be stored in the SST regardless of
the compression type if the user chooses a nonzero dictionary size.
During compaction, computes the dictionary by randomly sampling the first
output file in each subcompaction. It pre-computes the intervals to sample
by assuming the output file will have the maximum allowable length. In case
the file is smaller, some of the pre-computed sampling intervals can be beyond
end-of-file, in which case we skip over those samples and the dictionary will
be a bit smaller. After the dictionary is generated using the first file in a
subcompaction, it is loaded into the compression library before writing each
block in each subsequent file of that subcompaction.
On the read path, gets the dictionary from the metablock, if it exists. Then,
loads that dictionary into the compression library before reading each block.
Test Plan: new unit test
Reviewers: yhchiang, IslamAbdelRahman, cyan, sdong
Reviewed By: sdong
Subscribers: andrewkr, yoshinorim, kradhakrishnan, dhruba, leveldb
Differential Revision: https://reviews.facebook.net/D52287
2016-04-28 00:36:03 +00:00
|
|
|
compression_opts.max_dict_bytes);
|
2018-03-22 22:10:53 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.compression_opts.zstd_max_train_bytes: "
|
2019-04-04 19:05:42 +00:00
|
|
|
"%" PRIu32,
|
2018-03-22 22:10:53 +00:00
|
|
|
compression_opts.zstd_max_train_bytes);
|
Support using ZDICT_finalizeDictionary to generate zstd dictionary (#9857)
Summary:
An untrained dictionary is currently simply the concatenation of several samples. The ZSTD API, ZDICT_finalizeDictionary(), can improve such a dictionary's effectiveness at low cost. This PR changes how dictionary is created by calling the ZSTD ZDICT_finalizeDictionary() API instead of creating raw content dictionary (when max_dict_buffer_bytes > 0), and pass in all buffered uncompressed data blocks as samples.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/9857
Test Plan:
#### db_bench test for cpu/memory of compression+decompression and space saving on synthetic data:
Set up: change the parameter [here](https://github.com/facebook/rocksdb/blob/fb9a167a55e0970b1ef6f67c1600c8d9c4c6114f/tools/db_bench_tool.cc#L1766) to 16384 to make synthetic data more compressible.
```
# linked local ZSTD with version 1.5.2
# DEBUG_LEVEL=0 ROCKSDB_NO_FBCODE=1 ROCKSDB_DISABLE_ZSTD=1 EXTRA_CXXFLAGS="-DZSTD_STATIC_LINKING_ONLY -DZSTD -I/data/users/changyubi/install/include/" EXTRA_LDFLAGS="-L/data/users/changyubi/install/lib/ -l:libzstd.a" make -j32 db_bench
dict_bytes=16384
train_bytes=1048576
echo "========== No Dictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=0 -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=0 -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
echo "========== Raw Content Dictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench_main -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench_main -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
echo "========== FinalizeDictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
echo "========== TrainDictionary =========="
TEST_TMPDIR=/dev/shm ./db_bench -benchmarks=filluniquerandom,compact -num=10000000 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -block_size=4096 -max_background_jobs=24 -memtablerep=vector -allow_concurrent_memtable_write=false -disable_wal=true -max_write_buffer_number=8 >/dev/null 2>&1
TEST_TMPDIR=/dev/shm /usr/bin/time ./db_bench -use_existing_db=true -benchmarks=compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -block_size=4096 2>&1 | grep elapsed
du -hc /dev/shm/dbbench/*sst | grep total
# Result: TrainDictionary is much better on space saving, but FinalizeDictionary seems to use less memory.
# before compression data size: 1.2GB
dict_bytes=16384
max_dict_buffer_bytes = 1048576
space cpu/memory
No Dictionary 468M 14.93user 1.00system 0:15.92elapsed 100%CPU (0avgtext+0avgdata 23904maxresident)k
Raw Dictionary 251M 15.81user 0.80system 0:16.56elapsed 100%CPU (0avgtext+0avgdata 156808maxresident)k
FinalizeDictionary 236M 11.93user 0.64system 0:12.56elapsed 100%CPU (0avgtext+0avgdata 89548maxresident)k
TrainDictionary 84M 7.29user 0.45system 0:07.75elapsed 100%CPU (0avgtext+0avgdata 97288maxresident)k
```
#### Benchmark on 10 sample SST files for spacing saving and CPU time on compression:
FinalizeDictionary is comparable to TrainDictionary in terms of space saving, and takes less time in compression.
```
dict_bytes=16384
train_bytes=1048576
for sst_file in `ls ../temp/myrock-sst/`
do
echo "********** $sst_file **********"
echo "========== No Dictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD
echo "========== Raw Content Dictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD --compression_max_dict_bytes=$dict_bytes
echo "========== FinalizeDictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD --compression_max_dict_bytes=$dict_bytes --compression_zstd_max_train_bytes=$train_bytes --compression_use_zstd_finalize_dict
echo "========== TrainDictionary =========="
./sst_dump --file="../temp/myrock-sst/$sst_file" --command=recompress --compression_level_from=6 --compression_level_to=6 --compression_types=kZSTD --compression_max_dict_bytes=$dict_bytes --compression_zstd_max_train_bytes=$train_bytes
done
010240.sst (Size/Time) 011029.sst 013184.sst 021552.sst 185054.sst 185137.sst 191666.sst 7560381.sst 7604174.sst 7635312.sst
No Dictionary 28165569 / 2614419 32899411 / 2976832 32977848 / 3055542 31966329 / 2004590 33614351 / 1755877 33429029 / 1717042 33611933 / 1776936 33634045 / 2771417 33789721 / 2205414 33592194 / 388254
Raw Content Dictionary 28019950 / 2697961 33748665 / 3572422 33896373 / 3534701 26418431 / 2259658 28560825 / 1839168 28455030 / 1846039 28494319 / 1861349 32391599 / 3095649 33772142 / 2407843 33592230 / 474523
FinalizeDictionary 27896012 / 2650029 33763886 / 3719427 33904283 / 3552793 26008225 / 2198033 28111872 / 1869530 28014374 / 1789771 28047706 / 1848300 32296254 / 3204027 33698698 / 2381468 33592344 / 517433
TrainDictionary 28046089 / 2740037 33706480 / 3679019 33885741 / 3629351 25087123 / 2204558 27194353 / 1970207 27234229 / 1896811 27166710 / 1903119 32011041 / 3322315 32730692 / 2406146 33608631 / 570593
```
#### Decompression/Read test:
With FinalizeDictionary/TrainDictionary, some data structure used for decompression are in stored in dictionary, so they are expected to be faster in terms of decompression/reads.
```
dict_bytes=16384
train_bytes=1048576
echo "No Dictionary"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=0 > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=0 2>&1 | grep MB/s
echo "Raw Dictionary"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes 2>&1 | grep MB/s
echo "FinalizeDict"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes -compression_use_zstd_dict_trainer=false 2>&1 | grep MB/s
echo "Train Dictionary"
TEST_TMPDIR=/dev/shm/ ./db_bench -benchmarks=filluniquerandom,compact -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes > /dev/null 2>&1
TEST_TMPDIR=/dev/shm/ ./db_bench -use_existing_db=true -benchmarks=readrandom -cache_size=0 -compression_type=zstd -compression_max_dict_bytes=$dict_bytes -compression_zstd_max_train_bytes=$train_bytes 2>&1 | grep MB/s
No Dictionary
readrandom : 12.183 micros/op 82082 ops/sec 12.183 seconds 1000000 operations; 9.1 MB/s (1000000 of 1000000 found)
Raw Dictionary
readrandom : 12.314 micros/op 81205 ops/sec 12.314 seconds 1000000 operations; 9.0 MB/s (1000000 of 1000000 found)
FinalizeDict
readrandom : 9.787 micros/op 102180 ops/sec 9.787 seconds 1000000 operations; 11.3 MB/s (1000000 of 1000000 found)
Train Dictionary
readrandom : 9.698 micros/op 103108 ops/sec 9.699 seconds 1000000 operations; 11.4 MB/s (1000000 of 1000000 found)
```
Reviewed By: ajkr
Differential Revision: D35720026
Pulled By: cbi42
fbshipit-source-id: 24d230fdff0fd28a1bb650658798f00dfcfb2a1f
2022-05-20 19:09:09 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.compression_opts.use_zstd_dict_trainer: %s",
|
|
|
|
compression_opts.use_zstd_dict_trainer ? "true" : "false");
|
2020-04-01 23:37:54 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.compression_opts.parallel_threads: "
|
|
|
|
"%" PRIu32,
|
|
|
|
compression_opts.parallel_threads);
|
2018-06-28 00:34:07 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.compression_opts.enabled: %s",
|
|
|
|
compression_opts.enabled ? "true" : "false");
|
Limit buffering for collecting samples for compression dictionary (#7970)
Summary:
For dictionary compression, we need to collect some representative samples of the data to be compressed, which we use to either generate or train (when `CompressionOptions::zstd_max_train_bytes > 0`) a dictionary. Previously, the strategy was to buffer all the data blocks during flush, and up to the target file size during compaction. That strategy allowed us to randomly pick samples from as wide a range as possible that'd be guaranteed to land in a single output file.
However, some users try to make huge files in memory-constrained environments, where this strategy can cause OOM. This PR introduces an option, `CompressionOptions::max_dict_buffer_bytes`, that limits how much data blocks are buffered before we switch to unbuffered mode (which means creating the per-SST dictionary, writing out the buffered data, and compressing/writing new blocks as soon as they are built). It is not strict as we currently buffer more than just data blocks -- also keys are buffered. But it does make a step towards giving users predictable memory usage.
Related changes include:
- Changed sampling for dictionary compression to select unique data blocks when there is limited availability of data blocks
- Made use of `BlockBuilder::SwapAndReset()` to save an allocation+memcpy when buffering data blocks for building a dictionary
- Changed `ParseBoolean()` to accept an input containing characters after the boolean. This is necessary since, with this PR, a value for `CompressionOptions::enabled` is no longer necessarily the final component in the `CompressionOptions` string.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/7970
Test Plan:
- updated `CompressionOptions` unit tests to verify limit is respected (to the extent expected in the current implementation) in various scenarios of flush/compaction to bottommost/non-bottommost level
- looked at jemalloc heap profiles right before and after switching to unbuffered mode during flush/compaction. Verified memory usage in buffering is proportional to the limit set.
Reviewed By: pdillinger
Differential Revision: D26467994
Pulled By: ajkr
fbshipit-source-id: 3da4ef9fba59974e4ef40e40c01611002c861465
2021-02-19 22:06:59 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.compression_opts.max_dict_buffer_bytes: "
|
|
|
|
"%" PRIu64,
|
|
|
|
compression_opts.max_dict_buffer_bytes);
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.level0_file_num_compaction_trigger: %d",
|
|
|
|
level0_file_num_compaction_trigger);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.level0_slowdown_writes_trigger: %d",
|
|
|
|
level0_slowdown_writes_trigger);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.level0_stop_writes_trigger: %d",
|
|
|
|
level0_stop_writes_trigger);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.target_file_size_base: %" PRIu64,
|
2012-08-27 19:10:26 +00:00
|
|
|
target_file_size_base);
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.target_file_size_multiplier: %d",
|
|
|
|
target_file_size_multiplier);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.max_bytes_for_level_base: %" PRIu64,
|
2014-09-22 18:15:03 +00:00
|
|
|
max_bytes_for_level_base);
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, "Options.level_compaction_dynamic_level_bytes: %d",
|
|
|
|
level_compaction_dynamic_level_bytes);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.max_bytes_for_level_multiplier: %f",
|
|
|
|
max_bytes_for_level_multiplier);
|
2015-03-30 21:04:21 +00:00
|
|
|
for (size_t i = 0; i < max_bytes_for_level_multiplier_additional.size();
|
|
|
|
i++) {
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, "Options.max_bytes_for_level_multiplier_addtl[%" ROCKSDB_PRIszt
|
|
|
|
"]: %d",
|
|
|
|
i, max_bytes_for_level_multiplier_additional[i]);
|
2013-05-21 18:37:06 +00:00
|
|
|
}
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.max_sequential_skip_in_iterations: %" PRIu64,
|
2014-09-22 18:15:03 +00:00
|
|
|
max_sequential_skip_in_iterations);
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.max_compaction_bytes: %" PRIu64,
|
|
|
|
max_compaction_bytes);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.arena_block_size: %" ROCKSDB_PRIszt,
|
|
|
|
arena_block_size);
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.soft_pending_compaction_bytes_limit: %" PRIu64,
|
|
|
|
soft_pending_compaction_bytes_limit);
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.hard_pending_compaction_bytes_limit: %" PRIu64,
|
|
|
|
hard_pending_compaction_bytes_limit);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.disable_auto_compactions: %d",
|
|
|
|
disable_auto_compactions);
|
2017-02-07 18:35:15 +00:00
|
|
|
|
|
|
|
const auto& it_compaction_style =
|
|
|
|
compaction_style_to_string.find(compaction_style);
|
|
|
|
std::string str_compaction_style;
|
|
|
|
if (it_compaction_style == compaction_style_to_string.end()) {
|
|
|
|
assert(false);
|
|
|
|
str_compaction_style = "unknown_" + std::to_string(compaction_style);
|
|
|
|
} else {
|
|
|
|
str_compaction_style = it_compaction_style->second;
|
|
|
|
}
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
2017-05-09 22:44:48 +00:00
|
|
|
" Options.compaction_style: %s",
|
2017-03-16 02:22:52 +00:00
|
|
|
str_compaction_style.c_str());
|
2017-02-07 18:35:15 +00:00
|
|
|
|
|
|
|
const auto& it_compaction_pri =
|
|
|
|
compaction_pri_to_string.find(compaction_pri);
|
|
|
|
std::string str_compaction_pri;
|
|
|
|
if (it_compaction_pri == compaction_pri_to_string.end()) {
|
|
|
|
assert(false);
|
|
|
|
str_compaction_pri = "unknown_" + std::to_string(compaction_pri);
|
|
|
|
} else {
|
|
|
|
str_compaction_pri = it_compaction_pri->second;
|
|
|
|
}
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
2017-05-09 22:44:48 +00:00
|
|
|
" Options.compaction_pri: %s",
|
2017-03-16 02:22:52 +00:00
|
|
|
str_compaction_pri.c_str());
|
|
|
|
ROCKS_LOG_HEADER(log,
|
2017-05-09 22:44:48 +00:00
|
|
|
"Options.compaction_options_universal.size_ratio: %u",
|
2017-03-16 02:22:52 +00:00
|
|
|
compaction_options_universal.size_ratio);
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
"Options.compaction_options_universal.min_merge_width: %u",
|
|
|
|
compaction_options_universal.min_merge_width);
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
"Options.compaction_options_universal.max_merge_width: %u",
|
|
|
|
compaction_options_universal.max_merge_width);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
"Options.compaction_options_universal."
|
|
|
|
"max_size_amplification_percent: %u",
|
2013-09-09 23:06:10 +00:00
|
|
|
compaction_options_universal.max_size_amplification_percent);
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
2014-09-19 20:09:25 +00:00
|
|
|
"Options.compaction_options_universal.compression_size_percent: %d",
|
2013-12-03 20:32:07 +00:00
|
|
|
compaction_options_universal.compression_size_percent);
|
2017-05-09 22:44:48 +00:00
|
|
|
const auto& it_compaction_stop_style = compaction_stop_style_to_string.find(
|
|
|
|
compaction_options_universal.stop_style);
|
|
|
|
std::string str_compaction_stop_style;
|
|
|
|
if (it_compaction_stop_style == compaction_stop_style_to_string.end()) {
|
|
|
|
assert(false);
|
|
|
|
str_compaction_stop_style =
|
|
|
|
"unknown_" + std::to_string(compaction_options_universal.stop_style);
|
|
|
|
} else {
|
|
|
|
str_compaction_stop_style = it_compaction_stop_style->second;
|
|
|
|
}
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
"Options.compaction_options_universal.stop_style: %s",
|
|
|
|
str_compaction_stop_style.c_str());
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, "Options.compaction_options_fifo.max_table_files_size: %" PRIu64,
|
2014-05-21 18:43:35 +00:00
|
|
|
compaction_options_fifo.max_table_files_size);
|
2017-05-05 01:14:29 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
"Options.compaction_options_fifo.allow_compaction: %d",
|
|
|
|
compaction_options_fifo.allow_compaction);
|
2020-04-14 02:56:02 +00:00
|
|
|
std::ostringstream collector_info;
|
TablePropertiesCollectorFactory
Summary:
This diff addresses task #4296714 and rethinks how users provide us with TablePropertiesCollectors as part of Options.
Here's description of task #4296714:
I'm debugging #4295529 and noticed that our count of user properties kDeletedKeys is wrong. We're sharing one single InternalKeyPropertiesCollector with all Table Builders. In LOG Files, we're outputting number of kDeletedKeys as connected with a single table, while it's actually the total count of deleted keys since creation of the DB.
For example, this table has 3155 entries and 1391828 deleted keys.
The problem with current approach that we call methods on a single TablePropertiesCollector for all the tables we create. Even worse, we could do it from multiple threads at the same time and TablePropertiesCollector has no way of knowing which table we're calling it for.
Good part: Looks like nobody inside Facebook is using Options::table_properties_collectors. This means we should be able to painfully change the API.
In this change, I introduce TablePropertiesCollectorFactory. For every table we create, we call `CreateTablePropertiesCollector`, which creates a TablePropertiesCollector for a single table. We then use it sequentially from a single thread, which means it doesn't have to be thread-safe.
Test Plan:
Added a test in table_properties_collector_test that fails on master (build two tables, assert that kDeletedKeys count is correct for the second one).
Also, all other tests
Reviewers: sdong, dhruba, haobo, kailiu
Reviewed By: kailiu
CC: leveldb
Differential Revision: https://reviews.facebook.net/D18579
2014-05-13 19:30:55 +00:00
|
|
|
for (const auto& collector_factory : table_properties_collector_factories) {
|
2020-04-14 02:56:02 +00:00
|
|
|
collector_info << collector_factory->ToString() << ';';
|
2013-10-16 18:50:50 +00:00
|
|
|
}
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.table_properties_collectors: %s",
|
2020-04-14 02:56:02 +00:00
|
|
|
collector_info.str().c_str());
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.inplace_update_support: %d",
|
|
|
|
inplace_update_support);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.inplace_update_num_locks: %" ROCKSDB_PRIszt,
|
|
|
|
inplace_update_num_locks);
|
2013-11-27 22:27:02 +00:00
|
|
|
// TODO: easier config for bloom (maybe based on avg key/value size)
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.memtable_prefix_bloom_size_ratio: %f",
|
|
|
|
memtable_prefix_bloom_size_ratio);
|
2019-02-19 20:12:25 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.memtable_whole_key_filtering: %d",
|
|
|
|
memtable_whole_key_filtering);
|
2015-07-01 23:13:49 +00:00
|
|
|
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.memtable_huge_page_size: %" ROCKSDB_PRIszt,
|
|
|
|
memtable_huge_page_size);
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.bloom_locality: %d",
|
|
|
|
bloom_locality);
|
2015-07-01 23:13:49 +00:00
|
|
|
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log,
|
|
|
|
" Options.max_successive_merges: %" ROCKSDB_PRIszt,
|
|
|
|
max_successive_merges);
|
2024-02-21 21:15:27 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.strict_max_successive_merges: %d",
|
|
|
|
strict_max_successive_merges);
|
2017-03-16 02:22:52 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.optimize_filters_for_hits: %d",
|
|
|
|
optimize_filters_for_hits);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.paranoid_file_checks: %d",
|
|
|
|
paranoid_file_checks);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.force_consistency_checks: %d",
|
|
|
|
force_consistency_checks);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.report_bg_io_stats: %d",
|
|
|
|
report_bg_io_stats);
|
2019-04-04 19:05:42 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.ttl: %" PRIu64,
|
|
|
|
ttl);
|
Periodic Compactions (#5166)
Summary:
Introducing Periodic Compactions.
This feature allows all the files in a CF to be periodically compacted. It could help in catching any corruptions that could creep into the DB proactively as every file is constantly getting re-compacted. And also, of course, it helps to cleanup data older than certain threshold.
- Introduced a new option `periodic_compaction_time` to control how long a file can live without being compacted in a CF.
- This works across all levels.
- The files are put in the same level after going through the compaction. (Related files in the same level are picked up as `ExpandInputstoCleanCut` is used).
- Compaction filters, if any, are invoked as usual.
- A new table property, `file_creation_time`, is introduced to implement this feature. This property is set to the time at which the SST file was created (and that time is given by the underlying Env/OS).
This feature can be enabled on its own, or in conjunction with `ttl`. It is possible to set a different time threshold for the bottom level when used in conjunction with ttl. Since `ttl` works only on 0 to last but one levels, you could set `ttl` to, say, 1 day, and `periodic_compaction_time` to, say, 7 days. Since `ttl < periodic_compaction_time` all files in last but one levels keep getting picked up based on ttl, and almost never based on periodic_compaction_time. The files in the bottom level get picked up for compaction based on `periodic_compaction_time`.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5166
Differential Revision: D14884441
Pulled By: sagar0
fbshipit-source-id: 408426cbacb409c06386a98632dcf90bfa1bda47
2019-04-11 02:24:25 +00:00
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.periodic_compaction_seconds: %" PRIu64,
|
|
|
|
periodic_compaction_seconds);
|
2023-08-18 00:06:57 +00:00
|
|
|
const auto& it_temp = temperature_to_string.find(default_temperature);
|
|
|
|
std::string str_default_temperature;
|
|
|
|
if (it_temp == temperature_to_string.end()) {
|
|
|
|
assert(false);
|
|
|
|
str_default_temperature = "unknown_temperature";
|
|
|
|
} else {
|
|
|
|
str_default_temperature = it_temp->second;
|
|
|
|
}
|
|
|
|
ROCKS_LOG_HEADER(log,
|
|
|
|
" Options.default_temperature: %s",
|
|
|
|
str_default_temperature.c_str());
|
2022-07-15 04:49:34 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.preclude_last_level_data_seconds: %" PRIu64,
|
|
|
|
preclude_last_level_data_seconds);
|
2022-10-08 01:49:40 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.preserve_internal_time_seconds: %" PRIu64,
|
|
|
|
preserve_internal_time_seconds);
|
Make it possible to force the garbage collection of the oldest blob files (#8994)
Summary:
The current BlobDB garbage collection logic works by relocating the valid
blobs from the oldest blob files as they are encountered during compaction,
and cleaning up blob files once they contain nothing but garbage. However,
with sufficiently skewed workloads, it is theoretically possible to end up in a
situation when few or no compactions get scheduled for the SST files that contain
references to the oldest blob files, which can lead to increased space amp due
to the lack of GC.
In order to efficiently handle such workloads, the patch adds a new BlobDB
configuration option called `blob_garbage_collection_force_threshold`,
which signals to BlobDB to schedule targeted compactions for the SST files
that keep alive the oldest batch of blob files if the overall ratio of garbage in
the given blob files meets the threshold *and* all the given blob files are
eligible for GC based on `blob_garbage_collection_age_cutoff`. (For example,
if the new option is set to 0.9, targeted compactions will get scheduled if the
sum of garbage bytes meets or exceeds 90% of the sum of total bytes in the
oldest blob files, assuming all affected blob files are below the age-based cutoff.)
The net result of these targeted compactions is that the valid blobs in the oldest
blob files are relocated and the oldest blob files themselves cleaned up (since
*all* SST files that rely on them get compacted away).
These targeted compactions are similar to periodic compactions in the sense
that they force certain SST files that otherwise would not get picked up to undergo
compaction and also in the sense that instead of merging files from multiple levels,
they target a single file. (Note: such compactions might still include neighboring files
from the same level due to the need of having a "clean cut" boundary but they never
include any files from any other level.)
This functionality is currently only supported with the leveled compaction style
and is inactive by default (since the default value is set to 1.0, i.e. 100%).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8994
Test Plan: Ran `make check` and tested using `db_bench` and the stress/crash tests.
Reviewed By: riversand963
Differential Revision: D31489850
Pulled By: ltamasi
fbshipit-source-id: 44057d511726a0e2a03c5d9313d7511b3f0c4eab
2021-10-12 01:00:44 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.enable_blob_files: %s",
|
2020-08-19 01:31:31 +00:00
|
|
|
enable_blob_files ? "true" : "false");
|
Make it possible to force the garbage collection of the oldest blob files (#8994)
Summary:
The current BlobDB garbage collection logic works by relocating the valid
blobs from the oldest blob files as they are encountered during compaction,
and cleaning up blob files once they contain nothing but garbage. However,
with sufficiently skewed workloads, it is theoretically possible to end up in a
situation when few or no compactions get scheduled for the SST files that contain
references to the oldest blob files, which can lead to increased space amp due
to the lack of GC.
In order to efficiently handle such workloads, the patch adds a new BlobDB
configuration option called `blob_garbage_collection_force_threshold`,
which signals to BlobDB to schedule targeted compactions for the SST files
that keep alive the oldest batch of blob files if the overall ratio of garbage in
the given blob files meets the threshold *and* all the given blob files are
eligible for GC based on `blob_garbage_collection_age_cutoff`. (For example,
if the new option is set to 0.9, targeted compactions will get scheduled if the
sum of garbage bytes meets or exceeds 90% of the sum of total bytes in the
oldest blob files, assuming all affected blob files are below the age-based cutoff.)
The net result of these targeted compactions is that the valid blobs in the oldest
blob files are relocated and the oldest blob files themselves cleaned up (since
*all* SST files that rely on them get compacted away).
These targeted compactions are similar to periodic compactions in the sense
that they force certain SST files that otherwise would not get picked up to undergo
compaction and also in the sense that instead of merging files from multiple levels,
they target a single file. (Note: such compactions might still include neighboring files
from the same level due to the need of having a "clean cut" boundary but they never
include any files from any other level.)
This functionality is currently only supported with the leveled compaction style
and is inactive by default (since the default value is set to 1.0, i.e. 100%).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8994
Test Plan: Ran `make check` and tested using `db_bench` and the stress/crash tests.
Reviewed By: riversand963
Differential Revision: D31489850
Pulled By: ltamasi
fbshipit-source-id: 44057d511726a0e2a03c5d9313d7511b3f0c4eab
2021-10-12 01:00:44 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.min_blob_size: %" PRIu64,
|
|
|
|
min_blob_size);
|
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.blob_file_size: %" PRIu64,
|
|
|
|
blob_file_size);
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.blob_compression_type: %s",
|
2020-08-19 01:31:31 +00:00
|
|
|
CompressionTypeToString(blob_compression_type).c_str());
|
Make it possible to force the garbage collection of the oldest blob files (#8994)
Summary:
The current BlobDB garbage collection logic works by relocating the valid
blobs from the oldest blob files as they are encountered during compaction,
and cleaning up blob files once they contain nothing but garbage. However,
with sufficiently skewed workloads, it is theoretically possible to end up in a
situation when few or no compactions get scheduled for the SST files that contain
references to the oldest blob files, which can lead to increased space amp due
to the lack of GC.
In order to efficiently handle such workloads, the patch adds a new BlobDB
configuration option called `blob_garbage_collection_force_threshold`,
which signals to BlobDB to schedule targeted compactions for the SST files
that keep alive the oldest batch of blob files if the overall ratio of garbage in
the given blob files meets the threshold *and* all the given blob files are
eligible for GC based on `blob_garbage_collection_age_cutoff`. (For example,
if the new option is set to 0.9, targeted compactions will get scheduled if the
sum of garbage bytes meets or exceeds 90% of the sum of total bytes in the
oldest blob files, assuming all affected blob files are below the age-based cutoff.)
The net result of these targeted compactions is that the valid blobs in the oldest
blob files are relocated and the oldest blob files themselves cleaned up (since
*all* SST files that rely on them get compacted away).
These targeted compactions are similar to periodic compactions in the sense
that they force certain SST files that otherwise would not get picked up to undergo
compaction and also in the sense that instead of merging files from multiple levels,
they target a single file. (Note: such compactions might still include neighboring files
from the same level due to the need of having a "clean cut" boundary but they never
include any files from any other level.)
This functionality is currently only supported with the leveled compaction style
and is inactive by default (since the default value is set to 1.0, i.e. 100%).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8994
Test Plan: Ran `make check` and tested using `db_bench` and the stress/crash tests.
Reviewed By: riversand963
Differential Revision: D31489850
Pulled By: ltamasi
fbshipit-source-id: 44057d511726a0e2a03c5d9313d7511b3f0c4eab
2021-10-12 01:00:44 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.enable_blob_garbage_collection: %s",
|
2020-11-13 02:57:20 +00:00
|
|
|
enable_blob_garbage_collection ? "true" : "false");
|
Make it possible to force the garbage collection of the oldest blob files (#8994)
Summary:
The current BlobDB garbage collection logic works by relocating the valid
blobs from the oldest blob files as they are encountered during compaction,
and cleaning up blob files once they contain nothing but garbage. However,
with sufficiently skewed workloads, it is theoretically possible to end up in a
situation when few or no compactions get scheduled for the SST files that contain
references to the oldest blob files, which can lead to increased space amp due
to the lack of GC.
In order to efficiently handle such workloads, the patch adds a new BlobDB
configuration option called `blob_garbage_collection_force_threshold`,
which signals to BlobDB to schedule targeted compactions for the SST files
that keep alive the oldest batch of blob files if the overall ratio of garbage in
the given blob files meets the threshold *and* all the given blob files are
eligible for GC based on `blob_garbage_collection_age_cutoff`. (For example,
if the new option is set to 0.9, targeted compactions will get scheduled if the
sum of garbage bytes meets or exceeds 90% of the sum of total bytes in the
oldest blob files, assuming all affected blob files are below the age-based cutoff.)
The net result of these targeted compactions is that the valid blobs in the oldest
blob files are relocated and the oldest blob files themselves cleaned up (since
*all* SST files that rely on them get compacted away).
These targeted compactions are similar to periodic compactions in the sense
that they force certain SST files that otherwise would not get picked up to undergo
compaction and also in the sense that instead of merging files from multiple levels,
they target a single file. (Note: such compactions might still include neighboring files
from the same level due to the need of having a "clean cut" boundary but they never
include any files from any other level.)
This functionality is currently only supported with the leveled compaction style
and is inactive by default (since the default value is set to 1.0, i.e. 100%).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8994
Test Plan: Ran `make check` and tested using `db_bench` and the stress/crash tests.
Reviewed By: riversand963
Differential Revision: D31489850
Pulled By: ltamasi
fbshipit-source-id: 44057d511726a0e2a03c5d9313d7511b3f0c4eab
2021-10-12 01:00:44 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.blob_garbage_collection_age_cutoff: %f",
|
2020-11-13 02:57:20 +00:00
|
|
|
blob_garbage_collection_age_cutoff);
|
Make it possible to force the garbage collection of the oldest blob files (#8994)
Summary:
The current BlobDB garbage collection logic works by relocating the valid
blobs from the oldest blob files as they are encountered during compaction,
and cleaning up blob files once they contain nothing but garbage. However,
with sufficiently skewed workloads, it is theoretically possible to end up in a
situation when few or no compactions get scheduled for the SST files that contain
references to the oldest blob files, which can lead to increased space amp due
to the lack of GC.
In order to efficiently handle such workloads, the patch adds a new BlobDB
configuration option called `blob_garbage_collection_force_threshold`,
which signals to BlobDB to schedule targeted compactions for the SST files
that keep alive the oldest batch of blob files if the overall ratio of garbage in
the given blob files meets the threshold *and* all the given blob files are
eligible for GC based on `blob_garbage_collection_age_cutoff`. (For example,
if the new option is set to 0.9, targeted compactions will get scheduled if the
sum of garbage bytes meets or exceeds 90% of the sum of total bytes in the
oldest blob files, assuming all affected blob files are below the age-based cutoff.)
The net result of these targeted compactions is that the valid blobs in the oldest
blob files are relocated and the oldest blob files themselves cleaned up (since
*all* SST files that rely on them get compacted away).
These targeted compactions are similar to periodic compactions in the sense
that they force certain SST files that otherwise would not get picked up to undergo
compaction and also in the sense that instead of merging files from multiple levels,
they target a single file. (Note: such compactions might still include neighboring files
from the same level due to the need of having a "clean cut" boundary but they never
include any files from any other level.)
This functionality is currently only supported with the leveled compaction style
and is inactive by default (since the default value is set to 1.0, i.e. 100%).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8994
Test Plan: Ran `make check` and tested using `db_bench` and the stress/crash tests.
Reviewed By: riversand963
Differential Revision: D31489850
Pulled By: ltamasi
fbshipit-source-id: 44057d511726a0e2a03c5d9313d7511b3f0c4eab
2021-10-12 01:00:44 +00:00
|
|
|
ROCKS_LOG_HEADER(log, "Options.blob_garbage_collection_force_threshold: %f",
|
|
|
|
blob_garbage_collection_force_threshold);
|
2021-11-20 01:52:42 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " Options.blob_compaction_readahead_size: %" PRIu64,
|
|
|
|
blob_compaction_readahead_size);
|
2022-06-03 03:04:33 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.blob_file_starting_level: %d",
|
|
|
|
blob_file_starting_level);
|
2022-06-14 21:19:26 +00:00
|
|
|
if (blob_cache) {
|
|
|
|
ROCKS_LOG_HEADER(log, " Options.blob_cache: %s",
|
|
|
|
blob_cache->Name());
|
|
|
|
ROCKS_LOG_HEADER(log, " blob_cache options: %s",
|
|
|
|
blob_cache->GetPrintableOptions().c_str());
|
2022-07-17 14:13:59 +00:00
|
|
|
ROCKS_LOG_HEADER(
|
|
|
|
log, " blob_cache prepopulated: %s",
|
|
|
|
prepopulate_blob_cache == PrepopulateBlobCache::kFlushOnly
|
|
|
|
? "flush only"
|
|
|
|
: "disabled");
|
2022-06-14 21:19:26 +00:00
|
|
|
}
|
2023-08-03 02:58:56 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.experimental_mempurge_threshold: %f",
|
2022-06-23 16:42:18 +00:00
|
|
|
experimental_mempurge_threshold);
|
2023-08-03 02:58:56 +00:00
|
|
|
ROCKS_LOG_HEADER(log, " Options.memtable_max_range_deletions: %d",
|
|
|
|
memtable_max_range_deletions);
|
2014-02-07 05:39:20 +00:00
|
|
|
} // ColumnFamilyOptions::Dump
|
|
|
|
|
|
|
|
void Options::Dump(Logger* log) const {
|
|
|
|
DBOptions::Dump(log);
|
|
|
|
ColumnFamilyOptions::Dump(log);
|
2022-06-23 16:42:18 +00:00
|
|
|
} // Options::Dump
|
2012-08-22 18:43:53 +00:00
|
|
|
|
2015-06-18 17:15:54 +00:00
|
|
|
void Options::DumpCFOptions(Logger* log) const {
|
|
|
|
ColumnFamilyOptions::Dump(log);
|
|
|
|
} // Options::DumpCFOptions
|
|
|
|
|
2013-03-08 17:19:24 +00:00
|
|
|
//
|
|
|
|
// The goal of this method is to create a configuration that
|
|
|
|
// allows an application to write all files into L0 and
|
|
|
|
// then do a single compaction to output all files into L1.
|
2013-02-26 06:57:37 +00:00
|
|
|
Options*
|
|
|
|
Options::PrepareForBulkLoad()
|
|
|
|
{
|
2013-03-08 17:19:24 +00:00
|
|
|
// never slowdown ingest.
|
2013-02-26 06:57:37 +00:00
|
|
|
level0_file_num_compaction_trigger = (1<<30);
|
|
|
|
level0_slowdown_writes_trigger = (1<<30);
|
|
|
|
level0_stop_writes_trigger = (1<<30);
|
2016-06-16 21:05:34 +00:00
|
|
|
soft_pending_compaction_bytes_limit = 0;
|
|
|
|
hard_pending_compaction_bytes_limit = 0;
|
2013-03-08 17:19:24 +00:00
|
|
|
|
|
|
|
// no auto compactions please. The application should issue a
|
|
|
|
// manual compaction after all data is loaded into L0.
|
2013-02-26 06:57:37 +00:00
|
|
|
disable_auto_compactions = true;
|
2013-03-08 17:19:24 +00:00
|
|
|
// A manual compaction run should pick all files in L0 in
|
|
|
|
// a single compaction run.
|
2016-06-16 23:02:52 +00:00
|
|
|
max_compaction_bytes = (static_cast<uint64_t>(1) << 60);
|
2013-02-26 06:57:37 +00:00
|
|
|
|
2013-03-08 17:19:24 +00:00
|
|
|
// It is better to have only 2 levels, otherwise a manual
|
|
|
|
// compaction would compact at every possible level, thereby
|
|
|
|
// increasing the total time needed for compactions.
|
|
|
|
num_levels = 2;
|
|
|
|
|
2015-02-02 19:09:21 +00:00
|
|
|
// Need to allow more write buffers to allow more parallism
|
|
|
|
// of flushes.
|
|
|
|
max_write_buffer_number = 6;
|
|
|
|
min_write_buffer_number_to_merge = 1;
|
|
|
|
|
|
|
|
// When compaction is disabled, more parallel flush threads can
|
|
|
|
// help with write throughput.
|
|
|
|
max_background_flushes = 4;
|
|
|
|
|
2013-03-08 17:19:24 +00:00
|
|
|
// Prevent a memtable flush to automatically promote files
|
|
|
|
// to L1. This is helpful so that all files that are
|
|
|
|
// input to the manual compaction are all at L0.
|
|
|
|
max_background_compactions = 2;
|
|
|
|
|
|
|
|
// The compaction would create large files in L1.
|
|
|
|
target_file_size_base = 256 * 1024 * 1024;
|
2013-02-26 06:57:37 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2016-05-05 23:50:32 +00:00
|
|
|
Options* Options::OptimizeForSmallDb() {
|
2019-04-11 17:22:07 +00:00
|
|
|
// 16MB block cache
|
|
|
|
std::shared_ptr<Cache> cache = NewLRUCache(16 << 20);
|
|
|
|
|
|
|
|
ColumnFamilyOptions::OptimizeForSmallDb(&cache);
|
|
|
|
DBOptions::OptimizeForSmallDb(&cache);
|
2016-05-05 23:50:32 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2022-01-19 01:25:33 +00:00
|
|
|
Options* Options::DisableExtraChecks() {
|
|
|
|
// See https://github.com/facebook/rocksdb/issues/9354
|
|
|
|
force_consistency_checks = false;
|
|
|
|
// Considered but no clear performance impact seen:
|
|
|
|
// * paranoid_checks
|
|
|
|
// * flush_verify_memtable_count
|
|
|
|
// By current API contract, not including
|
|
|
|
// * verify_checksums
|
|
|
|
// because checking storage data integrity is a more standard practice.
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2016-03-24 19:45:50 +00:00
|
|
|
Options* Options::OldDefaults(int rocksdb_major_version,
|
|
|
|
int rocksdb_minor_version) {
|
|
|
|
ColumnFamilyOptions::OldDefaults(rocksdb_major_version,
|
|
|
|
rocksdb_minor_version);
|
|
|
|
DBOptions::OldDefaults(rocksdb_major_version, rocksdb_minor_version);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBOptions* DBOptions::OldDefaults(int rocksdb_major_version,
|
|
|
|
int rocksdb_minor_version) {
|
2016-04-08 00:40:42 +00:00
|
|
|
if (rocksdb_major_version < 4 ||
|
|
|
|
(rocksdb_major_version == 4 && rocksdb_minor_version < 7)) {
|
|
|
|
max_file_opening_threads = 1;
|
|
|
|
table_cache_numshardbits = 4;
|
|
|
|
}
|
2017-02-02 04:25:01 +00:00
|
|
|
if (rocksdb_major_version < 5 ||
|
|
|
|
(rocksdb_major_version == 5 && rocksdb_minor_version < 2)) {
|
|
|
|
delayed_write_rate = 2 * 1024U * 1024U;
|
2017-05-24 16:52:08 +00:00
|
|
|
} else if (rocksdb_major_version < 5 ||
|
|
|
|
(rocksdb_major_version == 5 && rocksdb_minor_version < 6)) {
|
|
|
|
delayed_write_rate = 16 * 1024U * 1024U;
|
2017-02-02 04:25:01 +00:00
|
|
|
}
|
2016-04-08 00:40:42 +00:00
|
|
|
max_open_files = 5000;
|
|
|
|
wal_recovery_mode = WALRecoveryMode::kTolerateCorruptedTailRecords;
|
2016-03-24 19:45:50 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnFamilyOptions* ColumnFamilyOptions::OldDefaults(
|
|
|
|
int rocksdb_major_version, int rocksdb_minor_version) {
|
2019-01-24 00:44:02 +00:00
|
|
|
if (rocksdb_major_version < 5 ||
|
|
|
|
(rocksdb_major_version == 5 && rocksdb_minor_version <= 18)) {
|
|
|
|
compaction_pri = CompactionPri::kByCompensatedSize;
|
|
|
|
}
|
2016-04-08 00:40:42 +00:00
|
|
|
if (rocksdb_major_version < 4 ||
|
|
|
|
(rocksdb_major_version == 4 && rocksdb_minor_version < 7)) {
|
|
|
|
write_buffer_size = 4 << 20;
|
|
|
|
target_file_size_base = 2 * 1048576;
|
|
|
|
max_bytes_for_level_base = 10 * 1048576;
|
|
|
|
soft_pending_compaction_bytes_limit = 0;
|
|
|
|
hard_pending_compaction_bytes_limit = 0;
|
|
|
|
}
|
2016-11-23 17:19:11 +00:00
|
|
|
if (rocksdb_major_version < 5) {
|
|
|
|
level0_stop_writes_trigger = 24;
|
2017-02-02 04:25:01 +00:00
|
|
|
} else if (rocksdb_major_version == 5 && rocksdb_minor_version < 2) {
|
|
|
|
level0_stop_writes_trigger = 30;
|
2016-11-23 17:19:11 +00:00
|
|
|
}
|
2021-02-07 06:32:57 +00:00
|
|
|
|
2016-03-24 19:45:50 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2014-05-10 17:49:33 +00:00
|
|
|
// Optimization functions
|
2019-04-11 17:22:07 +00:00
|
|
|
DBOptions* DBOptions::OptimizeForSmallDb(std::shared_ptr<Cache>* cache) {
|
2016-05-05 23:50:32 +00:00
|
|
|
max_file_opening_threads = 1;
|
|
|
|
max_open_files = 5000;
|
2019-04-11 17:22:07 +00:00
|
|
|
|
|
|
|
// Cost memtable to block cache too.
|
2020-02-20 20:07:53 +00:00
|
|
|
std::shared_ptr<ROCKSDB_NAMESPACE::WriteBufferManager> wbm =
|
|
|
|
std::make_shared<ROCKSDB_NAMESPACE::WriteBufferManager>(
|
2019-04-11 17:22:07 +00:00
|
|
|
0, (cache != nullptr) ? *cache : std::shared_ptr<Cache>());
|
|
|
|
write_buffer_manager = wbm;
|
|
|
|
|
2016-05-05 23:50:32 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-04-11 17:22:07 +00:00
|
|
|
ColumnFamilyOptions* ColumnFamilyOptions::OptimizeForSmallDb(
|
|
|
|
std::shared_ptr<Cache>* cache) {
|
2016-03-24 19:45:50 +00:00
|
|
|
write_buffer_size = 2 << 20;
|
|
|
|
target_file_size_base = 2 * 1048576;
|
|
|
|
max_bytes_for_level_base = 10 * 1048576;
|
|
|
|
soft_pending_compaction_bytes_limit = 256 * 1048576;
|
|
|
|
hard_pending_compaction_bytes_limit = 1073741824ul;
|
2019-04-11 17:22:07 +00:00
|
|
|
|
|
|
|
BlockBasedTableOptions table_options;
|
|
|
|
table_options.block_cache =
|
|
|
|
(cache != nullptr) ? *cache : std::shared_ptr<Cache>();
|
|
|
|
table_options.cache_index_and_filter_blocks = true;
|
|
|
|
// Two level iterator to avoid LRU cache imbalance
|
|
|
|
table_options.index_type =
|
|
|
|
BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch;
|
|
|
|
table_factory.reset(new BlockBasedTableFactory(table_options));
|
|
|
|
|
2016-03-24 19:45:50 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2014-08-26 21:15:00 +00:00
|
|
|
ColumnFamilyOptions* ColumnFamilyOptions::OptimizeForPointLookup(
|
|
|
|
uint64_t block_cache_size_mb) {
|
2014-05-10 17:49:33 +00:00
|
|
|
BlockBasedTableOptions block_based_options;
|
2018-07-27 22:35:41 +00:00
|
|
|
block_based_options.data_block_index_type =
|
2018-08-15 21:27:47 +00:00
|
|
|
BlockBasedTableOptions::kDataBlockBinaryAndHash;
|
|
|
|
block_based_options.data_block_hash_table_util_ratio = 0.75;
|
2014-08-26 21:15:00 +00:00
|
|
|
block_based_options.filter_policy.reset(NewBloomFilterPolicy(10));
|
|
|
|
block_based_options.block_cache =
|
2014-11-13 19:39:30 +00:00
|
|
|
NewLRUCache(static_cast<size_t>(block_cache_size_mb * 1024 * 1024));
|
2014-05-10 17:49:33 +00:00
|
|
|
table_factory.reset(new BlockBasedTableFactory(block_based_options));
|
2017-01-20 18:43:59 +00:00
|
|
|
memtable_prefix_bloom_size_ratio = 0.02;
|
2019-04-11 17:22:07 +00:00
|
|
|
memtable_whole_key_filtering = true;
|
2014-05-10 17:49:33 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnFamilyOptions* ColumnFamilyOptions::OptimizeLevelStyleCompaction(
|
|
|
|
uint64_t memtable_memory_budget) {
|
2014-11-13 19:39:30 +00:00
|
|
|
write_buffer_size = static_cast<size_t>(memtable_memory_budget / 4);
|
2014-05-10 17:49:33 +00:00
|
|
|
// merge two memtables when flushing to L0
|
|
|
|
min_write_buffer_number_to_merge = 2;
|
|
|
|
// this means we'll use 50% extra memory in the worst case, but will reduce
|
|
|
|
// write stalls.
|
|
|
|
max_write_buffer_number = 6;
|
|
|
|
// start flushing L0->L1 as soon as possible. each file on level0 is
|
|
|
|
// (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
|
|
|
|
// memtable_memory_budget.
|
|
|
|
level0_file_num_compaction_trigger = 2;
|
|
|
|
// doesn't really matter much, but we don't want to create too many files
|
|
|
|
target_file_size_base = memtable_memory_budget / 8;
|
|
|
|
// make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
|
|
|
|
max_bytes_for_level_base = memtable_memory_budget;
|
|
|
|
|
|
|
|
// level style compaction
|
|
|
|
compaction_style = kCompactionStyleLevel;
|
|
|
|
|
|
|
|
// only compress levels >= 2
|
|
|
|
compression_per_level.resize(num_levels);
|
|
|
|
for (int i = 0; i < num_levels; ++i) {
|
|
|
|
if (i < 2) {
|
|
|
|
compression_per_level[i] = kNoCompression;
|
|
|
|
} else {
|
2019-05-02 03:36:09 +00:00
|
|
|
compression_per_level[i] =
|
|
|
|
LZ4_Supported()
|
|
|
|
? kLZ4Compression
|
|
|
|
: (Snappy_Supported() ? kSnappyCompression : kNoCompression);
|
2014-05-10 17:49:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnFamilyOptions* ColumnFamilyOptions::OptimizeUniversalStyleCompaction(
|
|
|
|
uint64_t memtable_memory_budget) {
|
2014-11-13 19:39:30 +00:00
|
|
|
write_buffer_size = static_cast<size_t>(memtable_memory_budget / 4);
|
2014-05-10 17:49:33 +00:00
|
|
|
// merge two memtables when flushing to L0
|
|
|
|
min_write_buffer_number_to_merge = 2;
|
|
|
|
// this means we'll use 50% extra memory in the worst case, but will reduce
|
|
|
|
// write stalls.
|
|
|
|
max_write_buffer_number = 6;
|
|
|
|
// universal style compaction
|
|
|
|
compaction_style = kCompactionStyleUniversal;
|
|
|
|
compaction_options_universal.compression_size_percent = 80;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBOptions* DBOptions::IncreaseParallelism(int total_threads) {
|
2017-12-04 09:53:49 +00:00
|
|
|
max_background_jobs = total_threads;
|
2014-05-10 17:49:33 +00:00
|
|
|
env->SetBackgroundThreads(total_threads, Env::LOW);
|
|
|
|
env->SetBackgroundThreads(1, Env::HIGH);
|
|
|
|
return this;
|
|
|
|
}
|
2023-05-08 19:50:04 +00:00
|
|
|
|
|
|
|
ReadOptions::ReadOptions(bool _verify_checksums, bool _fill_cache)
|
|
|
|
: verify_checksums(_verify_checksums), fill_cache(_fill_cache) {}
|
2023-04-21 16:07:18 +00:00
|
|
|
|
|
|
|
ReadOptions::ReadOptions(Env::IOActivity _io_activity)
|
2023-05-08 19:50:04 +00:00
|
|
|
: io_activity(_io_activity) {}
|
2015-02-18 19:49:31 +00:00
|
|
|
|
Group SST write in flush, compaction and db open with new stats (#11910)
Summary:
## Context/Summary
Similar to https://github.com/facebook/rocksdb/pull/11288, https://github.com/facebook/rocksdb/pull/11444, categorizing SST/blob file write according to different io activities allows more insight into the activity.
For that, this PR does the following:
- Tag different write IOs by passing down and converting WriteOptions to IOOptions
- Add new SST_WRITE_MICROS histogram in WritableFileWriter::Append() and breakdown FILE_WRITE_{FLUSH|COMPACTION|DB_OPEN}_MICROS
Some related code refactory to make implementation cleaner:
- Blob stats
- Replace high-level write measurement with low-level WritableFileWriter::Append() measurement for BLOB_DB_BLOB_FILE_WRITE_MICROS. This is to make FILE_WRITE_{FLUSH|COMPACTION|DB_OPEN}_MICROS include blob file. As a consequence, this introduces some behavioral changes on it, see HISTORY and db bench test plan below for more info.
- Fix bugs where BLOB_DB_BLOB_FILE_SYNCED/BLOB_DB_BLOB_FILE_BYTES_WRITTEN include file failed to sync and bytes failed to write.
- Refactor WriteOptions constructor for easier construction with io_activity and rate_limiter_priority
- Refactor DBImpl::~DBImpl()/BlobDBImpl::Close() to bypass thread op verification
- Build table
- TableBuilderOptions now includes Read/WriteOpitons so BuildTable() do not need to take these two variables
- Replace the io_priority passed into BuildTable() with TableBuilderOptions::WriteOpitons::rate_limiter_priority. Similar for BlobFileBuilder.
This parameter is used for dynamically changing file io priority for flush, see https://github.com/facebook/rocksdb/pull/9988?fbclid=IwAR1DtKel6c-bRJAdesGo0jsbztRtciByNlvokbxkV6h_L-AE9MACzqRTT5s for more
- Update ThreadStatus::FLUSH_BYTES_WRITTEN to use io_activity to track flush IO in flush job and db open instead of io_priority
## Test
### db bench
Flush
```
./db_bench --statistics=1 --benchmarks=fillseq --num=100000 --write_buffer_size=100
rocksdb.sst.write.micros P50 : 1.830863 P95 : 4.094720 P99 : 6.578947 P100 : 26.000000 COUNT : 7875 SUM : 20377
rocksdb.file.write.flush.micros P50 : 1.830863 P95 : 4.094720 P99 : 6.578947 P100 : 26.000000 COUNT : 7875 SUM : 20377
rocksdb.file.write.compaction.micros P50 : 0.000000 P95 : 0.000000 P99 : 0.000000 P100 : 0.000000 COUNT : 0 SUM : 0
rocksdb.file.write.db.open.micros P50 : 0.000000 P95 : 0.000000 P99 : 0.000000 P100 : 0.000000 COUNT : 0 SUM : 0
```
compaction, db oopen
```
Setup: ./db_bench --statistics=1 --benchmarks=fillseq --num=10000 --disable_auto_compactions=1 -write_buffer_size=100 --db=../db_bench
Run:./db_bench --statistics=1 --benchmarks=compact --db=../db_bench --use_existing_db=1
rocksdb.sst.write.micros P50 : 2.675325 P95 : 9.578788 P99 : 18.780000 P100 : 314.000000 COUNT : 638 SUM : 3279
rocksdb.file.write.flush.micros P50 : 0.000000 P95 : 0.000000 P99 : 0.000000 P100 : 0.000000 COUNT : 0 SUM : 0
rocksdb.file.write.compaction.micros P50 : 2.757353 P95 : 9.610687 P99 : 19.316667 P100 : 314.000000 COUNT : 615 SUM : 3213
rocksdb.file.write.db.open.micros P50 : 2.055556 P95 : 3.925000 P99 : 9.000000 P100 : 9.000000 COUNT : 23 SUM : 66
```
blob stats - just to make sure they aren't broken by this PR
```
Integrated Blob DB
Setup: ./db_bench --enable_blob_files=1 --statistics=1 --benchmarks=fillseq --num=10000 --disable_auto_compactions=1 -write_buffer_size=100 --db=../db_bench
Run:./db_bench --enable_blob_files=1 --statistics=1 --benchmarks=compact --db=../db_bench --use_existing_db=1
pre-PR:
rocksdb.blobdb.blob.file.write.micros P50 : 7.298246 P95 : 9.771930 P99 : 9.991813 P100 : 16.000000 COUNT : 235 SUM : 1600
rocksdb.blobdb.blob.file.synced COUNT : 1
rocksdb.blobdb.blob.file.bytes.written COUNT : 34842
post-PR:
rocksdb.blobdb.blob.file.write.micros P50 : 2.000000 P95 : 2.829360 P99 : 2.993779 P100 : 9.000000 COUNT : 707 SUM : 1614
- COUNT is higher and values are smaller as it includes header and footer write
- COUNT is 3X higher due to each Append() count as one post-PR, while in pre-PR, 3 Append()s counts as one. See https://github.com/facebook/rocksdb/pull/11910/files#diff-32b811c0a1c000768cfb2532052b44dc0b3bf82253f3eab078e15ff201a0dabfL157-L164
rocksdb.blobdb.blob.file.synced COUNT : 1 (stay the same)
rocksdb.blobdb.blob.file.bytes.written COUNT : 34842 (stay the same)
```
```
Stacked Blob DB
Run: ./db_bench --use_blob_db=1 --statistics=1 --benchmarks=fillseq --num=10000 --disable_auto_compactions=1 -write_buffer_size=100 --db=../db_bench
pre-PR:
rocksdb.blobdb.blob.file.write.micros P50 : 12.808042 P95 : 19.674497 P99 : 28.539683 P100 : 51.000000 COUNT : 10000 SUM : 140876
rocksdb.blobdb.blob.file.synced COUNT : 8
rocksdb.blobdb.blob.file.bytes.written COUNT : 1043445
post-PR:
rocksdb.blobdb.blob.file.write.micros P50 : 1.657370 P95 : 2.952175 P99 : 3.877519 P100 : 24.000000 COUNT : 30001 SUM : 67924
- COUNT is higher and values are smaller as it includes header and footer write
- COUNT is 3X higher due to each Append() count as one post-PR, while in pre-PR, 3 Append()s counts as one. See https://github.com/facebook/rocksdb/pull/11910/files#diff-32b811c0a1c000768cfb2532052b44dc0b3bf82253f3eab078e15ff201a0dabfL157-L164
rocksdb.blobdb.blob.file.synced COUNT : 8 (stay the same)
rocksdb.blobdb.blob.file.bytes.written COUNT : 1043445 (stay the same)
```
### Rehearsal CI stress test
Trigger 3 full runs of all our CI stress tests
### Performance
Flush
```
TEST_TMPDIR=/dev/shm ./db_basic_bench_pre_pr --benchmark_filter=ManualFlush/key_num:524288/per_key_size:256 --benchmark_repetitions=1000
-- default: 1 thread is used to run benchmark; enable_statistics = true
Pre-pr: avg 507515519.3 ns
497686074,499444327,500862543,501389862,502994471,503744435,504142123,504224056,505724198,506610393,506837742,506955122,507695561,507929036,508307733,508312691,508999120,509963561,510142147,510698091,510743096,510769317,510957074,511053311,511371367,511409911,511432960,511642385,511691964,511730908,
Post-pr: avg 511971266.5 ns, regressed 0.88%
502744835,506502498,507735420,507929724,508313335,509548582,509994942,510107257,510715603,511046955,511352639,511458478,512117521,512317380,512766303,512972652,513059586,513804934,513808980,514059409,514187369,514389494,514447762,514616464,514622882,514641763,514666265,514716377,514990179,515502408,
```
Compaction
```
TEST_TMPDIR=/dev/shm ./db_basic_bench_{pre|post}_pr --benchmark_filter=ManualCompaction/comp_style:0/max_data:134217728/per_key_size:256/enable_statistics:1 --benchmark_repetitions=1000
-- default: 1 thread is used to run benchmark
Pre-pr: avg 495346098.30 ns
492118301,493203526,494201411,494336607,495269217,495404950,496402598,497012157,497358370,498153846
Post-pr: avg 504528077.20, regressed 1.85%. "ManualCompaction" include flush so the isolated regression for compaction should be around 1.85-0.88 = 0.97%
502465338,502485945,502541789,502909283,503438601,504143885,506113087,506629423,507160414,507393007
```
Put with WAL (in case passing WriteOptions slows down this path even without collecting SST write stats)
```
TEST_TMPDIR=/dev/shm ./db_basic_bench_pre_pr --benchmark_filter=DBPut/comp_style:0/max_data:107374182400/per_key_size:256/enable_statistics:1/wal:1 --benchmark_repetitions=1000
-- default: 1 thread is used to run benchmark
Pre-pr: avg 3848.10 ns
3814,3838,3839,3848,3854,3854,3854,3860,3860,3860
Post-pr: avg 3874.20 ns, regressed 0.68%
3863,3867,3871,3874,3875,3877,3877,3877,3880,3881
```
Pull Request resolved: https://github.com/facebook/rocksdb/pull/11910
Reviewed By: ajkr
Differential Revision: D49788060
Pulled By: hx235
fbshipit-source-id: 79e73699cda5be3b66461687e5147c2484fc5eff
2023-12-29 23:29:23 +00:00
|
|
|
WriteOptions::WriteOptions(Env::IOActivity _io_activity)
|
|
|
|
: io_activity(_io_activity) {}
|
|
|
|
|
|
|
|
WriteOptions::WriteOptions(Env::IOPriority _rate_limiter_priority,
|
|
|
|
Env::IOActivity _io_activity)
|
|
|
|
: rate_limiter_priority(_rate_limiter_priority),
|
|
|
|
io_activity(_io_activity) {}
|
2020-02-20 20:07:53 +00:00
|
|
|
} // namespace ROCKSDB_NAMESPACE
|