Commit 3e9fcd10 authored by Yoni Fogel's avatar Yoni Fogel

Addresses #1125 refs [t:1125] Add two tests for nested transactions at ydb layer.

Shuffled around some constants at the newbrt layer, extracted tokuconst.h

git-svn-id: file:///svn/toku/tokudb@13670 c7de825b-a66e-492c-adef-691d508d4ae1
parent c64a5725
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2009 Tokutek Inc. All rights reserved."
#ifndef TOKUCONST_H
#define TOKUCONST_H
/* The number of transaction ids stored in the xids structure is
* represented by an 8-bit value. The value 255 is reserved.
* The constant MAX_NESTED_TRANSACTIONS is one less because
* one slot in the packed leaf entry is used for the implicit
* root transaction (id 0).
*/
enum {MAX_NESTED_TRANSACTIONS = 253};
enum {MAX_TRANSACTION_RECORDS = MAX_NESTED_TRANSACTIONS + 1};
#endif
......@@ -19,16 +19,7 @@
#include "rbuf.h"
#include "wbuf.h"
/* The number of transaction ids stored in the xids structure is
* represented by an 8-bit value. The value 255 is reserved.
* The constant MAX_NESTED_TRANSACTIONS is one less because
* one slot in the packed leaf entry is used for the implicit
* root transaction (id 0).
*/
enum {MAX_NESTED_TRANSACTIONS = 253};
enum {MAX_TRANSACTION_RECORDS = MAX_NESTED_TRANSACTIONS + 1};
#include "tokuconst.h"
//Retrieve an XIDS representing the root transaction.
XIDS xids_get_root_xids(void);
......
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 200o Tokutek Inc. All rights reserved."
#ident "Copyright (c) 2009 Tokutek Inc. All rights reserved."
#include "test.h"
#include <stdio.h>
#include <assert.h>
......@@ -9,10 +8,8 @@
#include <memory.h>
#include <sys/stat.h>
#include <db.h>
// #include "xids.h"
// fix later (maybe pass in desired depth as a param?)
#define MAX_NEST 250
#include "tokuconst.h"
#define MAX_NEST MAX_NESTED_TRANSACTIONS
/*********************
......@@ -26,7 +23,7 @@
* - insert, query
*
* for i = 1 to MAX
* - txnid = txns[MAX - i]
* - txnid = txns[MAX - i - 1]
* - commit or abort(txnid), query
*
*/
......@@ -51,6 +48,8 @@ setup_db (void) {
r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
r = db_create(&db, env, 0); CKERR(r);
r = db->set_bt_compare(db, int_dbt_cmp); CKERR(r);
r = db->set_dup_compare(db, int_dbt_cmp); CKERR(r);
r = db->open(db, txn, "test.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
r = txn->commit(txn, 0); CKERR(r);
}
......@@ -64,42 +63,71 @@ close_db (void) {
r=env->close(env, 0); CKERR(r);
}
int
static void
test_txn_nesting (int depth) {
int r;
if (verbose) { fprintf(stderr, "%s (%s):%d [depth = %d]\n", __FILE__, __FUNCTION__, __LINE__, depth); fflush(stderr); }
DBT key, val;
DBT key, val, observed_val;
dbt_init(&observed_val, NULL, 0);
int i;
DB_TXN * txns[depth];
DB_TXN * parent = NULL;
int vals[depth];
int mykey = 42;
dbt_init(&key, &mykey, sizeof mykey);
for (i = 0; i < depth; i++){
int r;
DB_TXN * this_txn;
if (verbose)
printf("Begin txn at level %d\n", i);
dbt_init(&key, &i, sizeof i);
dbt_init(&val, &i, sizeof i);
vals[i] = i;
dbt_init(&val, &vals[i], sizeof i);
r = env->txn_begin(env, parent, &this_txn, 0); CKERR(r);
txns[i] = this_txn;
parent = this_txn; // will be parent in next iteration
r = db->put(db, this_txn, &key, &val, 0); CKERR(r);
r = db->put(db, this_txn, &key, &val, DB_YESOVERWRITE); CKERR(r);
r = db->get(db, this_txn, &key, &observed_val, 0); CKERR(r);
assert(int_dbt_cmp(db, &val, &observed_val) == 0);
}
for (i = 0; i < depth; i++) {
int r;
DB_TXN * this_txn;
int which_val = depth-1;
for (i = depth-1; i >= 0; i--) {
//Query, verify the correct value is stored.
//Close (abort/commit) innermost transaction
if (verbose)
printf("Commit txn at level %d\n", i);
this_txn = txns[depth - i - 1];
r = this_txn->commit(this_txn, DB_TXN_NOSYNC); CKERR(r);
}
if (verbose)
printf("Commit txn at level %d\n", i);
return 0;
dbt_init(&observed_val, NULL, 0);
r = db->get(db, txns[i], &key, &observed_val, 0); CKERR(r);
dbt_init(&val, &vals[which_val], sizeof i);
assert(int_dbt_cmp(db, &val, &observed_val) == 0);
if (i % 2) {
r = txns[i]->commit(txns[i], DB_TXN_NOSYNC); CKERR(r);
//which_val does not change (it gets promoted)
}
else {
r = txns[i]->abort(txns[i]); CKERR(r);
which_val = i - 1;
}
txns[i] = NULL;
}
//Query, verify the correct value is stored.
r = db->get(db, NULL, &key, &observed_val, 0);
if (which_val == -1) CKERR2(r, DB_NOTFOUND);
else {
CKERR(r);
dbt_init(&val, &vals[which_val], sizeof i);
assert(int_dbt_cmp(db, &val, &observed_val) == 0);
}
}
......
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2009 Tokutek Inc. All rights reserved."
#include "test.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <sys/stat.h>
#include <db.h>
#include "tokuconst.h"
#define MAX_NEST MAX_TRANSACTION_RECORDS
#define MAX_SIZE MAX_TRANSACTION_RECORDS
u_int8_t valbufs[MAX_NEST][MAX_SIZE];
DBT vals [MAX_NEST];
u_int8_t keybuf [MAX_SIZE];
DBT key;
DB_TXN *txns [MAX_NEST];
DB_TXN *txn_query;
int which_expected;
static void
fillrandom(u_int8_t buf[MAX_SIZE], u_int32_t length) {
assert(length < MAX_SIZE);
u_int32_t i;
for (i = 0; i < length; i++) {
buf[i] = random() & 0xFF;
}
}
static void
initialize_values (void) {
int nest_level;
for (nest_level = 0; nest_level < MAX_NEST; nest_level++) {
fillrandom(valbufs[nest_level], nest_level);
dbt_init(&vals[nest_level], &valbufs[nest_level][0], nest_level);
}
u_int32_t len = random() % MAX_SIZE;
fillrandom(keybuf, len);
dbt_init(&vals[nest_level], &keybuf[0], len);
}
/*********************
*
* Purpose of this test is to verify nested transactions (support right number of possible values)
for test = 1 to MAX
create empty db
for nesting_level = 1 to MAX
- begin txn
- insert a value/len unique to this txn
- query
abort txn (MAX-test) (test-th innermost) // for test=1 don't abort anything
commit txn 1 (outermost) // for test = MAX don't commit anything
query // only query that really matters
*/
static DB *db;
static DB_ENV *env;
static void
setup_db (void) {
system("rm -rf " ENVDIR);
toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);
int r;
r = db_env_create(&env, 0); CKERR(r);
r = env->set_data_dir(env, ENVDIR);
r = env->set_lg_dir(env, ENVDIR);
r = env->open(env, 0, DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_TXN | DB_PRIVATE | DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO);
CKERR(r);
{
DB_TXN *txn = 0;
r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
r = db_create(&db, env, 0); CKERR(r);
r = db->open(db, txn, "test.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
r = txn->commit(txn, 0); CKERR(r);
}
}
static void
close_db (void) {
int r;
r = txn_query->commit(txn_query, 0);
CKERR(r);
r=db->close(db, 0); CKERR(r);
r=env->close(env, 0); CKERR(r);
}
static void
verify_val(void) {
int r;
DBT observed_val;
dbt_init(&observed_val, NULL, 0);
r = db->get(db, txn_query, &key, &observed_val, 0);
if (which_expected==-1)
CKERR2(r, DB_NOTFOUND);
else {
CKERR(r);
assert(observed_val.size == vals[which_expected].size);
assert(memcmp(observed_val.data, vals[which_expected].data, vals[which_expected].size) == 0);
}
}
static void
initialize_db(void) {
int r;
r = env->txn_begin(env, NULL, &txn_query, DB_READ_UNCOMMITTED);
CKERR(r);
which_expected = -1;
verify_val();
//Put in a 'committed value'
r = db->put(db, NULL, &key, &vals[0], DB_YESOVERWRITE);
CKERR(r);
txns[0] = NULL;
int i;
which_expected = 0;
for (i = 1; i < MAX_NEST; i++) {
r = env->txn_begin(env, txns[i-1], &txns[i], 0);
CKERR(r);
verify_val();
r = db->put(db, txns[i], &key, &vals[i], DB_YESOVERWRITE);
CKERR(r);
which_expected = i;
verify_val();
}
}
static void
test_txn_nested_shortcut (int abort_at_depth) {
int r;
if (verbose) { fprintf(stderr, "%s (%s):%d [abortdepth = %d]\n", __FILE__, __FUNCTION__, __LINE__, abort_at_depth); fflush(stderr); }
setup_db();
initialize_db();
which_expected = MAX_NEST-1;
verify_val();
assert(abort_at_depth > 0); //Cannot abort 'committed' txn.
assert(abort_at_depth <= MAX_NEST); //must be in range
if (abort_at_depth < MAX_NEST) {
//MAX_NEST means no abort
DB_TXN *abort_txn = txns[abort_at_depth];
r = abort_txn->abort(abort_txn);
CKERR(r);
which_expected = abort_at_depth - 1;
verify_val();
}
if (abort_at_depth > 1) {
//abort_at_depth 1 means abort the whole thing (nothing left to commit)
DB_TXN *commit_txn = txns[1];
r = commit_txn->commit(commit_txn, DB_TXN_NOSYNC);
CKERR(r);
verify_val();
}
close_db();
}
static void
test_txn_nested_slow (int abort_at_depth) {
int r;
if (verbose) { fprintf(stderr, "%s (%s):%d [abortdepth = %d]\n", __FILE__, __FUNCTION__, __LINE__, abort_at_depth); fflush(stderr); }
setup_db();
initialize_db();
which_expected = MAX_NEST-1;
verify_val();
assert(abort_at_depth > 0); //Cannot abort 'committed' txn.
assert(abort_at_depth <= MAX_NEST); //must be in range
//MAX_NEST means no abort
int nest;
for (nest = MAX_NEST - 1; nest >= abort_at_depth; nest--) {
DB_TXN *abort_txn = txns[nest];
r = abort_txn->abort(abort_txn);
CKERR(r);
which_expected = nest - 1;
verify_val();
}
//which_expected does not change anymore
for (nest = abort_at_depth-1; nest > 0; nest--) {
DB_TXN *commit_txn = txns[nest];
r = commit_txn->commit(commit_txn, DB_TXN_NOSYNC);
CKERR(r);
verify_val();
}
close_db();
}
int
test_main(int argc, char *argv[]) {
parse_args(argc, argv);
initialize_values();
int i;
for (i = 1; i <= MAX_NEST; i++) {
test_txn_nested_shortcut(i);
test_txn_nested_slow(i);
}
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment