#!/usr/bin/env bash # vim: ts=8 sw=2 smarttab # # run_seed_to.sh - Run ceph_test_filestore_idempotent_sequence up until an # injection point, generating a sequence of operations based on a # provided seed. # # We also perform three additional tests, focused on assessing if # replaying a larger chunck of the journal affects the expected store # behavior. These tests will be performed by increasing the store's # journal sync interval to a very large value, allowing the store to # finish execution before the first sync (unless the store runs for # over 10 hours, case on which the interval variables must be changed # to an appropriate value). Unless the '--no-journal-test' option is # specified, we will run the 3 following scenarios: # # 1) journal sync'ing for both stores is good as disabled # (we call it '00', for store naming purposes) # 2) journal sync'ing for store A is as good as disabled # (we call it '01', for store naming purposes) # 3) journal sync'ing for store B is as good as disabled # (we call it '10', for store naming purposes) # # All log files are also appropriately named accordingly (i.e., a.00.fail, # a.10.recover, or b.01.clean). # # By default, the test will not exit on error, although it will show the # fail message. This behavior is so defined so we run the whole battery of # tests, and obtain as many mismatches as possible in one go. We may force # the test to exit on error by specifying the '--exit-on-error' option. # # set -e test_opts="" usage() { echo "usage: $1 [options..] " echo echo "options:" echo " -c, --colls # of collections" echo " -o, --objs # of objects" echo " -b, --btrfs seq number for btrfs stores" echo " --no-journal-test don't perform journal replay tests" echo " -e, --exit-on-error exit with 1 on error" echo " -v, --valgrind run commands through valgrind" echo echo "env vars:" echo " OPTS_STORE additional opts for both stores" echo " OPTS_STORE_A additional opts for store A" echo " OPTS_STORE_B additional opts for store B" echo } echo $0 $* die_on_missing_arg() { if [[ "$2" == "" ]]; then echo "$1: missing required parameter" exit 1 fi } required_args=2 obtained_args=0 seed="" killat="" on_btrfs=0 on_btrfs_seq=0 journal_test=1 min_sync_interval="36000" # ten hours, yes. max_sync_interval="36001" exit_on_error=0 v="" do_rm() { if [[ $on_btrfs -eq 0 ]]; then rm -fr $* fi } set_arg() { if [[ $1 -eq 1 ]]; then seed=$2 elif [[ $1 -eq 2 ]]; then killat=$2 else echo "error: unknown purpose for '$2'" usage $0 exit 1 fi } while [[ $# -gt 0 ]]; do case "$1" in -c | --colls) die_on_missing_arg "$1" "$2" test_opts="$test_opts --test-num-colls $2" shift 2 ;; -o | --objs) die_on_missing_arg "$1" "$2" test_opts="$test_opts --test-num-objs $2" shift 2 ;; -h | --help) usage $0 ; exit 0 ;; -b | --btrfs) die_on_missing_arg "$1" "$2" on_btrfs=1 on_btrfs_seq=$2 shift 2 ;; --no-journal-test) journal_test=0 shift ;; -e | --exit-on-error) exit_on_error=1 shift ;; -v | --valgrind) v="valgrind --leak-check=full" shift ;; --) shift break ;; -*) echo "$1: unknown option" >&2 usage $0 exit 1 ;; *) obtained_args=$(($obtained_args+1)) set_arg $obtained_args $1 shift ;; esac done if [[ $obtained_args -ne $required_args ]]; then echo "error: missing argument" usage $0 ; exit 1 fi if [[ "$OPTS_STORE" != "" ]]; then test_opts="$test_opts $OPTS_STORE" fi test_opts_a="$test_opts" test_opts_b="$test_opts" if [[ "$OPTS_STORE_A" != "" ]]; then test_opts_a="$test_opts_a $OPTS_STORE_A" fi if [[ "$OPTS_STORE_B" != "" ]]; then test_opts_b="$test_opts_b $OPTS_STORE_B" fi echo seed $seed echo kill at $killat # run forever, until $killat... to=1000000000 # # store names # # We need these for two reasons: # 1) if we are running the tests on a btrfs volume, then we need to use # a seq number for each run. Being on btrfs means we will fail when # removing the store's directories and it's far more simple to just # specify differente store names such as 'a.$seq' or 'b.$seq'. # # 2) unless the '--no-journal-test' option is specified, we will run # three additional tests for each store, and we will reuse the same # command for each one of the runs, but varying the store's name and # arguments. # store_a="a" store_b="b" if [[ $on_btrfs -eq 1 ]]; then store_a="$store_a.$on_btrfs_seq" store_b="$store_b.$on_btrfs_seq" fi total_runs=1 if [[ $journal_test -eq 1 ]]; then total_runs=$(($total_runs + 3)) fi num_runs=0 opt_min_sync="--filestore-min-sync-interval $min_sync_interval" opt_max_sync="--filestore-max-sync-interval $max_sync_interval" ret=0 while [[ $num_runs -lt $total_runs ]]; do tmp_name_a=$store_a tmp_name_b=$store_b tmp_opts_a=$test_opts_a tmp_opts_b=$test_opts_b # # We have already tested whether there are diffs when both journals # are properly working. Now let's try on three other scenarios: # 1) journal sync'ing for both stores is good as disabled # (we call it '00') # 2) journal sync'ing for store A is as good as disabled # (we call it '01') # 3) journal sync'ing for store B is as good as disabled # (we call it '10') # if [[ $num_runs -gt 0 && $journal_test -eq 1 ]]; then echo "run #$num_runs" case $num_runs in 1) tmp_name_a="$tmp_name_a.00" tmp_name_b="$tmp_name_b.00" tmp_opts_a="$tmp_opts_a $opt_min_sync $opt_max_sync" tmp_opts_b="$tmp_opts_b $opt_min_sync $opt_max_sync" ;; 2) tmp_name_a="$tmp_name_a.01" tmp_name_b="$tmp_name_b.01" tmp_opts_a="$tmp_opts_a $opt_min_sync $opt_max_sync" ;; 3) tmp_name_a="$tmp_name_a.10" tmp_name_b="$tmp_name_b.10" tmp_opts_b="$tmp_opts_b $opt_min_sync $opt_max_sync" ;; esac fi do_rm $tmp_name_a $tmp_name_a.fail $tmp_name_a.recover $v ceph_test_filestore_idempotent_sequence run-sequence-to $to \ $tmp_name_a $tmp_name_a/journal \ --test-seed $seed --osd-journal-size 100 \ --filestore-kill-at $killat $tmp_opts_a \ --log-file $tmp_name_a.fail --debug-filestore 20 --no-log-to-stderr || true stop_at=`ceph_test_filestore_idempotent_sequence get-last-op \ $tmp_name_a $tmp_name_a/journal \ --log-file $tmp_name_a.recover \ --debug-filestore 20 --debug-journal 20 --no-log-to-stderr` if [[ "`expr $stop_at - $stop_at 2>/dev/null`" != "0" ]]; then echo "error: get-last-op returned '$stop_at'" exit 1 fi echo stopped at $stop_at do_rm $tmp_name_b $tmp_name_b.clean $v ceph_test_filestore_idempotent_sequence run-sequence-to \ $stop_at $tmp_name_b $tmp_name_b/journal \ --test-seed $seed --osd-journal-size 100 \ --log-file $tmp_name_b.clean --debug-filestore 20 --no-log-to-stderr \ $tmp_opts_b if $v ceph_test_filestore_idempotent_sequence diff \ $tmp_name_a $tmp_name_a/journal $tmp_name_b $tmp_name_b/journal --no-log-to-stderr --log-file $tmp_name_a.diff.log --debug-filestore 20 ; then echo OK else echo "FAIL" echo " see:" echo " $tmp_name_a.fail -- leading up to failure" echo " $tmp_name_a.recover -- journal replay" echo " $tmp_name_b.clean -- the clean reference" ret=1 if [[ $exit_on_error -eq 1 ]]; then exit 1 fi fi num_runs=$(($num_runs+1)) done exit $ret