The branch, master has been updated via 3e5d2b61fcb4d0062d2573d99724f630a4fc4622 (commit) via c6433e43ad2481d84e8d9a1ee1c6e29b90423a86 (commit) via 25d797f61c3b5b7090fb662adde6ed9e434e8a61 (commit) from 70d22efdf104db1fc951263cedfbdb95b0b44342 (commit)
http://gitweb.samba.org/?p=ctdb.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 3e5d2b61fcb4d0062d2573d99724f630a4fc4622 Author: Ronnie Sahlberg <ronniesahlb...@gmail.com> Date: Wed Feb 8 08:59:53 2012 +1100 TESTS: Add a test that verifies that RecoverPDBBySeqNum works as expected. If this tunable is set to 1 AND the persistent database contains a record "__db_sequence_number__" then we will recover the whole database as-is instead of doing the record by record recovery commit c6433e43ad2481d84e8d9a1ee1c6e29b90423a86 Author: Ronnie Sahlberg <ronniesahlb...@gmail.com> Date: Tue Feb 7 12:14:57 2012 +1100 Ad test tool to store data and ctdb header into a local tdb file commit 25d797f61c3b5b7090fb662adde6ed9e434e8a61 Author: Ronnie Sahlberg <ronniesahlb...@gmail.com> Date: Tue Feb 7 10:53:49 2012 +1100 TFETCH add verbose flag to print also the record ltdb heaer ----------------------------------------------------------------------- Summary of changes: tests/simple/70_recoverpdbbyseqnum.sh | 232 +++++++++++++++++++++++++++++++++ tools/ctdb.c | 83 +++++++++++- 2 files changed, 309 insertions(+), 6 deletions(-) create mode 100755 tests/simple/70_recoverpdbbyseqnum.sh Changeset truncated at 500 lines: diff --git a/tests/simple/70_recoverpdbbyseqnum.sh b/tests/simple/70_recoverpdbbyseqnum.sh new file mode 100755 index 0000000..4b46cbb --- /dev/null +++ b/tests/simple/70_recoverpdbbyseqnum.sh @@ -0,0 +1,232 @@ +#!/bin/bash + +test_info() +{ + cat <<EOF +The tunable RecoverPDBBySeqNum controls how we perform recovery +on persistent databases. +The default is that persistent databases are recovered exactly the same +way as normal databases. That is that we recover record by record. + +If RecoverPDBBySeqNum is set to 1 AND if a record with the key +"__db_sequence_number__" can be found in the database, then instead we will +perform the recovery by picking the copy of the database from the node +that has the highest sequence number and ignore the content on all other +nodes. + + +Prerequisites: + +* An active CTDB cluster with at least 2 active nodes. + +Steps: + +1. Verify that the status on all of the ctdb nodes is 'OK'. +2. create a persistent test database +3. test that RecoveryPDBBySeqNum==0 and no seqnum record blends the database + during recovery +4. test that RecoveryPDBBySeqNum==0 and seqnum record blends the database + during recovery +5. test that RecoveryPDBBySeqNum==1 and no seqnum record blends the database + during recovery +6. test that RecoveryPDBBySeqNum==1 and seqnum record does not blend the database + during recovery + +Expected results: + +* that 3,4,5 will blend the databases and that 6 will recovery the highest seqnum + database + +EOF +} + +. ctdb_test_functions.bash + +ctdb_test_init "$@" + +set -e + +cluster_is_healthy + +try_command_on_node 0 "$CTDB listnodes" +num_nodes=$(echo "$out" | wc -l) + +# create a temporary persistent database to test with +echo create persistent test database persistent_test.tdb +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb attach persistent_test.tdb persistent + + +# set RecoverPDBBySeqNum=0 +echo "setting RecoverPDBBySeqNum to 0" +try_command_on_node -q all $CTDB_TEST_WRAPPER ctdb setvar RecoverPDBBySeqNum 0 + + + +# 3, +# If RecoverPDBBySeqNum==0 and no __db_sequence_number__ +# recover record by record +# +# wipe database +echo +echo test that RecoverPDBBySeqNum==0 and no __db_sequence_number__ blends the database during recovery +echo wipe the test database +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb wipedb persistent_test.tdb + +# add one record to node 0 key==ABC data==ABC +TDB=`try_command_on_node -v -q 0 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(ABC) data(ABC) on node 0" +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x414243 0x070000000000000000000000000000000000000000000000414243 +# +# add one record to node 1 key==DEF data==DEF +TDB=`try_command_on_node -v -q 1 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(DEF) data(DEF) on node 1" +try_command_on_node -q 1 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x444546 0x070000000000000000000000000000000000000000000000444546 + +# force a recovery +echo force a recovery +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb recover + +# check that we now have both records on node 0 +num_records=$(try_command_on_node -v -pq 0 $CTDB_TEST_WRAPPER ctdb cattdb persistent_test.tdb | grep key | egrep "ABC|DEF" | wc -l) +[ $num_records != "2" ] && { + echo "BAD: we did not end up with the expected two records after the recovery" + exit 1 +} +echo "OK. databases were blended" + + + +# 4, +# If RecoverPDBBySeqNum==0 and __db_sequence_number__ +# recover record by record +# +# wipe database +echo +echo test that RecoverPDBBySeqNum==0 and __db_sequence_number__ blends the database during recovery +echo wipe the test database +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb wipedb persistent_test.tdb + +echo "add __db_sequence_number__==5 record to all nodes" +try_command_on_node -v 0 $CTDB_TEST_WRAPPER ctdb nodestatus all | grep pnn | sed -e"s/^pnn://" -e "s/ .*//" | while read PNN; do + TDB=`try_command_on_node -v -q $PNN $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` + try_command_on_node -q $PNN $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x5f5f64625f73657175656e63655f6e756d6265725f5f00 0x0700000000000000000000000000000000000000000000000500000000000000 +done + +# add one record to node 0 key==ABC data==ABC +TDB=`try_command_on_node -v -q 0 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(ABC) data(ABC) on node 0" +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x414243 0x070000000000000000000000000000000000000000000000414243 +echo "add __db_sequence_number__==7 record to node 0" +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x5f5f64625f73657175656e63655f6e756d6265725f5f00 0x0700000000000000000000000000000000000000000000000700000000000000 + +# add one record to node 1 key==DEF data==DEF +TDB=`try_command_on_node -v -q 1 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(DEF) data(DEF) on node 1" +try_command_on_node -q 1 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x444546 0x070000000000000000000000000000000000000000000000444546 +echo "add __db_sequence_number__==8 record to node 1" +try_command_on_node -q 1 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x5f5f64625f73657175656e63655f6e756d6265725f5f00 0x0700000000000000000000000000000000000000000000000800000000000000 + +# force a recovery +echo force a recovery +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb recover + +# check that we now have both records on node 0 +num_records=$(try_command_on_node -v -pq 0 $CTDB_TEST_WRAPPER ctdb cattdb persistent_test.tdb | grep key | egrep "ABC|DEF" | wc -l) +[ $num_records != "2" ] && { + echo "BAD: we did not end up with the expected two records after the recovery" + exit 1 +} +echo "OK. databases were blended" + + + +# set RecoverPDBBySeqNum=1 +echo +echo "setting RecoverPDBBySeqNum to 1" +try_command_on_node -q all $CTDB_TEST_WRAPPER ctdb setvar RecoverPDBBySeqNum 1 + + + +# 5, +# If RecoverPDBBySeqNum==1 and no __db_sequence_number__ +# recover record by record +# +# wipe database +echo +echo test that RecoverPDBBySeqNum==1 and no __db_sequence_number__ blends the database during recovery +echo wipe the test database +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb wipedb persistent_test.tdb + +# add one record to node 0 key==ABC data==ABC +TDB=`try_command_on_node -v -q 0 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(ABC) data(ABC) on node 0" +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x414243 0x070000000000000000000000000000000000000000000000414243 + +# add one record to node 1 key==DEF data==DEF +TDB=`try_command_on_node -v -q 1 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(DEF) data(DEF) on node 1" +try_command_on_node -q 1 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x444546 0x070000000000000000000000000000000000000000000000444546 + +# force a recovery +echo force a recovery +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb recover + +# check that we now have both records on node 0 +num_records=$(try_command_on_node -v -pq 0 $CTDB_TEST_WRAPPER ctdb cattdb persistent_test.tdb | grep key | egrep "ABC|DEF" | wc -l) +[ $num_records != "2" ] && { + echo "BAD: we did not end up with the expected two records after the recovery" + exit 1 +} +echo "OK. databases were blended" + + + +# 6, +# If RecoverPDBBySeqNum==1 and __db_sequence_number__ +# recover whole database +# +# wipe database +echo +echo test that RecoverPDBBySeqNum==1 and __db_sequence_number__ does not blend the database during recovery +echo wipe the test database +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb wipedb persistent_test.tdb + +echo "add __db_sequence_number__==5 record to all nodes" +try_command_on_node -v 0 $CTDB_TEST_WRAPPER ctdb nodestatus all | grep pnn | sed -e"s/^pnn://" -e "s/ .*//" | while read PNN; do + TDB=`try_command_on_node -v -q $PNN $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` + try_command_on_node -q $PNN $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x5f5f64625f73657175656e63655f6e756d6265725f5f00 0x0700000000000000000000000000000000000000000000000500000000000000 +done + + +# add one record to node 0 key==ABC data==ABC +TDB=`try_command_on_node -v -q 0 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(ABC) data(ABC) on node 0" +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x414243 0x070000000000000000000000000000000000000000000000414243 +echo "add __db_sequence_number__==7 record to node 0" +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x5f5f64625f73657175656e63655f6e756d6265725f5f00 0x0700000000000000000000000000000000000000000000000700000000000000 + +# add one record to node 1 key==DEF data==DEF +TDB=`try_command_on_node -v -q 1 $CTDB_TEST_WRAPPER ctdb getdbmap | grep persistent_test.tdb | sed -e "s/.*path://" -e "s/ .*//"` +echo "store key(DEF) data(DEF) on node 1" +try_command_on_node -q 1 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x444546 0x070000000000000000000000000000000000000000000000444546 +echo "add __db_sequence_number__==8 record to node 1" +try_command_on_node -q 1 $CTDB_TEST_WRAPPER ctdb tstore $TDB 0x5f5f64625f73657175656e63655f6e756d6265725f5f00 0x0700000000000000000000000000000000000000000000000800000000000000 + +# force a recovery +echo force a recovery +try_command_on_node -q 0 $CTDB_TEST_WRAPPER ctdb recover + +# check that we now have both records on node 0 +num_records=$(try_command_on_node -v -pq 0 $CTDB_TEST_WRAPPER ctdb cattdb persistent_test.tdb | grep key | egrep "ABC|DEF" | wc -l) +[ $num_records != "1" ] && { + echo "BAD: we did not end up with the expected single record after the recovery" + exit 1 +} + +echo "OK. databases were not blended" + + + +# set RecoverPDBBySeqNum=1 +echo "setting RecoverPDBBySeqNum back to 0" +try_command_on_node -q all $CTDB_TEST_WRAPPER ctdb setvar RecoverPDBBySeqNum 0 diff --git a/tools/ctdb.c b/tools/ctdb.c index 8ef869b..e852ca2 100644 --- a/tools/ctdb.c +++ b/tools/ctdb.c @@ -3487,23 +3487,24 @@ static int control_tfetch(struct ctdb_context *ctdb, int argc, const char **argv tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0); if (tdb == NULL) { - fprintf(stderr, "Failed to open TDB file %s\n", tdb_file); + printf("Failed to open TDB file %s\n", tdb_file); return -1; } if (!strncmp(argv[1], "0x", 2)) { key = hextodata(tmp_ctx, argv[1] + 2); if (key.dsize == 0) { - fprintf(stderr, "Failed to convert \"%s\" into a TDB_DATA\n", argv[1]); + printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]); return -1; } } else { key.dptr = discard_const(argv[1]); key.dsize = strlen(argv[1]); } + data = tdb_fetch(tdb, key); if (data.dptr == NULL || data.dsize < sizeof(struct ctdb_ltdb_header)) { - fprintf(stderr, "Failed to read record %s from tdb %s\n", argv[1], tdb_file); + printf("Failed to read record %s from tdb %s\n", argv[1], tdb_file); tdb_close(tdb); return -1; } @@ -3516,10 +3517,18 @@ static int control_tfetch(struct ctdb_context *ctdb, int argc, const char **argv printf("Failed to open output file %s\n", argv[2]); return -1; } - write(fd, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header)); + if (options.verbose){ + write(fd, data.dptr, data.dsize); + } else { + write(fd, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header)); + } close(fd); } else { - write(1, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header)); + if (options.verbose){ + write(1, data.dptr, data.dsize); + } else { + write(1, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header)); + } } talloc_free(tmp_ctx); @@ -3527,6 +3536,66 @@ static int control_tfetch(struct ctdb_context *ctdb, int argc, const char **argv } /* + store a record and header to a tdb-file + */ +static int control_tstore(struct ctdb_context *ctdb, int argc, const char **argv) +{ + const char *tdb_file; + TDB_CONTEXT *tdb; + TDB_DATA key, data; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + if (argc < 3) { + usage(); + } + + tdb_file = argv[0]; + + tdb = tdb_open(tdb_file, 0, 0, O_RDWR, 0); + if (tdb == NULL) { + printf("Failed to open TDB file %s\n", tdb_file); + return -1; + } + + if (!strncmp(argv[1], "0x", 2)) { + key = hextodata(tmp_ctx, argv[1] + 2); + if (key.dsize == 0) { + printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]); + return -1; + } + } else { + key.dptr = discard_const(argv[1]); + key.dsize = strlen(argv[1]); + } + + if (!strncmp(argv[2], "0x", 2)) { + data = hextodata(tmp_ctx, argv[2] + 2); + if (data.dsize == 0) { + printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[2]); + return -1; + } + } else { + data.dptr = discard_const(argv[2]); + data.dsize = strlen(argv[2]); + } + + if (data.dsize < sizeof(struct ctdb_ltdb_header)) { + printf("Not enough data. You must specify the full ctdb_ltdb_header too when storing\n"); + return -1; + } + if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) { + printf("Failed to write record %s to tdb %s\n", argv[1], tdb_file); + tdb_close(tdb); + return -1; + } + + tdb_close(tdb); + + talloc_free(tmp_ctx); + return 0; +} + +/* write a record to a persistent database */ static int control_pstore(struct ctdb_context *ctdb, int argc, const char **argv) @@ -5356,7 +5425,8 @@ static const struct { { "sync", control_ipreallocate, false, false, "wait until ctdbd has synced all state changes" }, { "pfetch", control_pfetch, false, false, "fetch a record from a persistent database", "<db> <key> [<file>]" }, { "pstore", control_pstore, false, false, "write a record to a persistent database", "<db> <key> <file containing record>" }, - { "tfetch", control_tfetch, false, true, "fetch a record from a [c]tdb-file", "<tdb-file> <key> [<file>]" }, + { "tfetch", control_tfetch, false, true, "fetch a record from a [c]tdb-file [-v]", "<tdb-file> <key> [<file>]" }, + { "tstore", control_tstore, false, true, "store a record (including ltdb header)", "<tdb-file> <key> <data+header>" }, { "readkey", control_readkey, true, false, "read the content off a database key", "<tdb-file> <key>" }, { "writekey", control_writekey, true, false, "write to a database key", "<tdb-file> <key> <value>" }, { "checktcpport", control_chktcpport, false, true, "check if a service is bound to a specific tcp port or not", "<port>" }, @@ -5543,4 +5613,5 @@ int main(int argc, const char *argv[]) (void)poptFreeContext(pc); return ret; + } -- CTDB repository