mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-07 11:32:34 -05:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51e7cb6d39 | ||
|
|
3e417a6607 | ||
|
|
d382ae7de6 | ||
|
|
53d66df0c4 | ||
|
|
a993c0139d | ||
|
|
e80709a33a | ||
|
|
7ffce2805b | ||
|
|
09b6bf828a | ||
|
|
1cbc96d236 | ||
|
|
82137f0ce8 | ||
|
|
2e3d407778 | ||
|
|
4d51feab0b | ||
|
|
118058ba69 | ||
|
|
88c3e26cc0 | ||
|
|
620823f88b | ||
|
|
de6cf95a53 | ||
|
|
7429b20e39 | ||
|
|
fa8c050e9f | ||
|
|
7a6353bd1c | ||
|
|
70282cf876 | ||
|
|
2ce8f63f81 | ||
|
|
d5585bb605 | ||
|
|
f1b7b790c9 | ||
|
|
8823487ff7 | ||
|
|
6383e42362 | ||
|
|
61785c73ed | ||
|
|
93d52696bf |
No files matched your search
@@ -569,6 +569,7 @@ set(SOURCES
|
||||
util/status_message.cc
|
||||
util/string_util.cc
|
||||
util/sync_point.cc
|
||||
util/sync_point_impl.cc
|
||||
util/testutil.cc
|
||||
util/thread_local.cc
|
||||
util/threadpool_imp.cc
|
||||
|
||||
+7
-13
@@ -1,16 +1,14 @@
|
||||
# Rocksdb Change Log
|
||||
## 5.13.2 (5/25/2018)
|
||||
## Unreleased
|
||||
### Public API Change
|
||||
* Introduced `CompressionOptions::kDefaultCompressionLevel`, which is a generic way to tell RocksDB to use the compression library's default level. It is now the default value for `CompressionOptions::level`. Previously the level defaulted to -1, which gave poor compression ratios in ZSTD.
|
||||
|
||||
### New Features
|
||||
|
||||
### Bug Fixes
|
||||
* Fix segfault caused by object premature destruction (PR #3898)
|
||||
* Fix an issue with unnecessary capture in lambda expressions (PR #3904)
|
||||
* Fsync after writing global seq number to the ingestion file in ExternalSstFileIngestionJob.
|
||||
|
||||
## 5.13.1 (4/30/2018)
|
||||
### New Features
|
||||
* Add `Env::LowerThreadPoolCPUPriority(Priority)` method, which lowers the CPU priority of background (esp. compaction) threads to minimize interference with foreground tasks.
|
||||
* Eliminate use of temporary directories in BackupEngine to improve reliability on distributed file systems.
|
||||
### Java API Changes
|
||||
* Add `BlockBasedTableConfig.setBlockCache` to allow sharing a block cache across DB instances.
|
||||
|
||||
## 5.13.0 (3/20/2018)
|
||||
### Public API Change
|
||||
@@ -22,15 +20,11 @@
|
||||
* Avoid unnecessarily flushing in `CompactRange()` when the range specified by the user does not overlap unflushed memtables.
|
||||
* If `ColumnFamilyOptions::max_subcompactions` is set greater than one, we now parallelize large manual level-based compactions.
|
||||
* Add "rocksdb.live-sst-files-size" DB property to return total bytes of all SST files belong to the latest LSM tree.
|
||||
* NewSstFileManager to add an argument bytes_max_delete_chunk with default 64MB. With this argument, a file larger than 64MB will be ftruncated multiple times based on this size.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a leak in prepared_section_completed_ where the zeroed entries would not removed from the map.
|
||||
* Fix WAL corruption caused by race condition between user write thread and backup/checkpoint thread.
|
||||
* Fsync after writing global seq number to the ingestion file in ExternalSstFileIngestionJob.
|
||||
* Fix memory leak when pin_l0_filter_and_index_blocks_in_cache is used with partitioned filters
|
||||
|
||||
### Java API Changes
|
||||
* Add `BlockBasedTableConfig.setBlockCache` to allow sharing a block cache across DB instances.
|
||||
|
||||
## 5.12.0 (2/14/2018)
|
||||
### Public API Change
|
||||
|
||||
@@ -215,6 +215,7 @@ cpp_library(
|
||||
"util/status_message.cc",
|
||||
"util/string_util.cc",
|
||||
"util/sync_point.cc",
|
||||
"util/sync_point_impl.cc",
|
||||
"util/thread_local.cc",
|
||||
"util/threadpool_imp.cc",
|
||||
"util/transaction_test_util.cc",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Detects OS we're compiling on and outputs a file specified by the first
|
||||
# argument, which in turn gets read while processing Makefile.
|
||||
@@ -66,11 +66,19 @@ rm -f "$OUTPUT"
|
||||
touch "$OUTPUT"
|
||||
|
||||
if test -z "$CC"; then
|
||||
CC=cc
|
||||
if [ -x "$(command -v clang)" ]; then
|
||||
CC=clang
|
||||
else
|
||||
CC=cc
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$CXX"; then
|
||||
CXX=g++
|
||||
if [ -x "$(command -v clang++)" ]; then
|
||||
CXX=clang++
|
||||
else
|
||||
CXX=g++
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect OS
|
||||
@@ -87,7 +95,7 @@ if test -z "$CLANG_SCAN_BUILD"; then
|
||||
fi
|
||||
|
||||
if test -z "$CLANG_ANALYZER"; then
|
||||
CLANG_ANALYZER=$(which clang++ 2> /dev/null)
|
||||
CLANG_ANALYZER=$(command -v clang++ 2> /dev/null)
|
||||
fi
|
||||
|
||||
if test -z "$FIND"; then
|
||||
@@ -498,9 +506,9 @@ if test -z "$PORTABLE"; then
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep ^arm`"; then
|
||||
# TODO: Handle this with approprite options.
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif [ "$TARGET_OS" == IOS ]; then
|
||||
elif [ "$TARGET_OS" == "IOS" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif [ "$TARGET_OS" != AIX ] && [ "$TARGET_OS" != SunOS ]; then
|
||||
elif [ "$TARGET_OS" != "AIX" ] && [ "$TARGET_OS" != "SunOS" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=native "
|
||||
elif test "$USE_SSE"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -msse4.2 -mpclmul"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#/usr/bin/env bash
|
||||
if [ "$#" = "0" ]; then
|
||||
echo "Usage: $0 major|minor|patch|full"
|
||||
exit 1
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
#include "rocksdb/utilities/write_batch_with_index.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
using rocksdb::BytewiseComparator;
|
||||
@@ -101,6 +102,8 @@ using rocksdb::OptimisticTransactionDB;
|
||||
using rocksdb::OptimisticTransactionOptions;
|
||||
using rocksdb::Transaction;
|
||||
using rocksdb::Checkpoint;
|
||||
using rocksdb::PerfLevel;
|
||||
using rocksdb::PerfContext;
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
@@ -141,6 +144,7 @@ struct rocksdb_envoptions_t { EnvOptions rep; };
|
||||
struct rocksdb_ingestexternalfileoptions_t { IngestExternalFileOptions rep; };
|
||||
struct rocksdb_sstfilewriter_t { SstFileWriter* rep; };
|
||||
struct rocksdb_ratelimiter_t { RateLimiter* rep; };
|
||||
struct rocksdb_perfcontext_t { PerfContext* rep; };
|
||||
struct rocksdb_pinnableslice_t {
|
||||
PinnableSlice rep;
|
||||
};
|
||||
@@ -2552,6 +2556,176 @@ void rocksdb_ratelimiter_destroy(rocksdb_ratelimiter_t *limiter) {
|
||||
delete limiter;
|
||||
}
|
||||
|
||||
void rocksdb_set_perf_level(int v) {
|
||||
PerfLevel level = static_cast<PerfLevel>(v);
|
||||
SetPerfLevel(level);
|
||||
}
|
||||
|
||||
rocksdb_perfcontext_t* rocksdb_perfcontext_create() {
|
||||
rocksdb_perfcontext_t* context = new rocksdb_perfcontext_t;
|
||||
context->rep = rocksdb::get_perf_context();
|
||||
return context;
|
||||
}
|
||||
|
||||
void rocksdb_perfcontext_reset(rocksdb_perfcontext_t* context) {
|
||||
context->rep->Reset();
|
||||
}
|
||||
|
||||
char* rocksdb_perfcontext_report(rocksdb_perfcontext_t* context,
|
||||
unsigned char exclude_zero_counters) {
|
||||
return strdup(context->rep->ToString(exclude_zero_counters).c_str());
|
||||
}
|
||||
|
||||
uint64_t rocksdb_perfcontext_metric(rocksdb_perfcontext_t* context,
|
||||
int metric) {
|
||||
PerfContext* rep = context->rep;
|
||||
switch (metric) {
|
||||
case rocksdb_user_key_comparison_count:
|
||||
return rep->user_key_comparison_count;
|
||||
case rocksdb_block_cache_hit_count:
|
||||
return rep->block_cache_hit_count;
|
||||
case rocksdb_block_read_count:
|
||||
return rep->block_read_count;
|
||||
case rocksdb_block_read_byte:
|
||||
return rep->block_read_byte;
|
||||
case rocksdb_block_read_time:
|
||||
return rep->block_read_time;
|
||||
case rocksdb_block_checksum_time:
|
||||
return rep->block_checksum_time;
|
||||
case rocksdb_block_decompress_time:
|
||||
return rep->block_decompress_time;
|
||||
case rocksdb_get_read_bytes:
|
||||
return rep->get_read_bytes;
|
||||
case rocksdb_multiget_read_bytes:
|
||||
return rep->multiget_read_bytes;
|
||||
case rocksdb_iter_read_bytes:
|
||||
return rep->iter_read_bytes;
|
||||
case rocksdb_internal_key_skipped_count:
|
||||
return rep->internal_key_skipped_count;
|
||||
case rocksdb_internal_delete_skipped_count:
|
||||
return rep->internal_delete_skipped_count;
|
||||
case rocksdb_internal_recent_skipped_count:
|
||||
return rep->internal_recent_skipped_count;
|
||||
case rocksdb_internal_merge_count:
|
||||
return rep->internal_merge_count;
|
||||
case rocksdb_get_snapshot_time:
|
||||
return rep->get_snapshot_time;
|
||||
case rocksdb_get_from_memtable_time:
|
||||
return rep->get_from_memtable_time;
|
||||
case rocksdb_get_from_memtable_count:
|
||||
return rep->get_from_memtable_count;
|
||||
case rocksdb_get_post_process_time:
|
||||
return rep->get_post_process_time;
|
||||
case rocksdb_get_from_output_files_time:
|
||||
return rep->get_from_output_files_time;
|
||||
case rocksdb_seek_on_memtable_time:
|
||||
return rep->seek_on_memtable_time;
|
||||
case rocksdb_seek_on_memtable_count:
|
||||
return rep->seek_on_memtable_count;
|
||||
case rocksdb_next_on_memtable_count:
|
||||
return rep->next_on_memtable_count;
|
||||
case rocksdb_prev_on_memtable_count:
|
||||
return rep->prev_on_memtable_count;
|
||||
case rocksdb_seek_child_seek_time:
|
||||
return rep->seek_child_seek_time;
|
||||
case rocksdb_seek_child_seek_count:
|
||||
return rep->seek_child_seek_count;
|
||||
case rocksdb_seek_min_heap_time:
|
||||
return rep->seek_min_heap_time;
|
||||
case rocksdb_seek_max_heap_time:
|
||||
return rep->seek_max_heap_time;
|
||||
case rocksdb_seek_internal_seek_time:
|
||||
return rep->seek_internal_seek_time;
|
||||
case rocksdb_find_next_user_entry_time:
|
||||
return rep->find_next_user_entry_time;
|
||||
case rocksdb_write_wal_time:
|
||||
return rep->write_wal_time;
|
||||
case rocksdb_write_memtable_time:
|
||||
return rep->write_memtable_time;
|
||||
case rocksdb_write_delay_time:
|
||||
return rep->write_delay_time;
|
||||
case rocksdb_write_pre_and_post_process_time:
|
||||
return rep->write_pre_and_post_process_time;
|
||||
case rocksdb_db_mutex_lock_nanos:
|
||||
return rep->db_mutex_lock_nanos;
|
||||
case rocksdb_db_condition_wait_nanos:
|
||||
return rep->db_condition_wait_nanos;
|
||||
case rocksdb_merge_operator_time_nanos:
|
||||
return rep->merge_operator_time_nanos;
|
||||
case rocksdb_read_index_block_nanos:
|
||||
return rep->read_index_block_nanos;
|
||||
case rocksdb_read_filter_block_nanos:
|
||||
return rep->read_filter_block_nanos;
|
||||
case rocksdb_new_table_block_iter_nanos:
|
||||
return rep->new_table_block_iter_nanos;
|
||||
case rocksdb_new_table_iterator_nanos:
|
||||
return rep->new_table_iterator_nanos;
|
||||
case rocksdb_block_seek_nanos:
|
||||
return rep->block_seek_nanos;
|
||||
case rocksdb_find_table_nanos:
|
||||
return rep->find_table_nanos;
|
||||
case rocksdb_bloom_memtable_hit_count:
|
||||
return rep->bloom_memtable_hit_count;
|
||||
case rocksdb_bloom_memtable_miss_count:
|
||||
return rep->bloom_memtable_miss_count;
|
||||
case rocksdb_bloom_sst_hit_count:
|
||||
return rep->bloom_sst_hit_count;
|
||||
case rocksdb_bloom_sst_miss_count:
|
||||
return rep->bloom_sst_miss_count;
|
||||
case rocksdb_key_lock_wait_time:
|
||||
return rep->key_lock_wait_time;
|
||||
case rocksdb_key_lock_wait_count:
|
||||
return rep->key_lock_wait_count;
|
||||
case rocksdb_env_new_sequential_file_nanos:
|
||||
return rep->env_new_sequential_file_nanos;
|
||||
case rocksdb_env_new_random_access_file_nanos:
|
||||
return rep->env_new_random_access_file_nanos;
|
||||
case rocksdb_env_new_writable_file_nanos:
|
||||
return rep->env_new_writable_file_nanos;
|
||||
case rocksdb_env_reuse_writable_file_nanos:
|
||||
return rep->env_reuse_writable_file_nanos;
|
||||
case rocksdb_env_new_random_rw_file_nanos:
|
||||
return rep->env_new_random_rw_file_nanos;
|
||||
case rocksdb_env_new_directory_nanos:
|
||||
return rep->env_new_directory_nanos;
|
||||
case rocksdb_env_file_exists_nanos:
|
||||
return rep->env_file_exists_nanos;
|
||||
case rocksdb_env_get_children_nanos:
|
||||
return rep->env_get_children_nanos;
|
||||
case rocksdb_env_get_children_file_attributes_nanos:
|
||||
return rep->env_get_children_file_attributes_nanos;
|
||||
case rocksdb_env_delete_file_nanos:
|
||||
return rep->env_delete_file_nanos;
|
||||
case rocksdb_env_create_dir_nanos:
|
||||
return rep->env_create_dir_nanos;
|
||||
case rocksdb_env_create_dir_if_missing_nanos:
|
||||
return rep->env_create_dir_if_missing_nanos;
|
||||
case rocksdb_env_delete_dir_nanos:
|
||||
return rep->env_delete_dir_nanos;
|
||||
case rocksdb_env_get_file_size_nanos:
|
||||
return rep->env_get_file_size_nanos;
|
||||
case rocksdb_env_get_file_modification_time_nanos:
|
||||
return rep->env_get_file_modification_time_nanos;
|
||||
case rocksdb_env_rename_file_nanos:
|
||||
return rep->env_rename_file_nanos;
|
||||
case rocksdb_env_link_file_nanos:
|
||||
return rep->env_link_file_nanos;
|
||||
case rocksdb_env_lock_file_nanos:
|
||||
return rep->env_lock_file_nanos;
|
||||
case rocksdb_env_unlock_file_nanos:
|
||||
return rep->env_unlock_file_nanos;
|
||||
case rocksdb_env_new_logger_nanos:
|
||||
return rep->env_new_logger_nanos;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rocksdb_perfcontext_destroy(rocksdb_perfcontext_t* context) {
|
||||
delete context;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO:
|
||||
DB::OpenForReadOnly
|
||||
|
||||
+4
-1
@@ -54,6 +54,9 @@ ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
|
||||
#endif // ROCKSDB_LITE
|
||||
// Job id == 0 means that this is not our background process, but rather
|
||||
// user thread
|
||||
// Need to hold some shared pointers owned by the initial_cf_options
|
||||
// before final cleaning up finishes.
|
||||
ColumnFamilyOptions initial_cf_options_copy = cfd_->initial_cf_options();
|
||||
JobContext job_context(0);
|
||||
mutex_->Lock();
|
||||
if (cfd_->Unref()) {
|
||||
@@ -383,7 +386,7 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
next_(nullptr),
|
||||
prev_(nullptr),
|
||||
log_number_(0),
|
||||
flush_reason_(FlushReason::kUnknown),
|
||||
flush_reason_(FlushReason::kOthers),
|
||||
column_family_set_(column_family_set),
|
||||
pending_flush_(false),
|
||||
pending_compaction_(false),
|
||||
|
||||
@@ -370,6 +370,10 @@ class ColumnFamilyData {
|
||||
|
||||
bool initialized() const { return initialized_.load(); }
|
||||
|
||||
const ColumnFamilyOptions& initial_cf_options() {
|
||||
return initial_cf_options_;
|
||||
}
|
||||
|
||||
Env::WriteLifeTimeHint CalculateSSTWriteHint(int level);
|
||||
|
||||
private:
|
||||
|
||||
@@ -383,9 +383,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
void AssertFilesPerLevel(const std::string& value, int cf) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ(value, FilesPerLevel(cf));
|
||||
#else
|
||||
(void) value;
|
||||
(void) cf;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -400,8 +397,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
void AssertCountLiveFiles(int expected_value) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ(expected_value, CountLiveFiles());
|
||||
#else
|
||||
(void) expected_value;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -450,8 +445,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
void AssertCountLiveLogFiles(int value) {
|
||||
#ifndef ROCKSDB_LITE // GetSortedWalFiles is not supported
|
||||
ASSERT_EQ(value, CountLiveLogFiles());
|
||||
#else
|
||||
(void) value;
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
@@ -2810,27 +2803,6 @@ TEST_F(ColumnFamilyTest, CreateAndDestoryOptions) {
|
||||
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
|
||||
}
|
||||
|
||||
TEST_F(ColumnFamilyTest, CreateDropAndDestroy) {
|
||||
ColumnFamilyHandle* cfh;
|
||||
Open();
|
||||
ASSERT_OK(db_->CreateColumnFamily(ColumnFamilyOptions(), "yoyo", &cfh));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), cfh, "foo", "bar"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions(), cfh));
|
||||
ASSERT_OK(db_->DropColumnFamily(cfh));
|
||||
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
|
||||
}
|
||||
|
||||
TEST_F(ColumnFamilyTest, CreateDropAndDestroyWithoutFileDeletion) {
|
||||
ColumnFamilyHandle* cfh;
|
||||
Open();
|
||||
ASSERT_OK(db_->CreateColumnFamily(ColumnFamilyOptions(), "yoyo", &cfh));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), cfh, "foo", "bar"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions(), cfh));
|
||||
ASSERT_OK(db_->DisableFileDeletions());
|
||||
ASSERT_OK(db_->DropColumnFamily(cfh));
|
||||
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(ColumnFamilyTest, FlushCloseWALFiles) {
|
||||
SpecialEnv env(Env::Default());
|
||||
|
||||
@@ -318,7 +318,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as DBImpl::CompactFiles is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
@@ -1034,7 +1034,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED, not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1043,5 +1043,5 @@ int main(int /*argc*/, char** /*argv*/) {
|
||||
|
||||
#else
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) { return 0; }
|
||||
int main(int argc, char** argv) { return 0; }
|
||||
#endif // !defined(IOS_CROSS_COMPILE)
|
||||
@@ -946,7 +946,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as CompactionJobStats is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
@@ -510,7 +510,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as RepairDB() is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as Cuckoo table is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3482,8 +3482,6 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -501,8 +501,6 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -74,7 +74,7 @@ Status DBImpl::EnableFileDeletions(bool force) {
|
||||
}
|
||||
|
||||
int DBImpl::IsFileDeletionsEnabled() const {
|
||||
return disable_delete_obsolete_files_;
|
||||
return !disable_delete_obsolete_files_;
|
||||
}
|
||||
|
||||
Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
|
||||
|
||||
+8
-8
@@ -2145,9 +2145,9 @@ Status DBImpl::DeleteFile(std::string name) {
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
&edit, &mutex_, directories_.GetDbDir());
|
||||
if (status.ok()) {
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
cfd, &job_context.superversion_context,
|
||||
*cfd->GetLatestMutableCFOptions());
|
||||
InstallSuperVersionAndScheduleWork(cfd, &job_context.superversion_context,
|
||||
*cfd->GetLatestMutableCFOptions(),
|
||||
FlushReason::kDeleteFiles);
|
||||
}
|
||||
FindObsoleteFiles(&job_context, false);
|
||||
} // lock released here
|
||||
@@ -2229,9 +2229,9 @@ Status DBImpl::DeleteFilesInRanges(ColumnFamilyHandle* column_family,
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
&edit, &mutex_, directories_.GetDbDir());
|
||||
if (status.ok()) {
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
cfd, &job_context.superversion_context,
|
||||
*cfd->GetLatestMutableCFOptions());
|
||||
InstallSuperVersionAndScheduleWork(cfd, &job_context.superversion_context,
|
||||
*cfd->GetLatestMutableCFOptions(),
|
||||
FlushReason::kDeleteFiles);
|
||||
}
|
||||
for (auto* deleted_file : deleted_files) {
|
||||
deleted_file->being_compacted = false;
|
||||
@@ -2859,8 +2859,8 @@ Status DBImpl::IngestExternalFile(
|
||||
&mutex_, directories_.GetDbDir());
|
||||
}
|
||||
if (status.ok()) {
|
||||
InstallSuperVersionAndScheduleWork(cfd, &sv_context,
|
||||
*mutable_cf_options);
|
||||
InstallSuperVersionAndScheduleWork(cfd, &sv_context, *mutable_cf_options,
|
||||
FlushReason::kExternalFileIngestion);
|
||||
}
|
||||
|
||||
// Resume writes to the DB
|
||||
|
||||
+7
-3
@@ -223,6 +223,8 @@ class DBImpl : public DB {
|
||||
virtual Status SyncWAL() override;
|
||||
|
||||
virtual SequenceNumber GetLatestSequenceNumber() const override;
|
||||
// REQUIRES: joined the main write queue if two_write_queues is disabled, and
|
||||
// the second write queue otherwise.
|
||||
virtual void SetLastPublishedSequence(SequenceNumber seq);
|
||||
// Returns LastSequence in last_seq_same_as_publish_seq_
|
||||
// mode and LastAllocatedSequence otherwise. This is useful when visiblility
|
||||
@@ -833,7 +835,8 @@ class DBImpl : public DB {
|
||||
|
||||
Status ScheduleFlushes(WriteContext* context);
|
||||
|
||||
Status SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context);
|
||||
Status SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
|
||||
FlushReason flush_reason = FlushReason::kOthers);
|
||||
|
||||
// Force current memtable contents to be flushed.
|
||||
Status FlushMemTable(ColumnFamilyData* cfd, const FlushOptions& options,
|
||||
@@ -873,7 +876,7 @@ class DBImpl : public DB {
|
||||
size_t seq_inc);
|
||||
|
||||
// Used by WriteImpl to update bg_error_ if paranoid check is enabled.
|
||||
void WriteCallbackStatusCheck(const Status& status);
|
||||
void WriteStatusCheck(const Status& status);
|
||||
|
||||
// Used by WriteImpl to update bg_error_ in case of memtable insert error.
|
||||
void MemTableInsertStatusCheck(const Status& memtable_insert_status);
|
||||
@@ -1359,7 +1362,8 @@ class DBImpl : public DB {
|
||||
// state needs flush or compaction.
|
||||
void InstallSuperVersionAndScheduleWork(
|
||||
ColumnFamilyData* cfd, SuperVersionContext* sv_context,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
FlushReason flush_reason = FlushReason::kOthers);
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
using DB::GetPropertiesOfAllTables;
|
||||
|
||||
@@ -655,7 +655,7 @@ Status DBImpl::CompactFilesImpl(
|
||||
if (status.ok()) {
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
c->column_family_data(), &job_context->superversion_context,
|
||||
*c->mutable_cf_options());
|
||||
*c->mutable_cf_options(), FlushReason::kManualCompaction);
|
||||
}
|
||||
c->ReleaseCompactionFiles(s);
|
||||
|
||||
@@ -891,7 +891,7 @@ Status DBImpl::Flush(const FlushOptions& flush_options,
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log, "[%s] Manual flush start.",
|
||||
cfh->GetName().c_str());
|
||||
Status s =
|
||||
FlushMemTable(cfh->cfd(), flush_options, FlushReason::kManualCompaction);
|
||||
FlushMemTable(cfh->cfd(), flush_options, FlushReason::kManualFlush);
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log,
|
||||
"[%s] Manual flush finished, status: %s\n",
|
||||
cfh->GetName().c_str(), s.ToString().c_str());
|
||||
@@ -1727,7 +1727,7 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
&mutex_, directories_.GetDbDir());
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
c->column_family_data(), &job_context->superversion_context,
|
||||
*c->mutable_cf_options());
|
||||
*c->mutable_cf_options(), FlushReason::kAutoCompaction);
|
||||
ROCKS_LOG_BUFFER(log_buffer, "[%s] Deleted %d files\n",
|
||||
c->column_family_data()->GetName().c_str(),
|
||||
c->num_input_files(0));
|
||||
@@ -1774,7 +1774,7 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
// Use latest MutableCFOptions
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
c->column_family_data(), &job_context->superversion_context,
|
||||
*c->mutable_cf_options());
|
||||
*c->mutable_cf_options(), FlushReason::kAutoCompaction);
|
||||
|
||||
VersionStorageInfo::LevelSummaryStorage tmp;
|
||||
c->column_family_data()->internal_stats()->IncBytesMoved(c->output_level(),
|
||||
@@ -1853,7 +1853,7 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
if (status.ok()) {
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
c->column_family_data(), &job_context->superversion_context,
|
||||
*c->mutable_cf_options());
|
||||
*c->mutable_cf_options(), FlushReason::kAutoCompaction);
|
||||
}
|
||||
*made_progress = true;
|
||||
}
|
||||
@@ -2044,7 +2044,7 @@ bool DBImpl::MCOverlap(ManualCompactionState* m, ManualCompactionState* m1) {
|
||||
|
||||
void DBImpl::InstallSuperVersionAndScheduleWork(
|
||||
ColumnFamilyData* cfd, SuperVersionContext* sv_context,
|
||||
const MutableCFOptions& mutable_cf_options) {
|
||||
const MutableCFOptions& mutable_cf_options, FlushReason flush_reason) {
|
||||
mutex_.AssertHeld();
|
||||
|
||||
// Update max_total_in_memory_state_
|
||||
@@ -2063,7 +2063,7 @@ void DBImpl::InstallSuperVersionAndScheduleWork(
|
||||
|
||||
// Whenever we install new SuperVersion, we might need to issue new flushes or
|
||||
// compactions.
|
||||
SchedulePendingFlush(cfd, FlushReason::kSuperVersionChange);
|
||||
SchedulePendingFlush(cfd, flush_reason);
|
||||
SchedulePendingCompaction(cfd);
|
||||
MaybeScheduleFlushOrCompaction();
|
||||
|
||||
|
||||
+17
-11
@@ -133,7 +133,8 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
for (auto* writer : *(w.write_group)) {
|
||||
if (!writer->CallbackFailed() && writer->pre_release_callback) {
|
||||
assert(writer->sequence != kMaxSequenceNumber);
|
||||
Status ws = writer->pre_release_callback->Callback(writer->sequence);
|
||||
Status ws = writer->pre_release_callback->Callback(writer->sequence,
|
||||
disable_memtable);
|
||||
if (!ws.ok()) {
|
||||
status = ws;
|
||||
break;
|
||||
@@ -339,7 +340,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
PERF_TIMER_START(write_pre_and_post_process_time);
|
||||
|
||||
if (!w.CallbackFailed()) {
|
||||
WriteCallbackStatusCheck(status);
|
||||
WriteStatusCheck(status);
|
||||
}
|
||||
|
||||
if (need_log_sync) {
|
||||
@@ -368,7 +369,8 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
for (auto* writer : write_group) {
|
||||
if (!writer->CallbackFailed() && writer->pre_release_callback) {
|
||||
assert(writer->sequence != kMaxSequenceNumber);
|
||||
Status ws = writer->pre_release_callback->Callback(writer->sequence);
|
||||
Status ws = writer->pre_release_callback->Callback(writer->sequence,
|
||||
disable_memtable);
|
||||
if (!ws.ok()) {
|
||||
status = ws;
|
||||
break;
|
||||
@@ -462,7 +464,7 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
|
||||
}
|
||||
|
||||
if (!w.CallbackFailed()) {
|
||||
WriteCallbackStatusCheck(w.status);
|
||||
WriteStatusCheck(w.status);
|
||||
}
|
||||
|
||||
if (need_log_sync) {
|
||||
@@ -623,13 +625,15 @@ Status DBImpl::WriteImplWALOnly(const WriteOptions& write_options,
|
||||
PERF_TIMER_START(write_pre_and_post_process_time);
|
||||
|
||||
if (!w.CallbackFailed()) {
|
||||
WriteCallbackStatusCheck(status);
|
||||
WriteStatusCheck(status);
|
||||
}
|
||||
if (status.ok()) {
|
||||
for (auto* writer : write_group) {
|
||||
if (!writer->CallbackFailed() && writer->pre_release_callback) {
|
||||
assert(writer->sequence != kMaxSequenceNumber);
|
||||
Status ws = writer->pre_release_callback->Callback(writer->sequence);
|
||||
const bool DISABLE_MEMTABLE = true;
|
||||
Status ws = writer->pre_release_callback->Callback(writer->sequence,
|
||||
DISABLE_MEMTABLE);
|
||||
if (!ws.ok()) {
|
||||
status = ws;
|
||||
break;
|
||||
@@ -647,7 +651,7 @@ Status DBImpl::WriteImplWALOnly(const WriteOptions& write_options,
|
||||
return status;
|
||||
}
|
||||
|
||||
void DBImpl::WriteCallbackStatusCheck(const Status& status) {
|
||||
void DBImpl::WriteStatusCheck(const Status& status) {
|
||||
// Is setting bg_error_ enough here? This will at least stop
|
||||
// compaction and fail any further writes.
|
||||
if (immutable_db_options_.paranoid_checks && !status.ok() &&
|
||||
@@ -1062,7 +1066,8 @@ Status DBImpl::HandleWriteBufferFull(WriteContext* write_context) {
|
||||
}
|
||||
}
|
||||
if (cfd_picked != nullptr) {
|
||||
status = SwitchMemtable(cfd_picked, write_context);
|
||||
status = SwitchMemtable(cfd_picked, write_context,
|
||||
FlushReason::kWriteBufferFull);
|
||||
if (status.ok()) {
|
||||
cfd_picked->imm()->FlushRequested();
|
||||
SchedulePendingFlush(cfd_picked, FlushReason::kWriteBufferFull);
|
||||
@@ -1163,7 +1168,7 @@ Status DBImpl::ThrottleLowPriWritesIfNeeded(const WriteOptions& write_options,
|
||||
Status DBImpl::ScheduleFlushes(WriteContext* context) {
|
||||
ColumnFamilyData* cfd;
|
||||
while ((cfd = flush_scheduler_.TakeNextColumnFamily()) != nullptr) {
|
||||
auto status = SwitchMemtable(cfd, context);
|
||||
auto status = SwitchMemtable(cfd, context, FlushReason::kWriteBufferFull);
|
||||
if (cfd->Unref()) {
|
||||
delete cfd;
|
||||
}
|
||||
@@ -1192,7 +1197,8 @@ void DBImpl::NotifyOnMemTableSealed(ColumnFamilyData* /*cfd*/,
|
||||
|
||||
// REQUIRES: mutex_ is held
|
||||
// REQUIRES: this thread is currently at the front of the writer queue
|
||||
Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
|
||||
FlushReason flush_reason) {
|
||||
mutex_.AssertHeld();
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (two_write_queues_) {
|
||||
@@ -1360,7 +1366,7 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
new_mem->Ref();
|
||||
cfd->SetMemtable(new_mem);
|
||||
InstallSuperVersionAndScheduleWork(cfd, &context->superversion_context,
|
||||
mutable_cf_options);
|
||||
mutable_cf_options, flush_reason);
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
|
||||
@@ -289,8 +289,6 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -69,27 +69,27 @@ TEST_F(DBPropertiesTest, Empty) {
|
||||
ASSERT_OK(db_->DisableFileDeletions());
|
||||
ASSERT_TRUE(
|
||||
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
|
||||
ASSERT_EQ("1", num);
|
||||
ASSERT_EQ("0", num);
|
||||
|
||||
ASSERT_OK(db_->DisableFileDeletions());
|
||||
ASSERT_TRUE(
|
||||
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
|
||||
ASSERT_EQ("2", num);
|
||||
ASSERT_EQ("0", num);
|
||||
|
||||
ASSERT_OK(db_->DisableFileDeletions());
|
||||
ASSERT_TRUE(
|
||||
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
|
||||
ASSERT_EQ("3", num);
|
||||
ASSERT_EQ("0", num);
|
||||
|
||||
ASSERT_OK(db_->EnableFileDeletions(false));
|
||||
ASSERT_TRUE(
|
||||
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
|
||||
ASSERT_EQ("2", num);
|
||||
ASSERT_EQ("0", num);
|
||||
|
||||
ASSERT_OK(db_->EnableFileDeletions());
|
||||
ASSERT_TRUE(
|
||||
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
|
||||
ASSERT_EQ("0", num);
|
||||
ASSERT_EQ("1", num);
|
||||
} while (ChangeOptions());
|
||||
}
|
||||
|
||||
|
||||
@@ -809,8 +809,6 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -1759,8 +1759,6 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -80,6 +80,22 @@ TEST_P(DBWriteTest, IOErrorOnWALWritePropagateToWriteThreadFollower) {
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_P(DBWriteTest, IOErrorOnWALWriteTriggersReadOnlyMode) {
|
||||
std::unique_ptr<FaultInjectionTestEnv> mock_env(
|
||||
new FaultInjectionTestEnv(Env::Default()));
|
||||
Options options = GetOptions();
|
||||
options.env = mock_env.get();
|
||||
Reopen(options);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Forcibly fail WAL write for the first Put only. Subsequent Puts should
|
||||
// fail due to read-only mode
|
||||
mock_env->SetFilesystemActive(i != 0);
|
||||
ASSERT_FALSE(Put("key" + ToString(i), "value").ok());
|
||||
}
|
||||
// Close before mock_env destruct.
|
||||
Close();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBWriteTestInstance, DBWriteTest,
|
||||
testing::Values(DBTestBase::kDefault,
|
||||
DBTestBase::kConcurrentWALWrites,
|
||||
|
||||
@@ -106,45 +106,6 @@ const char* InternalKeyComparator::Name() const {
|
||||
return name_.c_str();
|
||||
}
|
||||
|
||||
int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
|
||||
// Order by:
|
||||
// increasing user key (according to user-supplied comparator)
|
||||
// decreasing sequence number
|
||||
// decreasing type (though sequence# should be enough to disambiguate)
|
||||
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
||||
PERF_COUNTER_ADD(user_key_comparison_count, 1);
|
||||
if (r == 0) {
|
||||
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
|
||||
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
|
||||
if (anum > bnum) {
|
||||
r = -1;
|
||||
} else if (anum < bnum) {
|
||||
r = +1;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int InternalKeyComparator::CompareKeySeq(const Slice& akey,
|
||||
const Slice& bkey) const {
|
||||
// Order by:
|
||||
// increasing user key (according to user-supplied comparator)
|
||||
// decreasing sequence number
|
||||
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
||||
PERF_COUNTER_ADD(user_key_comparison_count, 1);
|
||||
if (r == 0) {
|
||||
// Shift the number to exclude the last byte which contains the value type
|
||||
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8) >> 8;
|
||||
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8) >> 8;
|
||||
if (anum > bnum) {
|
||||
r = -1;
|
||||
} else if (anum < bnum) {
|
||||
r = +1;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int InternalKeyComparator::Compare(const ParsedInternalKey& a,
|
||||
const ParsedInternalKey& b) const {
|
||||
// Order by:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "monitoring/perf_context_imp.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/filter_policy.h"
|
||||
@@ -607,4 +608,46 @@ struct RangeTombstone {
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
|
||||
// Order by:
|
||||
// increasing user key (according to user-supplied comparator)
|
||||
// decreasing sequence number
|
||||
// decreasing type (though sequence# should be enough to disambiguate)
|
||||
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
||||
PERF_COUNTER_ADD(user_key_comparison_count, 1);
|
||||
if (r == 0) {
|
||||
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
|
||||
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
|
||||
if (anum > bnum) {
|
||||
r = -1;
|
||||
} else if (anum < bnum) {
|
||||
r = +1;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
int InternalKeyComparator::CompareKeySeq(const Slice& akey,
|
||||
const Slice& bkey) const {
|
||||
// Order by:
|
||||
// increasing user key (according to user-supplied comparator)
|
||||
// decreasing sequence number
|
||||
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
||||
PERF_COUNTER_ADD(user_key_comparison_count, 1);
|
||||
if (r == 0) {
|
||||
// Shift the number to exclude the last byte which contains the value type
|
||||
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8) >> 8;
|
||||
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8) >> 8;
|
||||
if (anum > bnum) {
|
||||
r = -1;
|
||||
} else if (anum < bnum) {
|
||||
r = +1;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
} // namespace rocksdb
|
||||
@@ -500,7 +500,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as DBImpl::DeleteFile is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
@@ -2002,7 +2002,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as External SST File Writer and Ingestion are not supported "
|
||||
"in ROCKSDB_LITE\n");
|
||||
|
||||
+8
-4
@@ -56,8 +56,8 @@ namespace rocksdb {
|
||||
|
||||
const char* GetFlushReasonString (FlushReason flush_reason) {
|
||||
switch (flush_reason) {
|
||||
case FlushReason::kUnknown:
|
||||
return "Unknown";
|
||||
case FlushReason::kOthers:
|
||||
return "Other Reasons";
|
||||
case FlushReason::kGetLiveFiles:
|
||||
return "Get Live Files";
|
||||
case FlushReason::kShutDown:
|
||||
@@ -72,8 +72,12 @@ const char* GetFlushReasonString (FlushReason flush_reason) {
|
||||
return "Write Buffer Full";
|
||||
case FlushReason::kTest:
|
||||
return "Test";
|
||||
case FlushReason::kSuperVersionChange:
|
||||
return "SuperVersion Change";
|
||||
case FlushReason::kDeleteFiles:
|
||||
return "Delete Files";
|
||||
case FlushReason::kAutoCompaction:
|
||||
return "Auto Compaction";
|
||||
case FlushReason::kManualFlush:
|
||||
return "Manual Flush";
|
||||
default:
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ int MemTable::KeyComparator::operator()(const char* prefix_len_key1,
|
||||
}
|
||||
|
||||
int MemTable::KeyComparator::operator()(const char* prefix_len_key,
|
||||
const Slice& key)
|
||||
const KeyComparator::DecodedType& key)
|
||||
const {
|
||||
// Internal keys are encoded as length-prefixed strings.
|
||||
Slice a = GetLengthPrefixedSlice(prefix_len_key);
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ struct MemTablePostProcessInfo {
|
||||
};
|
||||
|
||||
// Note: Many of the methods in this class have comments indicating that
|
||||
// external synchromization is required as these methods are not thread-safe.
|
||||
// external synchronization is required as these methods are not thread-safe.
|
||||
// It is up to higher layers of code to decide how to prevent concurrent
|
||||
// invokation of these methods. This is usually done by acquiring either
|
||||
// the db mutex or the single writer thread.
|
||||
@@ -84,7 +84,7 @@ class MemTable {
|
||||
virtual int operator()(const char* prefix_len_key1,
|
||||
const char* prefix_len_key2) const override;
|
||||
virtual int operator()(const char* prefix_len_key,
|
||||
const Slice& key) const override;
|
||||
const DecodedType& key) const override;
|
||||
};
|
||||
|
||||
// MemTables are reference counted. The initial reference count
|
||||
|
||||
@@ -112,7 +112,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
printf("Skipped as Options file is not supported in RocksDBLite.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1170,7 +1170,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as plain table is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ class PreReleaseCallback {
|
||||
// propagated to all the writers in the write group.
|
||||
// seq is the sequence number that is used for this write and will be
|
||||
// released.
|
||||
virtual Status Callback(SequenceNumber seq) = 0;
|
||||
// is_mem_disabled is currently used for debugging purposes to assert that
|
||||
// the callback is done from the right write queue.
|
||||
virtual Status Callback(SequenceNumber seq, const bool is_mem_disabled) = 0;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
+1
-1
@@ -887,7 +887,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as HashSkipList and HashLinkList are not supported in "
|
||||
"ROCKSDB_LITE\n");
|
||||
|
||||
@@ -536,4 +536,11 @@ bool RangeDelAggregator::IsEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RangeDelAggregator::AddFile(uint64_t file_number) {
|
||||
if (added_files_ == nullptr) {
|
||||
added_files_.reset(new std::set<uint64_t>());
|
||||
}
|
||||
return added_files_->emplace(file_number).second;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
@@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -140,6 +141,7 @@ class RangeDelAggregator {
|
||||
CompactionIterationStats* range_del_out_stats = nullptr,
|
||||
bool bottommost_level = false);
|
||||
bool IsEmpty();
|
||||
bool AddFile(uint64_t file_number);
|
||||
|
||||
private:
|
||||
// Maps tombstone user start key -> tombstone object
|
||||
@@ -180,6 +182,10 @@ class RangeDelAggregator {
|
||||
const InternalKeyComparator& icmp_;
|
||||
// collapse range deletions so they're binary searchable
|
||||
const bool collapse_deletions_;
|
||||
|
||||
// Record files whose tombstones have been added, to avoid duplicate adding.
|
||||
// Same as rep_, we initializes it lazily.
|
||||
std::unique_ptr<std::set<uint64_t>> added_files_;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
+1
-1
@@ -356,7 +356,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as RepairDB is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
+9
-7
@@ -247,13 +247,15 @@ InternalIterator* TableCache::NewIterator(
|
||||
}
|
||||
}
|
||||
if (s.ok() && range_del_agg != nullptr && !options.ignore_range_deletions) {
|
||||
std::unique_ptr<InternalIterator> range_del_iter(
|
||||
table_reader->NewRangeTombstoneIterator(options));
|
||||
if (range_del_iter != nullptr) {
|
||||
s = range_del_iter->status();
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = range_del_agg->AddTombstones(std::move(range_del_iter));
|
||||
if (range_del_agg->AddFile(fd.GetNumber())) {
|
||||
std::unique_ptr<InternalIterator> range_del_iter(
|
||||
table_reader->NewRangeTombstoneIterator(options));
|
||||
if (range_del_iter != nullptr) {
|
||||
s = range_del_iter->status();
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = range_del_agg->AddTombstones(std::move(range_del_iter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as WalManager is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,8 @@ TEST_F(WriteCallbackTest, WriteWithCallbackTest) {
|
||||
public:
|
||||
PublishSeqCallback(DBImpl* db_impl_in)
|
||||
: db_impl_(db_impl_in) {}
|
||||
virtual Status Callback(SequenceNumber last_seq) {
|
||||
virtual Status Callback(SequenceNumber last_seq,
|
||||
const bool /*not used*/) override {
|
||||
db_impl_->SetLastPublishedSequence(last_seq);
|
||||
return Status::OK();
|
||||
}
|
||||
@@ -431,7 +432,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as WriteWithCallback is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
Vendored
-9
@@ -802,15 +802,6 @@ class PosixEnv : public Env {
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void LowerThreadPoolCPUPriority(Priority pool = LOW) override {
|
||||
assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH);
|
||||
#ifdef OS_LINUX
|
||||
thread_pools_[pool].LowerCPUPriority();
|
||||
#else
|
||||
(void)pool;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual std::string TimeToString(uint64_t secondsSince1970) override {
|
||||
const time_t seconds = (time_t)secondsSince1970;
|
||||
struct tm t;
|
||||
|
||||
Vendored
+2
-6
@@ -873,12 +873,8 @@ void PosixWritableFile::SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) {
|
||||
if (fcntl(fd_, F_SET_RW_HINT, &hint) == 0) {
|
||||
write_hint_ = hint;
|
||||
}
|
||||
#else
|
||||
(void)hint;
|
||||
#endif // ROCKSDB_VALGRIND_RUN
|
||||
#else
|
||||
(void)hint;
|
||||
#endif // OS_LINUX
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
Status PosixWritableFile::InvalidateCache(size_t offset, size_t length) {
|
||||
|
||||
@@ -87,14 +87,6 @@ struct CompactionOptionsFIFO {
|
||||
|
||||
// Compression options for different compression algorithms like Zlib
|
||||
struct CompressionOptions {
|
||||
// RocksDB's generic default compression level. Internally it'll be translated
|
||||
// to the default compression level specific to the library being used (see
|
||||
// comment above `ColumnFamilyOptions::compression`).
|
||||
//
|
||||
// The default value is the max 16-bit int as it'll be written out in OPTIONS
|
||||
// file, which should be portable.
|
||||
const static int kDefaultCompressionLevel = 32767;
|
||||
|
||||
int window_bits;
|
||||
int level;
|
||||
int strategy;
|
||||
@@ -128,7 +120,7 @@ struct CompressionOptions {
|
||||
|
||||
CompressionOptions()
|
||||
: window_bits(-14),
|
||||
level(kDefaultCompressionLevel),
|
||||
level(-1),
|
||||
strategy(0),
|
||||
max_dict_bytes(0),
|
||||
zstd_max_train_bytes(0) {}
|
||||
|
||||
@@ -113,6 +113,7 @@ typedef struct rocksdb_envoptions_t rocksdb_envoptions_t;
|
||||
typedef struct rocksdb_ingestexternalfileoptions_t rocksdb_ingestexternalfileoptions_t;
|
||||
typedef struct rocksdb_sstfilewriter_t rocksdb_sstfilewriter_t;
|
||||
typedef struct rocksdb_ratelimiter_t rocksdb_ratelimiter_t;
|
||||
typedef struct rocksdb_perfcontext_t rocksdb_perfcontext_t;
|
||||
typedef struct rocksdb_pinnableslice_t rocksdb_pinnableslice_t;
|
||||
typedef struct rocksdb_transactiondb_options_t rocksdb_transactiondb_options_t;
|
||||
typedef struct rocksdb_transactiondb_t rocksdb_transactiondb_t;
|
||||
@@ -969,6 +970,97 @@ extern ROCKSDB_LIBRARY_API rocksdb_ratelimiter_t* rocksdb_ratelimiter_create(
|
||||
int64_t rate_bytes_per_sec, int64_t refill_period_us, int32_t fairness);
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_ratelimiter_destroy(rocksdb_ratelimiter_t*);
|
||||
|
||||
/* PerfContext */
|
||||
enum {
|
||||
rocksdb_uninitialized = 0,
|
||||
rocksdb_disable = 1,
|
||||
rocksdb_enable_count = 2,
|
||||
rocksdb_enable_time_except_for_mutex = 3,
|
||||
rocksdb_enable_time = 4,
|
||||
rocksdb_out_of_bounds = 5
|
||||
};
|
||||
|
||||
enum {
|
||||
rocksdb_user_key_comparison_count = 0,
|
||||
rocksdb_block_cache_hit_count,
|
||||
rocksdb_block_read_count,
|
||||
rocksdb_block_read_byte,
|
||||
rocksdb_block_read_time,
|
||||
rocksdb_block_checksum_time,
|
||||
rocksdb_block_decompress_time,
|
||||
rocksdb_get_read_bytes,
|
||||
rocksdb_multiget_read_bytes,
|
||||
rocksdb_iter_read_bytes,
|
||||
rocksdb_internal_key_skipped_count,
|
||||
rocksdb_internal_delete_skipped_count,
|
||||
rocksdb_internal_recent_skipped_count,
|
||||
rocksdb_internal_merge_count,
|
||||
rocksdb_get_snapshot_time,
|
||||
rocksdb_get_from_memtable_time,
|
||||
rocksdb_get_from_memtable_count,
|
||||
rocksdb_get_post_process_time,
|
||||
rocksdb_get_from_output_files_time,
|
||||
rocksdb_seek_on_memtable_time,
|
||||
rocksdb_seek_on_memtable_count,
|
||||
rocksdb_next_on_memtable_count,
|
||||
rocksdb_prev_on_memtable_count,
|
||||
rocksdb_seek_child_seek_time,
|
||||
rocksdb_seek_child_seek_count,
|
||||
rocksdb_seek_min_heap_time,
|
||||
rocksdb_seek_max_heap_time,
|
||||
rocksdb_seek_internal_seek_time,
|
||||
rocksdb_find_next_user_entry_time,
|
||||
rocksdb_write_wal_time,
|
||||
rocksdb_write_memtable_time,
|
||||
rocksdb_write_delay_time,
|
||||
rocksdb_write_pre_and_post_process_time,
|
||||
rocksdb_db_mutex_lock_nanos,
|
||||
rocksdb_db_condition_wait_nanos,
|
||||
rocksdb_merge_operator_time_nanos,
|
||||
rocksdb_read_index_block_nanos,
|
||||
rocksdb_read_filter_block_nanos,
|
||||
rocksdb_new_table_block_iter_nanos,
|
||||
rocksdb_new_table_iterator_nanos,
|
||||
rocksdb_block_seek_nanos,
|
||||
rocksdb_find_table_nanos,
|
||||
rocksdb_bloom_memtable_hit_count,
|
||||
rocksdb_bloom_memtable_miss_count,
|
||||
rocksdb_bloom_sst_hit_count,
|
||||
rocksdb_bloom_sst_miss_count,
|
||||
rocksdb_key_lock_wait_time,
|
||||
rocksdb_key_lock_wait_count,
|
||||
rocksdb_env_new_sequential_file_nanos,
|
||||
rocksdb_env_new_random_access_file_nanos,
|
||||
rocksdb_env_new_writable_file_nanos,
|
||||
rocksdb_env_reuse_writable_file_nanos,
|
||||
rocksdb_env_new_random_rw_file_nanos,
|
||||
rocksdb_env_new_directory_nanos,
|
||||
rocksdb_env_file_exists_nanos,
|
||||
rocksdb_env_get_children_nanos,
|
||||
rocksdb_env_get_children_file_attributes_nanos,
|
||||
rocksdb_env_delete_file_nanos,
|
||||
rocksdb_env_create_dir_nanos,
|
||||
rocksdb_env_create_dir_if_missing_nanos,
|
||||
rocksdb_env_delete_dir_nanos,
|
||||
rocksdb_env_get_file_size_nanos,
|
||||
rocksdb_env_get_file_modification_time_nanos,
|
||||
rocksdb_env_rename_file_nanos,
|
||||
rocksdb_env_link_file_nanos,
|
||||
rocksdb_env_lock_file_nanos,
|
||||
rocksdb_env_unlock_file_nanos,
|
||||
rocksdb_env_new_logger_nanos,
|
||||
rocksdb_total_metric_count = 68
|
||||
};
|
||||
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_set_perf_level(int);
|
||||
extern ROCKSDB_LIBRARY_API rocksdb_perfcontext_t* rocksdb_perfcontext_create();
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_perfcontext_reset(
|
||||
rocksdb_perfcontext_t* context);
|
||||
extern ROCKSDB_LIBRARY_API char* rocksdb_perfcontext_report(
|
||||
rocksdb_perfcontext_t* context, unsigned char exclude_zero_counters);
|
||||
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_perfcontext_metric(
|
||||
rocksdb_perfcontext_t* context, int metric);
|
||||
|
||||
/* Compaction Filter */
|
||||
|
||||
extern ROCKSDB_LIBRARY_API rocksdb_compactionfilter_t*
|
||||
|
||||
@@ -391,9 +391,6 @@ class Env {
|
||||
// Lower IO priority for threads from the specified pool.
|
||||
virtual void LowerThreadPoolIOPriority(Priority /*pool*/ = LOW) {}
|
||||
|
||||
// Lower CPU priority for threads from the specified pool.
|
||||
virtual void LowerThreadPoolCPUPriority(Priority /*pool*/ = LOW) {}
|
||||
|
||||
// Converts seconds-since-Jan-01-1970 to a printable string
|
||||
virtual std::string TimeToString(uint64_t time) = 0;
|
||||
|
||||
@@ -1085,10 +1082,6 @@ class EnvWrapper : public Env {
|
||||
target_->LowerThreadPoolIOPriority(pool);
|
||||
}
|
||||
|
||||
void LowerThreadPoolCPUPriority(Priority pool = LOW) override {
|
||||
target_->LowerThreadPoolCPUPriority(pool);
|
||||
}
|
||||
|
||||
std::string TimeToString(uint64_t time) override {
|
||||
return target_->TimeToString(time);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ enum class CompactionReason {
|
||||
};
|
||||
|
||||
enum class FlushReason : int {
|
||||
kUnknown = 0x00,
|
||||
kOthers = 0x00,
|
||||
kGetLiveFiles = 0x01,
|
||||
kShutDown = 0x02,
|
||||
kExternalFileIngestion = 0x03,
|
||||
@@ -91,7 +91,9 @@ enum class FlushReason : int {
|
||||
kWriteBufferManager = 0x05,
|
||||
kWriteBufferFull = 0x06,
|
||||
kTest = 0x07,
|
||||
kSuperVersionChange = 0x08,
|
||||
kDeleteFiles = 0x08,
|
||||
kAutoCompaction = 0x09,
|
||||
kManualFlush = 0x0a,
|
||||
};
|
||||
|
||||
enum class BackgroundErrorReason {
|
||||
|
||||
@@ -39,24 +39,34 @@
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <rocksdb/slice.h>
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class Arena;
|
||||
class Allocator;
|
||||
class LookupKey;
|
||||
class Slice;
|
||||
class SliceTransform;
|
||||
class Logger;
|
||||
|
||||
typedef void* KeyHandle;
|
||||
|
||||
extern Slice GetLengthPrefixedSlice(const char* data);
|
||||
|
||||
class MemTableRep {
|
||||
public:
|
||||
// KeyComparator provides a means to compare keys, which are internal keys
|
||||
// concatenated with values.
|
||||
class KeyComparator {
|
||||
public:
|
||||
typedef rocksdb::Slice DecodedType;
|
||||
|
||||
virtual DecodedType decode_key(const char* key) const {
|
||||
// The format of key is frozen and can be terated as a part of the API
|
||||
// contract. Refer to MemTable::Add for details.
|
||||
return GetLengthPrefixedSlice(key);
|
||||
}
|
||||
|
||||
// Compare a and b. Return a negative value if a is less than b, 0 if they
|
||||
// are equal, and a positive value if a is greater than b
|
||||
virtual int operator()(const char* prefix_len_key1,
|
||||
|
||||
@@ -197,21 +197,11 @@ struct ColumnFamilyOptions : public AdvancedColumnFamilyOptions {
|
||||
// Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:
|
||||
// ~200-500MB/s compression
|
||||
// ~400-800MB/s decompression
|
||||
//
|
||||
// Note that these speeds are significantly faster than most
|
||||
// persistent storage speeds, and therefore it is typically never
|
||||
// worth switching to kNoCompression. Even if the input data is
|
||||
// incompressible, the kSnappyCompression implementation will
|
||||
// efficiently detect that and will switch to uncompressed mode.
|
||||
//
|
||||
// If you do not set `compression_opts.level`, or set it to
|
||||
// `CompressionOptions::kDefaultCompressionLevel`, we will attempt to pick the
|
||||
// default corresponding to `compression` as follows:
|
||||
//
|
||||
// - kZSTD: 3
|
||||
// - kZlibCompression: Z_DEFAULT_COMPRESSION (currently -1)
|
||||
// - kLZ4HCCompression: 0
|
||||
// - For all others, we do not specify a compression level
|
||||
CompressionType compression;
|
||||
|
||||
// Compression algorithm that will be used for the bottommost level that
|
||||
|
||||
@@ -96,10 +96,14 @@ class SstFileManager {
|
||||
// @param max_trash_db_ratio: If the trash size constitutes for more than this
|
||||
// fraction of the total DB size we will start deleting new files passed to
|
||||
// DeleteScheduler immediately
|
||||
// @param bytes_max_delete_chunk: if a single file is larger than delete chunk,
|
||||
// ftruncate the file by this size each time, rather than dropping the whole
|
||||
// file. 0 means to always delete the whole file.
|
||||
extern SstFileManager* NewSstFileManager(
|
||||
Env* env, std::shared_ptr<Logger> info_log = nullptr,
|
||||
std::string trash_dir = "", int64_t rate_bytes_per_sec = 0,
|
||||
bool delete_existing_trash = true, Status* status = nullptr,
|
||||
double max_trash_db_ratio = 0.25);
|
||||
double max_trash_db_ratio = 0.25,
|
||||
uint64_t bytes_max_delete_chunk = 64 * 1024 * 1024);
|
||||
|
||||
} // namespace rocksdb
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define ROCKSDB_MAJOR 5
|
||||
#define ROCKSDB_MINOR 13
|
||||
#define ROCKSDB_PATCH 2
|
||||
#define ROCKSDB_PATCH 0
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
@@ -304,14 +304,11 @@ jobject Java_org_rocksdb_TransactionDB_getLockStatusData(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo>
|
||||
fn_map_kv =
|
||||
[env](
|
||||
const std::pair<const int32_t, const rocksdb::KeyLockInfo>&
|
||||
pair) {
|
||||
const jobject jlong_column_family_id =
|
||||
rocksdb::LongJni::valueOf(env, pair.first);
|
||||
if (jlong_column_family_id == nullptr) {
|
||||
const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo> fn_map_kv =
|
||||
[env, txn_db, &lock_status_data](const std::pair<const int32_t, const rocksdb::KeyLockInfo>& pair) {
|
||||
const jobject jlong_column_family_id =
|
||||
rocksdb::LongJni::valueOf(env, pair.first);
|
||||
if (jlong_column_family_id == nullptr) {
|
||||
// an error occurred
|
||||
return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
|
||||
}
|
||||
|
||||
+38
-17
@@ -45,9 +45,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
#include "port/likely.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "util/allocator.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace rocksdb {
|
||||
@@ -59,6 +62,9 @@ class InlineSkipList {
|
||||
struct Splice;
|
||||
|
||||
public:
|
||||
using DecodedKey = \
|
||||
typename std::remove_reference<Comparator>::type::DecodedType;
|
||||
|
||||
static const uint16_t kMaxPossibleHeight = 32;
|
||||
|
||||
// Create a new InlineSkipList object that will use "cmp" for comparing
|
||||
@@ -212,6 +218,7 @@ class InlineSkipList {
|
||||
// Return true if key is greater than the data stored in "n". Null n
|
||||
// is considered infinite. n should not be head_.
|
||||
bool KeyIsAfterNode(const char* key, Node* n) const;
|
||||
bool KeyIsAfterNode(const DecodedKey& key, Node* n) const;
|
||||
|
||||
// Returns the earliest node with a key >= key.
|
||||
// Return nullptr if there is no such node.
|
||||
@@ -241,12 +248,12 @@ class InlineSkipList {
|
||||
// a node that is after the key. after should be nullptr if a good after
|
||||
// node isn't conveniently available.
|
||||
template<bool prefetch_before>
|
||||
void FindSpliceForLevel(const char* key, Node* before, Node* after, int level,
|
||||
void FindSpliceForLevel(const DecodedKey& key, Node* before, Node* after, int level,
|
||||
Node** out_prev, Node** out_next);
|
||||
|
||||
// Recomputes Splice levels from highest_level (inclusive) down to
|
||||
// lowest_level (inclusive).
|
||||
void RecomputeSpliceLevels(const char* key, Splice* splice,
|
||||
void RecomputeSpliceLevels(const DecodedKey& key, Splice* splice,
|
||||
int recompute_level);
|
||||
|
||||
// No copying allowed
|
||||
@@ -435,6 +442,14 @@ bool InlineSkipList<Comparator>::KeyIsAfterNode(const char* key,
|
||||
return (n != nullptr) && (compare_(n->Key(), key) < 0);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
bool InlineSkipList<Comparator>::KeyIsAfterNode(const DecodedKey& key,
|
||||
Node* n) const {
|
||||
// nullptr n is considered infinite
|
||||
assert(n != head_);
|
||||
return (n != nullptr) && (compare_(n->Key(), key) < 0);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
typename InlineSkipList<Comparator>::Node*
|
||||
InlineSkipList<Comparator>::FindGreaterOrEqual(const char* key) const {
|
||||
@@ -446,6 +461,7 @@ InlineSkipList<Comparator>::FindGreaterOrEqual(const char* key) const {
|
||||
Node* x = head_;
|
||||
int level = GetMaxHeight() - 1;
|
||||
Node* last_bigger = nullptr;
|
||||
const DecodedKey key_decoded = compare_.decode_key(key);
|
||||
while (true) {
|
||||
Node* next = x->Next(level);
|
||||
if (next != nullptr) {
|
||||
@@ -454,10 +470,10 @@ InlineSkipList<Comparator>::FindGreaterOrEqual(const char* key) const {
|
||||
// Make sure the lists are sorted
|
||||
assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x));
|
||||
// Make sure we haven't overshot during our search
|
||||
assert(x == head_ || KeyIsAfterNode(key, x));
|
||||
assert(x == head_ || KeyIsAfterNode(key_decoded, x));
|
||||
int cmp = (next == nullptr || next == last_bigger)
|
||||
? 1
|
||||
: compare_(next->Key(), key);
|
||||
: compare_(next->Key(), key_decoded);
|
||||
if (cmp == 0 || (cmp > 0 && level == 0)) {
|
||||
return next;
|
||||
} else if (cmp < 0) {
|
||||
@@ -487,6 +503,7 @@ InlineSkipList<Comparator>::FindLessThan(const char* key, Node** prev,
|
||||
Node* x = root;
|
||||
// KeyIsAfter(key, last_not_after) is definitely false
|
||||
Node* last_not_after = nullptr;
|
||||
const DecodedKey key_decoded = compare_.decode_key(key);
|
||||
while (true) {
|
||||
assert(x != nullptr);
|
||||
Node* next = x->Next(level);
|
||||
@@ -494,8 +511,8 @@ InlineSkipList<Comparator>::FindLessThan(const char* key, Node** prev,
|
||||
PREFETCH(next->Next(level), 0, 1);
|
||||
}
|
||||
assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x));
|
||||
assert(x == head_ || KeyIsAfterNode(key, x));
|
||||
if (next != last_not_after && KeyIsAfterNode(key, next)) {
|
||||
assert(x == head_ || KeyIsAfterNode(key_decoded, x));
|
||||
if (next != last_not_after && KeyIsAfterNode(key_decoded, next)) {
|
||||
// Keep searching in this list
|
||||
assert(next != nullptr);
|
||||
x = next;
|
||||
@@ -540,13 +557,14 @@ uint64_t InlineSkipList<Comparator>::EstimateCount(const char* key) const {
|
||||
|
||||
Node* x = head_;
|
||||
int level = GetMaxHeight() - 1;
|
||||
const DecodedKey key_decoded = compare_.decode_key(key);
|
||||
while (true) {
|
||||
assert(x == head_ || compare_(x->Key(), key) < 0);
|
||||
assert(x == head_ || compare_(x->Key(), key_decoded) < 0);
|
||||
Node* next = x->Next(level);
|
||||
if (next != nullptr) {
|
||||
PREFETCH(next->Next(level), 0, 1);
|
||||
}
|
||||
if (next == nullptr || compare_(next->Key(), key) >= 0) {
|
||||
if (next == nullptr || compare_(next->Key(), key_decoded) >= 0) {
|
||||
if (level == 0) {
|
||||
return count;
|
||||
} else {
|
||||
@@ -654,7 +672,7 @@ bool InlineSkipList<Comparator>::InsertWithHint(const char* key, void** hint) {
|
||||
|
||||
template <class Comparator>
|
||||
template <bool prefetch_before>
|
||||
void InlineSkipList<Comparator>::FindSpliceForLevel(const char* key,
|
||||
void InlineSkipList<Comparator>::FindSpliceForLevel(const DecodedKey& key,
|
||||
Node* before, Node* after,
|
||||
int level, Node** out_prev,
|
||||
Node** out_next) {
|
||||
@@ -682,7 +700,7 @@ void InlineSkipList<Comparator>::FindSpliceForLevel(const char* key,
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void InlineSkipList<Comparator>::RecomputeSpliceLevels(const char* key,
|
||||
void InlineSkipList<Comparator>::RecomputeSpliceLevels(const DecodedKey& key,
|
||||
Splice* splice,
|
||||
int recompute_level) {
|
||||
assert(recompute_level > 0);
|
||||
@@ -698,6 +716,7 @@ template <bool UseCAS>
|
||||
bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
|
||||
bool allow_partial_splice_fix) {
|
||||
Node* x = reinterpret_cast<Node*>(const_cast<char*>(key)) - 1;
|
||||
const DecodedKey key_decoded = compare_.decode_key(key);
|
||||
int height = x->UnstashHeight();
|
||||
assert(height >= 1 && height <= kMaxHeight_);
|
||||
|
||||
@@ -765,7 +784,8 @@ bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
|
||||
// our chances of success.
|
||||
++recompute_height;
|
||||
} else if (splice->prev_[recompute_height] != head_ &&
|
||||
!KeyIsAfterNode(key, splice->prev_[recompute_height])) {
|
||||
!KeyIsAfterNode(key_decoded,
|
||||
splice->prev_[recompute_height])) {
|
||||
// key is from before splice
|
||||
if (allow_partial_splice_fix) {
|
||||
// skip all levels with the same node without more comparisons
|
||||
@@ -777,7 +797,8 @@ bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
|
||||
// we're pessimistic, recompute everything
|
||||
recompute_height = max_height;
|
||||
}
|
||||
} else if (KeyIsAfterNode(key, splice->next_[recompute_height])) {
|
||||
} else if (KeyIsAfterNode(key_decoded,
|
||||
splice->next_[recompute_height])) {
|
||||
// key is from after splice
|
||||
if (allow_partial_splice_fix) {
|
||||
Node* bad = splice->next_[recompute_height];
|
||||
@@ -795,7 +816,7 @@ bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
|
||||
}
|
||||
assert(recompute_height <= max_height);
|
||||
if (recompute_height > 0) {
|
||||
RecomputeSpliceLevels(key, splice, recompute_height);
|
||||
RecomputeSpliceLevels(key_decoded, splice, recompute_height);
|
||||
}
|
||||
|
||||
bool splice_is_valid = true;
|
||||
@@ -827,8 +848,8 @@ bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
|
||||
// search, because it should be unlikely that lots of nodes have
|
||||
// been inserted between prev[i] and next[i]. No point in using
|
||||
// next[i] as the after hint, because we know it is stale.
|
||||
FindSpliceForLevel<false>(key, splice->prev_[i], nullptr, i, &splice->prev_[i],
|
||||
&splice->next_[i]);
|
||||
FindSpliceForLevel<false>(key_decoded, splice->prev_[i], nullptr, i,
|
||||
&splice->prev_[i], &splice->next_[i]);
|
||||
|
||||
// Since we've narrowed the bracket for level i, we might have
|
||||
// violated the Splice constraint between i and i-1. Make sure
|
||||
@@ -842,8 +863,8 @@ bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
|
||||
for (int i = 0; i < height; ++i) {
|
||||
if (i >= recompute_height &&
|
||||
splice->prev_[i]->Next(i) != splice->next_[i]) {
|
||||
FindSpliceForLevel<false>(key, splice->prev_[i], nullptr, i, &splice->prev_[i],
|
||||
&splice->next_[i]);
|
||||
FindSpliceForLevel<false>(key_decoded, splice->prev_[i], nullptr, i,
|
||||
&splice->prev_[i], &splice->next_[i]);
|
||||
}
|
||||
// Checking for duplicate keys on the level 0 is sufficient
|
||||
if (UNLIKELY(i == 0 && splice->next_[i] != nullptr &&
|
||||
|
||||
@@ -32,6 +32,12 @@ static Key Decode(const char* key) {
|
||||
}
|
||||
|
||||
struct TestComparator {
|
||||
typedef Key DecodedType;
|
||||
|
||||
static DecodedType decode_key(const char* b) {
|
||||
return Decode(b);
|
||||
}
|
||||
|
||||
int operator()(const char* a, const char* b) const {
|
||||
if (Decode(a) < Decode(b)) {
|
||||
return -1;
|
||||
@@ -41,6 +47,16 @@ struct TestComparator {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int operator()(const char* a, const DecodedType b) const {
|
||||
if (Decode(a) < b) {
|
||||
return -1;
|
||||
} else if (Decode(a) > b) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef InlineSkipList<TestComparator> TestInlineSkipList;
|
||||
|
||||
@@ -168,6 +168,10 @@ void ColumnFamilyOptions::Dump(Logger* log) const {
|
||||
log,
|
||||
" Options.compression_opts.max_dict_bytes: %" ROCKSDB_PRIszt,
|
||||
compression_opts.max_dict_bytes);
|
||||
ROCKS_LOG_HEADER(log,
|
||||
" Options.compression_opts.zstd_max_train_bytes: "
|
||||
"%" ROCKSDB_PRIszt,
|
||||
compression_opts.zstd_max_train_bytes);
|
||||
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",
|
||||
|
||||
@@ -919,6 +919,17 @@ Status ParseColumnFamilyOption(const std::string& name,
|
||||
}
|
||||
new_options->compression_opts.max_dict_bytes =
|
||||
ParseInt(value.substr(start, value.size() - start));
|
||||
end = value.find(':', start);
|
||||
}
|
||||
// zstd_max_train_bytes is optional for backwards compatibility
|
||||
if (end != std::string::npos) {
|
||||
start = end + 1;
|
||||
if (start >= value.size()) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
}
|
||||
new_options->compression_opts.zstd_max_train_bytes =
|
||||
ParseInt(value.substr(start, value.size() - start));
|
||||
}
|
||||
} else {
|
||||
auto iter = cf_options_type_info.find(name);
|
||||
|
||||
@@ -138,7 +138,9 @@ void WindowsThread::join() {
|
||||
"WaitForSingleObjectFailed: thread join");
|
||||
}
|
||||
|
||||
CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
|
||||
BOOL rc;
|
||||
rc = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
|
||||
assert(rc != 0);
|
||||
data_->handle_ = 0;
|
||||
}
|
||||
|
||||
@@ -154,7 +156,7 @@ bool WindowsThread::detach() {
|
||||
BOOL ret = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
|
||||
data_->handle_ = 0;
|
||||
|
||||
return (ret == TRUE);
|
||||
return (ret != 0);
|
||||
}
|
||||
|
||||
void WindowsThread::swap(WindowsThread& o) {
|
||||
|
||||
@@ -148,6 +148,7 @@ LIB_SOURCES = \
|
||||
util/status_message.cc \
|
||||
util/string_util.cc \
|
||||
util/sync_point.cc \
|
||||
util/sync_point_impl.cc \
|
||||
util/thread_local.cc \
|
||||
util/threadpool_imp.cc \
|
||||
util/transaction_test_util.cc \
|
||||
|
||||
@@ -67,7 +67,8 @@ BlockBasedFilterBlockBuilder::BlockBasedFilterBlockBuilder(
|
||||
prefix_extractor_(prefix_extractor),
|
||||
whole_key_filtering_(table_opt.whole_key_filtering),
|
||||
prev_prefix_start_(0),
|
||||
prev_prefix_size_(0) {
|
||||
prev_prefix_size_(0),
|
||||
num_added_(0) {
|
||||
assert(policy_);
|
||||
}
|
||||
|
||||
@@ -91,6 +92,7 @@ void BlockBasedFilterBlockBuilder::Add(const Slice& key) {
|
||||
|
||||
// Add key to filter if needed
|
||||
inline void BlockBasedFilterBlockBuilder::AddKey(const Slice& key) {
|
||||
num_added_++;
|
||||
start_.push_back(entries_.size());
|
||||
entries_.append(key.data(), key.size());
|
||||
}
|
||||
@@ -106,10 +108,9 @@ inline void BlockBasedFilterBlockBuilder::AddPrefix(const Slice& key) {
|
||||
Slice prefix = prefix_extractor_->Transform(key);
|
||||
// insert prefix only when it's different from the previous prefix.
|
||||
if (prev.size() == 0 || prefix != prev) {
|
||||
start_.push_back(entries_.size());
|
||||
AddKey(prefix);
|
||||
prev_prefix_start_ = entries_.size();
|
||||
prev_prefix_size_ = prefix.size();
|
||||
entries_.append(prefix.data(), prefix.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class BlockBasedFilterBlockBuilder : public FilterBlockBuilder {
|
||||
virtual bool IsBlockBased() override { return true; }
|
||||
virtual void StartBlock(uint64_t block_offset) override;
|
||||
virtual void Add(const Slice& key) override;
|
||||
virtual size_t NumAdded() const override { return num_added_; }
|
||||
virtual Slice Finish(const BlockHandle& tmp, Status* status) override;
|
||||
using FilterBlockBuilder::Finish;
|
||||
|
||||
@@ -65,6 +66,7 @@ class BlockBasedFilterBlockBuilder : public FilterBlockBuilder {
|
||||
std::string result_; // Filter data computed so far
|
||||
std::vector<Slice> tmp_entries_; // policy_->CreateFilter() argument
|
||||
std::vector<uint32_t> filter_offsets_;
|
||||
size_t num_added_; // Number of keys added
|
||||
|
||||
// No copying allowed
|
||||
BlockBasedFilterBlockBuilder(const BlockBasedFilterBlockBuilder&);
|
||||
|
||||
@@ -65,6 +65,7 @@ TEST_F(FilterBlockTest, EmptyBuilder) {
|
||||
|
||||
TEST_F(FilterBlockTest, SingleChunk) {
|
||||
BlockBasedFilterBlockBuilder builder(nullptr, table_options_);
|
||||
ASSERT_EQ(0, builder.NumAdded());
|
||||
builder.StartBlock(100);
|
||||
builder.Add("foo");
|
||||
builder.Add("bar");
|
||||
@@ -73,6 +74,7 @@ TEST_F(FilterBlockTest, SingleChunk) {
|
||||
builder.Add("box");
|
||||
builder.StartBlock(300);
|
||||
builder.Add("hello");
|
||||
ASSERT_EQ(5, builder.NumAdded());
|
||||
BlockContents block(builder.Finish(), false, kNoCompression);
|
||||
BlockBasedFilterBlockReader reader(nullptr, table_options_, true,
|
||||
std::move(block), nullptr);
|
||||
|
||||
@@ -650,8 +650,11 @@ Status BlockBasedTableBuilder::Finish() {
|
||||
|
||||
BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle,
|
||||
compression_dict_block_handle, range_del_block_handle;
|
||||
|
||||
// Write filter block
|
||||
if (ok() && r->filter_builder != nullptr) {
|
||||
bool empty_filter_block = (r->filter_builder == nullptr ||
|
||||
r->filter_builder->NumAdded() == 0);
|
||||
if (ok() && !empty_filter_block) {
|
||||
Status s = Status::Incomplete();
|
||||
while (s.IsIncomplete()) {
|
||||
Slice filter_content = r->filter_builder->Finish(filter_block_handle, &s);
|
||||
@@ -687,7 +690,7 @@ Status BlockBasedTableBuilder::Finish() {
|
||||
}
|
||||
|
||||
if (ok()) {
|
||||
if (r->filter_builder != nullptr) {
|
||||
if (!empty_filter_block) {
|
||||
// Add mapping from "<filter_block_prefix>.Name" to location
|
||||
// of filter data.
|
||||
std::string key;
|
||||
|
||||
@@ -120,7 +120,7 @@ void ReleaseCachedEntry(void* arg, void* h) {
|
||||
void ForceReleaseCachedEntry(void* arg, void* h) {
|
||||
Cache* cache = reinterpret_cast<Cache*>(arg);
|
||||
Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);
|
||||
cache->Release(handle, true /* force_erase */);
|
||||
cache->Release(handle, true);
|
||||
}
|
||||
|
||||
Slice GetCacheKeyFromOffset(const char* cache_key_prefix,
|
||||
|
||||
@@ -419,7 +419,7 @@ struct BlockBasedTable::Rep {
|
||||
|
||||
const ImmutableCFOptions& ioptions;
|
||||
const EnvOptions& env_options;
|
||||
const BlockBasedTableOptions table_options;
|
||||
const BlockBasedTableOptions& table_options;
|
||||
const FilterPolicy* const filter_policy;
|
||||
const InternalKeyComparator& internal_comparator;
|
||||
Status status;
|
||||
|
||||
+10
-3
@@ -30,6 +30,7 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
inline
|
||||
void BlockFetcher::CheckBlockChecksum() {
|
||||
// Check the crc of the type and the block contents
|
||||
if (read_options_.verify_checksums) {
|
||||
@@ -62,6 +63,7 @@ void BlockFetcher::CheckBlockChecksum() {
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
bool BlockFetcher::TryGetUncompressBlockFromPersistentCache() {
|
||||
if (cache_options_.persistent_cache &&
|
||||
!cache_options_.persistent_cache->IsCompressed()) {
|
||||
@@ -83,6 +85,7 @@ bool BlockFetcher::TryGetUncompressBlockFromPersistentCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
bool BlockFetcher::TryGetFromPrefetchBuffer() {
|
||||
if (prefetch_buffer_ != nullptr &&
|
||||
prefetch_buffer_->TryReadFromCache(
|
||||
@@ -99,6 +102,7 @@ bool BlockFetcher::TryGetFromPrefetchBuffer() {
|
||||
return got_from_prefetch_buffer_;
|
||||
}
|
||||
|
||||
inline
|
||||
bool BlockFetcher::TryGetCompressedBlockFromPersistentCache() {
|
||||
if (cache_options_.persistent_cache &&
|
||||
cache_options_.persistent_cache->IsCompressed()) {
|
||||
@@ -119,6 +123,7 @@ bool BlockFetcher::TryGetCompressedBlockFromPersistentCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
void BlockFetcher::PrepareBufferForBlockFromFile() {
|
||||
// cache miss read from device
|
||||
if (do_uncompress_ &&
|
||||
@@ -127,12 +132,12 @@ void BlockFetcher::PrepareBufferForBlockFromFile() {
|
||||
// trivially allocated stack buffer instead of needing a full malloc()
|
||||
used_buf_ = &stack_buf_[0];
|
||||
} else {
|
||||
heap_buf_ =
|
||||
std::unique_ptr<char[]>(new char[block_size_ + kBlockTrailerSize]);
|
||||
heap_buf_.reset(new char[block_size_ + kBlockTrailerSize]);
|
||||
used_buf_ = heap_buf_.get();
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void BlockFetcher::InsertCompressedBlockToPersistentCacheIfNeeded() {
|
||||
if (status_.ok() && read_options_.fill_cache &&
|
||||
cache_options_.persistent_cache &&
|
||||
@@ -143,6 +148,7 @@ void BlockFetcher::InsertCompressedBlockToPersistentCacheIfNeeded() {
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void BlockFetcher::InsertUncompressedBlockToPersistentCacheIfNeeded() {
|
||||
if (status_.ok() && !got_from_prefetch_buffer_ && read_options_.fill_cache &&
|
||||
cache_options_.persistent_cache &&
|
||||
@@ -153,6 +159,7 @@ void BlockFetcher::InsertUncompressedBlockToPersistentCacheIfNeeded() {
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void BlockFetcher::GetBlockContents() {
|
||||
if (slice_.data() != used_buf_) {
|
||||
// the slice content is not the buffer provided
|
||||
@@ -161,7 +168,7 @@ void BlockFetcher::GetBlockContents() {
|
||||
} else {
|
||||
// page is uncompressed, the buffer either stack or heap provided
|
||||
if (got_from_prefetch_buffer_ || used_buf_ == &stack_buf_[0]) {
|
||||
heap_buf_ = std::unique_ptr<char[]>(new char[block_size_]);
|
||||
heap_buf_.reset(new char[block_size_]);
|
||||
memcpy(heap_buf_.get(), used_buf_, block_size_);
|
||||
}
|
||||
*contents_ = BlockContents(std::move(heap_buf_), block_size_, true,
|
||||
|
||||
@@ -625,7 +625,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as Cuckoo table is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as Cuckoo table is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class FilterBlockBuilder {
|
||||
virtual bool IsBlockBased() = 0; // If is blockbased filter
|
||||
virtual void StartBlock(uint64_t block_offset) = 0; // Start new block filter
|
||||
virtual void Add(const Slice& key) = 0; // Add a key to current filter
|
||||
virtual size_t NumAdded() const = 0; // Number of keys added
|
||||
Slice Finish() { // Generate Filter
|
||||
const BlockHandle empty_handle;
|
||||
Status dont_care_status;
|
||||
|
||||
@@ -45,6 +45,7 @@ class FullFilterBlockBuilder : public FilterBlockBuilder {
|
||||
virtual bool IsBlockBased() override { return false; }
|
||||
virtual void StartBlock(uint64_t /*block_offset*/) override {}
|
||||
virtual void Add(const Slice& key) override;
|
||||
virtual size_t NumAdded() const override { return num_added_; }
|
||||
virtual Slice Finish(const BlockHandle& tmp, Status* status) override;
|
||||
using FilterBlockBuilder::Finish;
|
||||
|
||||
|
||||
@@ -163,11 +163,13 @@ TEST_F(FullFilterBlockTest, EmptyBuilder) {
|
||||
TEST_F(FullFilterBlockTest, SingleChunk) {
|
||||
FullFilterBlockBuilder builder(
|
||||
nullptr, true, table_options_.filter_policy->GetFilterBitsBuilder());
|
||||
ASSERT_EQ(0, builder.NumAdded());
|
||||
builder.Add("foo");
|
||||
builder.Add("bar");
|
||||
builder.Add("box");
|
||||
builder.Add("box");
|
||||
builder.Add("hello");
|
||||
ASSERT_EQ(5, builder.NumAdded());
|
||||
Slice block = builder.Finish();
|
||||
FullFilterBlockReader reader(
|
||||
nullptr, true, block,
|
||||
|
||||
@@ -25,7 +25,8 @@ PartitionedFilterBlockBuilder::PartitionedFilterBlockBuilder(
|
||||
filter_bits_builder),
|
||||
index_on_filter_block_builder_(index_block_restart_interval),
|
||||
p_index_builder_(p_index_builder),
|
||||
filters_in_partition_(0) {
|
||||
filters_in_partition_(0),
|
||||
num_added_(0) {
|
||||
filters_per_partition_ =
|
||||
filter_bits_builder_->CalculateNumEntry(partition_size);
|
||||
}
|
||||
@@ -53,6 +54,7 @@ void PartitionedFilterBlockBuilder::AddKey(const Slice& key) {
|
||||
MaybeCutAFilterBlock();
|
||||
filter_bits_builder_->AddKey(key);
|
||||
filters_in_partition_++;
|
||||
num_added_++;
|
||||
}
|
||||
|
||||
Slice PartitionedFilterBlockBuilder::Finish(
|
||||
@@ -244,13 +246,6 @@ size_t PartitionedFilterBlockReader::ApproximateMemoryUsage() const {
|
||||
return idx_on_fltr_blk_->size();
|
||||
}
|
||||
|
||||
// Release the cached entry and decrement its ref count.
|
||||
void ReleaseFilterCachedEntry(void* arg, void* h) {
|
||||
Cache* cache = reinterpret_cast<Cache*>(arg);
|
||||
Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);
|
||||
cache->Release(handle);
|
||||
}
|
||||
|
||||
// TODO(myabandeh): merge this with the same function in IndexReader
|
||||
void PartitionedFilterBlockReader::CacheDependencies(bool pin) {
|
||||
// Before read partitions, prefetch them to avoid lots of IOs
|
||||
@@ -309,8 +304,6 @@ void PartitionedFilterBlockReader::CacheDependencies(bool pin) {
|
||||
if (LIKELY(filter.IsSet())) {
|
||||
if (pin) {
|
||||
filter_map_[handle.offset()] = std::move(filter);
|
||||
RegisterCleanup(&ReleaseFilterCachedEntry, block_cache,
|
||||
filter.cache_handle);
|
||||
} else {
|
||||
block_cache->Release(filter.cache_handle);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ class PartitionedFilterBlockBuilder : public FullFilterBlockBuilder {
|
||||
|
||||
void AddKey(const Slice& key) override;
|
||||
|
||||
size_t NumAdded() const override { return num_added_; }
|
||||
|
||||
virtual Slice Finish(const BlockHandle& last_partition_block_handle,
|
||||
Status* status) override;
|
||||
|
||||
@@ -59,10 +61,11 @@ class PartitionedFilterBlockBuilder : public FullFilterBlockBuilder {
|
||||
uint32_t filters_per_partition_;
|
||||
// The current number of filters in the last partition
|
||||
uint32_t filters_in_partition_;
|
||||
// Number of keys added
|
||||
size_t num_added_;
|
||||
};
|
||||
|
||||
class PartitionedFilterBlockReader : public FilterBlockReader,
|
||||
public Cleanable {
|
||||
class PartitionedFilterBlockReader : public FilterBlockReader {
|
||||
public:
|
||||
explicit PartitionedFilterBlockReader(const SliceTransform* prefix_extractor,
|
||||
bool whole_key_filtering,
|
||||
|
||||
+11
-18
@@ -302,11 +302,9 @@ class KeyConvertingIterator : public InternalIterator {
|
||||
class TableConstructor: public Constructor {
|
||||
public:
|
||||
explicit TableConstructor(const Comparator* cmp,
|
||||
bool convert_to_internal_key = false,
|
||||
int level = -1)
|
||||
bool convert_to_internal_key = false)
|
||||
: Constructor(cmp),
|
||||
convert_to_internal_key_(convert_to_internal_key),
|
||||
level_(level) {}
|
||||
convert_to_internal_key_(convert_to_internal_key) {}
|
||||
~TableConstructor() { Reset(); }
|
||||
|
||||
virtual Status FinishImpl(const Options& options,
|
||||
@@ -321,12 +319,14 @@ class TableConstructor: public Constructor {
|
||||
std::vector<std::unique_ptr<IntTblPropCollectorFactory>>
|
||||
int_tbl_prop_collector_factories;
|
||||
std::string column_family_name;
|
||||
int unknown_level = -1;
|
||||
builder.reset(ioptions.table_factory->NewTableBuilder(
|
||||
TableBuilderOptions(
|
||||
ioptions, internal_comparator, &int_tbl_prop_collector_factories,
|
||||
options.compression, CompressionOptions(),
|
||||
nullptr /* compression_dict */, false /* skip_filters */,
|
||||
column_family_name, level_),
|
||||
TableBuilderOptions(ioptions, internal_comparator,
|
||||
&int_tbl_prop_collector_factories,
|
||||
options.compression, CompressionOptions(),
|
||||
nullptr /* compression_dict */,
|
||||
false /* skip_filters */, column_family_name,
|
||||
unknown_level),
|
||||
TablePropertiesCollectorFactory::Context::kUnknownColumnFamily,
|
||||
file_writer_.get()));
|
||||
|
||||
@@ -351,10 +351,8 @@ class TableConstructor: public Constructor {
|
||||
uniq_id_ = cur_uniq_id_++;
|
||||
file_reader_.reset(test::GetRandomAccessFileReader(new test::StringSource(
|
||||
GetSink()->contents(), uniq_id_, ioptions.allow_mmap_reads)));
|
||||
const bool skip_filters = false;
|
||||
return ioptions.table_factory->NewTableReader(
|
||||
TableReaderOptions(ioptions, soptions, internal_comparator,
|
||||
skip_filters, level_),
|
||||
TableReaderOptions(ioptions, soptions, internal_comparator),
|
||||
std::move(file_reader_), GetSink()->contents().size(), &table_reader_);
|
||||
}
|
||||
|
||||
@@ -414,7 +412,6 @@ class TableConstructor: public Constructor {
|
||||
unique_ptr<RandomAccessFileReader> file_reader_;
|
||||
unique_ptr<TableReader> table_reader_;
|
||||
bool convert_to_internal_key_;
|
||||
int level_;
|
||||
|
||||
TableConstructor();
|
||||
|
||||
@@ -2252,7 +2249,6 @@ std::map<std::string, size_t> MockCache::marked_data_in_cache_;
|
||||
// table is closed. This test makes sure that the only items remains in the
|
||||
// cache after the table is closed are raw data blocks.
|
||||
TEST_F(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
|
||||
for (int level: {-1, 0, 1, 10}) {
|
||||
for (auto index_type :
|
||||
{BlockBasedTableOptions::IndexType::kBinarySearch,
|
||||
BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch}) {
|
||||
@@ -2289,9 +2285,7 @@ TEST_F(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
|
||||
rocksdb::NewBloomFilterPolicy(10, block_based_filter));
|
||||
opt.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
|
||||
bool convert_to_internal_key = false;
|
||||
TableConstructor c(BytewiseComparator(), convert_to_internal_key,
|
||||
level);
|
||||
TableConstructor c(BytewiseComparator());
|
||||
std::string user_key = "k01";
|
||||
std::string key =
|
||||
InternalKey(user_key, 0, kTypeValue).Encode().ToString();
|
||||
@@ -2332,7 +2326,6 @@ TEST_F(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} // level
|
||||
}
|
||||
|
||||
TEST_F(BlockBasedTableTest, BlockCacheLeak) {
|
||||
|
||||
@@ -24,11 +24,7 @@ class TwoLevelIterator : public InternalIterator {
|
||||
explicit TwoLevelIterator(TwoLevelIteratorState* state,
|
||||
InternalIterator* first_level_iter);
|
||||
|
||||
virtual ~TwoLevelIterator() {
|
||||
first_level_iter_.DeleteIter(false /* is_arena_mode */);
|
||||
second_level_iter_.DeleteIter(false /* is_arena_mode */);
|
||||
delete state_;
|
||||
}
|
||||
virtual ~TwoLevelIterator() { delete state_; }
|
||||
|
||||
virtual void Seek(const Slice& target) override;
|
||||
virtual void SeekForPrev(const Slice& target) override;
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace rocksdb {
|
||||
|
||||
struct ReadOptions;
|
||||
class InternalKeyComparator;
|
||||
class Arena;
|
||||
|
||||
// TwoLevelIteratorState expects iterators are not created using the arena
|
||||
struct TwoLevelIteratorState {
|
||||
TwoLevelIteratorState() {}
|
||||
|
||||
@@ -35,7 +35,11 @@ struct TwoLevelIteratorState {
|
||||
//
|
||||
// Uses a supplied function to convert an index_iter value into
|
||||
// an iterator over the contents of the corresponding block.
|
||||
// Note: this function expects first_level_iter was not created using the arena
|
||||
// arena: If not null, the arena is used to allocate the Iterator.
|
||||
// When destroying the iterator, the destructor will destroy
|
||||
// all the states but those allocated in arena.
|
||||
// need_free_iter_and_state: free `state` and `first_level_iter` if
|
||||
// true. Otherwise, just call destructor.
|
||||
extern InternalIterator* NewTwoLevelIterator(
|
||||
TwoLevelIteratorState* state, InternalIterator* first_level_iter);
|
||||
|
||||
|
||||
+8
-10
@@ -108,14 +108,12 @@ fi
|
||||
|
||||
params_w="$const_params \
|
||||
$l0_config \
|
||||
--max_background_compactions=16 \
|
||||
--max_write_buffer_number=8 \
|
||||
--max_background_flushes=7"
|
||||
--max_background_jobs=20 \
|
||||
--max_write_buffer_number=8"
|
||||
|
||||
params_bulkload="$const_params \
|
||||
--max_background_compactions=16 \
|
||||
--max_background_jobs=20 \
|
||||
--max_write_buffer_number=8 \
|
||||
--max_background_flushes=7 \
|
||||
--level0_file_num_compaction_trigger=$((10 * M)) \
|
||||
--level0_slowdown_writes_trigger=$((10 * M)) \
|
||||
--level0_stop_writes_trigger=$((10 * M))"
|
||||
@@ -126,14 +124,14 @@ params_bulkload="$const_params \
|
||||
# LSM. In level-based compaction, it means number of L0 files.
|
||||
#
|
||||
params_level_compact="$const_params \
|
||||
--max_background_flushes=4 \
|
||||
--max_background_jobs=16 \
|
||||
--max_write_buffer_number=4 \
|
||||
--level0_file_num_compaction_trigger=4 \
|
||||
--level0_slowdown_writes_trigger=16 \
|
||||
--level0_stop_writes_trigger=20"
|
||||
|
||||
params_univ_compact="$const_params \
|
||||
--max_background_flushes=4 \
|
||||
--max_background_jobs=20 \
|
||||
--max_write_buffer_number=4 \
|
||||
--level0_file_num_compaction_trigger=8 \
|
||||
--level0_slowdown_writes_trigger=16 \
|
||||
@@ -232,7 +230,7 @@ function run_manual_compaction_worker {
|
||||
--subcompactions=$3 \
|
||||
--memtablerep=vector \
|
||||
--disable_wal=1 \
|
||||
--max_background_compactions=$4 \
|
||||
--max_background_jobs=$4 \
|
||||
--seed=$( date +%s ) \
|
||||
2>&1 | tee -a $fillrandom_output_file"
|
||||
|
||||
@@ -276,7 +274,7 @@ function run_univ_compaction {
|
||||
|
||||
# Define a set of benchmarks.
|
||||
subcompactions=(1 2 4 8 16)
|
||||
max_background_compactions=(16 16 8 4 2)
|
||||
max_background_jobs=(20 20 10 5 4)
|
||||
|
||||
i=0
|
||||
total=${#subcompactions[@]}
|
||||
@@ -285,7 +283,7 @@ function run_univ_compaction {
|
||||
while [ "$i" -lt "$total" ]
|
||||
do
|
||||
run_manual_compaction_worker $io_stats $compaction_style ${subcompactions[$i]} \
|
||||
${max_background_compactions[$i]}
|
||||
${max_background_jobs[$i]}
|
||||
((i++))
|
||||
done
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ EOF
|
||||
done
|
||||
|
||||
declare -a backward_compatible_checkout_objs=("2.2.fb.branch" "2.3.fb.branch" "2.4.fb.branch" "2.5.fb.branch" "2.6.fb.branch" "2.7.fb.branch" "2.8.1.fb" "3.0.fb.branch" "3.1.fb" "3.2.fb" "3.3.fb" "3.4.fb" "3.5.fb" "3.6.fb" "3.7.fb" "3.8.fb" "3.9.fb")
|
||||
declare -a forward_compatible_checkout_objs=("3.10.fb" "3.11.fb" "3.12.fb" "3.13.fb" "4.0.fb" "4.1.fb" "4.2.fb" "4.3.fb" "4.4.fb" "4.5.fb" "4.6.fb" "4.7.fb" "4.8.fb" "4.9.fb" "4.10.fb" "4.11.fb" "4.12.fb" "4.13.fb" "5.0.fb" "5.1.fb" "5.2.fb" "5.3.fb" "5.4.fb" "5.5.fb" "5.6.fb" "5.7.fb" "5.8.fb" "5.9.fb" "5.10.fb")
|
||||
declare -a forward_compatible_checkout_objs=("3.10.fb" "3.11.fb" "3.12.fb" "3.13.fb" "4.0.fb" "4.1.fb" "4.2.fb" "4.3.fb" "4.4.fb" "4.5.fb" "4.6.fb" "4.7.fb" "4.8.fb" "4.9.fb" "4.10.fb" "4.11.fb" "4.12.fb" "4.13.fb" "5.0.fb" "5.1.fb" "5.2.fb" "5.3.fb" "5.4.fb" "5.5.fb" "5.6.fb" "5.7.fb" "5.8.fb" "5.9.fb" "5.10.fb" "5.11.fb" "5.12.fb")
|
||||
declare -a checkout_objs=(${backward_compatible_checkout_objs[@]} ${forward_compatible_checkout_objs[@]})
|
||||
|
||||
generate_db()
|
||||
|
||||
@@ -989,8 +989,6 @@ DEFINE_int32(memtable_insert_with_hint_prefix_size, 0,
|
||||
"memtable insert with hint with the given prefix size.");
|
||||
DEFINE_bool(enable_io_prio, false, "Lower the background flush/compaction "
|
||||
"threads' IO priority");
|
||||
DEFINE_bool(enable_cpu_prio, false, "Lower the background flush/compaction "
|
||||
"threads' CPU priority");
|
||||
DEFINE_bool(identity_as_first_hash, false, "the first hash function of cuckoo "
|
||||
"table becomes an identity function. This is only valid when key "
|
||||
"is 8 bytes");
|
||||
@@ -2943,8 +2941,6 @@ void VerifyDBFromDB(std::string& truth_db_name) {
|
||||
FLAGS_options_file.c_str(), s.ToString().c_str());
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
(void)opts;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -3319,10 +3315,6 @@ void VerifyDBFromDB(std::string& truth_db_name) {
|
||||
FLAGS_env->LowerThreadPoolIOPriority(Env::LOW);
|
||||
FLAGS_env->LowerThreadPoolIOPriority(Env::HIGH);
|
||||
}
|
||||
if (FLAGS_enable_cpu_prio) {
|
||||
FLAGS_env->LowerThreadPoolCPUPriority(Env::LOW);
|
||||
FLAGS_env->LowerThreadPoolCPUPriority(Env::HIGH);
|
||||
}
|
||||
options.env = FLAGS_env;
|
||||
|
||||
if (FLAGS_rate_limiter_bytes_per_sec > 0) {
|
||||
@@ -4004,9 +3996,6 @@ void VerifyDBFromDB(std::string& truth_db_name) {
|
||||
}
|
||||
return Status::OK();
|
||||
#else
|
||||
(void)thread;
|
||||
(void)compaction_style;
|
||||
(void)write_mode;
|
||||
fprintf(stderr, "Rocksdb Lite doesn't support filldeterministic\n");
|
||||
return Status::NotSupported(
|
||||
"Rocksdb Lite doesn't support filldeterministic");
|
||||
|
||||
+6
-9
@@ -1021,7 +1021,9 @@ class DbStressListener : public EventListener {
|
||||
: db_name_(db_name), db_paths_(db_paths) {}
|
||||
virtual ~DbStressListener() {}
|
||||
#ifndef ROCKSDB_LITE
|
||||
virtual void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override {
|
||||
virtual void OnFlushCompleted(DB* db, const FlushJobInfo& info) override {
|
||||
assert(db);
|
||||
assert(db->GetName() == db_name_);
|
||||
assert(IsValidColumnFamilyName(info.cf_name));
|
||||
VerifyFilePath(info.file_path);
|
||||
// pretending doing some work here
|
||||
@@ -1029,8 +1031,10 @@ class DbStressListener : public EventListener {
|
||||
std::chrono::microseconds(Random::GetTLSInstance()->Uniform(5000)));
|
||||
}
|
||||
|
||||
virtual void OnCompactionCompleted(DB* /*db*/,
|
||||
virtual void OnCompactionCompleted(DB* db,
|
||||
const CompactionJobInfo& ci) override {
|
||||
assert(db);
|
||||
assert(db->GetName() == db_name_);
|
||||
assert(IsValidColumnFamilyName(ci.cf_name));
|
||||
assert(ci.input_files.size() + ci.output_files.size() > 0U);
|
||||
for (const auto& file_path : ci.input_files) {
|
||||
@@ -1082,8 +1086,6 @@ class DbStressListener : public EventListener {
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
#else
|
||||
(void)file_dir;
|
||||
#endif // !NDEBUG
|
||||
}
|
||||
|
||||
@@ -1094,8 +1096,6 @@ class DbStressListener : public EventListener {
|
||||
bool result = ParseFileName(file_name, &file_number, &file_type);
|
||||
assert(result);
|
||||
assert(file_type == kTableFile);
|
||||
#else
|
||||
(void)file_name;
|
||||
#endif // !NDEBUG
|
||||
}
|
||||
|
||||
@@ -1110,8 +1110,6 @@ class DbStressListener : public EventListener {
|
||||
}
|
||||
VerifyFileName(file_path.substr(pos));
|
||||
}
|
||||
#else
|
||||
(void)file_path;
|
||||
#endif // !NDEBUG
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
@@ -2291,7 +2289,6 @@ class StressTest {
|
||||
size_t value_sz =
|
||||
((rand % kRandomValueMaxFactor) + 1) * FLAGS_value_size_mult;
|
||||
assert(value_sz <= max_sz && value_sz >= sizeof(uint32_t));
|
||||
(void) max_sz;
|
||||
*((uint32_t*)v) = rand;
|
||||
for (size_t i=sizeof(uint32_t); i < value_sz; i++) {
|
||||
v[i] = (char)(rand ^ i);
|
||||
|
||||
@@ -54,7 +54,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as LDBCommand is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as LDBCommand is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as SSTDumpTool is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as AutoRollLogger is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
@@ -27,9 +27,6 @@ template <class T>
|
||||
void AssertAutoVectorOnlyInStack(autovector<T, kSize>* vec, bool result) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ(vec->only_in_stack(), result);
|
||||
#else
|
||||
(void) vec;
|
||||
(void) result;
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
} // namespace
|
||||
|
||||
+5
-25
@@ -246,15 +246,9 @@ inline bool Zlib_Compress(const CompressionOptions& opts,
|
||||
// memLevel=9 uses maximum memory for optimal speed.
|
||||
// The default value is 8. See zconf.h for more details.
|
||||
static const int memLevel = 8;
|
||||
int level;
|
||||
if (opts.level == CompressionOptions::kDefaultCompressionLevel) {
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
} else {
|
||||
level = opts.level;
|
||||
}
|
||||
z_stream _stream;
|
||||
memset(&_stream, 0, sizeof(z_stream));
|
||||
int st = deflateInit2(&_stream, level, Z_DEFLATED, opts.window_bits,
|
||||
int st = deflateInit2(&_stream, opts.level, Z_DEFLATED, opts.window_bits,
|
||||
memLevel, opts.strategy);
|
||||
if (st != Z_OK) {
|
||||
return false;
|
||||
@@ -688,15 +682,9 @@ inline bool LZ4HC_Compress(const CompressionOptions& opts,
|
||||
output->resize(static_cast<size_t>(output_header_len + compress_bound));
|
||||
|
||||
int outlen;
|
||||
int level;
|
||||
if (opts.level == CompressionOptions::kDefaultCompressionLevel) {
|
||||
level = 0; // lz4hc.h says any value < 1 will be sanitized to default
|
||||
} else {
|
||||
level = opts.level;
|
||||
}
|
||||
#if LZ4_VERSION_NUMBER >= 10400 // r124+
|
||||
LZ4_streamHC_t* stream = LZ4_createStreamHC();
|
||||
LZ4_resetStreamHC(stream, level);
|
||||
LZ4_resetStreamHC(stream, opts.level);
|
||||
const char* compression_dict_data =
|
||||
compression_dict.size() > 0 ? compression_dict.data() : nullptr;
|
||||
size_t compression_dict_size = compression_dict.size();
|
||||
@@ -717,7 +705,7 @@ inline bool LZ4HC_Compress(const CompressionOptions& opts,
|
||||
#elif LZ4_VERSION_MAJOR // r113-r123
|
||||
outlen = LZ4_compressHC2_limitedOutput(input, &(*output)[output_header_len],
|
||||
static_cast<int>(length),
|
||||
compress_bound, level);
|
||||
compress_bound, opts.level);
|
||||
#else // up to r112
|
||||
outlen =
|
||||
LZ4_compressHC_limitedOutput(input, &(*output)[output_header_len],
|
||||
@@ -778,23 +766,15 @@ inline bool ZSTD_Compress(const CompressionOptions& opts, const char* input,
|
||||
size_t compressBound = ZSTD_compressBound(length);
|
||||
output->resize(static_cast<size_t>(output_header_len + compressBound));
|
||||
size_t outlen;
|
||||
int level;
|
||||
if (opts.level == CompressionOptions::kDefaultCompressionLevel) {
|
||||
// 3 is the value of ZSTD_CLEVEL_DEFAULT (not exposed publicly), see
|
||||
// https://github.com/facebook/zstd/issues/1148
|
||||
level = 3;
|
||||
} else {
|
||||
level = opts.level;
|
||||
}
|
||||
#if ZSTD_VERSION_NUMBER >= 500 // v0.5.0+
|
||||
ZSTD_CCtx* context = ZSTD_createCCtx();
|
||||
outlen = ZSTD_compress_usingDict(
|
||||
context, &(*output)[output_header_len], compressBound, input, length,
|
||||
compression_dict.data(), compression_dict.size(), level);
|
||||
compression_dict.data(), compression_dict.size(), opts.level);
|
||||
ZSTD_freeCCtx(context);
|
||||
#else // up to v0.4.x
|
||||
outlen = ZSTD_compress(&(*output)[output_header_len], compressBound, input,
|
||||
length, level);
|
||||
length, opts.level);
|
||||
#endif // ZSTD_VERSION_NUMBER >= 500
|
||||
if (outlen == 0) {
|
||||
return false;
|
||||
|
||||
+44
-11
@@ -22,11 +22,13 @@ namespace rocksdb {
|
||||
DeleteScheduler::DeleteScheduler(Env* env, int64_t rate_bytes_per_sec,
|
||||
Logger* info_log,
|
||||
SstFileManagerImpl* sst_file_manager,
|
||||
double max_trash_db_ratio)
|
||||
double max_trash_db_ratio,
|
||||
uint64_t bytes_max_delete_chunk)
|
||||
: env_(env),
|
||||
total_trash_size_(0),
|
||||
rate_bytes_per_sec_(rate_bytes_per_sec),
|
||||
pending_files_(0),
|
||||
bytes_max_delete_chunk_(bytes_max_delete_chunk),
|
||||
closing_(false),
|
||||
cv_(&mu_),
|
||||
info_log_(info_log),
|
||||
@@ -208,15 +210,18 @@ void DeleteScheduler::BackgroundEmptyTrash() {
|
||||
|
||||
// Get new file to delete
|
||||
std::string path_in_trash = queue_.front();
|
||||
queue_.pop();
|
||||
|
||||
// We dont need to hold the lock while deleting the file
|
||||
mu_.Unlock();
|
||||
uint64_t deleted_bytes = 0;
|
||||
bool is_complete = true;
|
||||
// Delete file from trash and update total_penlty value
|
||||
Status s = DeleteTrashFile(path_in_trash, &deleted_bytes);
|
||||
Status s = DeleteTrashFile(path_in_trash, &deleted_bytes, &is_complete);
|
||||
total_deleted_bytes += deleted_bytes;
|
||||
mu_.Lock();
|
||||
if (is_complete) {
|
||||
queue_.pop();
|
||||
}
|
||||
|
||||
if (!s.ok()) {
|
||||
bg_errors_[path_in_trash] = s;
|
||||
@@ -236,7 +241,9 @@ void DeleteScheduler::BackgroundEmptyTrash() {
|
||||
TEST_SYNC_POINT_CALLBACK("DeleteScheduler::BackgroundEmptyTrash:Wait",
|
||||
&total_penlty);
|
||||
|
||||
pending_files_--;
|
||||
if (is_complete) {
|
||||
pending_files_--;
|
||||
}
|
||||
if (pending_files_ == 0) {
|
||||
// Unblock WaitForEmptyTrash since there are no more files waiting
|
||||
// to be deleted
|
||||
@@ -247,23 +254,49 @@ void DeleteScheduler::BackgroundEmptyTrash() {
|
||||
}
|
||||
|
||||
Status DeleteScheduler::DeleteTrashFile(const std::string& path_in_trash,
|
||||
uint64_t* deleted_bytes) {
|
||||
uint64_t* deleted_bytes,
|
||||
bool* is_complete) {
|
||||
uint64_t file_size;
|
||||
Status s = env_->GetFileSize(path_in_trash, &file_size);
|
||||
*is_complete = true;
|
||||
TEST_SYNC_POINT("DeleteScheduler::DeleteTrashFile:DeleteFile");
|
||||
if (s.ok()) {
|
||||
TEST_SYNC_POINT("DeleteScheduler::DeleteTrashFile:DeleteFile");
|
||||
s = env_->DeleteFile(path_in_trash);
|
||||
}
|
||||
bool need_full_delete = true;
|
||||
if (bytes_max_delete_chunk_ != 0 && file_size > bytes_max_delete_chunk_) {
|
||||
unique_ptr<WritableFile> wf;
|
||||
Status my_status =
|
||||
env_->ReopenWritableFile(path_in_trash, &wf, EnvOptions());
|
||||
if (my_status.ok()) {
|
||||
my_status = wf->Truncate(file_size - bytes_max_delete_chunk_);
|
||||
if (my_status.ok()) {
|
||||
TEST_SYNC_POINT("DeleteScheduler::DeleteTrashFile:Fsync");
|
||||
my_status = wf->Fsync();
|
||||
}
|
||||
}
|
||||
if (my_status.ok()) {
|
||||
*deleted_bytes = bytes_max_delete_chunk_;
|
||||
need_full_delete = false;
|
||||
*is_complete = false;
|
||||
} else {
|
||||
ROCKS_LOG_WARN(info_log_,
|
||||
"Failed to partially delete %s from trash -- %s",
|
||||
path_in_trash.c_str(), my_status.ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (need_full_delete) {
|
||||
s = env_->DeleteFile(path_in_trash);
|
||||
*deleted_bytes = file_size;
|
||||
sst_file_manager_->OnDeleteFile(path_in_trash);
|
||||
}
|
||||
}
|
||||
if (!s.ok()) {
|
||||
// Error while getting file size or while deleting
|
||||
ROCKS_LOG_ERROR(info_log_, "Failed to delete %s from trash -- %s",
|
||||
path_in_trash.c_str(), s.ToString().c_str());
|
||||
*deleted_bytes = 0;
|
||||
} else {
|
||||
*deleted_bytes = file_size;
|
||||
total_trash_size_.fetch_sub(file_size);
|
||||
sst_file_manager_->OnDeleteFile(path_in_trash);
|
||||
total_trash_size_.fetch_sub(*deleted_bytes);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
@@ -34,7 +34,7 @@ class DeleteScheduler {
|
||||
public:
|
||||
DeleteScheduler(Env* env, int64_t rate_bytes_per_sec, Logger* info_log,
|
||||
SstFileManagerImpl* sst_file_manager,
|
||||
double max_trash_db_ratio);
|
||||
double max_trash_db_ratio, uint64_t bytes_max_delete_chunk);
|
||||
|
||||
~DeleteScheduler();
|
||||
|
||||
@@ -82,7 +82,7 @@ class DeleteScheduler {
|
||||
Status MarkAsTrash(const std::string& file_path, std::string* path_in_trash);
|
||||
|
||||
Status DeleteTrashFile(const std::string& path_in_trash,
|
||||
uint64_t* deleted_bytes);
|
||||
uint64_t* deleted_bytes, bool* is_complete);
|
||||
|
||||
void BackgroundEmptyTrash();
|
||||
|
||||
@@ -97,6 +97,7 @@ class DeleteScheduler {
|
||||
std::queue<std::string> queue_;
|
||||
// Number of trash files that are waiting to be deleted
|
||||
int32_t pending_files_;
|
||||
uint64_t bytes_max_delete_chunk_;
|
||||
// Errors that happened in BackgroundEmptyTrash (file_path => error)
|
||||
std::map<std::string, Status> bg_errors_;
|
||||
// Set to true in ~DeleteScheduler() to force BackgroundEmptyTrash to stop
|
||||
|
||||
@@ -99,7 +99,7 @@ class DeleteSchedulerTest : public testing::Test {
|
||||
// 25%)
|
||||
sst_file_mgr_.reset(
|
||||
new SstFileManagerImpl(env_, nullptr, rate_bytes_per_sec_,
|
||||
/* max_trash_db_ratio= */ 1.1));
|
||||
/* max_trash_db_ratio= */ 1.1, 128 * 1024));
|
||||
delete_scheduler_ = sst_file_mgr_->delete_scheduler();
|
||||
}
|
||||
|
||||
@@ -436,6 +436,34 @@ TEST_F(DeleteSchedulerTest, StartBGEmptyTrashMultipleTimes) {
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
}
|
||||
|
||||
TEST_F(DeleteSchedulerTest, DeletePartialFile) {
|
||||
int bg_delete_file = 0;
|
||||
int bg_fsync = 0;
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DeleteScheduler::DeleteTrashFile:DeleteFile",
|
||||
[&](void*) { bg_delete_file++; });
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DeleteScheduler::DeleteTrashFile:Fsync", [&](void*) { bg_fsync++; });
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
rate_bytes_per_sec_ = 1024 * 1024; // 1 MB / sec
|
||||
NewDeleteScheduler();
|
||||
|
||||
// Should delete in 4 batch
|
||||
ASSERT_OK(delete_scheduler_->DeleteFile(NewDummyFile("data_1", 500 * 1024)));
|
||||
ASSERT_OK(delete_scheduler_->DeleteFile(NewDummyFile("data_2", 100 * 1024)));
|
||||
// Should delete in 2 batch
|
||||
ASSERT_OK(delete_scheduler_->DeleteFile(NewDummyFile("data_2", 200 * 1024)));
|
||||
|
||||
delete_scheduler_->WaitForEmptyTrash();
|
||||
|
||||
auto bg_errors = delete_scheduler_->GetBackgroundErrors();
|
||||
ASSERT_EQ(bg_errors.size(), 0);
|
||||
ASSERT_EQ(7, bg_delete_file);
|
||||
ASSERT_EQ(4, bg_fsync);
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
}
|
||||
|
||||
// 1- Create a DeleteScheduler with very slow rate limit (1 Byte / sec)
|
||||
// 2- Delete 100 files using DeleteScheduler
|
||||
// 3- Delete the DeleteScheduler (call the destructor while queue is not empty)
|
||||
@@ -613,7 +641,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
#else
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
printf("DeleteScheduler is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ namespace rocksdb {
|
||||
#ifndef ROCKSDB_LITE
|
||||
SstFileManagerImpl::SstFileManagerImpl(Env* env, std::shared_ptr<Logger> logger,
|
||||
int64_t rate_bytes_per_sec,
|
||||
double max_trash_db_ratio)
|
||||
double max_trash_db_ratio,
|
||||
uint64_t bytes_max_delete_chunk)
|
||||
: env_(env),
|
||||
logger_(logger),
|
||||
total_files_size_(0),
|
||||
@@ -26,7 +27,7 @@ SstFileManagerImpl::SstFileManagerImpl(Env* env, std::shared_ptr<Logger> logger,
|
||||
cur_compactions_reserved_size_(0),
|
||||
max_allowed_space_(0),
|
||||
delete_scheduler_(env, rate_bytes_per_sec, logger.get(), this,
|
||||
max_trash_db_ratio) {}
|
||||
max_trash_db_ratio, bytes_max_delete_chunk) {}
|
||||
|
||||
SstFileManagerImpl::~SstFileManagerImpl() {}
|
||||
|
||||
@@ -196,10 +197,11 @@ SstFileManager* NewSstFileManager(Env* env, std::shared_ptr<Logger> info_log,
|
||||
std::string trash_dir,
|
||||
int64_t rate_bytes_per_sec,
|
||||
bool delete_existing_trash, Status* status,
|
||||
double max_trash_db_ratio) {
|
||||
double max_trash_db_ratio,
|
||||
uint64_t bytes_max_delete_chunk) {
|
||||
SstFileManagerImpl* res =
|
||||
new SstFileManagerImpl(env, info_log, rate_bytes_per_sec,
|
||||
max_trash_db_ratio);
|
||||
max_trash_db_ratio, bytes_max_delete_chunk);
|
||||
|
||||
// trash_dir is deprecated and not needed anymore, but if user passed it
|
||||
// we will still remove files in it.
|
||||
@@ -236,7 +238,8 @@ SstFileManager* NewSstFileManager(Env* env, std::shared_ptr<Logger> info_log,
|
||||
std::string trash_dir,
|
||||
int64_t rate_bytes_per_sec,
|
||||
bool delete_existing_trash, Status* status,
|
||||
double max_trash_db_ratio) {
|
||||
double max_trash_db_ratio,
|
||||
uint64_t bytes_max_delete_chunk) {
|
||||
if (status) {
|
||||
*status =
|
||||
Status::NotSupported("SstFileManager is not supported in ROCKSDB_LITE");
|
||||
|
||||
@@ -27,7 +27,8 @@ class SstFileManagerImpl : public SstFileManager {
|
||||
public:
|
||||
explicit SstFileManagerImpl(Env* env, std::shared_ptr<Logger> logger,
|
||||
int64_t rate_bytes_per_sec,
|
||||
double max_trash_db_ratio);
|
||||
double max_trash_db_ratio,
|
||||
uint64_t bytes_max_delete_chunk);
|
||||
|
||||
~SstFileManagerImpl();
|
||||
|
||||
|
||||
+24
-126
@@ -4,10 +4,7 @@
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "util/sync_point.h"
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include "port/port.h"
|
||||
#include "util/random.h"
|
||||
#include "util/sync_point_impl.h"
|
||||
|
||||
int rocksdb_kill_odds = 0;
|
||||
std::vector<std::string> rocksdb_kill_prefix_blacklist;
|
||||
@@ -15,156 +12,57 @@ std::vector<std::string> rocksdb_kill_prefix_blacklist;
|
||||
#ifndef NDEBUG
|
||||
namespace rocksdb {
|
||||
|
||||
void TestKillRandom(std::string kill_point, int odds,
|
||||
const std::string& srcfile, int srcline) {
|
||||
for (auto& p : rocksdb_kill_prefix_blacklist) {
|
||||
if (kill_point.substr(0, p.length()) == p) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert(odds > 0);
|
||||
if (odds % 7 == 0) {
|
||||
// class Random uses multiplier 16807, which is 7^5. If odds are
|
||||
// multiplier of 7, there might be limited values generated.
|
||||
odds++;
|
||||
}
|
||||
auto* r = Random::GetTLSInstance();
|
||||
bool crash = r->OneIn(odds);
|
||||
if (crash) {
|
||||
port::Crash(srcfile, srcline);
|
||||
}
|
||||
}
|
||||
|
||||
SyncPoint* SyncPoint::GetInstance() {
|
||||
static SyncPoint sync_point;
|
||||
return &sync_point;
|
||||
}
|
||||
|
||||
SyncPoint::SyncPoint() :
|
||||
impl_(new Data) {
|
||||
}
|
||||
|
||||
SyncPoint:: ~SyncPoint() {
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void SyncPoint::LoadDependency(const std::vector<SyncPointPair>& dependencies) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
successors_.clear();
|
||||
predecessors_.clear();
|
||||
cleared_points_.clear();
|
||||
for (const auto& dependency : dependencies) {
|
||||
successors_[dependency.predecessor].push_back(dependency.successor);
|
||||
predecessors_[dependency.successor].push_back(dependency.predecessor);
|
||||
}
|
||||
cv_.notify_all();
|
||||
impl_->LoadDependency(dependencies);
|
||||
}
|
||||
|
||||
void SyncPoint::LoadDependencyAndMarkers(
|
||||
const std::vector<SyncPointPair>& dependencies,
|
||||
const std::vector<SyncPointPair>& markers) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
successors_.clear();
|
||||
predecessors_.clear();
|
||||
cleared_points_.clear();
|
||||
markers_.clear();
|
||||
marked_thread_id_.clear();
|
||||
for (const auto& dependency : dependencies) {
|
||||
successors_[dependency.predecessor].push_back(dependency.successor);
|
||||
predecessors_[dependency.successor].push_back(dependency.predecessor);
|
||||
}
|
||||
for (const auto& marker : markers) {
|
||||
successors_[marker.predecessor].push_back(marker.successor);
|
||||
predecessors_[marker.successor].push_back(marker.predecessor);
|
||||
markers_[marker.predecessor].push_back(marker.successor);
|
||||
}
|
||||
cv_.notify_all();
|
||||
const std::vector<SyncPointPair>& dependencies,
|
||||
const std::vector<SyncPointPair>& markers) {
|
||||
impl_->LoadDependencyAndMarkers(dependencies, markers);
|
||||
}
|
||||
|
||||
bool SyncPoint::PredecessorsAllCleared(const std::string& point) {
|
||||
for (const auto& pred : predecessors_[point]) {
|
||||
if (cleared_points_.count(pred) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
void SyncPoint::SetCallBack(const std::string& point,
|
||||
const std::function<void(void*)>& callback) {
|
||||
impl_->SetCallBack(point, callback);
|
||||
}
|
||||
|
||||
void SyncPoint::SetCallBack(const std::string point,
|
||||
std::function<void(void*)> callback) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
callbacks_[point] = callback;
|
||||
}
|
||||
|
||||
void SyncPoint::ClearCallBack(const std::string point) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (num_callbacks_running_ > 0) {
|
||||
cv_.wait(lock);
|
||||
}
|
||||
callbacks_.erase(point);
|
||||
void SyncPoint::ClearCallBack(const std::string& point) {
|
||||
impl_->ClearCallBack(point);
|
||||
}
|
||||
|
||||
void SyncPoint::ClearAllCallBacks() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (num_callbacks_running_ > 0) {
|
||||
cv_.wait(lock);
|
||||
}
|
||||
callbacks_.clear();
|
||||
impl_->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
void SyncPoint::EnableProcessing() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
enabled_ = true;
|
||||
impl_->EnableProcessing();
|
||||
}
|
||||
|
||||
void SyncPoint::DisableProcessing() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
enabled_ = false;
|
||||
impl_->DisableProcessing();
|
||||
}
|
||||
|
||||
void SyncPoint::ClearTrace() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cleared_points_.clear();
|
||||
}
|
||||
|
||||
bool SyncPoint::DisabledByMarker(const std::string& point,
|
||||
std::thread::id thread_id) {
|
||||
auto marked_point_iter = marked_thread_id_.find(point);
|
||||
return marked_point_iter != marked_thread_id_.end() &&
|
||||
thread_id != marked_point_iter->second;
|
||||
impl_->ClearTrace();
|
||||
}
|
||||
|
||||
void SyncPoint::Process(const std::string& point, void* cb_arg) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto thread_id = std::this_thread::get_id();
|
||||
|
||||
auto marker_iter = markers_.find(point);
|
||||
if (marker_iter != markers_.end()) {
|
||||
for (auto marked_point : marker_iter->second) {
|
||||
marked_thread_id_.insert(std::make_pair(marked_point, thread_id));
|
||||
}
|
||||
}
|
||||
|
||||
if (DisabledByMarker(point, thread_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!PredecessorsAllCleared(point)) {
|
||||
cv_.wait(lock);
|
||||
if (DisabledByMarker(point, thread_id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto callback_pair = callbacks_.find(point);
|
||||
if (callback_pair != callbacks_.end()) {
|
||||
num_callbacks_running_++;
|
||||
mutex_.unlock();
|
||||
callback_pair->second(cb_arg);
|
||||
mutex_.lock();
|
||||
num_callbacks_running_--;
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
cleared_points_.insert(point);
|
||||
cv_.notify_all();
|
||||
impl_->Process(point, cb_arg);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
#endif // NDEBUG
|
||||
+15
-24
@@ -5,13 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
// This is only set from db_stress.cc and for testing only.
|
||||
@@ -65,6 +62,10 @@ class SyncPoint {
|
||||
public:
|
||||
static SyncPoint* GetInstance();
|
||||
|
||||
SyncPoint(const SyncPoint&) = delete;
|
||||
SyncPoint& operator=(const SyncPoint&) = delete;
|
||||
~SyncPoint();
|
||||
|
||||
struct SyncPointPair {
|
||||
std::string predecessor;
|
||||
std::string successor;
|
||||
@@ -81,15 +82,14 @@ class SyncPoint {
|
||||
void LoadDependencyAndMarkers(const std::vector<SyncPointPair>& dependencies,
|
||||
const std::vector<SyncPointPair>& markers);
|
||||
|
||||
// Set up a call back function in sync point.
|
||||
// The argument to the callback is passed through from
|
||||
// TEST_SYNC_POINT_CALLBACK(); nullptr if TEST_SYNC_POINT or
|
||||
// TEST_IDX_SYNC_POINT was used.
|
||||
void SetCallBack(const std::string point,
|
||||
std::function<void(void*)> callback);
|
||||
void SetCallBack(const std::string& point,
|
||||
const std::function<void(void*)>& callback);
|
||||
|
||||
// Clear callback function by point
|
||||
void ClearCallBack(const std::string point);
|
||||
void ClearCallBack(const std::string& point);
|
||||
|
||||
// Clear all call back functions.
|
||||
void ClearAllCallBacks();
|
||||
@@ -111,29 +111,20 @@ class SyncPoint {
|
||||
// TODO: it might be useful to provide a function that blocks until all
|
||||
// sync points are cleared.
|
||||
|
||||
// We want this to be public so we can
|
||||
// subclass the implementation
|
||||
struct Data;
|
||||
|
||||
private:
|
||||
bool PredecessorsAllCleared(const std::string& point);
|
||||
bool DisabledByMarker(const std::string& point, std::thread::id thread_id);
|
||||
|
||||
// successor/predecessor map loaded from LoadDependency
|
||||
std::unordered_map<std::string, std::vector<std::string>> successors_;
|
||||
std::unordered_map<std::string, std::vector<std::string>> predecessors_;
|
||||
std::unordered_map<std::string, std::function<void(void*)> > callbacks_;
|
||||
std::unordered_map<std::string, std::vector<std::string> > markers_;
|
||||
std::unordered_map<std::string, std::thread::id> marked_thread_id_;
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
// sync points that have been passed through
|
||||
std::unordered_set<std::string> cleared_points_;
|
||||
bool enabled_ = false;
|
||||
int num_callbacks_running_ = 0;
|
||||
// Singleton
|
||||
SyncPoint();
|
||||
Data* impl_;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
// Use TEST_SYNC_POINT to specify sync points inside code base.
|
||||
// Sync points can have happens-after dependency on other sync points,
|
||||
// Sync points can have happens-after depedency on other sync points,
|
||||
// configured at runtime via SyncPoint::LoadDependency. This could be
|
||||
// utilized to re-produce race conditions between threads.
|
||||
// See TransactionLogIteratorRace in db_test.cc for an example use case.
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// 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).
|
||||
|
||||
#include "util/sync_point_impl.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
namespace rocksdb {
|
||||
|
||||
void TestKillRandom(std::string kill_point, int odds,
|
||||
const std::string& srcfile, int srcline) {
|
||||
for (auto& p : rocksdb_kill_prefix_blacklist) {
|
||||
if (kill_point.substr(0, p.length()) == p) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert(odds > 0);
|
||||
if (odds % 7 == 0) {
|
||||
// class Random uses multiplier 16807, which is 7^5. If odds are
|
||||
// multiplier of 7, there might be limited values generated.
|
||||
odds++;
|
||||
}
|
||||
auto* r = Random::GetTLSInstance();
|
||||
bool crash = r->OneIn(odds);
|
||||
if (crash) {
|
||||
port::Crash(srcfile, srcline);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SyncPoint::Data::LoadDependency(const std::vector<SyncPointPair>& dependencies) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
successors_.clear();
|
||||
predecessors_.clear();
|
||||
cleared_points_.clear();
|
||||
for (const auto& dependency : dependencies) {
|
||||
successors_[dependency.predecessor].push_back(dependency.successor);
|
||||
predecessors_[dependency.successor].push_back(dependency.predecessor);
|
||||
}
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void SyncPoint::Data::LoadDependencyAndMarkers(
|
||||
const std::vector<SyncPointPair>& dependencies,
|
||||
const std::vector<SyncPointPair>& markers) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
successors_.clear();
|
||||
predecessors_.clear();
|
||||
cleared_points_.clear();
|
||||
markers_.clear();
|
||||
marked_thread_id_.clear();
|
||||
for (const auto& dependency : dependencies) {
|
||||
successors_[dependency.predecessor].push_back(dependency.successor);
|
||||
predecessors_[dependency.successor].push_back(dependency.predecessor);
|
||||
}
|
||||
for (const auto& marker : markers) {
|
||||
successors_[marker.predecessor].push_back(marker.successor);
|
||||
predecessors_[marker.successor].push_back(marker.predecessor);
|
||||
markers_[marker.predecessor].push_back(marker.successor);
|
||||
}
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
bool SyncPoint::Data::PredecessorsAllCleared(const std::string& point) {
|
||||
for (const auto& pred : predecessors_[point]) {
|
||||
if (cleared_points_.count(pred) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SyncPoint::Data::ClearCallBack(const std::string& point) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (num_callbacks_running_ > 0) {
|
||||
cv_.wait(lock);
|
||||
}
|
||||
callbacks_.erase(point);
|
||||
}
|
||||
|
||||
void SyncPoint::Data::ClearAllCallBacks() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (num_callbacks_running_ > 0) {
|
||||
cv_.wait(lock);
|
||||
}
|
||||
callbacks_.clear();
|
||||
}
|
||||
|
||||
void SyncPoint::Data::Process(const std::string& point, void* cb_arg) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto thread_id = std::this_thread::get_id();
|
||||
|
||||
auto marker_iter = markers_.find(point);
|
||||
if (marker_iter != markers_.end()) {
|
||||
for (auto& marked_point : marker_iter->second) {
|
||||
marked_thread_id_.emplace(marked_point, thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (DisabledByMarker(point, thread_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!PredecessorsAllCleared(point)) {
|
||||
cv_.wait(lock);
|
||||
if (DisabledByMarker(point, thread_id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto callback_pair = callbacks_.find(point);
|
||||
if (callback_pair != callbacks_.end()) {
|
||||
num_callbacks_running_++;
|
||||
mutex_.unlock();
|
||||
callback_pair->second(cb_arg);
|
||||
mutex_.lock();
|
||||
num_callbacks_running_--;
|
||||
}
|
||||
cleared_points_.insert(point);
|
||||
cv_.notify_all();
|
||||
}
|
||||
} // rocksdb
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// 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).
|
||||
|
||||
#include "util/sync_point.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "port/port.h"
|
||||
#include "util/random.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDEBUG
|
||||
namespace rocksdb {
|
||||
struct SyncPoint::Data {
|
||||
// Enable proper deletion by subclasses
|
||||
virtual ~Data() {}
|
||||
// successor/predecessor map loaded from LoadDependency
|
||||
std::unordered_map<std::string, std::vector<std::string>> successors_;
|
||||
std::unordered_map<std::string, std::vector<std::string>> predecessors_;
|
||||
std::unordered_map<std::string, std::function<void(void*)> > callbacks_;
|
||||
std::unordered_map<std::string, std::vector<std::string> > markers_;
|
||||
std::unordered_map<std::string, std::thread::id> marked_thread_id_;
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
// sync points that have been passed through
|
||||
std::unordered_set<std::string> cleared_points_;
|
||||
bool enabled_ = false;
|
||||
int num_callbacks_running_ = 0;
|
||||
|
||||
void LoadDependency(const std::vector<SyncPointPair>& dependencies);
|
||||
void LoadDependencyAndMarkers(const std::vector<SyncPointPair>& dependencies,
|
||||
const std::vector<SyncPointPair>& markers);
|
||||
bool PredecessorsAllCleared(const std::string& point);
|
||||
void SetCallBack(const std::string& point,
|
||||
const std::function<void(void*)>& callback) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
callbacks_[point] = callback;
|
||||
}
|
||||
|
||||
void ClearCallBack(const std::string& point);
|
||||
void ClearAllCallBacks();
|
||||
void EnableProcessing() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
enabled_ = true;
|
||||
}
|
||||
void DisableProcessing() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
enabled_ = false;
|
||||
}
|
||||
void ClearTrace() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
cleared_points_.clear();
|
||||
}
|
||||
bool DisabledByMarker(const std::string& point,
|
||||
std::thread::id thread_id) {
|
||||
auto marked_point_iter = marked_thread_id_.find(point);
|
||||
return marked_point_iter != marked_thread_id_.end() &&
|
||||
thread_id != marked_point_iter->second;
|
||||
}
|
||||
void Process(const std::string& point, void* cb_arg);
|
||||
};
|
||||
}
|
||||
#endif // NDEBUG
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#ifdef OS_LINUX
|
||||
# include <sys/syscall.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
@@ -54,8 +53,6 @@ struct ThreadPoolImpl::Impl {
|
||||
|
||||
void LowerIOPriority();
|
||||
|
||||
void LowerCPUPriority();
|
||||
|
||||
void WakeUpAllThreads() {
|
||||
bgsignal_.notify_all();
|
||||
}
|
||||
@@ -100,7 +97,6 @@ private:
|
||||
static void* BGThreadWrapper(void* arg);
|
||||
|
||||
bool low_io_priority_;
|
||||
bool low_cpu_priority_;
|
||||
Env::Priority priority_;
|
||||
Env* env_;
|
||||
|
||||
@@ -129,7 +125,6 @@ inline
|
||||
ThreadPoolImpl::Impl::Impl()
|
||||
:
|
||||
low_io_priority_(false),
|
||||
low_cpu_priority_(false),
|
||||
priority_(Env::LOW),
|
||||
env_(nullptr),
|
||||
total_threads_limit_(0),
|
||||
@@ -176,16 +171,9 @@ void ThreadPoolImpl::Impl::LowerIOPriority() {
|
||||
low_io_priority_ = true;
|
||||
}
|
||||
|
||||
inline
|
||||
void ThreadPoolImpl::Impl::LowerCPUPriority() {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
low_cpu_priority_ = true;
|
||||
}
|
||||
|
||||
void ThreadPoolImpl::Impl::BGThread(size_t thread_id) {
|
||||
bool low_io_priority = false;
|
||||
bool low_cpu_priority = false;
|
||||
|
||||
while (true) {
|
||||
// Wait until there is an item that is ready to run
|
||||
std::unique_lock<std::mutex> lock(mu_);
|
||||
@@ -225,20 +213,9 @@ void ThreadPoolImpl::Impl::BGThread(size_t thread_id) {
|
||||
std::memory_order_relaxed);
|
||||
|
||||
bool decrease_io_priority = (low_io_priority != low_io_priority_);
|
||||
bool decrease_cpu_priority = (low_cpu_priority != low_cpu_priority_);
|
||||
lock.unlock();
|
||||
|
||||
#ifdef OS_LINUX
|
||||
if (decrease_cpu_priority) {
|
||||
setpriority(
|
||||
PRIO_PROCESS,
|
||||
// Current thread.
|
||||
0,
|
||||
// Lowest priority possible.
|
||||
19);
|
||||
low_cpu_priority = true;
|
||||
}
|
||||
|
||||
if (decrease_io_priority) {
|
||||
#define IOPRIO_CLASS_SHIFT (13)
|
||||
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
|
||||
@@ -259,7 +236,6 @@ void ThreadPoolImpl::Impl::BGThread(size_t thread_id) {
|
||||
}
|
||||
#else
|
||||
(void)decrease_io_priority; // avoid 'unused variable' error
|
||||
(void)decrease_cpu_priority;
|
||||
#endif
|
||||
func();
|
||||
}
|
||||
@@ -445,10 +421,6 @@ void ThreadPoolImpl::LowerIOPriority() {
|
||||
impl_->LowerIOPriority();
|
||||
}
|
||||
|
||||
void ThreadPoolImpl::LowerCPUPriority() {
|
||||
impl_->LowerCPUPriority();
|
||||
}
|
||||
|
||||
void ThreadPoolImpl::IncBackgroundThreadsIfNeeded(int num) {
|
||||
impl_->SetBackgroundThreadsInternal(num, false);
|
||||
}
|
||||
|
||||
@@ -46,14 +46,10 @@ class ThreadPoolImpl : public ThreadPool {
|
||||
// start yet
|
||||
void WaitForJobsAndJoinAllThreads() override;
|
||||
|
||||
// Make threads to run at a lower kernel IO priority
|
||||
// Make threads to run at a lower kernel priority
|
||||
// Currently only has effect on Linux
|
||||
void LowerIOPriority();
|
||||
|
||||
// Make threads to run at a lower kernel CPU priority
|
||||
// Currently only has effect on Linux
|
||||
void LowerCPUPriority();
|
||||
|
||||
// Ensure there is at aleast num threads in the pool
|
||||
// but do not kill threads if there are more
|
||||
void IncBackgroundThreadsIfNeeded(int num);
|
||||
|
||||
@@ -747,19 +747,6 @@ Status BackupEngineImpl::CreateNewBackupWithMetadata(
|
||||
BackupID new_backup_id = latest_backup_id_ + 1;
|
||||
|
||||
assert(backups_.find(new_backup_id) == backups_.end());
|
||||
|
||||
auto private_dir = GetAbsolutePath(GetPrivateFileRel(new_backup_id));
|
||||
Status s = backup_env_->FileExists(private_dir);
|
||||
if (s.ok()) {
|
||||
// maybe last backup failed and left partial state behind, clean it up.
|
||||
// need to do this before updating backups_ such that a private dir
|
||||
// named after new_backup_id will be cleaned up
|
||||
s = GarbageCollect();
|
||||
} else if (s.IsNotFound()) {
|
||||
// normal case, the new backup's private dir doesn't exist yet
|
||||
s = Status::OK();
|
||||
}
|
||||
|
||||
auto ret = backups_.insert(std::make_pair(
|
||||
new_backup_id, unique_ptr<BackupMeta>(new BackupMeta(
|
||||
GetBackupMetaFile(new_backup_id, false /* tmp */),
|
||||
@@ -770,13 +757,23 @@ Status BackupEngineImpl::CreateNewBackupWithMetadata(
|
||||
new_backup->RecordTimestamp();
|
||||
new_backup->SetAppMetadata(app_metadata);
|
||||
|
||||
auto start_backup = backup_env_->NowMicros();
|
||||
auto start_backup = backup_env_-> NowMicros();
|
||||
|
||||
ROCKS_LOG_INFO(options_.info_log,
|
||||
"Started the backup process -- creating backup %u",
|
||||
new_backup_id);
|
||||
|
||||
auto private_tmp_dir = GetAbsolutePath(GetPrivateFileRel(new_backup_id, true));
|
||||
Status s = backup_env_->FileExists(private_tmp_dir);
|
||||
if (s.ok()) {
|
||||
s = backup_env_->CreateDir(private_dir);
|
||||
// maybe last backup failed and left partial state behind, clean it up
|
||||
s = GarbageCollect();
|
||||
} else if (s.IsNotFound()) {
|
||||
// normal case, the new backup's private dir doesn't exist yet
|
||||
s = Status::OK();
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = backup_env_->CreateDir(private_tmp_dir);
|
||||
}
|
||||
|
||||
RateLimiter* rate_limiter = options_.backup_rate_limiter.get();
|
||||
@@ -862,6 +859,18 @@ Status BackupEngineImpl::CreateNewBackupWithMetadata(
|
||||
// we copied all the files, enable file deletions
|
||||
db->EnableFileDeletions(false);
|
||||
|
||||
if (s.ok()) {
|
||||
// move tmp private backup to real backup folder
|
||||
ROCKS_LOG_INFO(
|
||||
options_.info_log,
|
||||
"Moving tmp backup directory to the real one: %s -> %s\n",
|
||||
GetAbsolutePath(GetPrivateFileRel(new_backup_id, true)).c_str(),
|
||||
GetAbsolutePath(GetPrivateFileRel(new_backup_id, false)).c_str());
|
||||
s = backup_env_->RenameFile(
|
||||
GetAbsolutePath(GetPrivateFileRel(new_backup_id, true)), // tmp
|
||||
GetAbsolutePath(GetPrivateFileRel(new_backup_id, false)));
|
||||
}
|
||||
|
||||
auto backup_time = backup_env_->NowMicros() - start_backup;
|
||||
|
||||
if (s.ok()) {
|
||||
@@ -1298,33 +1307,22 @@ Status BackupEngineImpl::AddBackupFileWorkItem(
|
||||
dst_relative_tmp = GetSharedFileRel(dst_relative, true);
|
||||
dst_relative = GetSharedFileRel(dst_relative, false);
|
||||
} else {
|
||||
dst_relative_tmp = GetPrivateFileRel(backup_id, true, dst_relative);
|
||||
dst_relative = GetPrivateFileRel(backup_id, false, dst_relative);
|
||||
}
|
||||
|
||||
// We copy into `temp_dest_path` and, once finished, rename it to
|
||||
// `final_dest_path`. This allows files to atomically appear at
|
||||
// `final_dest_path`. We can copy directly to the final path when atomicity
|
||||
// is unnecessary, like for files in private backup directories.
|
||||
const std::string* copy_dest_path;
|
||||
std::string temp_dest_path;
|
||||
std::string final_dest_path = GetAbsolutePath(dst_relative);
|
||||
if (!dst_relative_tmp.empty()) {
|
||||
temp_dest_path = GetAbsolutePath(dst_relative_tmp);
|
||||
copy_dest_path = &temp_dest_path;
|
||||
} else {
|
||||
copy_dest_path = &final_dest_path;
|
||||
}
|
||||
std::string dst_path = GetAbsolutePath(dst_relative);
|
||||
std::string dst_path_tmp = GetAbsolutePath(dst_relative_tmp);
|
||||
|
||||
// if it's shared, we also need to check if it exists -- if it does, no need
|
||||
// to copy it again.
|
||||
bool need_to_copy = true;
|
||||
// true if final_dest_path is the same path as another live file
|
||||
// true if dst_path is the same path as another live file
|
||||
const bool same_path =
|
||||
live_dst_paths.find(final_dest_path) != live_dst_paths.end();
|
||||
live_dst_paths.find(dst_path) != live_dst_paths.end();
|
||||
|
||||
bool file_exists = false;
|
||||
if (shared && !same_path) {
|
||||
Status exist = backup_env_->FileExists(final_dest_path);
|
||||
Status exist = backup_env_->FileExists(dst_path);
|
||||
if (exist.ok()) {
|
||||
file_exists = true;
|
||||
} else if (exist.IsNotFound()) {
|
||||
@@ -1353,7 +1351,7 @@ Status BackupEngineImpl::AddBackupFileWorkItem(
|
||||
"overwrite the file.",
|
||||
fname.c_str());
|
||||
need_to_copy = true;
|
||||
backup_env_->DeleteFile(final_dest_path);
|
||||
backup_env_->DeleteFile(dst_path);
|
||||
} else {
|
||||
// the file is present and referenced by a backup
|
||||
ROCKS_LOG_INFO(options_.info_log,
|
||||
@@ -1362,25 +1360,25 @@ Status BackupEngineImpl::AddBackupFileWorkItem(
|
||||
&checksum_value);
|
||||
}
|
||||
}
|
||||
live_dst_paths.insert(final_dest_path);
|
||||
live_dst_paths.insert(dst_path);
|
||||
|
||||
if (!contents.empty() || need_to_copy) {
|
||||
ROCKS_LOG_INFO(options_.info_log, "Copying %s to %s", fname.c_str(),
|
||||
copy_dest_path->c_str());
|
||||
dst_path_tmp.c_str());
|
||||
CopyOrCreateWorkItem copy_or_create_work_item(
|
||||
src_dir.empty() ? "" : src_dir + fname, *copy_dest_path, contents,
|
||||
db_env_, backup_env_, options_.sync, rate_limiter, size_limit,
|
||||
src_dir.empty() ? "" : src_dir + fname, dst_path_tmp, contents, db_env_,
|
||||
backup_env_, options_.sync, rate_limiter, size_limit,
|
||||
progress_callback);
|
||||
BackupAfterCopyOrCreateWorkItem after_copy_or_create_work_item(
|
||||
copy_or_create_work_item.result.get_future(), shared, need_to_copy,
|
||||
backup_env_, temp_dest_path, final_dest_path, dst_relative);
|
||||
backup_env_, dst_path_tmp, dst_path, dst_relative);
|
||||
files_to_copy_or_create_.write(std::move(copy_or_create_work_item));
|
||||
backup_items_to_finish.push_back(std::move(after_copy_or_create_work_item));
|
||||
} else {
|
||||
std::promise<CopyOrCreateResult> promise_result;
|
||||
BackupAfterCopyOrCreateWorkItem after_copy_or_create_work_item(
|
||||
promise_result.get_future(), shared, need_to_copy, backup_env_,
|
||||
temp_dest_path, final_dest_path, dst_relative);
|
||||
dst_path_tmp, dst_path, dst_relative);
|
||||
backup_items_to_finish.push_back(std::move(after_copy_or_create_work_item));
|
||||
CopyOrCreateResult result;
|
||||
result.status = s;
|
||||
@@ -1535,7 +1533,7 @@ Status BackupEngineImpl::GarbageCollect() {
|
||||
}
|
||||
// here we have to delete the dir and all its children
|
||||
std::string full_private_path =
|
||||
GetAbsolutePath(GetPrivateFileRel(backup_id));
|
||||
GetAbsolutePath(GetPrivateFileRel(backup_id, tmp_dir));
|
||||
std::vector<std::string> subchildren;
|
||||
backup_env_->GetChildren(full_private_path, &subchildren);
|
||||
for (auto& subchild : subchildren) {
|
||||
@@ -1735,25 +1733,51 @@ Status BackupEngineImpl::BackupMeta::StoreToFile(bool sync) {
|
||||
if (!app_metadata_.empty()) {
|
||||
std::string hex_encoded_metadata =
|
||||
Slice(app_metadata_).ToString(/* hex */ true);
|
||||
|
||||
// +1 to accomodate newline character
|
||||
size_t hex_meta_strlen = kMetaDataPrefix.ToString().length() + hex_encoded_metadata.length() + 1;
|
||||
if (hex_meta_strlen >= buf_size) {
|
||||
return Status::Corruption("Buffer too small to fit backup metadata");
|
||||
}
|
||||
else if (len + hex_meta_strlen >= buf_size) {
|
||||
backup_meta_file->Append(Slice(buf.get(), len));
|
||||
buf.reset();
|
||||
unique_ptr<char[]> new_reset_buf(new char[max_backup_meta_file_size_]);
|
||||
buf.swap(new_reset_buf);
|
||||
len = 0;
|
||||
}
|
||||
len += snprintf(buf.get() + len, buf_size - len, "%s%s\n",
|
||||
kMetaDataPrefix.ToString().c_str(),
|
||||
hex_encoded_metadata.c_str());
|
||||
if (len >= buf_size) {
|
||||
return Status::Corruption("Buffer too small to fit backup metadata");
|
||||
}
|
||||
}
|
||||
len += snprintf(buf.get() + len, buf_size - len, "%" ROCKSDB_PRIszt "\n",
|
||||
files_.size());
|
||||
if (len >= buf_size) {
|
||||
return Status::Corruption("Buffer too small to fit backup metadata");
|
||||
|
||||
char writelen_temp[19];
|
||||
if (len + sprintf(writelen_temp, "%" ROCKSDB_PRIszt "\n", files_.size()) >= buf_size) {
|
||||
backup_meta_file->Append(Slice(buf.get(), len));
|
||||
buf.reset();
|
||||
unique_ptr<char[]> new_reset_buf(new char[max_backup_meta_file_size_]);
|
||||
buf.swap(new_reset_buf);
|
||||
len = 0;
|
||||
}
|
||||
{
|
||||
const char *const_write = writelen_temp;
|
||||
len += snprintf(buf.get() + len, buf_size - len, "%s", const_write);
|
||||
}
|
||||
|
||||
for (const auto& file : files_) {
|
||||
// use crc32 for now, switch to something else if needed
|
||||
len += snprintf(buf.get() + len, buf_size - len, "%s crc32 %u\n",
|
||||
file->filename.c_str(), file->checksum_value);
|
||||
if (len >= buf_size) {
|
||||
return Status::Corruption("Buffer too small to fit backup metadata");
|
||||
|
||||
size_t newlen = len + file->filename.length() + sprintf(writelen_temp, " crc32 %u\n", file->checksum_value);
|
||||
const char *const_write = writelen_temp;
|
||||
if (newlen >= buf_size) {
|
||||
backup_meta_file->Append(Slice(buf.get(), len));
|
||||
buf.reset();
|
||||
unique_ptr<char[]> new_reset_buf(new char[max_backup_meta_file_size_]);
|
||||
buf.swap(new_reset_buf);
|
||||
len = 0;
|
||||
}
|
||||
len += snprintf(buf.get() + len, buf_size - len, "%s%s",
|
||||
file->filename.c_str(), const_write);
|
||||
}
|
||||
|
||||
s = backup_meta_file->Append(Slice(buf.get(), len));
|
||||
|
||||
@@ -811,8 +811,9 @@ TEST_F(BackupableDBTest, NoDoubleCopy) {
|
||||
test_db_env_->SetFilenamesForMockedAttrs(dummy_db_->live_files_);
|
||||
ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
|
||||
std::vector<std::string> should_have_written = {
|
||||
"/shared/.00010.sst.tmp", "/shared/.00011.sst.tmp", "/private/1/CURRENT",
|
||||
"/private/1/MANIFEST-01", "/private/1/00011.log", "/meta/.1.tmp"};
|
||||
"/shared/.00010.sst.tmp", "/shared/.00011.sst.tmp",
|
||||
"/private/1.tmp/CURRENT", "/private/1.tmp/MANIFEST-01",
|
||||
"/private/1.tmp/00011.log", "/meta/.1.tmp"};
|
||||
AppendPath(backupdir_, should_have_written);
|
||||
test_backup_env_->AssertWrittenFiles(should_have_written);
|
||||
|
||||
@@ -828,9 +829,9 @@ TEST_F(BackupableDBTest, NoDoubleCopy) {
|
||||
ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
|
||||
// should not open 00010.sst - it's already there
|
||||
|
||||
should_have_written = {"/shared/.00015.sst.tmp", "/private/2/CURRENT",
|
||||
"/private/2/MANIFEST-01", "/private/2/00011.log",
|
||||
"/meta/.2.tmp"};
|
||||
should_have_written = {"/shared/.00015.sst.tmp", "/private/2.tmp/CURRENT",
|
||||
"/private/2.tmp/MANIFEST-01",
|
||||
"/private/2.tmp/00011.log", "/meta/.2.tmp"};
|
||||
AppendPath(backupdir_, should_have_written);
|
||||
test_backup_env_->AssertWrittenFiles(should_have_written);
|
||||
|
||||
@@ -975,7 +976,7 @@ TEST_F(BackupableDBTest, InterruptCreationTest) {
|
||||
backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)).ok());
|
||||
CloseDBAndBackupEngine();
|
||||
// should also fail cleanup so the tmp directory stays behind
|
||||
ASSERT_OK(backup_chroot_env_->FileExists(backupdir_ + "/private/1/"));
|
||||
ASSERT_OK(backup_chroot_env_->FileExists(backupdir_ + "/private/1.tmp/"));
|
||||
|
||||
OpenDBAndBackupEngine(false /* destroy_old_data */);
|
||||
test_backup_env_->SetLimitWrittenFiles(1000000);
|
||||
@@ -1170,7 +1171,7 @@ TEST_F(BackupableDBTest, DeleteTmpFiles) {
|
||||
shared_tmp += "/shared";
|
||||
}
|
||||
shared_tmp += "/.00006.sst.tmp";
|
||||
std::string private_tmp_dir = backupdir_ + "/private/10";
|
||||
std::string private_tmp_dir = backupdir_ + "/private/10.tmp";
|
||||
std::string private_tmp_file = private_tmp_dir + "/00003.sst";
|
||||
file_manager_->WriteToFile(shared_tmp, "tmp");
|
||||
file_manager_->CreateDir(private_tmp_dir);
|
||||
@@ -1588,7 +1589,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as BackupableDB is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user