From 28752b831d46e41553d14ef0ca42748239e543dc Mon Sep 17 00:00:00 2001 From: Barry Perlman Date: Tue, 16 Apr 2013 23:58:06 -0400 Subject: [PATCH] Addresses #2037 refs[t:2037] Add test to verify correct use of directory range locks." git-svn-id: file:///svn/toku/tokudb.2037b@15681 c7de825b-a66e-492c-adef-691d508d4ae1 --- src/tests/transactional_fileops.c | 188 ++++++++++++++++++++++++++---- 1 file changed, 164 insertions(+), 24 deletions(-) diff --git a/src/tests/transactional_fileops.c b/src/tests/transactional_fileops.c index 078d5dd7b58..64806d94014 100644 --- a/src/tests/transactional_fileops.c +++ b/src/tests/transactional_fileops.c @@ -77,17 +77,17 @@ * create a, b, c * commit txn * - * verify_abc() // verify a,b,c exist, c2 and x do not exist + * verify_abcd() // verify a,b,c exist, c2 and x do not exist * * begin txn * perform_ops() // delete b, rename c to c2, create x - * verify_ac2x() // verify a,c2,x exist, b and c do not + * verify_ac2dx() // verify a,c2,x exist, b and c do not * abort txn - * verify_abc() // verify a,b,c exist, c2 and x do not exist + * verify_abcd() // verify a,b,c exist, c2 and x do not exist * begin_txn * perform_ops() * commit - * verify_ac2x() // verify a,c2,x exist, b and c do not + * verify_ac2dx() // verify a,c2,x exist, b and c do not * * * perform_ops() { @@ -97,17 +97,18 @@ * } * * - * verify_abc() { - * a,b,c exist, x, c2 do not exist + * verify_abcd() { + * a,b,c,d exist, x, c2 do not exist * } * * - * verify_ac2x() { - * a exists + * verify_ac2dx() { + * a exists * c2 exists - * x exists - * b does not exist - * c does not exist + * d exists + * x exists + * b does not exist + * c does not exist * } * * @@ -147,28 +148,32 @@ test_shutdown(void) { // create dictionaries a.db, b.db, c.db static void -create_abc(void) { +create_abcd(void) { int r; DB_TXN * txn; DB * db_a; DB * db_b; DB * db_c; + DB * db_d; r=env->txn_begin(env, 0, &txn, 0); CKERR(r); r=db_create(&db_a, env, 0); CKERR(r); r=db_create(&db_b, env, 0); CKERR(r); r=db_create(&db_c, env, 0); CKERR(r); + r=db_create(&db_d, env, 0); CKERR(r); r=db_a->open(db_a, txn, "a.db", 0, DB_BTREE, DB_CREATE, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_b->open(db_b, txn, "b.db", 0, DB_BTREE, DB_CREATE, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_c->open(db_c, txn, "c.db", 0, DB_BTREE, DB_CREATE, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); + r=db_d->open(db_d, txn, "d.db", 0, DB_BTREE, DB_CREATE, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_a->close(db_a, 0); CKERR(r); r=db_b->close(db_b, 0); CKERR(r); + r=db_c->close(db_c, 0); CKERR(r); r=txn->commit(txn, 0); CKERR(r); - r=db_c->close(db_c, 0); CKERR(r); //Should work whether close is before or after commit. Do one after. + r=db_d->close(db_d, 0); CKERR(r); //Should work whether close is before or after commit. Do one after. } @@ -192,15 +197,16 @@ perform_ops(DB_TXN * txn) { // verify that: -// dictionaries a.db, b.db, c.db exist +// dictionaries a.db, b.db, c.db, d.db exist // dictionaries x.db and c2.db do not exist static void -verify_abc(void) { +verify_abcd(void) { int r; DB_TXN * txn; DB * db_a; DB * db_b; DB * db_c; + DB * db_d; DB * db_x; DB * db_c2; @@ -208,6 +214,7 @@ verify_abc(void) { r=db_create(&db_a, env, 0); CKERR(r); r=db_create(&db_b, env, 0); CKERR(r); r=db_create(&db_c, env, 0); CKERR(r); + r=db_create(&db_d, env, 0); CKERR(r); r=db_create(&db_x, env, 0); CKERR(r); r=db_create(&db_c2, env, 0); CKERR(r); @@ -215,6 +222,7 @@ verify_abc(void) { r=db_a->open(db_a, txn, "a.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_b->open(db_b, txn, "b.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_c->open(db_c, txn, "c.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); + r=db_d->open(db_d, txn, "d.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); // should not exist: r=db_x->open(db_x, txn, "x.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR2(r, ENOENT); @@ -223,6 +231,7 @@ verify_abc(void) { r=db_a->close(db_a, 0); CKERR(r); r=db_b->close(db_b, 0); CKERR(r); r=db_c->close(db_c, 0); CKERR(r); + r=db_d->close(db_d, 0); CKERR(r); r=db_x->close(db_x, 0); CKERR(r); r=db_c2->close(db_c2, 0); CKERR(r); @@ -234,14 +243,16 @@ verify_abc(void) { // dictionary a.db exists // dictionaries b.db, c.db do not exist // dictionary c2.db exists +// dictionary d.db exists // dictionary x.db exists static void -verify_ac2x(DB_TXN * parent_txn) { +verify_ac2dx(DB_TXN * parent_txn) { int r; DB_TXN * txn; DB * db_a; DB * db_b; DB * db_c; + DB * db_d; DB * db_x; DB * db_c2; @@ -249,12 +260,14 @@ verify_ac2x(DB_TXN * parent_txn) { r=db_create(&db_a, env, 0); CKERR(r); r=db_create(&db_b, env, 0); CKERR(r); r=db_create(&db_c, env, 0); CKERR(r); + r=db_create(&db_d, env, 0); CKERR(r); r=db_create(&db_x, env, 0); CKERR(r); r=db_create(&db_c2, env, 0); CKERR(r); // should exist: r=db_a->open(db_a, txn, "a.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_c2->open(db_c2, txn, "c2.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); + r=db_d->open(db_d, txn, "d.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); r=db_x->open(db_x, txn, "x.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); // should not exist: @@ -264,6 +277,7 @@ verify_ac2x(DB_TXN * parent_txn) { r=db_a->close(db_a, 0); CKERR(r); r=db_b->close(db_b, 0); CKERR(r); r=db_c->close(db_c, 0); CKERR(r); + r=db_d->close(db_d, 0); CKERR(r); r=db_x->close(db_x, 0); CKERR(r); r=db_c2->close(db_c2, 0); CKERR(r); @@ -272,28 +286,152 @@ verify_ac2x(DB_TXN * parent_txn) { static void -test_fileops(void) { +test_fileops_1(void) { int r; DB_TXN *txn; - create_abc(); - verify_abc(); + create_abcd(); + verify_abcd(); r=env->txn_begin(env, 0, &txn, 0); CKERR(r); perform_ops(txn); - verify_ac2x(txn); // verify that operations appear effective within this txn + verify_ac2dx(txn); // verify that operations appear effective within this txn r=txn->abort(txn); CKERR(r); // verify that aborted transaction changed nothing - verify_abc(); + verify_abcd(); r=env->txn_begin(env, 0, &txn, 0); CKERR(r); perform_ops(txn); - verify_ac2x(txn); // verify that operations appear effective within this txn + verify_ac2dx(txn); // verify that operations appear effective within this txn r=txn->commit(txn, 0); CKERR(r); // verify that committed transaction actually changed db - verify_ac2x(NULL); + verify_ac2dx(NULL); +} + + + +static void +verify_locked_open(char * name) { + int r; + DB_TXN * txn; + DB * db; + + r=env->txn_begin(env, 0, &txn, 0); CKERR(r); + r=db_create(&db, env, 0); CKERR(r); + r=db->open(db, txn, name, 0, DB_BTREE, DB_CREATE, S_IRWXU|S_IRWXG|S_IRWXO); + CKERR2(r, DB_LOCK_NOTGRANTED); + r=db->close(db, 0); CKERR(r); // always safe to close + r=txn->abort(txn); CKERR(r); +} + +static void +verify_locked_remove(char * name) { + int r; + DB_TXN * txn; + + r=env->txn_begin(env, 0, &txn, 0); CKERR(r); + r = env->dbremove(env, txn, name, NULL, 0); + CKERR2(r, DB_LOCK_NOTGRANTED); + r=txn->abort(txn); CKERR(r); +} + +static void +verify_locked_rename(char * oldname, char * newname) { + int r; + DB_TXN * txn; + + r=env->txn_begin(env, 0, &txn, 0); CKERR(r); + r = env->dbrename(env, txn, oldname, NULL, newname, 0); + CKERR2(r, DB_LOCK_NOTGRANTED); + r=txn->abort(txn); CKERR(r); +} + + +// Purpose of test_fileops_2() is to verify correct operation of +// directory range locks. It should not be possible to open or +// rename or remove a dictionary that is marked for removal or +// rename by another open transaction. +static void +test_fileops_2(void) { + int r; + DB_TXN * txn_a; + + verify_ac2dx(NULL); // should still exist + + // begin txn_a + // remove a + // create e + // rename x->x2 + // rename c2->c3 + // open x2, c3, should succeed + // close x2, c3 + { + DB * db_e; + DB * db_c3; + DB * db_x2; + + r=env->txn_begin(env, 0, &txn_a, 0); CKERR(r); + r=db_create(&db_e, env, 0); CKERR(r); + r=db_create(&db_x2, env, 0); CKERR(r); + r=db_create(&db_c3, env, 0); CKERR(r); + + r = env->dbremove(env, txn_a, "a.db", NULL, 0); CKERR(r); + r=db_e->open(db_e, txn_a, "e.db", 0, DB_BTREE, DB_CREATE, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); + r = env->dbrename(env, txn_a, "x.db", NULL, "x2.db", 0); CKERR(r); + r = env->dbrename(env, txn_a, "c2.db", NULL, "c3.db", 0); CKERR(r); + + r=db_x2->open(db_x2, txn_a, "x2.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); + r=db_c3->open(db_c3, txn_a, "c3.db", 0, DB_BTREE, 0, S_IRWXU|S_IRWXG|S_IRWXO); CKERR(r); + + r=db_e->close(db_e, 0); CKERR(r); // abort requires db be closed first + r=db_x2->close(db_x2, 0); CKERR(r); // abort requires db be closed first + r=db_c3->close(db_c3, 0); CKERR(r); // abort requires db be closed first + + } + + // within another transaction: + // open a, should fail DB_LOCK_NOTGRANTED + // open e, should fail DB_LOCK_NOTGRANTED + // open x, should fail DB_LOCK_NOTGRANTED + // open x2, should fail DB_LOCK_NOTGRANTED + // open c2, should fail DB_LOCK_NOTGRANTED + // open c3, should fail DB_LOCK_NOTGRANTED + // remove a, e, x, x2, c2, c3 DB_LOCK_NOTGRANTED + // rename a, e, x, x2, c2, c3 DB_LOCK_NOTGRANTED + + verify_locked_open("a.db"); + verify_locked_open("e.db"); + verify_locked_open("x.db"); + verify_locked_open("x2.db"); + verify_locked_open("c2.db"); + verify_locked_open("c3.db"); + + verify_locked_remove("a.db"); + verify_locked_remove("e.db"); + verify_locked_remove("x.db"); + verify_locked_remove("x2.db"); + verify_locked_remove("c2.db"); + verify_locked_remove("c3.db"); + + verify_locked_rename("a.db", "z.db"); + verify_locked_rename("e.db", "z.db"); + verify_locked_rename("x.db", "z.db"); + verify_locked_rename("x2.db", "z.db"); + verify_locked_rename("c2.db", "z.db"); + verify_locked_rename("c3.db", "z.db"); + + verify_locked_rename("d.db", "a.db"); + verify_locked_rename("d.db", "e.db"); + verify_locked_rename("d.db", "x.db"); + verify_locked_rename("d.db", "x2.db"); + verify_locked_rename("d.db", "c2.db"); + verify_locked_rename("d.db", "c3.db"); + + + r=txn_a->abort(txn_a); CKERR(r); + } @@ -302,7 +440,9 @@ test_main (int argc, char *argv[]) { parse_args(argc, argv); setup(); print_engine_status(env); - test_fileops(); + test_fileops_1(); + print_engine_status(env); + test_fileops_2(); print_engine_status(env); test_shutdown(); return 0;