import argparse
import math
import os
import random
import shlex
import shutil
import subprocess
import sys
import tempfile
import time
per_iteration_random_seed_override = 0
remain_argv = None
is_remote_db = False
def get_random_seed(override):
if override == 0:
return random.randint(1, 2**64)
else:
return override
def quote_arg_for_display(arg):
if "=" not in arg:
return arg
flag, value = arg.split("=", 1)
return f"{flag}={shlex.quote(value)}"
def early_argument_parsing_before_main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--initial_random_seed_override",
default=0,
type=int,
help="Random seed used for initialize the test parameters at the beginning of stress test run",
)
parser.add_argument(
"--per_iteration_random_seed_override",
default=0,
type=int,
help="Random seed used for initialize the test parameters in each iteration of the stress test run",
)
global remain_args
args, remain_args = parser.parse_known_args()
init_random_seed = get_random_seed(args.initial_random_seed_override)
global per_iteration_random_seed_override
per_iteration_random_seed_override = args.per_iteration_random_seed_override
global is_remote_db
for arg in remain_args:
parts = arg.split("=", 1)
if parts[0] in ["--env_uri", "--fs_uri"] and len(parts) > 1 and parts[1]:
is_remote_db = True
break
print(f"Start with random seed {init_random_seed}")
random.seed(init_random_seed)
def apply_random_seed_per_iteration():
per_iteration_random_seed = get_random_seed(per_iteration_random_seed_override)
print(f"Use random seed for iteration {per_iteration_random_seed}")
random.seed(per_iteration_random_seed)
early_argument_parsing_before_main()
default_params = {
"acquire_snapshot_one_in": lambda: random.choice([100, 10000]),
"backup_max_size": 100 * 1024 * 1024,
"backup_one_in": lambda: random.choice([1000, 100000]),
"batch_protection_bytes_per_key": lambda: random.choice([0, 8]),
"memtable_protection_bytes_per_key": lambda: random.choice([0, 1, 2, 4, 8]),
"block_protection_bytes_per_key": lambda: random.choice([0, 1, 2, 4, 8]),
"block_size": 16384,
"bloom_bits": lambda: random.choice(
[random.randint(0, 19), random.lognormvariate(2.3, 1.3)]
),
"cache_index_and_filter_blocks": lambda: random.randint(0, 1),
"cache_size": lambda: random.choice([8388608, 33554432]),
"charge_compression_dictionary_building_buffer": lambda: random.choice([0, 1]),
"charge_filter_construction": lambda: random.choice([0, 1]),
"charge_table_reader": lambda: random.choice([0, 1]),
"charge_file_metadata": lambda: random.choice([0, 1]),
"checkpoint_one_in": lambda: random.choice([0, 0, 10000, 1000000]),
"compression_type": lambda: random.choice(
["none", "snappy", "zlib", "lz4", "lz4hc", "xpress", "zstd"]
),
"bottommost_compression_type": lambda: (
"disable"
if random.randint(0, 1) == 0
else random.choice(["none", "snappy", "zlib", "lz4", "lz4hc", "xpress", "zstd"])
),
"checksum_type": lambda: random.choice(
["kCRC32c", "kxxHash", "kxxHash64", "kXXH3"]
),
"compression_max_dict_bytes": lambda: 16384 * random.randint(0, 1),
"compression_zstd_max_train_bytes": lambda: 65536 * random.randint(0, 1),
"compression_parallel_threads": lambda: random.choice([1, 1, 2, 3, 4, 5, 8, 9, 16]),
"compression_max_dict_buffer_bytes": lambda: (1 << random.randint(0, 40)) - 1,
"compression_use_zstd_dict_trainer": lambda: random.randint(0, 1),
"compression_checksum": lambda: random.randint(0, 1),
"clear_column_family_one_in": 0,
"compact_files_one_in": lambda: random.choice([1000, 1000000]),
"compact_range_one_in": lambda: random.choice([1000, 1000000]),
"promote_l0_one_in": 0,
"compaction_pri": random.randint(0, 4),
"key_may_exist_one_in": lambda: random.choice([100, 100000]),
"data_block_index_type": lambda: random.choice([0, 1]),
"decouple_partitioned_filters": lambda: random.choice([0, 1, 1]),
"delpercent": 4,
"delrangepercent": 1,
"destroy_db_initially": 0,
"enable_pipelined_write": lambda: random.randint(0, 1),
"enable_compaction_filter": lambda: random.choice([0, 0, 0, 1]),
"enable_compaction_on_deletion_trigger": lambda: random.choice([0, 0, 0, 1]),
"inplace_update_support": random.choice([0] * 9 + [1]),
"expected_values_dir": lambda: setup_expected_values_dir(),
"flush_one_in": lambda: random.choice([1000, 1000000]),
"manual_wal_flush_one_in": lambda: random.choice([0, 1000]),
"file_checksum_impl": lambda: random.choice(["none", "crc32c", "xxh64", "big"]),
"get_live_files_apis_one_in": lambda: random.choice([10000, 1000000]),
"get_all_column_family_metadata_one_in": lambda: random.choice([10000, 1000000]),
"get_sorted_wal_files_one_in": 0,
"get_current_wal_file_one_in": 0,
"index_type": lambda: random.choice([0, 0, 0, 2, 2, 3]),
"index_block_search_type": lambda: random.choice([0, 1]),
"ingest_external_file_one_in": lambda: random.choice([1000, 1000000]),
"test_ingest_standalone_range_deletion_one_in": lambda: random.choice([0, 5, 10]),
"iterpercent": 10,
"lock_wal_one_in": lambda: random.choice([10000, 1000000]),
"mark_for_compaction_one_file_in": lambda: 10 * random.randint(0, 1),
"max_background_compactions": lambda: random.choice([2, 20]),
"num_bottom_pri_threads": lambda: random.choice([0, 1, 20]),
"max_bytes_for_level_base": 10485760,
"max_key": random.choice([100000, 25000000]),
"max_sequential_skip_in_iterations": lambda: random.choice([1, 2, 8, 16]),
"max_write_buffer_number": 3,
"mmap_read": lambda: random.choice([0, 0, 1]),
"nooverwritepercent": 1,
"open_files": lambda: random.choice([-1, -1, 100, 500000]),
"optimize_filters_for_memory": lambda: random.randint(0, 1),
"partition_filters": lambda: random.randint(0, 1),
"partition_pinning": lambda: random.randint(0, 3),
"reset_stats_one_in": lambda: random.choice([10000, 1000000]),
"pause_background_one_in": lambda: random.choice([10000, 1000000]),
"disable_file_deletions_one_in": lambda: random.choice([10000, 1000000]),
"disable_manual_compaction_one_in": lambda: random.choice([10000, 1000000]),
"abort_and_resume_compactions_one_in": lambda: random.choice([10000, 1000000]),
"prefix_size": lambda: random.choice([-1, 1, 5, 7, 8]),
"prefixpercent": 5,
"progress_reports": 0,
"readpercent": 45,
"recycle_log_file_num": 0,
"snapshot_hold_ops": 100000,
"sqfc_name": lambda: random.choice(["foo", "bar"]),
"sqfc_version": lambda: random.choice([0, 1, 1, 2, 2]),
"sst_file_manager_bytes_per_sec": lambda: random.choice([0, 104857600]),
"sst_file_manager_bytes_per_truncate": lambda: random.choice([0, 1048576]),
"long_running_snapshots": lambda: random.randint(0, 1),
"subcompactions": lambda: random.randint(1, 4),
"target_file_size_base": lambda: random.choice([512 * 1024, 2048 * 1024]),
"target_file_size_multiplier": 2,
"test_batches_snapshots": random.randint(0, 1),
"top_level_index_pinning": lambda: random.randint(0, 3),
"unpartitioned_pinning": lambda: random.randint(0, 3),
"use_direct_reads": lambda: random.randint(0, 1),
"use_direct_io_for_flush_and_compaction": lambda: random.randint(0, 1),
"use_sqfc_for_range_queries": lambda: random.choice([0, 1, 1, 1]),
"mock_direct_io": False,
"cache_type": lambda: random.choice(
[
"lru_cache",
"fixed_hyper_clock_cache",
"auto_hyper_clock_cache",
"auto_hyper_clock_cache",
"tiered_lru_cache",
"tiered_fixed_hyper_clock_cache",
"tiered_auto_hyper_clock_cache",
"tiered_auto_hyper_clock_cache",
]
),
"uncache_aggressiveness": lambda: int(math.pow(10, 4.0 * random.random()) - 1.0),
"use_full_merge_v1": lambda: random.randint(0, 1),
"use_merge": lambda: random.randint(0, 1),
"use_put_entity_one_in": random.choice([0] * 7 + [1, 5, 10]),
"use_attribute_group": lambda: random.randint(0, 1),
"use_multi_cf_iterator": lambda: random.randint(0, 1),
"bloom_before_level": lambda: random.choice(
[random.randint(-1, 2), random.randint(-1, 10), 0x7FFFFFFF - 1, 0x7FFFFFFF]
),
"value_size_mult": 32,
"verification_only": 0,
"verify_checksum": 1,
"write_buffer_size": lambda: random.choice([1024 * 1024, 4 * 1024 * 1024]),
"writepercent": 35,
"format_version": lambda: random.choice([2, 3, 4, 5, 6, 7, 7]),
"separate_key_value_in_data_block": lambda: random.choice([0, 1, 1]),
"index_block_restart_interval": lambda: random.choice(range(1, 16)),
"use_multiget": lambda: random.randint(0, 1),
"use_get_entity": lambda: random.choice([0] * 7 + [1]),
"use_multi_get_entity": lambda: random.choice([0] * 7 + [1]),
"periodic_compaction_seconds": lambda: random.choice([0, 0, 1, 2, 10, 100, 1000]),
"daily_offpeak_time_utc": lambda: random.choice(
["", "", "00:00-23:59", "04:00-08:00", "23:30-03:15"]
),
"stats_dump_period_sec": lambda: random.choice([0, 10, 600]),
"compaction_ttl": lambda: random.choice([0, 0, 1, 2, 10, 100, 1000]),
"fifo_allow_compaction": lambda: random.randint(0, 1),
"fifo_compaction_max_data_files_size_mb": lambda: random.choice([0, 100, 500]),
"fifo_compaction_use_kv_ratio_compaction": lambda: random.randint(0, 1),
"max_manifest_file_size": lambda: random.choice(
[t * 2048 if t < 5 else 1024 * 1024 * 1024 for t in range(1, 30)]
),
"max_manifest_space_amp_pct": lambda: random.choice([0, 10, 100, 1000]),
"sync": lambda: random.choice([1 if t == 0 else 0 for t in range(0, 20)]),
"bytes_per_sync": lambda: random.choice([0, 262144]),
"wal_bytes_per_sync": 0,
"compaction_readahead_size": lambda: random.choice([0, 0, 1024 * 1024]),
"db_write_buffer_size": lambda: random.choice(
[0, 0, 0, 1024 * 1024, 8 * 1024 * 1024, 128 * 1024 * 1024]
),
"use_write_buffer_manager": lambda: random.randint(0, 1),
"avoid_unnecessary_blocking_io": random.randint(0, 1),
"write_dbid_to_manifest": random.randint(0, 1),
"write_identity_file": random.randint(0, 1),
"avoid_flush_during_recovery": lambda: random.choice(
[1 if t == 0 else 0 for t in range(0, 8)]
),
"max_write_batch_group_size_bytes": lambda: random.choice(
[16, 64, 1024 * 1024, 16 * 1024 * 1024]
),
"level_compaction_dynamic_level_bytes": lambda: random.randint(0, 1),
"verify_checksum_one_in": lambda: random.choice([1000, 1000000]),
"verify_file_checksums_one_in": lambda: random.choice([1000, 1000000]),
"verify_db_one_in": lambda: random.choice([10000, 100000]),
"continuous_verification_interval": 0,
"max_key_len": 3,
"key_len_percent_dist": "1,30,69",
"error_recovery_with_no_fault_injection": lambda: random.randint(0, 1),
"metadata_read_fault_one_in": lambda: random.choice([0, 32, 1000]),
"metadata_write_fault_one_in": lambda: random.choice([0, 128, 1000]),
"read_fault_one_in": lambda: random.choice([0, 32, 1000]),
"write_fault_one_in": lambda: random.choice([0, 128, 1000]),
"exclude_wal_from_write_fault_injection": 0,
"open_metadata_write_fault_one_in": lambda: random.choice([0, 0, 8]),
"open_metadata_read_fault_one_in": lambda: random.choice([0, 0, 8]),
"open_write_fault_one_in": lambda: random.choice([0, 0, 16]),
"open_read_fault_one_in": lambda: random.choice([0, 0, 32]),
"sync_fault_injection": lambda: random.randint(0, 1),
"get_property_one_in": lambda: random.choice([100000, 1000000]),
"get_properties_of_all_tables_one_in": lambda: random.choice([100000, 1000000]),
"paranoid_file_checks": lambda: random.choice([0, 1, 1, 1]),
"max_write_buffer_size_to_maintain": lambda: random.choice(
[0, 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024, 8 * 1024 * 1024]
),
"user_timestamp_size": 0,
"secondary_cache_fault_one_in": lambda: random.choice([0, 0, 32]),
"compressed_secondary_cache_size": lambda: random.choice([8388608, 16777216]),
"prepopulate_block_cache": lambda: random.choice([0, 1]),
"memtable_prefix_bloom_size_ratio": lambda: random.choice([0.001, 0.01, 0.1, 0.5]),
"memtable_whole_key_filtering": lambda: random.randint(0, 1),
"detect_filter_construct_corruption": lambda: random.choice([0, 1]),
"adaptive_readahead": lambda: random.choice([0, 1]),
"async_io": lambda: random.choice([0, 1]),
"wal_compression": lambda: random.choice(["none", "zstd"]),
"verify_sst_unique_id_in_manifest": 1, "secondary_cache_uri": lambda: random.choice(
[
"",
"",
"",
"compressed_secondary_cache://capacity=8388608;enable_custom_split_merge=true",
]
),
"allow_data_in_errors": True,
"enable_thread_tracking": lambda: random.choice([0, 1]),
"readahead_size": lambda: random.choice([0, 16384, 524288]),
"initial_auto_readahead_size": lambda: random.choice([0, 16384, 524288]),
"max_auto_readahead_size": lambda: random.choice([0, 16384, 524288]),
"num_file_reads_for_auto_readahead": lambda: random.choice([0, 1, 2]),
"min_write_buffer_number_to_merge": lambda: random.choice([1, 2]),
"preserve_internal_time_seconds": lambda: random.choice([0, 60, 3600, 36000]),
"memtable_max_range_deletions": lambda: random.choice([0] * 6 + [100, 1000]),
"bottommost_file_compaction_delay": lambda: random.choice(
[0, 0, 0, 600, 3600, 86400]
),
"auto_readahead_size": lambda: random.choice([0, 1]),
"verify_iterator_with_expected_state_one_in": 5,
"allow_fallocate": lambda: random.choice([0, 1]),
"table_cache_numshardbits": lambda: random.choice([6] * 3 + [-1] * 2 + [0]),
"enable_write_thread_adaptive_yield": lambda: random.choice([0, 1]),
"log_readahead_size": lambda: random.choice([0, 16 * 1024 * 1024]),
"bgerror_resume_retry_interval": lambda: random.choice([100, 1000000]),
"delete_obsolete_files_period_micros": lambda: random.choice(
[6 * 60 * 60 * 1000000, 30 * 1000000]
),
"max_log_file_size": lambda: random.choice([0, 1024 * 1024]),
"log_file_time_to_roll": lambda: random.choice([0, 60]),
"use_adaptive_mutex": lambda: random.choice([0, 1]),
"advise_random_on_open": lambda: random.choice([0] + [1] * 3),
"WAL_ttl_seconds": lambda: random.choice([0, 60]),
"WAL_size_limit_MB": lambda: random.choice([0, 1]),
"strict_bytes_per_sync": lambda: random.choice([0, 1]),
"avoid_flush_during_shutdown": lambda: random.choice([0, 1]),
"fill_cache": lambda: random.choice([0, 1]),
"optimize_multiget_for_io": lambda: random.choice([0, 1]),
"memtable_insert_hint_per_batch": lambda: random.choice([0, 1]),
"dump_malloc_stats": lambda: random.choice([0, 1]),
"stats_history_buffer_size": lambda: random.choice([0, 1024 * 1024]),
"skip_stats_update_on_db_open": lambda: random.choice([0, 1]),
"optimize_filters_for_hits": lambda: random.choice([0, 1]),
"sample_for_compression": lambda: random.choice([0, 5]),
"report_bg_io_stats": lambda: random.choice([0, 1]),
"cache_index_and_filter_blocks_with_high_priority": lambda: random.choice([0, 1]),
"use_delta_encoding": lambda: random.choice([0, 1]),
"verify_compression": lambda: random.choice([0, 1]),
"read_amp_bytes_per_bit": lambda: random.choice([0, 32]),
"enable_index_compression": lambda: random.choice([0, 1]),
"index_shortening": lambda: random.choice([0, 1, 2]),
"metadata_charge_policy": lambda: random.choice([0, 1]),
"use_adaptive_mutex_lru": lambda: random.choice([0, 1]),
"manifest_preallocation_size": lambda: random.choice([0, 5 * 1024]),
"enable_checksum_handoff": lambda: random.choice([0, 1]),
"max_total_wal_size": lambda: random.choice([0] * 4 + [64 * 1024 * 1024]),
"high_pri_pool_ratio": lambda: random.choice([0, 0.5]),
"low_pri_pool_ratio": lambda: random.choice([0, 0.5]),
"soft_pending_compaction_bytes_limit": lambda: random.choice(
[1024 * 1024] + [64 * 1073741824] * 4
),
"hard_pending_compaction_bytes_limit": lambda: random.choice(
[2 * 1024 * 1024] + [256 * 1073741824] * 4
),
"enable_sst_partitioner_factory": lambda: random.choice([0, 1]),
"enable_do_not_compress_roles": lambda: random.choice([0, 1]),
"block_align": lambda: random.choice([0, 1]),
"super_block_alignment_size": lambda: random.choice(
[0, 128 * 1024, 512 * 1024, 2 * 1024 * 1024]
),
"super_block_alignment_space_overhead_ratio": lambda: random.choice([0, 32, 4096]),
"lowest_used_cache_tier": lambda: random.choice([0, 1, 2]),
"enable_custom_split_merge": lambda: random.choice([0, 1]),
"adm_policy": lambda: random.choice([0, 1, 2, 3]),
"last_level_temperature": lambda: random.choice(
["kUnknown", "kHot", "kWarm", "kCool", "kCold", "kIce"]
),
"default_write_temperature": lambda: random.choice(
["kUnknown", "kHot", "kWarm", "kCool", "kCold", "kIce"]
),
"default_temperature": lambda: random.choice(
["kUnknown", "kHot", "kWarm", "kCool", "kCold", "kIce"]
),
"enable_memtable_insert_with_hint_prefix_extractor": 0,
"check_multiget_consistency": lambda: random.choice([0, 0, 0, 1]),
"check_multiget_entity_consistency": lambda: random.choice([0, 0, 0, 1]),
"use_timed_put_one_in": lambda: random.choice([0] * 7 + [1, 5, 10]),
"universal_max_read_amp": lambda: random.choice([-1] * 3 + [0, 4, 10]),
"paranoid_memory_checks": lambda: random.choice([0] * 7 + [1]),
"memtable_veirfy_per_key_checksum_on_seek": lambda: random.choice([0] * 7 + [1]),
"allow_unprepared_value": lambda: random.choice([0, 1]),
"track_and_verify_wals": lambda: random.choice([0]),
"remote_compaction_worker_threads": lambda: random.choice([0, 8]),
"allow_resumption_one_in": lambda: random.choice([0, 1, 2, 20]),
"remote_compaction_failure_fall_back_to_local": 1,
"auto_refresh_iterator_with_snapshot": lambda: random.choice([0, 1]),
"memtable_op_scan_flush_trigger": lambda: random.choice([0, 10, 100, 1000]),
"memtable_avg_op_scan_flush_trigger": lambda: random.choice([0, 2, 20, 200]),
"ingest_wbwi_one_in": lambda: random.choice([0, 0, 100, 500]),
"universal_reduce_file_locking": lambda: random.randint(0, 1),
"compression_manager": lambda: random.choice(
["mixed"] * 1
+ ["none"] * 2
+ ["autoskip"] * 2
+ ["randommixed"] * 2
+ ["custom"] * 3
),
"use_multiscan": random.choice([1] + [0] * 3),
"statistics": random.choice([0, 1]),
"multiscan_use_async_io": 0, }
_TEST_DIR_ENV_VAR = "TEST_TMPDIR"
_TEST_EXPECTED_DIR_ENV_VAR = "TEST_TMPDIR_EXPECTED"
_DEBUG_LEVEL_ENV_VAR = "DEBUG_LEVEL"
stress_cmd = "./db_stress"
def is_release_mode():
return os.environ.get(_DEBUG_LEVEL_ENV_VAR) == "0"
def get_dbname(test_name):
test_dir_name = "rocksdb_crashtest_" + test_name
test_tmpdir = os.environ.get(_TEST_DIR_ENV_VAR)
if test_tmpdir is None or test_tmpdir == "":
dbname = tempfile.mkdtemp(prefix=test_dir_name)
else:
dbname = test_tmpdir + "/" + test_dir_name
if not is_remote_db:
os.makedirs(dbname, exist_ok=True)
return dbname
expected_values_dir = None
def setup_expected_values_dir():
global expected_values_dir
if expected_values_dir is not None:
return expected_values_dir
expected_dir_prefix = "rocksdb_crashtest_expected_"
test_exp_tmpdir = os.environ.get(_TEST_EXPECTED_DIR_ENV_VAR)
if not is_remote_db and (test_exp_tmpdir is None or test_exp_tmpdir == ""):
test_exp_tmpdir = os.environ.get(_TEST_DIR_ENV_VAR)
if test_exp_tmpdir is None or test_exp_tmpdir == "":
expected_values_dir = tempfile.mkdtemp(prefix=expected_dir_prefix)
else:
expected_values_dir = test_exp_tmpdir + "/rocksdb_crashtest_expected"
if os.path.exists(expected_values_dir):
shutil.rmtree(expected_values_dir)
os.mkdir(expected_values_dir)
return expected_values_dir
multiops_txn_key_spaces_file = None
def setup_multiops_txn_key_spaces_file():
global multiops_txn_key_spaces_file
if multiops_txn_key_spaces_file is not None:
return multiops_txn_key_spaces_file
key_spaces_file_prefix = "rocksdb_crashtest_multiops_txn_key_spaces"
test_exp_tmpdir = os.environ.get(_TEST_EXPECTED_DIR_ENV_VAR)
if not is_remote_db and (test_exp_tmpdir is None or test_exp_tmpdir == ""):
test_exp_tmpdir = os.environ.get(_TEST_DIR_ENV_VAR)
if test_exp_tmpdir is None or test_exp_tmpdir == "":
multiops_txn_key_spaces_file = tempfile.mkstemp(prefix=key_spaces_file_prefix)[
1
]
else:
if not os.path.exists(test_exp_tmpdir):
os.mkdir(test_exp_tmpdir)
multiops_txn_key_spaces_file = tempfile.mkstemp(
prefix=key_spaces_file_prefix, dir=test_exp_tmpdir
)[1]
return multiops_txn_key_spaces_file
def is_direct_io_supported(dbname):
if is_remote_db:
return False
else:
os.makedirs(dbname, exist_ok=True)
with tempfile.NamedTemporaryFile(dir=dbname) as f:
try:
os.open(f.name, os.O_DIRECT)
except BaseException:
return False
return True
blackbox_default_params = {
"disable_wal": lambda: random.choice([0, 0, 0, 1]),
"duration": 6000,
"interval": 120,
"verify_timeout": 1200,
"ops_per_thread": 100000000,
"reopen": 0,
"set_options_one_in": 1000,
}
whitebox_default_params = {
"disable_wal": 0,
"remote_compaction_worker_threads": 0,
"duration": 10000,
"log2_keys_per_lock": 10,
"ops_per_thread": 200000,
"random_kill_odd": 888887,
"reopen": 20,
}
simple_default_params = {
"allow_concurrent_memtable_write": lambda: random.randint(0, 1),
"column_families": 1,
"max_background_compactions": 1,
"max_bytes_for_level_base": 67108864,
"memtablerep": "skip_list",
"target_file_size_base": 16777216,
"target_file_size_multiplier": 1,
"test_batches_snapshots": 0,
"write_buffer_size": 32 * 1024 * 1024,
"level_compaction_dynamic_level_bytes": lambda: random.randint(0, 1),
"paranoid_file_checks": lambda: random.choice([0, 1, 1, 1]),
"test_secondary": lambda: random.choice([0, 1]),
}
blackbox_simple_default_params = {
"open_files": -1,
"set_options_one_in": 0,
}
whitebox_simple_default_params = {}
cf_consistency_params = {
"disable_wal": lambda: random.randint(0, 1),
"reopen": 0,
"test_cf_consistency": 1,
"write_buffer_size": 1024 * 1024,
"enable_pipelined_write": lambda: random.randint(0, 1),
"enable_compaction_filter": 0,
"inplace_update_support": 0,
"ingest_external_file_one_in": 0,
"verify_iterator_with_expected_state_one_in": 0,
"memtablerep": random.choice(["skip_list"] * 9 + ["vector"]),
}
txn_params = {
"use_txn": 1,
"use_optimistic_txn": 0,
"txn_write_policy": random.randint(0, 2),
"unordered_write": random.randint(0, 1),
"use_per_key_point_lock_mgr": lambda: random.choice([0, 1]),
"disable_wal": 0,
"remote_compaction_worker_threads": 0,
"checkpoint_one_in": 0,
"enable_pipelined_write": 0,
"create_timestamped_snapshot_one_in": random.choice([0, 20]),
"inplace_update_support": 0,
"use_timed_put_one_in": 0,
"commit_bypass_memtable_one_in": random.choice([0] * 2 + [500, 1000]),
"two_write_queues": lambda: random.choice([0, 1]),
}
optimistic_txn_params = {
"use_txn": 1,
"use_optimistic_txn": 1,
"occ_validation_policy": random.randint(0, 1),
"share_occ_lock_buckets": random.randint(0, 1),
"occ_lock_bucket_count": lambda: random.choice([10, 100, 500]),
"inplace_update_support": 0,
"use_timed_put_one_in": 0,
}
best_efforts_recovery_params = {
"best_efforts_recovery": 1,
"disable_wal": 1,
"column_families": 1,
"skip_verifydb": 1,
"verify_db_one_in": 0,
}
blob_params = {
"allow_setting_blob_options_dynamically": 1,
"enable_blob_files": lambda: random.choice([0] + [1] * 3),
"min_blob_size": lambda: random.choice([0, 8, 16]),
"blob_file_size": lambda: random.choice([1048576, 16777216, 268435456, 1073741824]),
"blob_compression_type": lambda: random.choice(["none", "snappy", "lz4", "zstd"]),
"enable_blob_garbage_collection": lambda: random.choice([0] + [1] * 3),
"blob_garbage_collection_age_cutoff": lambda: random.choice(
[0.0, 0.25, 0.5, 0.75, 1.0]
),
"blob_garbage_collection_force_threshold": lambda: random.choice([0.5, 0.75, 1.0]),
"blob_compaction_readahead_size": lambda: random.choice([0, 1048576, 4194304]),
"blob_file_starting_level": lambda: random.choice(
[0] * 4 + [1] * 3 + [2] * 2 + [3]
),
"use_blob_cache": lambda: random.randint(0, 1),
"use_shared_block_and_blob_cache": lambda: random.randint(0, 1),
"blob_cache_size": lambda: random.choice([1048576, 2097152, 4194304, 8388608]),
"prepopulate_blob_cache": lambda: random.randint(0, 1),
"remote_compaction_worker_threads": 0,
}
ts_params = {
"test_cf_consistency": 0,
"test_batches_snapshots": 0,
"user_timestamp_size": 8,
"persist_user_defined_timestamps": random.choice([0, 1, 1]),
"use_merge": 0,
"use_multiscan": 0,
"use_full_merge_v1": 0,
"use_txn": 0,
"ingest_external_file_one_in": 0,
"use_put_entity_one_in": 0,
"use_timed_put_one_in": 0,
"remote_compaction_worker_threads": 0,
}
tiered_params = {
"preclude_last_level_data_seconds": lambda: random.choice(
[-1, -1, 10, 60, 1200, 86400]
),
"last_level_temperature": lambda: random.choice(["kCold", "kIce"]),
"file_temperature_age_thresholds": lambda: random.choice(
[
"{{temperature=kWarm;age=10}:{temperature=kCool;age=30}:{temperature=kCold;age=100}:{temperature=kIce;age=300}}",
"{{temperature=kWarm;age=30}:{temperature=kCold;age=300}}",
"{{temperature=kCold;age=100}}",
]
),
"allow_trivial_copy_when_change_temperature": lambda: random.choice([0, 1]),
"enable_blob_files": 0,
"use_blob_db": 0,
"default_write_temperature": lambda: random.choice(["kUnknown", "kHot", "kWarm"]),
}
multiops_txn_params = {
"test_cf_consistency": 0,
"test_batches_snapshots": 0,
"test_multi_ops_txns": 1,
"use_txn": 1,
"txn_write_policy": random.randint(0, 2),
"two_write_queues": lambda: random.choice([0, 1]),
"disable_wal": 0,
"remote_compaction_worker_threads": 0,
"use_only_the_last_commit_time_batch_for_recovery": lambda: random.choice([0, 1]),
"clear_column_family_one_in": 0,
"column_families": 1,
"enable_pipelined_write": 0,
"acquire_snapshot_one_in": 0,
"backup_one_in": 0,
"writepercent": 0,
"delpercent": 0,
"delrangepercent": 0,
"customopspercent": 80,
"readpercent": 5,
"iterpercent": 15,
"prefixpercent": 0,
"verify_db_one_in": 1000,
"continuous_verification_interval": 1000,
"delay_snapshot_read_one_in": 3,
"write_buffer_size": 65536,
"flush_one_in": 1000,
"key_spaces_path": setup_multiops_txn_key_spaces_file(),
"rollback_one_in": 4,
"enable_compaction_filter": 0,
"create_timestamped_snapshot_one_in": 50,
"sync_fault_injection": 0,
"metadata_write_fault_one_in": 0,
"manual_wal_flush_one_in": 0,
"write_fault_one_in": 0,
"metadata_write_fault_one_in": 0,
"use_put_entity_one_in": 0,
"use_get_entity": 0,
"use_multi_get_entity": 0,
"verify_iterator_with_expected_state_one_in": 0,
"inplace_update_support": 0,
"use_timed_put_one_in": 0,
"use_attribute_group": 0,
"commit_bypass_memtable_one_in": random.choice([0] * 4 + [100]),
}
def finalize_and_sanitize(src_params):
dest_params = {k: v() if callable(v) else v for (k, v) in src_params.items()}
if is_release_mode():
dest_params["read_fault_one_in"] = 0
if dest_params.get("compression_max_dict_bytes") == 0:
dest_params["compression_zstd_max_train_bytes"] = 0
dest_params["compression_max_dict_buffer_bytes"] = 0
if dest_params.get("compression_type") != "zstd":
dest_params["compression_zstd_max_train_bytes"] = 0
if dest_params["mmap_read"] == 1:
dest_params["use_direct_io_for_flush_and_compaction"] = 0
dest_params["use_direct_reads"] = 0
dest_params["multiscan_use_async_io"] = 0
if (
dest_params["use_direct_io_for_flush_and_compaction"] == 1
or dest_params["use_direct_reads"] == 1
) and not is_direct_io_supported(dest_params["db"]):
if is_release_mode():
print(
"{} does not support direct IO. Disabling use_direct_reads and "
"use_direct_io_for_flush_and_compaction.\n".format(dest_params["db"])
)
dest_params["use_direct_reads"] = 0
dest_params["use_direct_io_for_flush_and_compaction"] = 0
else:
dest_params["mock_direct_io"] = True
if dest_params.get("memtablerep") == "vector":
dest_params["inplace_update_support"] = 0
if dest_params.get("memtablerep") != "skip_list":
dest_params["paranoid_memory_checks"] = 0
dest_params["memtable_veirfy_per_key_checksum_on_seek"] = 0
if dest_params["test_batches_snapshots"] == 1:
dest_params["enable_compaction_filter"] = 0
dest_params["inplace_update_support"] = 0
dest_params["write_fault_one_in"] = 0
dest_params["metadata_write_fault_one_in"] = 0
dest_params["read_fault_one_in"] = 0
dest_params["metadata_read_fault_one_in"] = 0
dest_params["use_multiscan"] = 0
if dest_params["prefix_size"] < 0:
dest_params["prefix_size"] = 1
if dest_params.get("best_efforts_recovery") == 1:
dest_params["inplace_update_support"] = 0
if dest_params.get("remote_compaction_worker_threads", 0) > 0:
dest_params["enable_blob_files"] = 0
dest_params["enable_blob_garbage_collection"] = 0
dest_params["allow_setting_blob_options_dynamically"] = 0
dest_params["disable_wal"] = 1
dest_params["inplace_update_support"] = 0
dest_params["checkpoint_one_in"] = 0
dest_params["use_timed_put_one_in"] = 0
dest_params["test_secondary"] = 0
dest_params["mmap_read"] = 0
dest_params["open_metadata_write_fault_one_in"] = 0
dest_params["open_metadata_read_fault_one_in"] = 0
dest_params["open_write_fault_one_in"] = 0
dest_params["open_read_fault_one_in"] = 0
dest_params["sync_fault_injection"] = 0
else:
dest_params["allow_resumption_one_in"] = 0
if (
dest_params.get("test_batches_snapshots") == 1
or dest_params.get("use_txn") == 1
or dest_params.get("user_timestamp_size", 0) > 0
):
dest_params["ingest_external_file_one_in"] = 0
if (
dest_params.get("test_batches_snapshots") == 1
or dest_params.get("use_txn") == 1
):
dest_params["delpercent"] += dest_params["delrangepercent"]
dest_params["delrangepercent"] = 0
if dest_params["inplace_update_support"] == 1:
dest_params["delpercent"] += dest_params["delrangepercent"]
dest_params["delrangepercent"] = 0
dest_params["readpercent"] += dest_params["prefixpercent"]
dest_params["prefixpercent"] = 0
dest_params["allow_concurrent_memtable_write"] = 0
dest_params["sync_fault_injection"] = 0
dest_params["disable_wal"] = 0
dest_params["manual_wal_flush_one_in"] = 0
if (
dest_params.get("sync_fault_injection") == 1
or dest_params.get("disable_wal") == 1
or dest_params.get("manual_wal_flush_one_in", 0) > 0
):
dest_params["ingest_external_file_one_in"] = 0
dest_params["enable_compaction_filter"] = 0
if dest_params.get("create_timestamped_snapshot_one_in", 0) > 0:
dest_params["unordered_write"] = 0
if dest_params.get("txn_write_policy", 0) != 0:
dest_params["create_timestamped_snapshot_one_in"] = 0
if dest_params.get("unordered_write", 0) == 1:
if dest_params.get("txn_write_policy", 0) == 1:
dest_params["allow_concurrent_memtable_write"] = 1
else:
dest_params["unordered_write"] = 0
if dest_params.get("disable_wal", 0) == 1:
dest_params["atomic_flush"] = 1
dest_params["sync"] = 0
dest_params["write_fault_one_in"] = 0
dest_params["reopen"] = 0
dest_params["manual_wal_flush_one_in"] = 0
dest_params["recycle_log_file_num"] = 0
if dest_params.get("open_files", 1) != -1:
dest_params["compaction_ttl"] = 0
dest_params["periodic_compaction_seconds"] = 0
if dest_params.get("compaction_style", 0) == 2:
dest_params["compaction_ttl"] = 0
dest_params["periodic_compaction_seconds"] = 0
dest_params["preclude_last_level_data_seconds"] = 0
dest_params["last_level_temperature"] = "kUnknown"
else:
dest_params["file_temperature_age_thresholds"] = ""
dest_params["fifo_compaction_max_data_files_size_mb"] = 0
dest_params["fifo_compaction_use_kv_ratio_compaction"] = 0
if dest_params["partition_filters"] == 1:
if dest_params["index_type"] != 2:
dest_params["partition_filters"] = 0
if dest_params.get("atomic_flush", 0) == 1:
dest_params["enable_pipelined_write"] = 0
if (
dest_params.get("sst_file_manager_bytes_per_sec", 0) == 0
or dest_params.get("test_secondary") == 1
):
dest_params["sst_file_manager_bytes_per_truncate"] = 0
if dest_params.get("prefix_size") == -1:
dest_params["readpercent"] += dest_params.get("prefixpercent", 20)
dest_params["prefixpercent"] = 0
if (
dest_params.get("prefix_size") == -1
and dest_params.get("memtable_whole_key_filtering") == 0
):
dest_params["memtable_prefix_bloom_size_ratio"] = 0
if dest_params.get("two_write_queues") == 1:
dest_params["enable_pipelined_write"] = 0
if dest_params.get("best_efforts_recovery") == 1:
dest_params["disable_wal"] = 1
dest_params["enable_compaction_filter"] = 0
dest_params["sync"] = 0
dest_params["write_fault_one_in"] = 0
dest_params["skip_verifydb"] = 1
dest_params["verify_db_one_in"] = 0
if dest_params.get("use_txn") == 1 and dest_params.get("txn_write_policy", 0) != 0:
dest_params["sync_fault_injection"] = 0
dest_params["disable_wal"] = 0
dest_params["manual_wal_flush_one_in"] = 0
dest_params["use_put_entity_one_in"] = 0
dest_params["use_multi_cf_iterator"] = 0
dest_params["commit_bypass_memtable_one_in"] = 0
dest_params["remote_compaction_worker_threads"] = 0
if dest_params.get("test_multi_ops_txns") == 1:
dest_params["write_fault_one_in"] = 0
dest_params["metadata_write_fault_one_in"] = 0
dest_params["read_fault_one_in"] = 0
dest_params["metadata_read_fault_one_in"] = 0
if dest_params.get("txn_write_policy", 0) != 0:
dest_params["wp_snapshot_cache_bits"] = 1
dest_params["wp_commit_cache_bits"] = 10
dest_params["enable_pipelined_write"] = 0
dest_params["checkpoint_one_in"] = 0
dest_params["use_only_the_last_commit_time_batch_for_recovery"] = 1
dest_params["clear_wp_commit_cache_one_in"] = 10
dest_params["lock_wal_one_in"] = 0
if dest_params["use_put_entity_one_in"] != 0:
dest_params["use_full_merge_v1"] = 0
if dest_params["file_checksum_impl"] == "none":
dest_params["verify_file_checksums_one_in"] = 0
if dest_params["write_fault_one_in"] > 0:
dest_params["max_write_buffer_number"] = max(
dest_params["max_write_buffer_number"], 10
)
if dest_params["secondary_cache_uri"].find("compressed_secondary_cache") >= 0:
dest_params["compressed_secondary_cache_size"] = 0
dest_params["compressed_secondary_cache_ratio"] = 0.0
if dest_params["cache_type"].find("tiered_") >= 0:
if dest_params["compressed_secondary_cache_size"] > 0:
dest_params["compressed_secondary_cache_ratio"] = float(
dest_params["compressed_secondary_cache_size"]
/ (
dest_params["cache_size"]
+ dest_params["compressed_secondary_cache_size"]
)
)
dest_params["compressed_secondary_cache_size"] = 0
else:
dest_params["compressed_secondary_cache_ratio"] = 0.0
dest_params["cache_type"] = dest_params["cache_type"].replace("tiered_", "")
else:
if dest_params["secondary_cache_uri"]:
dest_params["compressed_secondary_cache_size"] = 0
dest_params["compressed_secondary_cache_ratio"] = 0.0
if dest_params["use_write_buffer_manager"]:
if dest_params["cache_size"] <= 0 or dest_params["db_write_buffer_size"] <= 0:
dest_params["use_write_buffer_manager"] = 0
if (
dest_params["user_timestamp_size"] > 0
and dest_params["persist_user_defined_timestamps"] == 0
):
dest_params["enable_blob_files"] = 0
dest_params["allow_setting_blob_options_dynamically"] = 0
dest_params["atomic_flush"] = 0
dest_params["allow_concurrent_memtable_write"] = 0
dest_params["block_protection_bytes_per_key"] = 0
dest_params["use_multiget"] = 0
dest_params["use_multi_get_entity"] = 0
dest_params["readpercent"] += dest_params.get("iterpercent", 10)
dest_params["iterpercent"] = 0
if dest_params["test_best_efforts_recovery"] == 0:
dest_params["disable_wal"] = 0
if dest_params.get("user_timestamp_size", 0) > 0:
dest_params["index_block_search_type"] = 0
if (
dest_params.get("enable_compaction_filter", 0) == 1
or dest_params.get("inplace_update_support", 0) == 1
):
dest_params["acquire_snapshot_one_in"] = 0
dest_params["compact_range_one_in"] = 0
dest_params["readpercent"] += dest_params.get(
"iterpercent", 10
) + dest_params.get("prefixpercent", 20)
dest_params["iterpercent"] = 0
dest_params["prefixpercent"] = 0
dest_params["check_multiget_consistency"] = 0
dest_params["check_multiget_entity_consistency"] = 0
if dest_params.get("disable_wal") == 0:
if (
dest_params.get("reopen", 0) > 0
or (
dest_params.get("manual_wal_flush_one_in")
and dest_params.get("column_families") != 1
)
or (
dest_params.get("use_txn") != 0
and dest_params.get("use_optimistic_txn") == 0
)
):
dest_params["exclude_wal_from_write_fault_injection"] = 1
dest_params["metadata_write_fault_one_in"] = 0
dest_params["remote_compaction_worker_threads"] = 0
if dest_params.get("compression_manager") == "custom":
if dest_params.get("block_align") == 1:
dest_params["block_align"] = 0
if dest_params["format_version"] < 7:
dest_params["format_version"] = 7
elif (
dest_params.get("compression_manager") == "mixed"
or dest_params.get("compression_manager") == "randommixed"
):
dest_params["block_align"] = 0
elif dest_params.get("compression_manager") == "autoskip":
if dest_params.get("compression_type") == "none":
dest_params["compression_type"] = random.choice(
["snappy", "zlib", "lz4", "lz4hc", "xpress", "zstd"]
)
if dest_params.get("bottommost_compression_type") == "none":
dest_params["bottommost_compression_type"] = random.choice(
["snappy", "zlib", "lz4", "lz4hc", "xpress", "zstd"]
)
dest_params["block_align"] = 0
else:
if dest_params.get("block_align") == 1:
dest_params["compression_type"] = "none"
dest_params["bottommost_compression_type"] = "none"
if dest_params.get("periodic_compaction_seconds") == 0:
dest_params["daily_offpeak_time_utc"] = ""
if dest_params.get("use_put_entity_one_in") == 1:
dest_params["use_timed_put_one_in"] = 0
elif (
dest_params.get("use_put_entity_one_in", 0) > 1
and dest_params.get("use_timed_put_one_in") == 1
):
dest_params["use_timed_put_one_in"] = 3
if (
dest_params.get("write_dbid_to_manifest") == 0
and dest_params.get("write_identity_file") == 0
):
dest_params["write_dbid_to_manifest"] = 1
if dest_params.get("checkpoint_one_in") != 0:
dest_params["lock_wal_one_in"] = 0
if (
dest_params.get("ingest_external_file_one_in") == 0
or dest_params.get("delrangepercent") == 0
):
dest_params["test_ingest_standalone_range_deletion_one_in"] = 0
if (
dest_params.get("use_txn", 0) == 1
and dest_params.get("commit_bypass_memtable_one_in", 0) > 0
):
dest_params["enable_blob_files"] = 0
dest_params["allow_setting_blob_options_dynamically"] = 0
dest_params["allow_concurrent_memtable_write"] = 0
dest_params["use_put_entity_one_in"] = 0
dest_params["use_get_entity"] = 0
dest_params["use_multi_get_entity"] = 0
dest_params["enable_pipelined_write"] = 0
dest_params["use_attribute_group"] = 0
if (
dest_params.get("enable_pipelined_write", 0)
or dest_params.get("unordered_write", 0)
or dest_params.get("disable_wal", 0) == 0
or dest_params.get("user_timestamp_size", 0)
):
dest_params["ingest_wbwi_one_in"] = 0
if dest_params.get("test_secondary") == 1:
dest_params["continuous_verification_interval"] = 0
if dest_params.get("use_multiscan") == 1:
dest_params["async_io"] = 0
dest_params["delpercent"] += dest_params["delrangepercent"]
dest_params["delrangepercent"] = 0
dest_params["prefix_size"] = -1
dest_params["iterpercent"] += dest_params["prefixpercent"]
dest_params["prefixpercent"] = 0
dest_params["read_fault_one_in"] = 0
dest_params["memtable_prefix_bloom_size_ratio"] = 0
dest_params["max_sequential_skip_in_iterations"] = sys.maxsize
dest_params["test_ingest_standalone_range_deletion_one_in"] = 0
dest_params["skip_stats_update_on_db_open"] = 0
if dest_params["inplace_update_support"] == 1:
dest_params["memtable_veirfy_per_key_checksum_on_seek"] = 0
return dest_params
def gen_cmd_params(args):
params = {}
params.update(default_params)
if args.test_type == "blackbox":
params.update(blackbox_default_params)
if args.test_type == "whitebox":
params.update(whitebox_default_params)
if args.simple:
params.update(simple_default_params)
if args.test_type == "blackbox":
params.update(blackbox_simple_default_params)
if args.test_type == "whitebox":
params.update(whitebox_simple_default_params)
if args.cf_consistency:
params.update(cf_consistency_params)
if args.txn:
params.update(txn_params)
if args.optimistic_txn:
params.update(optimistic_txn_params)
if args.test_best_efforts_recovery:
params.update(best_efforts_recovery_params)
if args.enable_ts:
params.update(ts_params)
if args.test_multiops_txn:
params.update(multiops_txn_params)
if args.test_tiered_storage:
params.update(tiered_params)
if (
not args.test_best_efforts_recovery
and not args.test_tiered_storage
and params.get("test_secondary", 0) == 0
and random.choice([0] * 9 + [1]) == 1
):
params.update(blob_params)
if "compaction_style" not in params:
params["compaction_style"] = 0 if not args.test_tiered_storage else 1
for k, v in vars(args).items():
if v is not None:
params[k] = v
return params
def gen_cmd(params, unknown_params):
finalzied_params = finalize_and_sanitize(params)
cmd = (
[stress_cmd]
+ [
f"--{k}={v}"
for k, v in [(k, finalzied_params[k]) for k in sorted(finalzied_params)]
if k
not in {
"test_type",
"simple",
"duration",
"interval",
"random_kill_odd",
"cf_consistency",
"txn",
"optimistic_txn",
"test_best_efforts_recovery",
"enable_ts",
"test_multiops_txn",
"stress_cmd",
"test_tiered_storage",
"cleanup_cmd",
"print_stderr_separately",
"verify_timeout",
}
and v is not None
]
+ unknown_params
)
return cmd
def execute_cmd(cmd, timeout=None, timeout_pstack=False):
child = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
print(
"Running db_stress with pid=%d: %s\n\n"
% (child.pid, " ".join(quote_arg_for_display(arg) for arg in cmd))
)
pid = child.pid
try:
outs, errs = child.communicate(timeout=timeout)
hit_timeout = False
print("WARNING: db_stress ended before kill: exitcode=%d\n" % child.returncode)
except subprocess.TimeoutExpired:
hit_timeout = True
if timeout_pstack:
os.system("pstack %d" % pid)
child.kill()
print("KILLED %d\n" % child.pid)
outs, errs = child.communicate()
return hit_timeout, child.returncode, outs.decode("utf-8"), errs.decode("utf-8")
def print_output_and_exit_on_error(stdout, stderr, print_stderr_separately=False):
print("stdout:\n", stdout)
if len(stderr) == 0:
return
if print_stderr_separately:
print("stderr:\n", stderr, file=sys.stderr)
else:
print("stderr:\n", stderr)
sys.exit(2)
def cleanup_after_success(dbname):
cleanup_cmd_parts = [stress_cmd, "--destroy_db_and_exit=1", "--db=" + dbname]
for arg in remain_args:
parts = arg.split("=", 1)
if parts[0] in ["--env_uri", "--fs_uri"]:
cleanup_cmd_parts.append(arg)
print("Running DB cleanup command - %s\n" % " ".join(cleanup_cmd_parts))
ret = subprocess.call(cleanup_cmd_parts)
if ret != 0:
print("ERROR: DB cleanup returned error %d\n" % ret)
sys.exit(2)
def blackbox_crash_main(args, unknown_args):
cmd_params = gen_cmd_params(args)
dbname = get_dbname("blackbox")
exit_time = time.time() + cmd_params["duration"]
print(
"Running blackbox-crash-test with \n"
+ "interval_between_crash="
+ str(cmd_params["interval"])
+ "\n"
+ "total-duration="
+ str(cmd_params["duration"])
+ "\n"
)
while time.time() < exit_time:
apply_random_seed_per_iteration()
cmd = gen_cmd(
dict(list(cmd_params.items()) + list({"db": dbname}.items())), unknown_args
)
hit_timeout, retcode, outs, errs = execute_cmd(cmd, cmd_params["interval"])
cmd_params["destroy_db_initially"] = 0
if not hit_timeout:
print("Exit Before Killing")
print_output_and_exit_on_error(outs, errs, args.print_stderr_separately)
sys.exit(2)
print_output_and_exit_on_error(outs, errs, args.print_stderr_separately)
time.sleep(1)
time.sleep(1)
print("Running final time for verification")
cmd_params.update({"verification_only": 1})
cmd_params.update({"skip_verifydb": 0})
cmd = gen_cmd(
dict(list(cmd_params.items()) + list({"db": dbname}.items())), unknown_args
)
hit_timeout, retcode, outs, errs = execute_cmd(
cmd, cmd_params["verify_timeout"], True
)
print_output_and_exit_on_error(outs, errs, args.print_stderr_separately)
cleanup_after_success(dbname)
def whitebox_crash_main(args, unknown_args):
cmd_params = gen_cmd_params(args)
dbname = get_dbname("whitebox")
cur_time = time.time()
exit_time = cur_time + cmd_params["duration"]
half_time = cur_time + cmd_params["duration"] // 2
print(
"Running whitebox-crash-test with \n"
+ "total-duration="
+ str(cmd_params["duration"])
+ "\n"
)
total_check_mode = 4
check_mode = 0
kill_random_test = cmd_params["random_kill_odd"]
kill_mode = 0
prev_compaction_style = -1
succeeded = True
hit_timeout = False
while time.time() < exit_time:
apply_random_seed_per_iteration()
if check_mode == 0:
additional_opts = {
"ops_per_thread": 100
* cmd_params["ops_per_thread"],
}
if kill_mode == 0:
additional_opts.update(
{
"kill_random_test": kill_random_test,
}
)
elif kill_mode == 1:
if cmd_params.get("disable_wal", 0) == 1:
my_kill_odd = kill_random_test // 50 + 1
else:
my_kill_odd = kill_random_test // 10 + 1
additional_opts.update(
{
"kill_random_test": my_kill_odd,
"kill_exclude_prefixes": "WritableFileWriter::Append,"
+ "WritableFileWriter::WriteBuffered",
}
)
elif kill_mode == 2:
additional_opts.update(
{
"kill_random_test": (kill_random_test // 5000 + 1),
"kill_exclude_prefixes": "WritableFileWriter::Append,"
"WritableFileWriter::WriteBuffered,"
"PosixMmapFile::Allocate,WritableFileWriter::Flush",
}
)
kill_mode = (kill_mode + 1) % 3
elif check_mode == 1:
additional_opts = {
"kill_random_test": None,
"ops_per_thread": cmd_params["ops_per_thread"],
"compaction_style": 1,
}
if not args.test_tiered_storage and random.randint(0, 1) == 1:
additional_opts["num_levels"] = 1
elif check_mode == 2:
additional_opts = {
"kill_random_test": None,
"ops_per_thread": cmd_params["ops_per_thread"] // 5,
"compaction_style": 2,
}
if args.test_tiered_storage:
additional_opts["num_levels"] = 1
else:
additional_opts = {
"kill_random_test": None,
"ops_per_thread": cmd_params["ops_per_thread"],
}
cur_compaction_style = additional_opts.get(
"compaction_style", cmd_params.get("compaction_style", 0)
)
if (
prev_compaction_style != -1
and prev_compaction_style != cur_compaction_style
):
print(
"`compaction_style` is changed in current run so `destroy_db_initially` is set to 1 as a short-term solution to avoid cycling through previous db of different compaction style."
+ "\n"
)
cmd_params["destroy_db_initially"] = 1
prev_compaction_style = cur_compaction_style
cmd = gen_cmd(
dict(
list(cmd_params.items())
+ list(additional_opts.items())
+ list({"db": dbname}.items())
),
unknown_args,
)
print(
"Running:" + " ".join(cmd) + "\n"
)
hit_timeout, retncode, stdoutdata, stderrdata = execute_cmd(
cmd, exit_time - time.time() + 900
)
cmd_params["destroy_db_initially"] = 0
msg = "check_mode={}, kill option={}, exitcode={}\n".format(
check_mode, additional_opts["kill_random_test"], retncode
)
print(msg)
print_output_and_exit_on_error(
stdoutdata, stderrdata, args.print_stderr_separately
)
if hit_timeout:
print("Killing the run for running too long")
break
succeeded = False
if additional_opts["kill_random_test"] is None and (retncode == 0):
succeeded = True
elif additional_opts["kill_random_test"] is not None and retncode <= 0:
succeeded = True
if not succeeded:
print("TEST FAILED. See kill option and exit code above!!!\n")
sys.exit(1)
if time.time() > half_time:
cmd_params["destroy_db_initially"] = 1
if expected_values_dir is not None:
shutil.rmtree(expected_values_dir, True)
os.mkdir(expected_values_dir)
check_mode = (check_mode + 1) % total_check_mode
time.sleep(1)
if succeeded or hit_timeout:
cleanup_after_success(dbname)
def main():
global stress_cmd
parser = argparse.ArgumentParser(
description="This script runs and kills \
db_stress multiple times"
)
parser.add_argument("test_type", choices=["blackbox", "whitebox"])
parser.add_argument("--simple", action="store_true")
parser.add_argument("--cf_consistency", action="store_true")
parser.add_argument("--txn", action="store_true")
parser.add_argument("--optimistic_txn", action="store_true")
parser.add_argument("--test_best_efforts_recovery", action="store_true")
parser.add_argument("--enable_ts", action="store_true")
parser.add_argument("--test_multiops_txn", action="store_true")
parser.add_argument("--stress_cmd")
parser.add_argument("--test_tiered_storage", action="store_true")
parser.add_argument("--cleanup_cmd") parser.add_argument("--print_stderr_separately", action="store_true", default=False)
all_params = dict(
list(default_params.items())
+ list(blackbox_default_params.items())
+ list(whitebox_default_params.items())
+ list(simple_default_params.items())
+ list(blackbox_simple_default_params.items())
+ list(whitebox_simple_default_params.items())
+ list(blob_params.items())
+ list(ts_params.items())
+ list(multiops_txn_params.items())
+ list(best_efforts_recovery_params.items())
+ list(cf_consistency_params.items())
+ list(tiered_params.items())
+ list(txn_params.items())
+ list(optimistic_txn_params.items())
)
for k, v in all_params.items():
parser.add_argument("--" + k, type=type(v() if callable(v) else v))
args, unknown_args = parser.parse_known_args(remain_args)
test_tmpdir = os.environ.get(_TEST_DIR_ENV_VAR)
if test_tmpdir is not None and not is_remote_db:
isdir = False
try:
isdir = os.path.isdir(test_tmpdir)
if not isdir:
print(
"ERROR: %s env var is set to a non-existent directory: %s. Update it to correct directory path."
% (_TEST_DIR_ENV_VAR, test_tmpdir)
)
sys.exit(1)
except OSError:
pass
if args.stress_cmd:
stress_cmd = args.stress_cmd
if args.test_type == "blackbox":
blackbox_crash_main(args, unknown_args)
if args.test_type == "whitebox":
whitebox_crash_main(args, unknown_args)
if expected_values_dir is not None:
shutil.rmtree(expected_values_dir)
if multiops_txn_key_spaces_file is not None:
os.remove(multiops_txn_key_spaces_file)
if __name__ == "__main__":
main()