diff --git a/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_debug_manual_compaction_delay_basic.result b/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_debug_manual_compaction_delay_basic.result new file mode 100644 index 000000000000..6c5db01533bf --- /dev/null +++ b/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_debug_manual_compaction_delay_basic.result @@ -0,0 +1,46 @@ +CREATE TABLE valid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO valid_values VALUES(2400); +INSERT INTO valid_values VALUES(100000); +CREATE TABLE invalid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO invalid_values VALUES('\'aaa\''); +SET @start_global_value = @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +SELECT @start_global_value; +@start_global_value +0 +'# Setting to valid values in global scope#' +"Trying to set variable @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY to 2400" +SET @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = 2400; +SELECT @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +@@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +2400 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = DEFAULT; +SELECT @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +@@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +0 +"Trying to set variable @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY to 100000" +SET @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = 100000; +SELECT @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +@@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +100000 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = DEFAULT; +SELECT @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +@@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +0 +"Trying to set variable @@session.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY to 444. It should fail because it is not session." +SET @@session.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = 444; +ERROR HY000: Variable 'rocksdb_debug_manual_compaction_delay' is a GLOBAL variable and should be set with SET GLOBAL +'# Testing with invalid values in global scope #' +"Trying to set variable @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY to 'aaa'" +SET @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = 'aaa'; +Got one of the listed errors +SELECT @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +@@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +0 +SET @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY = @start_global_value; +SELECT @@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY; +@@global.ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +0 +DROP TABLE valid_values; +DROP TABLE invalid_values; diff --git a/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_manual_compaction_threads_basic.result b/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_manual_compaction_threads_basic.result new file mode 100644 index 000000000000..3d599e1768ed --- /dev/null +++ b/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_manual_compaction_threads_basic.result @@ -0,0 +1,93 @@ +CREATE TABLE valid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO valid_values VALUES(0); +INSERT INTO valid_values VALUES(1); +INSERT INTO valid_values VALUES(99); +CREATE TABLE invalid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO invalid_values VALUES('\'aaa\''); +SET @start_global_value = @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +SELECT @start_global_value; +@start_global_value +0 +SET @start_session_value = @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +SELECT @start_session_value; +@start_session_value +0 +'# Setting to valid values in global scope#' +"Trying to set variable @@global.ROCKSDB_MANUAL_COMPACTION_THREADS to 0" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = 0; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = DEFAULT; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +"Trying to set variable @@global.ROCKSDB_MANUAL_COMPACTION_THREADS to 1" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = 1; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +1 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = DEFAULT; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +"Trying to set variable @@global.ROCKSDB_MANUAL_COMPACTION_THREADS to 99" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = 99; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +99 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = DEFAULT; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +'# Setting to valid values in session scope#' +"Trying to set variable @@session.ROCKSDB_MANUAL_COMPACTION_THREADS to 0" +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = 0; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +"Setting the session scope variable back to default" +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = DEFAULT; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +"Trying to set variable @@session.ROCKSDB_MANUAL_COMPACTION_THREADS to 1" +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = 1; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +1 +"Setting the session scope variable back to default" +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = DEFAULT; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +"Trying to set variable @@session.ROCKSDB_MANUAL_COMPACTION_THREADS to 99" +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = 99; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +99 +"Setting the session scope variable back to default" +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = DEFAULT; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +'# Testing with invalid values in global scope #' +"Trying to set variable @@global.ROCKSDB_MANUAL_COMPACTION_THREADS to 'aaa'" +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = 'aaa'; +Got one of the listed errors +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +SET @@global.ROCKSDB_MANUAL_COMPACTION_THREADS = @start_global_value; +SELECT @@global.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@global.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +SET @@session.ROCKSDB_MANUAL_COMPACTION_THREADS = @start_session_value; +SELECT @@session.ROCKSDB_MANUAL_COMPACTION_THREADS; +@@session.ROCKSDB_MANUAL_COMPACTION_THREADS +0 +DROP TABLE valid_values; +DROP TABLE invalid_values; diff --git a/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_max_manual_compactions_basic.result b/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_max_manual_compactions_basic.result new file mode 100644 index 000000000000..815506ccac8c --- /dev/null +++ b/mysql-test/suite/rocksdb.sys_vars/r/rocksdb_max_manual_compactions_basic.result @@ -0,0 +1,57 @@ +CREATE TABLE valid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO valid_values VALUES(1); +INSERT INTO valid_values VALUES(1024); +INSERT INTO valid_values VALUES(512*1024*1024); +CREATE TABLE invalid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO invalid_values VALUES('\'aaa\''); +SET @start_global_value = @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +SELECT @start_global_value; +@start_global_value +10 +'# Setting to valid values in global scope#' +"Trying to set variable @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS to 1" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = 1; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +1 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = DEFAULT; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +10 +"Trying to set variable @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS to 1024" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = 1024; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +1024 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = DEFAULT; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +10 +"Trying to set variable @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS to 536870912" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = 536870912; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +536870912 +"Setting the global scope variable back to default" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = DEFAULT; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +10 +"Trying to set variable @@session.ROCKSDB_MAX_MANUAL_COMPACTIONS to 444. It should fail because it is not session." +SET @@session.ROCKSDB_MAX_MANUAL_COMPACTIONS = 444; +ERROR HY000: Variable 'rocksdb_max_manual_compactions' is a GLOBAL variable and should be set with SET GLOBAL +'# Testing with invalid values in global scope #' +"Trying to set variable @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS to 'aaa'" +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = 'aaa'; +Got one of the listed errors +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +10 +SET @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS = @start_global_value; +SELECT @@global.ROCKSDB_MAX_MANUAL_COMPACTIONS; +@@global.ROCKSDB_MAX_MANUAL_COMPACTIONS +10 +DROP TABLE valid_values; +DROP TABLE invalid_values; diff --git a/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_debug_manual_compaction_delay_basic.test b/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_debug_manual_compaction_delay_basic.test new file mode 100644 index 000000000000..518c284c0cf8 --- /dev/null +++ b/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_debug_manual_compaction_delay_basic.test @@ -0,0 +1,16 @@ +--source include/have_rocksdb.inc + +CREATE TABLE valid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO valid_values VALUES(2400); +INSERT INTO valid_values VALUES(100000); + +CREATE TABLE invalid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO invalid_values VALUES('\'aaa\''); + +--let $sys_var=ROCKSDB_DEBUG_MANUAL_COMPACTION_DELAY +--let $read_only=0 +--let $session=0 +--source ../include/rocksdb_sys_var.inc + +DROP TABLE valid_values; +DROP TABLE invalid_values; diff --git a/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_manual_compaction_threads_basic.test b/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_manual_compaction_threads_basic.test new file mode 100644 index 000000000000..4f166a9ca8ed --- /dev/null +++ b/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_manual_compaction_threads_basic.test @@ -0,0 +1,17 @@ +--source include/have_rocksdb.inc + +CREATE TABLE valid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO valid_values VALUES(0); +INSERT INTO valid_values VALUES(1); +INSERT INTO valid_values VALUES(99); + +CREATE TABLE invalid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO invalid_values VALUES('\'aaa\''); + +--let $sys_var=ROCKSDB_MANUAL_COMPACTION_THREADS +--let $read_only=0 +--let $session=1 +--source ../include/rocksdb_sys_var.inc + +DROP TABLE valid_values; +DROP TABLE invalid_values; diff --git a/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_max_manual_compactions_basic.test b/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_max_manual_compactions_basic.test new file mode 100644 index 000000000000..1c66316858b8 --- /dev/null +++ b/mysql-test/suite/rocksdb.sys_vars/t/rocksdb_max_manual_compactions_basic.test @@ -0,0 +1,17 @@ +--source include/have_rocksdb.inc + +CREATE TABLE valid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO valid_values VALUES(1); +INSERT INTO valid_values VALUES(1024); +INSERT INTO valid_values VALUES(512*1024*1024); + +CREATE TABLE invalid_values (value varchar(255)) ENGINE=myisam; +INSERT INTO invalid_values VALUES('\'aaa\''); + +--let $sys_var=ROCKSDB_MAX_MANUAL_COMPACTIONS +--let $read_only=0 +--let $session=0 +--source ../include/rocksdb_sys_var.inc + +DROP TABLE valid_values; +DROP TABLE invalid_values; diff --git a/mysql-test/suite/rocksdb/r/non_blocking_manual_compaction.result b/mysql-test/suite/rocksdb/r/non_blocking_manual_compaction.result new file mode 100644 index 000000000000..00392a13606d --- /dev/null +++ b/mysql-test/suite/rocksdb/r/non_blocking_manual_compaction.result @@ -0,0 +1,18 @@ +CREATE TABLE t1 ( +a int not null, +b int not null, +primary key (a,b) comment 'cf1', +key (b) comment 'rev:cf2' +) ENGINE=ROCKSDB; +DELETE FROM t1; +SET GLOBAL rocksdb_max_manual_compactions = 2; +SET GLOBAL rocksdb_debug_manual_compaction_delay = 3600; +SET GLOBAL rocksdb_compact_cf='cf1'; +SET GLOBAL rocksdb_compact_cf='rev:cf2'; +Timeout in wait_condition.inc for select variable_value > 1 from performance_schema.global_status where variable_name='rocksdb_manual_compactions_running' +SET GLOBAL rocksdb_compact_cf='cf1'; +ERROR HY000: Internal error: Can't schedule more manual compactions. Increase rocksdb_max_manual_compactions or stop issuing more manual compactions. +SET GLOBAL rocksdb_compact_cf='rev:cf2'; +ERROR HY000: Internal error: Can't schedule more manual compactions. Increase rocksdb_max_manual_compactions or stop issuing more manual compactions. +DROP TABLE t1; +# restart diff --git a/mysql-test/suite/rocksdb/r/rocksdb.result b/mysql-test/suite/rocksdb/r/rocksdb.result index ce1c374b13b8..3fb62f3de101 100644 --- a/mysql-test/suite/rocksdb/r/rocksdb.result +++ b/mysql-test/suite/rocksdb/r/rocksdb.result @@ -922,6 +922,7 @@ rocksdb_datadir ./.rocksdb rocksdb_db_write_buffer_size 0 rocksdb_deadlock_detect OFF rocksdb_deadlock_detect_depth 50 +rocksdb_debug_manual_compaction_delay 0 rocksdb_debug_optimizer_no_zero_cardinality ON rocksdb_debug_ttl_ignore_pk OFF rocksdb_debug_ttl_read_filter_ts 0 @@ -954,11 +955,13 @@ rocksdb_lock_scanned_rows OFF rocksdb_lock_wait_timeout 1 rocksdb_log_file_time_to_roll 0 rocksdb_manifest_preallocation_size 4194304 +rocksdb_manual_compaction_threads 0 rocksdb_manual_wal_flush ON rocksdb_max_background_jobs 2 rocksdb_max_latest_deadlocks 5 rocksdb_max_log_file_size 0 rocksdb_max_manifest_file_size 1073741824 +rocksdb_max_manual_compactions 10 rocksdb_max_row_locks 1048576 rocksdb_max_subcompactions 1 rocksdb_max_total_wal_size 2147483648 @@ -1568,6 +1571,8 @@ rocksdb_get_hit_l1 # rocksdb_get_hit_l2_and_up # rocksdb_get_updates_since_calls # rocksdb_iter_bytes_read # +rocksdb_manual_compactions_processed # +rocksdb_manual_compactions_running # rocksdb_memtable_hit # rocksdb_memtable_miss # rocksdb_no_file_closes # @@ -1676,6 +1681,8 @@ rocksdb_get_hit_l1 rocksdb_get_hit_l2_and_up rocksdb_get_updates_since_calls rocksdb_iter_bytes_read +rocksdb_manual_compactions_processed +rocksdb_manual_compactions_running rocksdb_memtable_hit rocksdb_memtable_miss rocksdb_no_file_closes @@ -1786,6 +1793,8 @@ rocksdb_get_hit_l1 rocksdb_get_hit_l2_and_up rocksdb_get_updates_since_calls rocksdb_iter_bytes_read +rocksdb_manual_compactions_processed +rocksdb_manual_compactions_running rocksdb_memtable_hit rocksdb_memtable_miss rocksdb_no_file_closes diff --git a/mysql-test/suite/rocksdb/t/non_blocking_manual_compaction-master.opt b/mysql-test/suite/rocksdb/t/non_blocking_manual_compaction-master.opt new file mode 100644 index 000000000000..3016407cd346 --- /dev/null +++ b/mysql-test/suite/rocksdb/t/non_blocking_manual_compaction-master.opt @@ -0,0 +1,2 @@ +--loose-rocksdb_max_subcompactions=1 +--loose-rocksdb_default_cf_options=write_buffer_size=512k;target_file_size_base=512k;level0_file_num_compaction_trigger=2;level0_slowdown_writes_trigger=-1;level0_stop_writes_trigger=1000;max_bytes_for_level_base=1m diff --git a/mysql-test/suite/rocksdb/t/non_blocking_manual_compaction.test b/mysql-test/suite/rocksdb/t/non_blocking_manual_compaction.test new file mode 100644 index 000000000000..35420e1e75f3 --- /dev/null +++ b/mysql-test/suite/rocksdb/t/non_blocking_manual_compaction.test @@ -0,0 +1,48 @@ +--source include/have_rocksdb.inc +--source include/count_sessions.inc + +CREATE TABLE t1 ( + a int not null, + b int not null, + primary key (a,b) comment 'cf1', + key (b) comment 'rev:cf2' +) ENGINE=ROCKSDB; + +# Populate tables +let $max = 1000; +let $table = t1; +--source suite/rocksdb/include/drop_table_repopulate_table.inc + +# Run manual compaction, then restarting mysqld +# and confirming it is not blocked. +SET GLOBAL rocksdb_max_manual_compactions = 2; +SET GLOBAL rocksdb_debug_manual_compaction_delay = 3600; +connect (con1, localhost, root,,); +connect (con2, localhost, root,,); +connect (con3, localhost, root,,); +connection con1; +send SET GLOBAL rocksdb_compact_cf='cf1'; +connection con2; +send SET GLOBAL rocksdb_compact_cf='rev:cf2'; +connection default; +let $wait_condition = select count(*) = 2 from information_schema.processlist where info like 'SET GLOBAL rocksdb_compact_cf%'; +--source include/wait_condition.inc + +let $wait_condition = select variable_value > 1 from performance_schema.global_status where variable_name='rocksdb_manual_compactions_running'; +--source include/wait_condition.inc + +connection con3; +--error ER_INTERNAL_ERROR +SET GLOBAL rocksdb_compact_cf='cf1'; +--error ER_INTERNAL_ERROR +SET GLOBAL rocksdb_compact_cf='rev:cf2'; + +connection default; +disconnect con1; +disconnect con2; +disconnect con3; + +DROP TABLE t1; + +--source include/restart_mysqld.inc +--source include/wait_until_count_sessions.inc diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index 813af926e634..68a9476d1edd 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -115,11 +115,15 @@ static handler *rocksdb_create_handler(my_core::handlerton *hton, bool partitioned, my_core::MEM_ROOT *mem_root); -static rocksdb::CompactRangeOptions getCompactRangeOptions() { +static rocksdb::CompactRangeOptions +getCompactRangeOptions(int concurrency = 0) { rocksdb::CompactRangeOptions compact_range_options; compact_range_options.bottommost_level_compaction = rocksdb::BottommostLevelCompaction::kForce; compact_range_options.exclusive_manual_compaction = false; + if (concurrency > 0) { + compact_range_options.max_subcompactions = concurrency; + } return compact_range_options; } @@ -154,6 +158,8 @@ Rdb_hton_init_state hton_init_state; static Rdb_background_thread rdb_bg_thread; +static Rdb_manual_compaction_thread rdb_mc_thread; + // List of table names (using regex) that are exceptions to the strict // collation check requirement. Regex *rdb_collation_exceptions; @@ -167,31 +173,6 @@ static void rocksdb_flush_all_memtables() { } } -static void rocksdb_compact_column_family_stub(THD *const thd, - struct SYS_VAR *const var, - void *const var_ptr, - const void *const save) {} - -static int rocksdb_compact_column_family(THD *const thd, - struct SYS_VAR *const var, - void *const var_ptr, - struct st_mysql_value *const value) { - char buff[STRING_BUFFER_USUAL_SIZE]; - int len = sizeof(buff); - - DBUG_ASSERT(value != nullptr); - - if (const char *const cf = value->val_str(value, buff, &len)) { - auto cfh = cf_manager.get_cf(cf); - if (cfh != nullptr && rdb != nullptr) { - LogPluginErrMsg(INFORMATION_LEVEL, 0, - "RocksDB: Manual compaction of column family: %s\n", cf); - rdb->CompactRange(getCompactRangeOptions(), cfh, nullptr, nullptr); - } - } - return HA_EXIT_SUCCESS; -} - /////////////////////////////////////////////////////////// // Hash map: table name => open table handler /////////////////////////////////////////////////////////// @@ -304,7 +285,7 @@ static int rocksdb_force_flush_memtable_and_lzero_now( DBUG_ASSERT(metadata.levels[0].level == 0); std::vector file_names; - for (auto &file : metadata.levels[0].files) { + for (const auto &file : metadata.levels[0].files) { file_names.emplace_back(file.db_path + file.name); } @@ -494,11 +475,15 @@ static uint64_t rocksdb_write_policy = static bool rocksdb_error_on_suboptimal_collation = false; static uint32_t rocksdb_stats_recalc_rate = 0; static bool rocksdb_no_create_column_family = false; +static uint32_t rocksdb_debug_manual_compaction_delay = 0; +static uint32_t rocksdb_max_manual_compactions = 0; std::atomic rocksdb_row_lock_deadlocks(0); std::atomic rocksdb_row_lock_wait_timeouts(0); std::atomic rocksdb_snapshot_conflict_errors(0); std::atomic rocksdb_wal_group_syncs(0); +std::atomic rocksdb_manual_compactions_processed(0); +std::atomic rocksdb_manual_compactions_running(0); static std::unique_ptr rdb_init_rocksdb_db_options(void) { auto o = std::unique_ptr(new rocksdb::DBOptions()); @@ -615,6 +600,14 @@ static int rocksdb_validate_flush_log_at_trx_commit( *static_cast(var_ptr) = static_cast(new_value); return HA_EXIT_SUCCESS; } +static void rocksdb_compact_column_family_stub( + THD *const thd, struct st_mysql_sys_var *const var, void *const var_ptr, + const void *const save) {} + +static int rocksdb_compact_column_family(THD *const thd, + struct st_mysql_sys_var *const var, + void *const var_ptr, + struct st_mysql_value *const value); static const char *index_type_names[] = {"kBinarySearch", "kHashSearch", NullS}; @@ -755,6 +748,12 @@ static MYSQL_THDVAR_ULONGLONG( /* min (0ms) */ RDB_MIN_MERGE_TMP_FILE_REMOVAL_DELAY, /* max */ SIZE_T_MAX, 1); +static MYSQL_THDVAR_INT( + manual_compaction_threads, PLUGIN_VAR_RQCMDARG, + "How many rocksdb threads to run for manual compactions", nullptr, nullptr, + /* default rocksdb.dboption max_subcompactions */ 0, + /* min */ 0, /* max */ 128, 0); + static MYSQL_SYSVAR_BOOL( create_if_missing, *static_cast(&rocksdb_db_options->create_if_missing), @@ -1354,6 +1353,18 @@ static MYSQL_SYSVAR_BOOL( "on PK TTL data. This variable is a no-op in non-debug builds.", nullptr, nullptr, false); +static MYSQL_SYSVAR_UINT( + max_manual_compactions, rocksdb_max_manual_compactions, PLUGIN_VAR_RQCMDARG, + "Maximum number of pending + ongoing number of manual compactions.", + nullptr, nullptr, /* default */ 10, /* min */ 0, /* max */ UINT_MAX, 0); + +static MYSQL_SYSVAR_UINT( + debug_manual_compaction_delay, rocksdb_debug_manual_compaction_delay, + PLUGIN_VAR_RQCMDARG, + "For debugging purposes only. Sleeping specified seconds " + "for simulating long running compactions.", + nullptr, nullptr, 0, /* min */ 0, /* max */ UINT_MAX, 0); + static MYSQL_SYSVAR_BOOL( reset_stats, rocksdb_reset_stats, PLUGIN_VAR_RQCMDARG, "Reset the RocksDB internal statistics without restarting the DB.", nullptr, @@ -1677,6 +1688,9 @@ static struct SYS_VAR *rocksdb_system_variables[] = { MYSQL_SYSVAR(error_on_suboptimal_collation), MYSQL_SYSVAR(no_create_column_family), MYSQL_SYSVAR(stats_recalc_rate), + MYSQL_SYSVAR(debug_manual_compaction_delay), + MYSQL_SYSVAR(max_manual_compactions), + MYSQL_SYSVAR(manual_compaction_threads), nullptr}; static rocksdb::WriteOptions @@ -1691,6 +1705,50 @@ rdb_get_rocksdb_write_options(my_core::THD *const thd) { return opt; } +static int rocksdb_compact_column_family(THD *const thd, + struct st_mysql_sys_var *const var, + void *const var_ptr, + struct st_mysql_value *const value) { + char buff[STRING_BUFFER_USUAL_SIZE]; + int len = sizeof(buff); + + DBUG_ASSERT(value != nullptr); + + if (const char *const cf = value->val_str(value, buff, &len)) { + auto cfh = cf_manager.get_cf(cf); + if (cfh != nullptr && rdb != nullptr) { + int mc_id = rdb_mc_thread.request_manual_compaction( + cfh, nullptr, nullptr, THDVAR(thd, manual_compaction_threads)); + if (mc_id == -1) { + my_error(ER_INTERNAL_ERROR, MYF(0), + "Can't schedule more manual compactions. " + "Increase rocksdb_max_manual_compactions or stop issuing " + "more manual compactions."); + return HA_EXIT_FAILURE; + } else if (mc_id < 0) { + return HA_EXIT_FAILURE; + } + // NO_LINT_DEBUG + sql_print_information("RocksDB: Manual compaction of column family: %s\n", + cf); + // Checking thd state every short cycle (100ms). This is for allowing to + // exiting this function without waiting for CompactRange to finish. + do { + my_sleep(100000); + } while (!thd->killed && + !rdb_mc_thread.is_manual_compaction_finished(mc_id)); + + if (thd->killed) { + // This cancels if requested compaction state is INITED. + // TODO(yoshinorim): Cancel running compaction as well once + // it is supported in RocksDB. + rdb_mc_thread.clear_manual_compaction_request(mc_id, true); + } + } + } + return HA_EXIT_SUCCESS; +} + /* Drop index thread's control */ @@ -3919,9 +3977,11 @@ static int rocksdb_init_func(void *const p) { rdb_bg_thread.init(rdb_signal_bg_psi_mutex_key, rdb_signal_bg_psi_cond_key); rdb_drop_idx_thread.init(rdb_signal_drop_idx_psi_mutex_key, rdb_signal_drop_idx_psi_cond_key); + rdb_mc_thread.init(rdb_signal_mc_psi_mutex_key, rdb_signal_mc_psi_cond_key); #else rdb_bg_thread.init(); rdb_drop_idx_thread.init(); + rdb_mc_thread.init(); #endif mysql_mutex_init(rdb_collation_data_mutex_key, &rdb_collation_data_mutex, MY_MUTEX_INIT_FAST); @@ -4295,6 +4355,20 @@ static int rocksdb_init_func(void *const p) { DBUG_RETURN(HA_EXIT_FAILURE); } + err = rdb_mc_thread.create_thread(MANUAL_COMPACTION_THREAD_NAME +#ifdef HAVE_PSI_INTERFACE + , + rdb_mc_psi_thread_key +#endif + ); + if (err != 0) { + // NO_LINT_DEBUG + sql_print_error( + "RocksDB: Couldn't start the manual compaction thread: (errno=%d)", + err); + DBUG_RETURN(HA_EXIT_FAILURE); + } + rdb_set_collation_exception_list(rocksdb_strict_collation_exceptions); if (rocksdb_pause_background_work) { @@ -4367,6 +4441,16 @@ static int rocksdb_done_func(void *const p) { "Couldn't stop the index thread: (errno=%d)", err); } + // signal the manual compaction thread to stop + rdb_mc_thread.signal(true); + // Wait for the manual compaction thread to finish. + err = rdb_mc_thread.join(); + if (err != 0) { + // NO_LINT_DEBUG + sql_print_error( + "RocksDB: Couldn't stop the manual compaction thread: (errno=%d)", err); + } + if (rdb_open_tables.m_hash.size()) { // Looks like we are getting unloaded and yet we have some open tables // left behind. @@ -11977,6 +12061,10 @@ static SHOW_VAR rocksdb_status_vars[] = { &rocksdb_snapshot_conflict_errors, SHOW_LONGLONG), DEF_STATUS_VAR_PTR("wal_group_syncs", &rocksdb_wal_group_syncs, SHOW_LONGLONG), + DEF_STATUS_VAR_PTR("manual_compactions_processed", + &rocksdb_manual_compactions_processed, SHOW_LONGLONG), + DEF_STATUS_VAR_PTR("manual_compactions_running", + &rocksdb_manual_compactions_running, SHOW_LONGLONG), DEF_STATUS_VAR_PTR("number_sst_entry_put", &rocksdb_num_sst_entry_put, SHOW_LONGLONG), DEF_STATUS_VAR_PTR("number_sst_entry_delete", &rocksdb_num_sst_entry_delete, @@ -12097,6 +12185,159 @@ void Rdb_background_thread::run() { ddl_manager.persist_stats(); } +/* + A background thread to handle manual compactions, + except for dropping indexes/tables. Every second, it checks + pending manual compactions, and it calls CompactRange if there is. +*/ +void Rdb_manual_compaction_thread::run() { + mysql_mutex_init(0, &m_mc_mutex, MY_MUTEX_INIT_FAST); + RDB_MUTEX_LOCK_CHECK(m_signal_mutex); + for (;;) { + if (m_stop) { + break; + } + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 1; + + const auto ret MY_ATTRIBUTE((__unused__)) = + mysql_cond_timedwait(&m_signal_cond, &m_signal_mutex, &ts); + if (m_stop) { + break; + } + // make sure, no program error is returned + DBUG_ASSERT(ret == 0 || ret == ETIMEDOUT); + RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex); + + RDB_MUTEX_LOCK_CHECK(m_mc_mutex); + // Grab the first item and proceed, if not empty. + if (m_requests.empty()) { + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); + RDB_MUTEX_LOCK_CHECK(m_signal_mutex); + continue; + } + Manual_compaction_request &mcr = m_requests.begin()->second; + DBUG_ASSERT(mcr.cf != nullptr); + DBUG_ASSERT(mcr.state == Manual_compaction_request::INITED); + mcr.state = Manual_compaction_request::RUNNING; + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); + + DBUG_ASSERT(mcr.state == Manual_compaction_request::RUNNING); + // NO_LINT_DEBUG + sql_print_information("Manual Compaction id %d cf %s started.", mcr.mc_id, + mcr.cf->GetName().c_str()); + rocksdb_manual_compactions_running++; + if (rocksdb_debug_manual_compaction_delay > 0) { + // In Facebook MySQL 5.6.35, my_sleep breaks the sleep when the server + // gets a shutdown signal and this code depended on that behavior. + // In 5.7, for whatever reason, this is not the case. my_sleep will + // continue to sleep until the sleep time has elapsed. For the purpose + // of this variable and the accompanying test case, we need to break this + // down into a loop that sleeps and checks to see if the thread was + // signalled with the stop flag. It is ugly, but without having DBUG_SYNC + // available in background threads, it is good enough for the test. + for (uint32_t sleeps = 0; sleeps < rocksdb_debug_manual_compaction_delay; + sleeps++) { + RDB_MUTEX_LOCK_CHECK(m_signal_mutex); + const bool local_stop = m_stop; + RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex); + if (local_stop) + break; + my_sleep(1000000); + } + } + // CompactRange may take a very long time. On clean shutdown, + // it is cancelled by CancelAllBackgroundWork, then status is + // set to shutdownInProgress. + const rocksdb::Status s = rdb->CompactRange( + getCompactRangeOptions(mcr.concurrency), mcr.cf, mcr.start, mcr.limit); + rocksdb_manual_compactions_running--; + if (s.ok()) { + // NO_LINT_DEBUG + sql_print_information("Manual Compaction id %d cf %s ended.", mcr.mc_id, + mcr.cf->GetName().c_str()); + } else { + // NO_LINT_DEBUG + sql_print_information("Manual Compaction id %d cf %s aborted. %s", + mcr.mc_id, mcr.cf->GetName().c_str(), s.getState()); + if (!s.IsShutdownInProgress()) { + rdb_handle_io_error(s, RDB_IO_ERROR_BG_THREAD); + } else { + DBUG_ASSERT(m_requests.size() == 1); + } + } + rocksdb_manual_compactions_processed++; + clear_manual_compaction_request(mcr.mc_id, false); + RDB_MUTEX_LOCK_CHECK(m_signal_mutex); + } + clear_all_manual_compaction_requests(); + DBUG_ASSERT(m_requests.empty()); + RDB_MUTEX_UNLOCK_CHECK(m_signal_mutex); + mysql_mutex_destroy(&m_mc_mutex); +} + +void Rdb_manual_compaction_thread::clear_all_manual_compaction_requests() { + RDB_MUTEX_LOCK_CHECK(m_mc_mutex); + m_requests.clear(); + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); +} + +void Rdb_manual_compaction_thread::clear_manual_compaction_request( + int mc_id, bool init_only) { + bool erase = true; + RDB_MUTEX_LOCK_CHECK(m_mc_mutex); + auto it = m_requests.find(mc_id); + if (it != m_requests.end()) { + if (init_only) { + Manual_compaction_request mcr = it->second; + if (mcr.state != Manual_compaction_request::INITED) { + erase = false; + } + } + if (erase) { + m_requests.erase(it); + } + } else { + // Current code path guarantees that erasing by the same mc_id happens + // at most once. INITED state may be erased by a thread that requested + // the compaction. RUNNING state is erased by mc thread only. + DBUG_ASSERT(0); + } + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); +} + +int Rdb_manual_compaction_thread::request_manual_compaction( + rocksdb::ColumnFamilyHandle *cf, rocksdb::Slice *start, + rocksdb::Slice *limit, int concurrency) { + int mc_id = -1; + RDB_MUTEX_LOCK_CHECK(m_mc_mutex); + if (m_requests.size() >= rocksdb_max_manual_compactions) { + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); + return mc_id; + } + Manual_compaction_request mcr; + mc_id = mcr.mc_id = ++m_latest_mc_id; + mcr.state = Manual_compaction_request::INITED; + mcr.cf = cf; + mcr.start = start; + mcr.limit = limit; + mcr.concurrency = concurrency; + m_requests.insert(std::make_pair(mcr.mc_id, mcr)); + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); + return mc_id; +} + +bool Rdb_manual_compaction_thread::is_manual_compaction_finished(int mc_id) { + bool finished = false; + RDB_MUTEX_LOCK_CHECK(m_mc_mutex); + if (m_requests.count(mc_id) == 0) { + finished = true; + } + RDB_MUTEX_UNLOCK_CHECK(m_mc_mutex); + return finished; +} + bool ha_rocksdb::check_bloom_and_set_bounds( THD *thd, const Rdb_key_def &kd, const rocksdb::Slice &eq_cond, const bool use_all_keys, size_t bound_len, uchar *const lower_bound, diff --git a/storage/rocksdb/ha_rocksdb.h b/storage/rocksdb/ha_rocksdb.h index 3a5535624be5..b039e7443768 100644 --- a/storage/rocksdb/ha_rocksdb.h +++ b/storage/rocksdb/ha_rocksdb.h @@ -150,6 +150,11 @@ const char *const BG_THREAD_NAME = "myrocks-bg"; */ const char *const INDEX_THREAD_NAME = "myrocks-index"; +/* + Name for the manual compaction thread. +*/ +static const char constexpr MANUAL_COMPACTION_THREAD_NAME[] = "myrocks-mc"; + /* Separator between partition name and the qualifier. Sample usage: diff --git a/storage/rocksdb/rdb_psi.cc b/storage/rocksdb/rdb_psi.cc index da9d72326e99..315b20525bf1 100644 --- a/storage/rocksdb/rdb_psi.cc +++ b/storage/rocksdb/rdb_psi.cc @@ -35,17 +35,19 @@ my_core::PSI_stage_info stage_waiting_on_row_lock(0, "Waiting for row lock", 0, my_core::PSI_stage_info *all_rocksdb_stages[] = {&stage_waiting_on_row_lock}; my_core::PSI_thread_key rdb_background_psi_thread_key, - rdb_drop_idx_psi_thread_key; + rdb_drop_idx_psi_thread_key, rdb_mc_psi_thread_key; my_core::PSI_thread_info all_rocksdb_threads[] = { {&rdb_background_psi_thread_key, "background", PSI_FLAG_SINGLETON}, {&rdb_drop_idx_psi_thread_key, "drop index", PSI_FLAG_SINGLETON}, + {&rdb_mc_psi_thread_key, "manual compaction", PSI_FLAG_SINGLETON}, }; my_core::PSI_mutex_key rdb_psi_open_tbls_mutex_key, rdb_signal_bg_psi_mutex_key, - rdb_signal_drop_idx_psi_mutex_key, rdb_collation_data_mutex_key, - rdb_mem_cmp_space_mutex_key, key_mutex_tx_list, rdb_sysvars_psi_mutex_key, - rdb_cfm_mutex_key, rdb_sst_commit_key, rdb_block_cache_resize_mutex_key; + rdb_signal_drop_idx_psi_mutex_key, rdb_signal_mc_psi_mutex_key, + rdb_collation_data_mutex_key, rdb_mem_cmp_space_mutex_key, + key_mutex_tx_list, rdb_sysvars_psi_mutex_key, rdb_cfm_mutex_key, + rdb_sst_commit_key, rdb_block_cache_resize_mutex_key; my_core::PSI_mutex_info all_rocksdb_mutexes[] = { {&rdb_psi_open_tbls_mutex_key, "open tables", PSI_FLAG_SINGLETON}, @@ -53,6 +55,9 @@ my_core::PSI_mutex_info all_rocksdb_mutexes[] = { {&rdb_signal_drop_idx_psi_mutex_key, "signal drop index", PSI_FLAG_SINGLETON}, {&rdb_collation_data_mutex_key, "collation data init", PSI_FLAG_SINGLETON}, + {&rdb_signal_mc_psi_mutex_key, "signal manual compaction", + PSI_FLAG_SINGLETON}, + {&rdb_collation_data_mutex_key, "collation data init", PSI_FLAG_SINGLETON}, {&rdb_mem_cmp_space_mutex_key, "collation space char data init", PSI_FLAG_SINGLETON}, {&key_mutex_tx_list, "tx_list", PSI_FLAG_SINGLETON}, @@ -76,12 +81,14 @@ my_core::PSI_rwlock_info all_rocksdb_rwlocks[] = { }; my_core::PSI_cond_key rdb_signal_bg_psi_cond_key, - rdb_signal_drop_idx_psi_cond_key; + rdb_signal_drop_idx_psi_cond_key, rdb_signal_mc_psi_cond_key; my_core::PSI_cond_info all_rocksdb_conds[] = { {&rdb_signal_bg_psi_cond_key, "cond signal background", PSI_FLAG_SINGLETON}, {&rdb_signal_drop_idx_psi_cond_key, "cond signal drop index", PSI_FLAG_SINGLETON}, + {&rdb_signal_mc_psi_cond_key, "cond signal manual compaction", + PSI_FLAG_SINGLETON}, }; my_core::PSI_memory_key rdb_datadic_memory_key, rdb_open_tables_memory_key, diff --git a/storage/rocksdb/rdb_psi.h b/storage/rocksdb/rdb_psi.h index cab4bee14d93..5f64763a0d5c 100644 --- a/storage/rocksdb/rdb_psi.h +++ b/storage/rocksdb/rdb_psi.h @@ -38,19 +38,19 @@ extern my_core::PSI_stage_info stage_waiting_on_row_lock; #ifdef HAVE_PSI_INTERFACE extern my_core::PSI_thread_key rdb_background_psi_thread_key, - rdb_drop_idx_psi_thread_key; + rdb_drop_idx_psi_thread_key, rdb_mc_psi_thread_key; extern my_core::PSI_mutex_key rdb_psi_open_tbls_mutex_key, rdb_signal_bg_psi_mutex_key, rdb_signal_drop_idx_psi_mutex_key, - rdb_collation_data_mutex_key, rdb_mem_cmp_space_mutex_key, - key_mutex_tx_list, rdb_sysvars_psi_mutex_key, rdb_cfm_mutex_key, - rdb_sst_commit_key, rdb_block_cache_resize_mutex_key; + rdb_signal_mc_psi_mutex_key, rdb_collation_data_mutex_key, + rdb_mem_cmp_space_mutex_key, key_mutex_tx_list, rdb_sysvars_psi_mutex_key, + rdb_cfm_mutex_key, rdb_sst_commit_key, rdb_block_cache_resize_mutex_key; extern my_core::PSI_rwlock_key key_rwlock_collation_exception_list, key_rwlock_read_free_rpl_tables, key_rwlock_skip_unique_check_tables; extern my_core::PSI_cond_key rdb_signal_bg_psi_cond_key, - rdb_signal_drop_idx_psi_cond_key; + rdb_signal_drop_idx_psi_cond_key, rdb_signal_mc_psi_cond_key; extern my_core::PSI_memory_key rdb_datadic_memory_key, rdb_open_tables_memory_key, rdb_handler_memory_key; diff --git a/storage/rocksdb/rdb_threads.h b/storage/rocksdb/rdb_threads.h index d8b03f7d72cf..c2d8bc0e8647 100644 --- a/storage/rocksdb/rdb_threads.h +++ b/storage/rocksdb/rdb_threads.h @@ -18,6 +18,7 @@ /* C++ standard header files */ #include +#include #include /* MySQL includes */ @@ -27,6 +28,7 @@ /* MyRocks header files */ #include "./rdb_utils.h" +#include "rocksdb/db.h" namespace myrocks { @@ -101,6 +103,31 @@ class Rdb_background_thread : public Rdb_thread { } }; +class Rdb_manual_compaction_thread : public Rdb_thread { + private: + struct Manual_compaction_request { + int mc_id; + enum mc_state { INITED = 0, RUNNING } state; + rocksdb::ColumnFamilyHandle *cf; + rocksdb::Slice *start; + rocksdb::Slice *limit; + int concurrency = 0; + }; + + int m_latest_mc_id; + mysql_mutex_t m_mc_mutex; + std::map m_requests; + + public: + virtual void run() override; + int request_manual_compaction(rocksdb::ColumnFamilyHandle *cf, + rocksdb::Slice *start, rocksdb::Slice *limit, + int concurrency = 0); + bool is_manual_compaction_finished(int mc_id); + void clear_manual_compaction_request(int mc_id, bool init_only = false); + void clear_all_manual_compaction_requests(); +}; + /* Drop index thread control */