/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ // vim: expandtab:ts=8:sw=4:softtabstop=4: #include "test.h" // verify that del_multiple deletes the correct key from N dictionaries // verify that del_multiple locks the correct key for N dictionaries static int get_key(int i, int dbnum) { return htonl(i + dbnum); } static void get_data(int *v, int i, int ndbs) { for (int dbnum = 0; dbnum < ndbs; dbnum++) { v[dbnum] = get_key(i, dbnum); } } static int del_callback(DB *dest_db, DB *src_db, DBT *dest_key, const DBT *src_key, const DBT *src_data) { dest_db = dest_db; src_db = src_db; dest_key = dest_key; src_key = src_key; src_data = src_data; assert(src_db == NULL); unsigned int dbnum; assert(dest_db->descriptor->dbt.size == sizeof dbnum); memcpy(&dbnum, dest_db->descriptor->dbt.data, sizeof dbnum); assert(dbnum < src_data->size / sizeof (int)); int *pri_data = (int *) src_data->data; assert(dest_key->flags == 0); dest_key->size = sizeof (int); dest_key->data = &pri_data[dbnum]; return 0; } static void verify_locked(DB_ENV *env, DB *db, int k) { int r; DB_TXN *txn = NULL; r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r); DBT key; dbt_init(&key, &k, sizeof k); r = db->del(db, txn, &key, DB_DELETE_ANY); assert(r == DB_LOCK_NOTGRANTED); r = txn->abort(txn); assert_zero(r); } static void verify_empty(DB_ENV *env, DB *db) { int r; DB_TXN *txn = NULL; r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r); DBC *cursor = NULL; r = db->cursor(db, txn, &cursor, 0); assert_zero(r); int i; for (i = 0; ; i++) { DBT key; memset(&key, 0, sizeof key); DBT val; memset(&val, 0, sizeof val); r = cursor->c_get(cursor, &key, &val, DB_NEXT); if (r != 0) break; } assert_zero(i); r = cursor->c_close(cursor); assert_zero(r); r = txn->commit(txn, 0); assert_zero(r); } static void verify_del_multiple(DB_ENV *env, DB *db[], int ndbs, int nrows) { int r; DB_TXN *deltxn = NULL; r = env->txn_begin(env, NULL, &deltxn, 0); assert_zero(r); for (int i = 0; i < nrows; i++) { int k = get_key(i, 0); DBT pri_key; dbt_init(&pri_key, &k, sizeof k); int v[ndbs]; get_data(v, i, ndbs); DBT pri_data; dbt_init(&pri_data, &v[0], sizeof v); DBT keys[ndbs]; memset(keys, 0, sizeof keys); uint32_t flags[ndbs]; memset(flags, 0, sizeof flags); r = env->del_multiple(env, NULL, deltxn, &pri_key, &pri_data, ndbs, db, keys, flags); assert_zero(r); for (int dbnum = 0; dbnum < ndbs; dbnum++) verify_locked(env, db[dbnum], get_key(i, dbnum)); } r = deltxn->commit(deltxn, 0); assert_zero(r); for (int dbnum = 0; dbnum < ndbs; dbnum++) verify_empty(env, db[dbnum]); } static void populate_primary(DB_ENV *env, DB *db, int ndbs, int nrows) { int r; DB_TXN *txn = NULL; r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r); // populate for (int i = 0; i < nrows; i++) { int k = get_key(i, 0); int v[ndbs]; get_data(v, i, ndbs); DBT key; dbt_init(&key, &k, sizeof k); DBT val; dbt_init(&val, &v[0], sizeof v); r = db->put(db, txn, &key, &val, 0); assert_zero(r); } r = txn->commit(txn, 0); assert_zero(r); } static void populate_secondary(DB_ENV *env, DB *db, int dbnum, int nrows) { int r; DB_TXN *txn = NULL; r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r); // populate for (int i = 0; i < nrows; i++) { int k = get_key(i, dbnum); DBT key; dbt_init(&key, &k, sizeof k); DBT val; dbt_init(&val, NULL, 0); r = db->put(db, txn, &key, &val, 0); assert_zero(r); } r = txn->commit(txn, 0); assert_zero(r); } static void run_test(int ndbs, int nrows) { int r; DB_ENV *env = NULL; r = db_env_create(&env, 0); assert_zero(r); r = env->set_generate_row_callback_for_del(env, del_callback); assert_zero(r); r = env->open(env, ENVDIR, DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r); DB *db[ndbs]; for (int dbnum = 0; dbnum < ndbs; dbnum++) { r = db_create(&db[dbnum], env, 0); assert_zero(r); char dbname[32]; sprintf(dbname, "%d.tdb", dbnum); r = db[dbnum]->open(db[dbnum], NULL, dbname, NULL, DB_BTREE, DB_AUTO_COMMIT+DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r); DBT dbt_dbnum; dbt_init(&dbt_dbnum, &dbnum, sizeof dbnum); IN_TXN_COMMIT(env, NULL, txn_desc, 0, { { int chk_r = db[dbnum]->change_descriptor(db[dbnum], txn_desc, &dbt_dbnum, 0); CKERR(chk_r); } }); } for (int dbnum = 0; dbnum < ndbs; dbnum++) { if (dbnum == 0) populate_primary(env, db[dbnum], ndbs, nrows); else populate_secondary(env, db[dbnum], dbnum, nrows); } verify_del_multiple(env, db, ndbs, nrows); for (int dbnum = 0; dbnum < ndbs; dbnum++) r = db[dbnum]->close(db[dbnum], 0); assert_zero(r); r = env->close(env, 0); assert_zero(r); } int test_main(int argc, char * const argv[]) { int r; int ndbs = 2; int nrows = 2; // parse_args(argc, argv); for (int i = 1; i < argc; i++) { char * const arg = argv[i]; if (strcmp(arg, "-v") == 0) { verbose++; continue; } if (strcmp(arg, "-q") == 0) { verbose = 0; continue; } if (strcmp(arg, "--ndbs") == 0 && i+1 < argc) { ndbs = atoi(argv[++i]); continue; } if (strcmp(arg, "--nrows") == 0 && i+1 < argc) { nrows = atoi(argv[++i]); continue; } } r = system("rm -rf " ENVDIR); assert_zero(r); r = toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r); run_test(ndbs, nrows); return 0; }