test_txn_nested2.cc 5.56 KB
Newer Older
1 2 3
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
4 5 6
#ident "Copyright (c) 2009 Tokutek Inc.  All rights reserved."
#include "test.h"
#include <stdio.h>
7

8 9 10 11 12
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <sys/stat.h>
#include <db.h>
13
#include <ft/tokuconst.h>
14 15 16
#define MAX_NEST MAX_TRANSACTION_RECORDS
#define MAX_SIZE MAX_TRANSACTION_RECORDS

Yoni Fogel's avatar
Yoni Fogel committed
17
uint8_t valbufs[MAX_NEST][MAX_SIZE];
18
DBT vals        [MAX_NEST];
Yoni Fogel's avatar
Yoni Fogel committed
19
uint8_t keybuf [MAX_SIZE];
20 21 22 23 24 25
DBT key;
DB_TXN   *txns   [MAX_NEST];
DB_TXN   *txn_query;
int which_expected;

static void
Yoni Fogel's avatar
Yoni Fogel committed
26
fillrandom(uint8_t buf[MAX_SIZE], uint32_t length) {
27
    assert(length < MAX_SIZE);
Yoni Fogel's avatar
Yoni Fogel committed
28
    uint32_t i;
29 30 31 32 33 34 35 36 37 38 39 40
    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);
    }
Yoni Fogel's avatar
Yoni Fogel committed
41
    uint32_t len = random() % MAX_SIZE;
42
    fillrandom(keybuf, len);
43
    dbt_init(&key, &keybuf[0], len);
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
}


/*********************
 *
 * 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) {
66 67 68
    int r;
    r = system("rm -rf " ENVDIR);
    CKERR(r);
69 70 71
    toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);

    r = db_env_create(&env, 0); CKERR(r);
72
    r = env->open(env, ENVDIR, DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_TXN | DB_PRIVATE | DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); 
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    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'
118
    r = db->put(db, NULL, &key, &vals[0], 0);
119 120 121 122 123 124 125 126 127
        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();
128
        r = db->put(db, txns[i], &key, &vals[i], 0);
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
            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
200
test_main(int argc, char *const argv[]) {
201 202 203 204 205 206 207 208 209
    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;
}