Commit bbb3a7c5 authored by Rich Prohaska's avatar Rich Prohaska

make sure the db parameter is passed to the user's key compare function

when using cursors



git-svn-id: file:///svn/tokudb@385 c7de825b-a66e-492c-adef-691d508d4ae1
parent 10062cb1
......@@ -815,7 +815,22 @@ static void test_wrongendian_compare (int wrong_p, unsigned int N) {
int test_cursor_debug = 0;
void assert_cursor_notfound(BRT brt, int position) {
DB *test_db;
void set_test_db(DB *db) {
test_db = db;
}
void clear_test_db() {
test_db = null_db;
}
int test_brt_cursor_keycompare(DB *db, const DBT *a, const DBT *b) {
assert(db == test_db);
return keycompare(a->data, a->size, b->data, b->size);
}
void assert_cursor_notfound(BRT brt, int position, DB *db) {
BRT_CURSOR cursor;
int r;
DBT kbt, vbt;
......@@ -825,14 +840,14 @@ void assert_cursor_notfound(BRT brt, int position) {
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, position, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, position, db, null_txn);
assert(r == DB_NOTFOUND);
r = brt_cursor_close(cursor);
assert(r==0);
}
void assert_cursor_value(BRT brt, int position, long long value) {
void assert_cursor_value(BRT brt, int position, long long value, DB *db) {
BRT_CURSOR cursor;
int r;
DBT kbt, vbt;
......@@ -844,7 +859,7 @@ void assert_cursor_value(BRT brt, int position, long long value) {
if (test_cursor_debug) printf("key: ");
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, position, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, position, db, null_txn);
assert(r == 0);
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
assert(vbt.size == sizeof v);
......@@ -858,7 +873,7 @@ void assert_cursor_value(BRT brt, int position, long long value) {
assert(r==0);
}
void assert_cursor_first_last(BRT brt, long long firstv, long long lastv) {
void assert_cursor_first_last(BRT brt, long long firstv, long long lastv, DB *db) {
BRT_CURSOR cursor;
int r;
DBT kbt, vbt;
......@@ -870,7 +885,7 @@ void assert_cursor_first_last(BRT brt, long long firstv, long long lastv) {
if (test_cursor_debug) printf("first key: ");
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_FIRST, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_FIRST, db, null_txn);
assert(r == 0);
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
assert(vbt.size == sizeof v);
......@@ -883,7 +898,7 @@ void assert_cursor_first_last(BRT brt, long long firstv, long long lastv) {
if (test_cursor_debug) printf("last key:");
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_LAST, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_LAST, db, null_txn);
assert(r == 0);
if (test_cursor_debug)printf("%s ", (char*)kbt.data);
assert(vbt.size == sizeof v);
......@@ -897,21 +912,22 @@ void assert_cursor_first_last(BRT brt, long long firstv, long long lastv) {
assert(r==0);
}
void test_brt_cursor_first(int n) {
void test_brt_cursor_first(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_first:%d\n", n);
printf("test_brt_cursor_first:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
......@@ -923,40 +939,43 @@ void test_brt_cursor_first(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
if (n == 0)
assert_cursor_notfound(brt, DB_FIRST);
assert_cursor_notfound(brt, DB_FIRST, db);
else
assert_cursor_value(brt, DB_FIRST, 0);
assert_cursor_value(brt, DB_FIRST, 0, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_brt_cursor_last(int n) {
void test_brt_cursor_last(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_last:%d\n", n);
printf("test_brt_cursor_last:%d %p\n", n, db);
set_test_db(db);;
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
/* insert keys 0, 1, .. (n-1) */
for (i=0; i<n; i++) {
char key[8]; long long v;
DBT kbt, vbt;
......@@ -965,31 +984,34 @@ void test_brt_cursor_last(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
if (n == 0)
assert_cursor_notfound(brt, DB_LAST);
assert_cursor_notfound(brt, DB_LAST, db);
else
assert_cursor_value(brt, DB_LAST, n-1);
assert_cursor_value(brt, DB_LAST, n-1, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_brt_cursor_first_last(int n) {
void test_brt_cursor_first_last(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_first_last:%d\n", n);
printf("test_brt_cursor_first_last:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
......@@ -1007,41 +1029,44 @@ void test_brt_cursor_first_last(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
if (n == 0) {
assert_cursor_notfound(brt, DB_FIRST);
assert_cursor_notfound(brt, DB_LAST);
assert_cursor_notfound(brt, DB_FIRST, db);
assert_cursor_notfound(brt, DB_LAST, db);
} else
assert_cursor_first_last(brt, 0, n-1);
assert_cursor_first_last(brt, 0, n-1, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
}
void test_brt_cursor_rfirst(int n) {
void test_brt_cursor_rfirst(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_rfirst:%d\n", n);
printf("test_brt_cursor_rfirst:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
/* insert keys n-1, n-2, ... , 0 */
for (i=n-1; i>=0; i--) {
char key[8]; long long v;
DBT kbt, vbt;
......@@ -1050,23 +1075,25 @@ void test_brt_cursor_rfirst(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
if (n == 0)
assert_cursor_notfound(brt, DB_FIRST);
assert_cursor_notfound(brt, DB_FIRST, db);
else
assert_cursor_value(brt, DB_FIRST, 0);
assert_cursor_value(brt, DB_FIRST, 0, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void assert_cursor_walk(BRT brt, int n) {
void assert_cursor_walk(BRT brt, int n, DB *db) {
BRT_CURSOR cursor;
int i;
int r;
......@@ -1081,7 +1108,7 @@ void assert_cursor_walk(BRT brt, int n) {
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, db, null_txn);
if (r != 0)
break;
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
......@@ -1098,21 +1125,22 @@ void assert_cursor_walk(BRT brt, int n) {
assert(r==0);
}
void test_brt_cursor_walk(int n) {
void test_brt_cursor_walk(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_walk:%d\n", n);
printf("test_brt_cursor_walk:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
......@@ -1124,21 +1152,23 @@ void test_brt_cursor_walk(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
/* walk the tree */
assert_cursor_walk(brt, n);
assert_cursor_walk(brt, n, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void assert_cursor_rwalk(BRT brt, int n) {
void assert_cursor_rwalk(BRT brt, int n, DB *db) {
BRT_CURSOR cursor;
int i;
int r;
......@@ -1153,7 +1183,7 @@ void assert_cursor_rwalk(BRT brt, int n) {
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_PREV, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_PREV, db, null_txn);
if (r != 0)
break;
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
......@@ -1170,21 +1200,22 @@ void assert_cursor_rwalk(BRT brt, int n) {
assert(r==0);
}
void test_brt_cursor_rwalk(int n) {
void test_brt_cursor_rwalk(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_rwalk:%d\n", n);
printf("test_brt_cursor_rwalk:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
......@@ -1196,21 +1227,23 @@ void test_brt_cursor_rwalk(int n) {
fill_dbt(&kbt, &k, sizeof k);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
/* walk the tree */
assert_cursor_rwalk(brt, n);
assert_cursor_rwalk(brt, n, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void assert_cursor_walk_inorder(BRT brt, int n) {
void assert_cursor_walk_inorder(BRT brt, int n, DB *db) {
BRT_CURSOR cursor;
int i;
int r;
......@@ -1227,7 +1260,7 @@ void assert_cursor_walk_inorder(BRT brt, int n) {
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, db, null_txn);
if (r != 0)
break;
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
......@@ -1248,21 +1281,22 @@ void assert_cursor_walk_inorder(BRT brt, int n) {
assert(r==0);
}
void test_brt_cursor_rand(int n) {
void test_brt_cursor_rand(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
int r;
int i;
printf("test_brt_cursor_rand:%d\n", n);
printf("test_brt_cursor_rand:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
......@@ -1276,28 +1310,30 @@ void test_brt_cursor_rand(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = i;
fill_dbt(&vbt, &v, sizeof v);
r = brt_lookup(brt, &kbt, &vbt, 0);
r = brt_lookup(brt, &kbt, &vbt, db);
if (r == 0) {
printf("dup");
continue;
}
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
break;
}
}
/* walk the tree */
assert_cursor_walk_inorder(brt, n);
assert_cursor_walk_inorder(brt, n, db);
r = close_brt(brt);
assert(r==0);
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_brt_cursor_split(int n) {
void test_brt_cursor_split(int n, DB *db) {
const char *fname="testbrt.brt";
CACHETABLE ct;
BRT brt;
......@@ -1307,14 +1343,15 @@ void test_brt_cursor_split(int n) {
int i;
DBT kbt, vbt;
printf("test_brt_cursor_split:%d\n", n);
printf("test_brt_cursor_split:%d %p\n", n, db);
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
/* insert a bunch of kv pairs */
......@@ -1325,7 +1362,7 @@ void test_brt_cursor_split(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = keyseqnum;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
......@@ -1336,7 +1373,7 @@ void test_brt_cursor_split(int n) {
for (i=0; i<n/2; i++) {
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, db, null_txn);
assert(r==0);
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
toku_free(kbt.data);
......@@ -1351,7 +1388,7 @@ void test_brt_cursor_split(int n) {
fill_dbt(&kbt, key, strlen(key)+1);
v = keyseqnum;
fill_dbt(&vbt, &v, sizeof v);
r = brt_insert(brt, &kbt, &vbt, 0, 0);
r = brt_insert(brt, &kbt, &vbt, db, 0);
assert(r==0);
}
......@@ -1359,7 +1396,7 @@ void test_brt_cursor_split(int n) {
for (;;) {
init_dbt(&kbt); kbt.flags = DB_DBT_MALLOC;
init_dbt(&vbt); vbt.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, null_db, null_txn);
r = brt_cursor_get(cursor, &kbt, &vbt, DB_NEXT, db, null_txn);
if (r != 0)
break;
if (test_cursor_debug) printf("%s ", (char*)kbt.data);
......@@ -1376,10 +1413,12 @@ void test_brt_cursor_split(int n) {
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_multiple_brt_cursors(int n) {
printf("test_multiple_brt_cursors:%d\n", n);
void test_multiple_brt_cursors(int n, DB *db) {
printf("test_multiple_brt_cursors:%d %p\n", n, db);
int r;
char fname[]="testbrt.brt";
......@@ -1387,12 +1426,13 @@ void test_multiple_brt_cursors(int n) {
BRT brt;
BRT_CURSOR cursors[n];
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
int i;
......@@ -1411,6 +1451,8 @@ void test_multiple_brt_cursors(int n) {
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
static int log16(int n) {
......@@ -1423,8 +1465,8 @@ static int log16(int n) {
return r;
}
void test_multiple_brt_cursor_walk(int n) {
printf("test_multiple_brt_cursor_walk:%d\n", n);
void test_multiple_brt_cursor_walk(int n, DB *db) {
printf("test_multiple_brt_cursor_walk:%d %p\n", n, db);
int r;
char fname[]="testbrt.brt";
......@@ -1434,6 +1476,7 @@ void test_multiple_brt_cursor_walk(int n) {
const int ncursors = n/cursor_gap;
BRT_CURSOR cursors[ncursors];
set_test_db(db);
unlink(fname);
int nodesize = 1<<12;
......@@ -1442,7 +1485,7 @@ void test_multiple_brt_cursor_walk(int n) {
r = brt_create_cachetable_size(&ct, 127, cachesize);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
int c;
......@@ -1462,7 +1505,7 @@ void test_multiple_brt_cursor_walk(int n) {
v = i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
r = brt_insert(brt, &key, &val, 0, 0);
r = brt_insert(brt, &key, &val, db, 0);
assert(r == 0);
/* point cursor i / cursor_gap to the current last key i */
......@@ -1470,7 +1513,7 @@ void test_multiple_brt_cursor_walk(int n) {
c = i / cursor_gap;
init_dbt(&key); key.flags = DB_DBT_MALLOC;
init_dbt(&val); val.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursors[c], &key, &val, DB_LAST, null_db, null_txn);
r = brt_cursor_get(cursors[c], &key, &val, DB_LAST, db, null_txn);
assert(r == 0);
toku_free(key.data);
toku_free(val.data);
......@@ -1482,7 +1525,7 @@ void test_multiple_brt_cursor_walk(int n) {
for (c=0; c<ncursors; c++) {
init_dbt(&key); key.flags = DB_DBT_MALLOC;
init_dbt(&val); val.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursors[c], &key, &val, DB_NEXT, null_db, null_txn);
r = brt_cursor_get(cursors[c], &key, &val, DB_NEXT, db, null_txn);
if (r == DB_NOTFOUND) {
/* we already consumed 1 previously */
assert(i == cursor_gap-1);
......@@ -1508,10 +1551,12 @@ void test_multiple_brt_cursor_walk(int n) {
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_brt_cursor_set(int n, int cursor_op) {
printf("test_brt_cursor_set:%d %d\n", n, cursor_op);
void test_brt_cursor_set(int n, int cursor_op, DB *db) {
printf("test_brt_cursor_set:%d %d %p\n", n, cursor_op, db);
int r;
char fname[]="testbrt.brt";
......@@ -1519,12 +1564,13 @@ void test_brt_cursor_set(int n, int cursor_op) {
BRT brt;
BRT_CURSOR cursor;
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
int i;
......@@ -1537,7 +1583,7 @@ void test_brt_cursor_set(int n, int cursor_op) {
v = 10*i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
r = brt_insert(brt, &key, &val, 0, 0);
r = brt_insert(brt, &key, &val, db, 0);
assert(r == 0);
}
......@@ -1552,7 +1598,7 @@ void test_brt_cursor_set(int n, int cursor_op) {
k = htonl(v);
fill_dbt(&key, &k, sizeof k);
init_dbt(&val); val.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &key, &val, cursor_op, null_db, null_txn);
r = brt_cursor_get(cursor, &key, &val, cursor_op, db, null_txn);
assert(r == 0);
assert(val.size == sizeof vv);
memcpy(&vv, val.data, val.size);
......@@ -1567,7 +1613,7 @@ void test_brt_cursor_set(int n, int cursor_op) {
k = htonl(i);
fill_dbt(&key, &k, sizeof k);
init_dbt(&val); val.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &key, &val, DB_SET, null_db, null_txn);
r = brt_cursor_get(cursor, &key, &val, DB_SET, db, null_txn);
assert(r == DB_NOTFOUND);
}
......@@ -1579,10 +1625,12 @@ void test_brt_cursor_set(int n, int cursor_op) {
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_brt_cursor_set_range(int n) {
printf("test_brt_cursor_set_range:%d\n", n);
void test_brt_cursor_set_range(int n, DB *db) {
printf("test_brt_cursor_set_range:%d %p\n", n, db);
int r;
char fname[]="testbrt.brt";
......@@ -1590,12 +1638,13 @@ void test_brt_cursor_set_range(int n) {
BRT brt;
BRT_CURSOR cursor;
set_test_db(db);
unlink(fname);
r = brt_create_cachetable(&ct, 0);
assert(r==0);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
r = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(r==0);
int i;
......@@ -1609,7 +1658,7 @@ void test_brt_cursor_set_range(int n) {
v = 10*i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
r = brt_insert(brt, &key, &val, 0, 0);
r = brt_insert(brt, &key, &val, db, 0);
assert(r == 0);
}
......@@ -1625,7 +1674,7 @@ void test_brt_cursor_set_range(int n) {
k = htonl(v);
fill_dbt(&key, &k, sizeof k);
init_dbt(&val); val.flags = DB_DBT_MALLOC;
r = brt_cursor_get(cursor, &key, &val, DB_SET_RANGE, null_db, null_txn);
r = brt_cursor_get(cursor, &key, &val, DB_SET_RANGE, db, null_txn);
if (v > max_key)
/* there is no smallest key if v > the max key */
assert(r == DB_NOTFOUND);
......@@ -1646,10 +1695,12 @@ void test_brt_cursor_set_range(int n) {
r = cachetable_close(&ct);
assert(r==0);
clear_test_db();
}
void test_brt_cursor_delete(int n) {
printf("test_brt_cursor_delete:%d\n", n);
void test_brt_cursor_delete(int n, DB *db) {
printf("test_brt_cursor_delete:%d %p\n", n, db);
int error;
char fname[]="testbrt.brt";
......@@ -1657,12 +1708,13 @@ void test_brt_cursor_delete(int n) {
BRT brt;
BRT_CURSOR cursor;
set_test_db(db);
unlink(fname);
error = brt_create_cachetable(&ct, 0);
assert(error == 0);
error = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
error = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(error == 0);
error = brt_cursor(brt, &cursor);
......@@ -1678,7 +1730,7 @@ void test_brt_cursor_delete(int n) {
v = i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_insert(brt, &key, &val, 0, 0);
error = brt_insert(brt, &key, &val, db, 0);
assert(error == 0);
}
......@@ -1686,7 +1738,7 @@ void test_brt_cursor_delete(int n) {
for (;;) {
init_dbt(&key); key.flags = DB_DBT_MALLOC;
init_dbt(&val); val.flags = DB_DBT_MALLOC;
error = brt_cursor_get(cursor, &key, &val, DB_NEXT, null_db, null_txn);
error = brt_cursor_get(cursor, &key, &val, DB_NEXT, db, null_txn);
if (error == DB_NOTFOUND)
break;
assert(error == 0);
......@@ -1708,10 +1760,12 @@ void test_brt_cursor_delete(int n) {
error = cachetable_close(&ct);
assert(error == 0);
clear_test_db();
}
void test_brt_cursor_get_both(int n) {
printf("test_brt_cursor_get_both:%d\n", n);
void test_brt_cursor_get_both(int n, DB *db) {
printf("test_brt_cursor_get_both:%d %p\n", n, db);
int error;
char fname[]="testbrt.brt";
......@@ -1719,12 +1773,13 @@ void test_brt_cursor_get_both(int n) {
BRT brt;
BRT_CURSOR cursor;
set_test_db(db);
unlink(fname);
error = brt_create_cachetable(&ct, 0);
assert(error == 0);
error = open_brt(fname, 0, 1, &brt, 1<<12, ct, default_compare_fun);
error = open_brt(fname, 0, 1, &brt, 1<<12, ct, test_brt_cursor_keycompare);
assert(error == 0);
error = brt_cursor(brt, &cursor);
......@@ -1738,7 +1793,7 @@ void test_brt_cursor_get_both(int n) {
v = n+1;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, null_db, null_txn);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, db, null_txn);
assert(error == DB_NOTFOUND);
int i;
......@@ -1748,7 +1803,7 @@ void test_brt_cursor_get_both(int n) {
v = i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_insert(brt, &key, &val, 0, 0);
error = brt_insert(brt, &key, &val, db, 0);
assert(error == 0);
}
......@@ -1757,7 +1812,7 @@ void test_brt_cursor_get_both(int n) {
v = n-1;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, null_db, null_txn);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, db, null_txn);
assert(error == DB_NOTFOUND);
/* verify that key match but data mismatch fails */
......@@ -1766,7 +1821,7 @@ void test_brt_cursor_get_both(int n) {
v = i+1;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, null_db, null_txn);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, db, null_txn);
assert(error == DB_NOTFOUND);
}
......@@ -1776,7 +1831,7 @@ void test_brt_cursor_get_both(int n) {
v = i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, null_db, null_txn);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, db, null_txn);
assert(error == 0);
#ifdef DB_CURRENT
init_dbt(&key); key.flags = DB_DBT_MALLOC;
......@@ -1797,7 +1852,7 @@ void test_brt_cursor_get_both(int n) {
v = i;
fill_dbt(&key, &k, sizeof k);
fill_dbt(&val, &v, sizeof v);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, null_db, null_txn);
error = brt_cursor_get(cursor, &key, &val, DB_GET_BOTH, db, null_txn);
assert(error == DB_NOTFOUND);
}
......@@ -1812,52 +1867,64 @@ void test_brt_cursor_get_both(int n) {
error = cachetable_close(&ct);
assert(error == 0);
clear_test_db();
}
extern int brt_do_push_cmd;
int test_brt_cursor_inc = 1000;
int test_brt_cursor_limit = 10000;
void test_brt_cursor() {
void test_brt_cursor(DB *db) {
int n;
test_multiple_brt_cursors(1);
test_multiple_brt_cursors(2);
test_multiple_brt_cursors(3);
int old_brt_do_push_cmd = brt_do_push_cmd;
brt_do_push_cmd = 0;
test_multiple_brt_cursors(1, db);
test_multiple_brt_cursors(2, db);
test_multiple_brt_cursors(3, db);
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_first(n); memory_check_all_free();
test_brt_cursor_first(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_rfirst(n); memory_check_all_free();
test_brt_cursor_rfirst(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_walk(n); memory_check_all_free();
test_brt_cursor_walk(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_last(n); memory_check_all_free();
test_brt_cursor_last(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_first_last(n); memory_check_all_free();
test_brt_cursor_first_last(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_split(n); memory_check_all_free();
test_brt_cursor_split(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_rand(n); memory_check_all_free();
test_brt_cursor_rand(n, db); memory_check_all_free();
}
for (n=0; n<test_brt_cursor_limit; n += test_brt_cursor_inc) {
test_brt_cursor_rwalk(n); memory_check_all_free();
}
test_brt_cursor_set(1000, DB_SET); memory_check_all_free();
test_brt_cursor_set(10000, DB_SET); memory_check_all_free();
test_brt_cursor_set(1000, DB_SET_RANGE); memory_check_all_free();
test_brt_cursor_set_range(1000); memory_check_all_free();
test_brt_cursor_set_range(10000); memory_check_all_free();
test_brt_cursor_delete(1000); memory_check_all_free();
test_multiple_brt_cursor_walk(10000); memory_check_all_free();
test_multiple_brt_cursor_walk(100000); memory_check_all_free();
test_brt_cursor_get_both(1000); memory_check_all_free();
test_brt_cursor_rwalk(n, db); memory_check_all_free();
}
test_brt_cursor_set(1000, DB_SET, db); memory_check_all_free();
test_brt_cursor_set(10000, DB_SET, db); memory_check_all_free();
test_brt_cursor_set(1000, DB_SET_RANGE, db); memory_check_all_free();
test_brt_cursor_set_range(1000, db); memory_check_all_free();
test_brt_cursor_set_range(10000, db); memory_check_all_free();
test_brt_cursor_delete(1000, db); memory_check_all_free();
test_multiple_brt_cursor_walk(10000, db); memory_check_all_free();
test_multiple_brt_cursor_walk(100000, db); memory_check_all_free();
test_brt_cursor_get_both(1000, db); memory_check_all_free();
brt_do_push_cmd = old_brt_do_push_cmd;
}
void test_large_kv(int bsize, int ksize, int vsize) {
......@@ -2178,7 +2245,11 @@ static void brt_blackbox_test (void) {
memory_check = 1;
test_brt_limits();
test_brt_cursor();
DB a_db;
DB *db = &a_db;
test_brt_cursor(db);
test_brt_delete();
// test3(1<<19, 1<<20, 0);
......
......@@ -892,6 +892,8 @@ static int brt_nonleaf_put_cmd_child (BRT t, BRTNODE node, BRT_CMD *cmd,
return r;
}
int brt_do_push_cmd = 1;
static int brt_nonleaf_put_cmd (BRT t, BRTNODE node, BRT_CMD *cmd,
int *did_split, BRTNODE *nodea, BRTNODE *nodeb,
DBT *splitk,
......@@ -969,7 +971,7 @@ static int brt_nonleaf_put_cmd (BRT t, BRTNODE node, BRT_CMD *cmd,
/* if the child is in the cache table then push the cmd to it
otherwise just put it into this node's buffer */
if (1) {
if (brt_do_push_cmd) {
int r = brt_nonleaf_put_cmd_child(t, node, cmd, did_split, nodea, nodeb, splitk, debug, txn, childnum, 1);
if (r == 0)
return r;
......@@ -1570,7 +1572,7 @@ int brt_flush_debug = 0;
* then reflect the node split up the cursor path towards the tree root.
* If the root is reached then create a new root
*/
void brt_flush_child(BRT t, BRTNODE node, int childnum, BRT_CURSOR cursor, TOKUTXN txn) {
void brt_flush_child(BRT t, BRTNODE node, int childnum, BRT_CURSOR cursor, void *app_private, DB *db, TOKUTXN txn) {
int r;
int child_did_split;
BRTNODE childa, childb;
......@@ -1583,7 +1585,7 @@ void brt_flush_child(BRT t, BRTNODE node, int childnum, BRT_CURSOR cursor, TOKUT
init_dbt(&child_splitk);
r = push_some_brt_cmds_down(t, node, childnum,
&child_did_split, &childa, &childb, &child_splitk, brt_flush_debug, 0, 0, txn);
&child_did_split, &childa, &childb, &child_splitk, brt_flush_debug, app_private, db, txn);
assert(r == 0);
if (brt_flush_debug) {
printf("brt_flush_child done %lld %d\n", node->thisnodename, childnum);
......@@ -1617,7 +1619,7 @@ void brt_flush_child(BRT t, BRTNODE node, int childnum, BRT_CURSOR cursor, TOKUT
r = handle_split_of_child(t, upnode, childnum,
childa, childb, &child_splitk,
&child_did_split, &childa, &childb, &child_splitk,
0, 0, txn);
app_private, db, txn);
assert(r == 0);
}
}
......@@ -1893,7 +1895,7 @@ void brt_cursor_print(BRT_CURSOR cursor) {
printf("\n");
}
int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off, DB *db, TOKUTXN txn) {
BRT brt=cursor->brt;
void *node_v;
......@@ -1916,7 +1918,7 @@ int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
cursor->pathcnum[cursor->path_len-1] = childnum;
brt_node_add_cursor(node, childnum, cursor);
if (node->u.n.n_bytes_in_hashtable[childnum] > 0) {
brt_flush_child(cursor->brt, node, childnum, cursor, txn);
brt_flush_child(cursor->brt, node, childnum, cursor, 0, db, txn);
/*
* the flush may have been partially successfull. it may have also
* changed the tree such that the current node have expanded or been
......@@ -1927,7 +1929,7 @@ int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
brt_node_remove_cursor(node, childnum, cursor);
goto try_last_child;
}
r=brtcurs_set_position_last (cursor, node->u.n.children[childnum], txn);
r=brtcurs_set_position_last (cursor, node->u.n.children[childnum], db, txn);
if (r == 0)
return 0;
assert(node == cursor->path[cursor->path_len-1]);
......@@ -1954,7 +1956,7 @@ int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
}
}
int brtcurs_set_position_first (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
int brtcurs_set_position_first (BRT_CURSOR cursor, diskoff off, DB *db, TOKUTXN txn) {
BRT brt=cursor->brt;
void *node_v;
......@@ -1977,7 +1979,7 @@ int brtcurs_set_position_first (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
cursor->pathcnum[cursor->path_len-1] = childnum;
brt_node_add_cursor(node, childnum, cursor);
if (node->u.n.n_bytes_in_hashtable[childnum] > 0) {
brt_flush_child(cursor->brt, node, childnum, cursor, txn);
brt_flush_child(cursor->brt, node, childnum, cursor, 0, db, txn);
/*
* the flush may have been partially successfull. it may have also
* changed the tree such that the current node have expanded or been
......@@ -1988,7 +1990,7 @@ int brtcurs_set_position_first (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
brt_node_remove_cursor(node, childnum, cursor);
goto try_first_child;
}
r=brtcurs_set_position_first (cursor, node->u.n.children[childnum], txn);
r=brtcurs_set_position_first (cursor, node->u.n.children[childnum], db, txn);
if (r == 0)
return r;
assert(node == cursor->path[cursor->path_len-1]);
......@@ -2016,7 +2018,7 @@ int brtcurs_set_position_first (BRT_CURSOR cursor, diskoff off, TOKUTXN txn) {
}
}
int brtcurs_set_position_next2(BRT_CURSOR cursor, TOKUTXN txn) {
int brtcurs_set_position_next2(BRT_CURSOR cursor, DB *db, TOKUTXN txn) {
BRTNODE node;
int childnum;
int r;
......@@ -2047,11 +2049,11 @@ int brtcurs_set_position_next2(BRT_CURSOR cursor, TOKUTXN txn) {
more = node->u.n.n_bytes_in_hashtable[childnum];
if (more == 0)
break;
brt_flush_child(cursor->brt, node, childnum, cursor, txn);
brt_flush_child(cursor->brt, node, childnum, cursor, 0, db, txn);
node = cursor->path[cursor->path_len-1];
childnum = cursor->pathcnum[cursor->path_len-1];
}
r = brtcurs_set_position_first(cursor, node->u.n.children[childnum], txn);
r = brtcurs_set_position_first(cursor, node->u.n.children[childnum], db, txn);
if (r == 0)
return 0;
assert(node == cursor->path[cursor->path_len-1]);
......@@ -2059,11 +2061,11 @@ int brtcurs_set_position_next2(BRT_CURSOR cursor, TOKUTXN txn) {
childnum += 1;
}
return brtcurs_set_position_next2(cursor, txn);
return brtcurs_set_position_next2(cursor, db, txn);
}
/* requires that the cursor is initialized. */
int brtcurs_set_position_next (BRT_CURSOR cursor, TOKUTXN txn) {
int brtcurs_set_position_next (BRT_CURSOR cursor, DB *db, TOKUTXN txn) {
int r = pma_cursor_set_position_next(cursor->pmacurs);
if (r==DB_NOTFOUND) {
/* We fell off the end of the pma. */
......@@ -2071,12 +2073,12 @@ int brtcurs_set_position_next (BRT_CURSOR cursor, TOKUTXN txn) {
/* Part of the trickyness is we need to leave the cursor pointing at the current (possibly deleted) value if there is no next value. */
r = pma_cursor_free(&cursor->pmacurs);
assert(r == 0);
return brtcurs_set_position_next2(cursor, txn);
return brtcurs_set_position_next2(cursor, db, txn);
}
return 0;
}
int brtcurs_set_position_prev2(BRT_CURSOR cursor, TOKUTXN txn) {
int brtcurs_set_position_prev2(BRT_CURSOR cursor, DB *db, TOKUTXN txn) {
BRTNODE node;
int childnum;
int r;
......@@ -2107,11 +2109,11 @@ int brtcurs_set_position_prev2(BRT_CURSOR cursor, TOKUTXN txn) {
more = node->u.n.n_bytes_in_hashtable[childnum];
if (more == 0)
break;
brt_flush_child(cursor->brt, node, childnum, cursor, txn);
brt_flush_child(cursor->brt, node, childnum, cursor, 0, db, txn);
node = cursor->path[cursor->path_len-1];
childnum = cursor->pathcnum[cursor->path_len-1];
}
r = brtcurs_set_position_last(cursor, node->u.n.children[childnum], txn);
r = brtcurs_set_position_last(cursor, node->u.n.children[childnum], 0, txn);
if (r == 0)
return 0;
assert(node == cursor->path[cursor->path_len-1]);
......@@ -2119,17 +2121,17 @@ int brtcurs_set_position_prev2(BRT_CURSOR cursor, TOKUTXN txn) {
childnum -= 1;
}
return brtcurs_set_position_prev2(cursor, txn);
return brtcurs_set_position_prev2(cursor, db, txn);
}
int brtcurs_set_position_prev (BRT_CURSOR cursor, TOKUTXN txn) {
int brtcurs_set_position_prev (BRT_CURSOR cursor, DB *db, TOKUTXN txn) {
int r = pma_cursor_set_position_prev(cursor->pmacurs);
if (r==DB_NOTFOUND) {
if (cursor->path_len==1)
return DB_NOTFOUND;
r = pma_cursor_free(&cursor->pmacurs);
assert(r == 0);
return brtcurs_set_position_prev2(cursor, txn);
return brtcurs_set_position_prev2(cursor, db, txn);
}
return 0;
}
......@@ -2155,7 +2157,7 @@ int brtcurs_set_key(BRT_CURSOR cursor, diskoff off, DBT *key, DBT *val, int flag
brt_node_add_cursor(node, childnum, cursor);
int more = node->u.n.n_bytes_in_hashtable[childnum];
if (more > 0) {
brt_flush_child(cursor->brt, node, childnum, cursor, txn);
brt_flush_child(cursor->brt, node, childnum, cursor, key->app_private, db, txn);
node = cursor->path[cursor->path_len-1];
childnum = cursor->pathcnum[cursor->path_len-1];
brt_node_remove_cursor(node, childnum, cursor);
......@@ -2217,7 +2219,7 @@ int brtcurs_set_range(BRT_CURSOR cursor, diskoff off, DBT *key, DB *db, TOKUTXN
brt_node_add_cursor(node, childnum, cursor);
int more = node->u.n.n_bytes_in_hashtable[childnum];
if (more > 0) {
brt_flush_child(cursor->brt, node, childnum, cursor, txn);
brt_flush_child(cursor->brt, node, childnum, cursor, key->app_private, db, txn);
node = cursor->path[cursor->path_len-1];
childnum = cursor->pathcnum[cursor->path_len-1];
brt_node_remove_cursor(node, childnum, cursor);
......@@ -2314,7 +2316,7 @@ int brt_cursor_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int flags, DB *db, TO
do_db_last:
r=unpin_cursor(cursor); if (r!=0) goto died0;
assert(cursor->pmacurs == 0);
r=brtcurs_set_position_last(cursor, *rootp, txn); if (r!=0) goto died0;
r=brtcurs_set_position_last(cursor, *rootp, db, txn); if (r!=0) goto died0;
r=pma_cursor_get_current(cursor->pmacurs, kbt, vbt);
if (r == 0) assert_cursor_path(cursor);
break;
......@@ -2322,21 +2324,21 @@ int brt_cursor_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int flags, DB *db, TO
do_db_first:
r=unpin_cursor(cursor); if (r!=0) goto died0;
assert(cursor->pmacurs == 0);
r=brtcurs_set_position_first(cursor, *rootp, txn); if (r!=0) goto died0;
r=brtcurs_set_position_first(cursor, *rootp, db, txn); if (r!=0) goto died0;
r=pma_cursor_get_current(cursor->pmacurs, kbt, vbt);
if (r == 0) assert_cursor_path(cursor);
break;
case DB_NEXT:
if (cursor->path_len<=0)
goto do_db_first;
r=brtcurs_set_position_next(cursor, txn); if (r!=0) goto died0;
r=brtcurs_set_position_next(cursor, db, txn); if (r!=0) goto died0;
r=pma_cursor_get_current(cursor->pmacurs, kbt, vbt); if (r!=0) goto died0;
if (r == 0) assert_cursor_path(cursor);
break;
case DB_PREV:
if (cursor->path_len<= 0)
goto do_db_last;
r = brtcurs_set_position_prev(cursor, txn); if (r!=0) goto died0;
r = brtcurs_set_position_prev(cursor, db, txn); if (r!=0) goto died0;
r = pma_cursor_get_current(cursor->pmacurs, kbt, vbt); if (r!=0) goto died0;
if (r == 0) assert_cursor_path(cursor);
break;
......
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