1
0
mirror of https://github.com/facebook/rocksdb.git synced 2026-10-23 08:09:02 +03:00

Enable core dumps for sanitizer crash tests (#15131)

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

ASAN and other sanitizer runtimes can disable coredumps or terminate without a core after the test driver sets its shell core limit. This leaves sanitizer stress-test failures with an LLDB stack but no core for the DB artifact.

Configure ASAN_OPTIONS, TSAN_OPTIONS, and UBSAN_OPTIONS during sanitizer crash-test steps so reports terminate with a core-generating abort and core dumping remains enabled. Preserve caller-provided options and the existing Make fallback semantics. Keep the behavior scoped to test steps and crash targets.

Enabling sanitizer cores raises a concern that the generated core-dump artifacts can be large because they include the process working set. Reduce RocksDB's cache and memtable contribution to the core size without replacing the normal randomized test configuration. Add a db_crashtest cache/write-buffer size multiplier that is applied after each iteration chooses its values, and pass 0.5 from ASAN, TSAN, and UBSAN crash lanes. For the simple profile, cache_size remains randomized with 8/32 MiB becoming 4/16 MiB, while the 32 MiB write buffer becomes 16 MiB. Preserve RocksDB's 64 KiB minimum write-buffer size and leave non-sanitizer lanes unchanged.

Reviewed By: rban1

Differential Revision: D116666171

fbshipit-source-id: aa157cfa255bb637d4a68e54ea2039db779fdc53
This commit is contained in:
Xingbo Wang
2026-08-20 04:59:40 -07:00
committed by meta-codesync[bot]
parent d3a82f28ce
commit 42fca1bb39
2 changed files with 74 additions and 0 deletions

View File

@@ -48,6 +48,7 @@ DEFAULT_LIVENESS_NO_PROGRESS_TIMEOUT_SEC = 300
REMOTE_DB_LIVENESS_TIMEOUT_MULTIPLIER = 2
_FAULT_INJECTION_LOG_DIR_NAME = "fault_injection_logs"
_REMOTE_DB_URI_FLAGS = ("--env_uri", "--fs_uri")
_MIN_WRITE_BUFFER_SIZE = 64 * 1024
def get_random_seed(override):
@@ -76,6 +77,25 @@ def stress_cmd_env():
return env
def apply_cache_and_write_buffer_size_multiplier(params):
"""Scale selected per-iteration memory sizes while preserving randomization."""
multiplier = params.pop("cache_and_write_buffer_size_multiplier", None)
if multiplier is None:
return
if not math.isfinite(multiplier) or multiplier <= 0:
raise ValueError(
"cache_and_write_buffer_size_multiplier must be finite and greater than zero"
)
for name, minimum in (
("cache_size", 1),
("write_buffer_size", _MIN_WRITE_BUFFER_SIZE),
):
value = params.get(name)
if value is not None and value > 0:
params[name] = max(int(value * multiplier), minimum)
def normalize_remote_db_args(args):
"""Normalize supported remote URI flags to --flag=value form."""
normalized_args = []
@@ -1053,6 +1073,7 @@ multiops_txn_params = {
def finalize_and_sanitize(src_params):
dest_params = {k: v() if callable(v) else v for (k, v) in src_params.items()}
apply_cache_and_write_buffer_size_multiplier(dest_params)
if is_release_mode():
dest_params["read_fault_one_in"] = 0
if dest_params.get("compression_max_dict_bytes") == 0:
@@ -2586,6 +2607,11 @@ def main():
parser.add_argument("--test_tiered_storage", action="store_true")
parser.add_argument("--cleanup_cmd") # ignore old option for now
parser.add_argument("--print_stderr_separately", action="store_true", default=False)
parser.add_argument(
"--cache_and_write_buffer_size_multiplier",
type=float,
help="Scale each iteration's cache_size and write_buffer_size",
)
all_params = dict(
list(default_params.items())
@@ -2613,6 +2639,11 @@ def main():
# unknown_args are passed directly to db_stress
args, unknown_args = parser.parse_known_args(remain_args)
multiplier = args.cache_and_write_buffer_size_multiplier
if multiplier is not None and (not math.isfinite(multiplier) or multiplier <= 0):
parser.error(
"--cache_and_write_buffer_size_multiplier must be finite and greater than zero"
)
test_tmpdir = os.environ.get(_TEST_DIR_ENV_VAR)
if test_tmpdir is not None and not is_remote_db:
isdir = False

View File

@@ -153,6 +153,49 @@ class DBCrashTestTest(unittest.TestCase):
any(arg.startswith("--use_coro_db_api=") for arg in command)
)
def test_cache_and_write_buffer_size_multiplier_preserves_randomization(self):
db_crashtest = self.load_db_crashtest()
cache_sizes = iter([8 * 1024 * 1024, 32 * 1024 * 1024])
params = self.build_params(
db_crashtest.default_params,
{
"cache_size": lambda: next(cache_sizes),
"write_buffer_size": 32 * 1024 * 1024,
"cache_and_write_buffer_size_multiplier": 0.5,
},
)
first_command, _ = db_crashtest.gen_cmd(params, [])
second_command, _ = db_crashtest.gen_cmd(params, [])
self.assertIn("--cache_size=4194304", first_command)
self.assertIn("--cache_size=16777216", second_command)
self.assertIn("--write_buffer_size=16777216", first_command)
self.assertIn("--write_buffer_size=16777216", second_command)
self.assertFalse(
any(
arg.startswith("--cache_and_write_buffer_size_multiplier=")
for arg in first_command
)
)
def test_cache_and_write_buffer_size_multiplier_respects_write_buffer_minimum(
self,
):
db_crashtest = self.load_db_crashtest()
params = self.build_params(
db_crashtest.default_params,
{
"write_buffer_size": 64 * 1024,
"cache_and_write_buffer_size_multiplier": 0.5,
},
)
finalized = db_crashtest.finalize_and_sanitize(params)
self.assertEqual(64 * 1024, finalized["write_buffer_size"])
self.assertNotIn("cache_and_write_buffer_size_multiplier", finalized)
def test_get_ev_parent_dir_preserves_existing_contents(self):
os.makedirs(self.expected_dir)
marker = os.path.join(self.expected_dir, "marker")