Commit 37fbff8b authored by Bradley C. Kuszmaul's avatar Bradley C. Kuszmaul Committed by Yoni Fogel

Merge changes to remove heaviside and straddle from the ydb layer. Fixes #2865. [t:2865].

{{{
svn merge -c22808 https://svn.tokutek.com/tokudb/toku/tokudb.2861
}}}
.


git-svn-id: file:///svn/toku/tokudb@22809 c7de825b-a66e-492c-adef-691d508d4ae1
parent 61119e42
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -459,14 +457,13 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range_reverse)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
void* __toku_dummy0[3];
void* __toku_dummy0[4];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=188 size=4, 64=bit offset=272 size=8 */
int (*c_count) (DBC *, db_recno_t *, u_int32_t); /* 32-bit offset=192 size=4, 64=bit offset=280 size=8 */
......
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -475,14 +473,13 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range_reverse)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
void* __toku_dummy0[1];
void* __toku_dummy0[2];
char __toku_dummy1[112];
int (*c_close) (DBC *); /* 32-bit offset=188 size=4, 64=bit offset=264 size=8 */
int (*c_count) (DBC *, db_recno_t *, u_int32_t); /* 32-bit offset=192 size=4, 64=bit offset=272 size=8 */
......
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -483,14 +481,13 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range_reverse)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
void* __toku_dummy0[3];
void* __toku_dummy0[4];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=188 size=4, 64=bit offset=272 size=8 */
int (*c_count) (DBC *, db_recno_t *, u_int32_t); /* 32-bit offset=192 size=4, 64=bit offset=280 size=8 */
......
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -483,14 +481,13 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range_reverse)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
void* __toku_dummy0[7];
void* __toku_dummy0[8];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=204 size=4, 64=bit offset=304 size=8 */
int (*c_count) (DBC *, db_recno_t *, u_int32_t); /* 32-bit offset=208 size=4, 64=bit offset=312 size=8 */
......
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -488,14 +486,13 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_get_both_range_reverse)(DBC *, u_int32_t, DBT *, DBT *, YDB_CALLBACK_FUNCTION, void *);
void* __toku_dummy0[17];
void* __toku_dummy0[18];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=244 size=4, 64=bit offset=384 size=8 */
int (*c_count) (DBC *, db_recno_t *, u_int32_t); /* 32-bit offset=248 size=4, 64=bit offset=392 size=8 */
......
......@@ -391,8 +391,6 @@ int main (int argc __attribute__((__unused__)), char *const argv[] __attribute__
printf("typedef struct __toku_dbt DBT;\n");
printf("typedef u_int32_t db_recno_t;\n");
printf("typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);\n");
printf("typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);\n");
printf("typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);\n");
printf("#include <tdb-internal.h>\n");
......@@ -652,9 +650,7 @@ int main (int argc __attribute__((__unused__)), char *const argv[] __attribute__
"int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_heaviside)(DBC *, u_int32_t, "
"YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, "
"YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction)",
"int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *)",
......
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -424,7 +422,6 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
......
......@@ -34,8 +34,6 @@ typedef struct __toku_dbc DBC;
typedef struct __toku_dbt DBT;
typedef u_int32_t db_recno_t;
typedef int(*YDB_CALLBACK_FUNCTION)(DBT const*, DBT const*, void*);
typedef int(*YDB_HEAVISIDE_CALLBACK_FUNCTION)(DBT const *key, DBT const *value, void *extra_f, int r_h);
typedef int(*YDB_HEAVISIDE_FUNCTION)(const DBT *key, const DBT *value, void *extra_h);
#include <tdb-internal.h>
#ifndef __BIGGEST_ALIGNMENT__
#define __BIGGEST_ALIGNMENT__ 16
......@@ -424,7 +422,6 @@ struct __toku_dbc {
int (*c_getf_prev_nodup)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_current_binding)(DBC *, u_int32_t, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_heaviside)(DBC *, u_int32_t, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f, YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
......
......@@ -5213,20 +5213,6 @@ toku_brt_cursor_peek(BRT_CURSOR cursor, const DBT **pkey, const DBT **pval)
*pval = &cursor->val;
}
static int brt_cursor_compare_heaviside(brt_search_t *search, DBT *x, DBT *y) {
HEAVI_WRAPPER wrapper = search->context;
int r = wrapper->h(x, y, wrapper->extra_h);
// wrapper->r_h must have the same signus as the final chosen element.
// it is initialized to -1 or 1. 0's are closer to the min (max) that we
// want so once we hit 0 we keep it.
if (r==0) wrapper->r_h = 0;
//direction>0 means BRT_SEARCH_LEFT
//direction<0 means BRT_SEARCH_RIGHT
//direction==0 is not allowed
r = (wrapper->direction>0) ? r>=0 : r<=0;
return r;
}
//We pass in toku_dbt_fake to the search functions, since it will not pass the
//key(or val) to the heaviside function if key(or val) is NULL.
//It is not used for anything else,
......@@ -5235,78 +5221,6 @@ static int brt_cursor_compare_heaviside(brt_search_t *search, DBT *x, DBT *y) {
static const DBT __toku_dbt_fake;
static const DBT* const toku_dbt_fake = &__toku_dbt_fake;
#ifdef BRT_LEVEL_STRADDLE_CALLBACK_LOGIC_NOT_READY
struct brt_cursor_straddle_search_struct {
BRT_GET_STRADDLE_CALLBACK_FUNCTION getf;
void *getf_v;
BRT_CURSOR cursor;
brt_search_t *search;
};
static int
straddle_hack_getf(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val,
ITEMLEN next_keylen, bytevec next_key, ITEMLEN next_vallen, bytevec next_val, void* v) {
struct brt_cursor_straddle_search_struct *bcsss = v;
int old_hack_value = STRADDLE_HACK_INSIDE_CALLBACK;
STRADDLE_HACK_INSIDE_CALLBACK = 1;
int r = bcsss->getf(keylen, key, vallen, val, next_keylen, next_key, next_vallen, next_val, bcsss->getf_v);
STRADDLE_HACK_INSIDE_CALLBACK = old_hack_value;
return r;
}
#endif
/* search for the first kv pair that matches the search object */
static int
brt_cursor_straddle_search(BRT_CURSOR cursor, brt_search_t *search, BRT_GET_STRADDLE_CALLBACK_FUNCTION getf, void *getf_v)
{
brt_cursor_invalidate(cursor);
#ifdef BRT_LEVEL_STRADDLE_CALLBACK_LOGIC_NOT_READY
struct brt_cursor_straddle_search_struct bcsss = {getf, getf_v, cursor, search};
int r = toku_brt_search(cursor->brt, search, straddle_hack_getf, &bcsss, cursor, &cursor->root_put_counter);
#else
int r = toku_brt_search(cursor->brt, search, getf, getf_v, logger, cursor, &cursor->root_put_counter);
#endif
return r;
}
struct brt_cursor_heaviside_struct {
BRT_GET_STRADDLE_CALLBACK_FUNCTION getf;
void *getf_v;
HEAVI_WRAPPER wrapper;
};
static int
heaviside_getf(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val,
ITEMLEN next_keylen, bytevec next_key, ITEMLEN next_vallen, bytevec next_val, void* v) {
struct brt_cursor_heaviside_struct *bchs = v;
if (bchs->wrapper->r_h==0) {
//PROVDELs can confuse the heaviside query.
//If r_h is 0, it might be wrong.
//Run the heaviside function again to get correct answer.
DBT dbtkey, dbtval;
bchs->wrapper->r_h = bchs->wrapper->h(toku_fill_dbt(&dbtkey, key, keylen),
toku_fill_dbt(&dbtval, val, vallen),
bchs->wrapper->extra_h);
}
int r = bchs->getf(keylen, key, vallen, val, next_keylen, next_key, next_vallen, next_val, bchs->getf_v);
return r;
}
int
toku_brt_cursor_heaviside(BRT_CURSOR cursor, BRT_GET_STRADDLE_CALLBACK_FUNCTION getf, void *getf_v, HEAVI_WRAPPER wrapper)
{
brt_search_t search; brt_search_init(&search, brt_cursor_compare_heaviside,
wrapper->direction < 0 ? BRT_SEARCH_RIGHT : BRT_SEARCH_LEFT,
toku_dbt_fake,
cursor->brt->flags & TOKU_DB_DUPSORT ? (DBT*)toku_dbt_fake : NULL,
wrapper);
struct brt_cursor_heaviside_struct bchs = {getf, getf_v, wrapper};
return brt_cursor_straddle_search(cursor, &search, heaviside_getf, &bchs);
}
BOOL toku_brt_cursor_uninitialized(BRT_CURSOR c) {
return brt_cursor_not_set(c);
}
......
......@@ -151,13 +151,6 @@ int toku_brt_cursor_get_both_range(BRT_CURSOR cursor, DBT *key, DBT *val, BRT_GE
int toku_brt_cursor_get_both_range_reverse(BRT_CURSOR cursor, DBT *key, DBT *val, BRT_GET_CALLBACK_FUNCTION getf, void *getf_v);
typedef struct {
YDB_HEAVISIDE_FUNCTION h;
void *extra_h;
int r_h;
int direction;
} *HEAVI_WRAPPER, HEAVI_WRAPPER_S;
int toku_brt_cursor_heaviside(BRT_CURSOR cursor, BRT_GET_STRADDLE_CALLBACK_FUNCTION getf, void *getf_v, HEAVI_WRAPPER wrapper);
int toku_brt_cursor_delete(BRT_CURSOR cursor, int flags, TOKUTXN);
int toku_brt_cursor_close (BRT_CURSOR curs);
BOOL toku_brt_cursor_uninitialized(BRT_CURSOR c);
......
......@@ -125,7 +125,7 @@ extern "C" {
//
// The brt cursor implements its search by first finding a leaf node,
// containing an OMT. The BRT then passes its OMTCURSOR into the lookup
// method (i.e., one of toku_ebdomt_fetch, toku_omt_find_zero,
// method (i.e., one of toku_omt_fetch, toku_omt_find_zero,
// toku_omt_find). The lookup method, if successful, sets the
// OMTCURSOR to refer to that element.
//
......
......@@ -148,11 +148,8 @@ BDB_DONTRUN_TESTS = \
test_db_descriptor \
test_db_descriptor_named_db \
test_dbremove_old \
test_db_txn_locks_heaviside \
test_dupsort_get_both_range_reverse \
test_dupsort_set_range_reverse \
test_heaviside_rh_1756 \
test_heaviside_straddle_1622 \
test_logflush \
test_txn_abort6 \
test_txn_abort8 \
......
/* -*- mode: C; c-basic-offset: 4 -*- */
#include <toku_portability.h>
#ident "Copyright (c) 2007 Tokutek Inc. All rights reserved."
#include <memory.h>
#include <toku_portability.h>
#include <db.h>
#include <errno.h>
#include <sys/stat.h>
#include "test.h"
struct heavi_extra {
DBT key;
DBT val;
DB* db;
};
static int
heavi_after (const DBT *key, const DBT *val, void *extra) {
//Assumes cmp is int_dbt_cmp
struct heavi_extra *info = extra;
int cmp = int_dbt_cmp(info->db, key, &info->key);
if (cmp!=0) return cmp;
if (!val) return -1;
cmp = int_dbt_cmp(info->db, val, &info->val);
return cmp<=0 ? -1 : 0;
//Returns <0 for too small/equal
//Returns 0 for greater, but with the same key
//Returns >0 for greater with different key
}
static int
heavi_before (const DBT *key, const DBT *val, void *extra) {
struct heavi_extra *info = extra;
int cmp = int_dbt_cmp(info->db, key, &info->key);
if (cmp!=0) return cmp;
if (!val) return +1;
cmp = int_dbt_cmp(info->db, val, &info->val);
return cmp>=0 ? 1 : 0;
//Returns >0 for too large/equal
//Returns 0 for smaller with same key
//returns -1 for smaller with different key
}
// ENVDIR is defined in the Makefile
static DB *db;
static DB_TXN* txns[(int)256];
static DB_ENV* dbenv;
static DBC* cursors[(int)256];
static void
put(BOOL success, char txn, int _key, int _data) {
assert(txns[(int)txn]);
int r;
DBT key;
DBT data;
r = db->put(db, txns[(int)txn],
dbt_init(&key, &_key, sizeof(int)),
dbt_init(&data, &_data, sizeof(int)),
DB_YESOVERWRITE);
if (success) CKERR(r);
else CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
}
static void
cget(BOOL success, BOOL find, char txn, int _key, int _data,
int _key_expect, int _data_expect, u_int32_t flags) {
assert(txns[(int)txn] && cursors[(int)txn]);
int r;
DBT key;
DBT data;
r = cursors[(int)txn]->c_get(cursors[(int)txn],
dbt_init(&key, &_key, sizeof(int)),
dbt_init(&data, &_data, sizeof(int)),
flags);
if (success) {
if (find) {
CKERR(r);
assert(*(int *)key.data == _key_expect);
assert(*(int *)data.data == _data_expect);
}
else CKERR2(r, DB_NOTFOUND);
}
else CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
}
static void
init_txn (char name) {
int r;
assert(!txns[(int)name]);
r = dbenv->txn_begin(dbenv, NULL, &txns[(int)name], DB_TXN_NOWAIT);
CKERR(r);
assert(txns[(int)name]);
}
static void
init_dbc (char name) {
int r;
assert(!cursors[(int)name] && txns[(int)name]);
r = db->cursor(db, txns[(int)name], &cursors[(int)name], 0);
CKERR(r);
assert(cursors[(int)name]);
}
static void
commit_txn (char name) {
int r;
assert(txns[(int)name] && !cursors[(int)name]);
r = txns[(int)name]->commit(txns[(int)name], 0);
CKERR(r);
txns[(int)name] = NULL;
}
static void
abort_txn (char name) {
int r;
assert(txns[(int)name] && !cursors[(int)name]);
r = txns[(int)name]->abort(txns[(int)name]);
CKERR(r);
txns[(int)name] = NULL;
}
static void
close_dbc (char name) {
int r;
assert(cursors[(int)name]);
r = cursors[(int)name]->c_close(cursors[(int)name]);
CKERR(r);
cursors[(int)name] = NULL;
}
static void
early_commit (char name) {
assert(cursors[(int)name] && txns[(int)name]);
close_dbc(name);
commit_txn(name);
}
static void
early_abort (char name) {
assert(cursors[(int)name] && txns[(int)name]);
close_dbc(name);
abort_txn(name);
}
static void
setup_dbs (u_int32_t dup_flags) {
int r;
r = system("rm -rf " ENVDIR);
CKERR(r);
toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);
dbenv = NULL;
db = NULL;
/* Open/create primary */
r = db_env_create(&dbenv, 0);
CKERR(r);
u_int32_t env_txn_flags = DB_INIT_TXN | DB_INIT_LOCK;
u_int32_t env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL;
r = dbenv->open(dbenv, ENVDIR, env_open_flags | env_txn_flags, 0600);
CKERR(r);
r = db_create(&db, dbenv, 0);
CKERR(r);
if (dup_flags) {
r = db->set_flags(db, dup_flags);
CKERR(r);
}
r = db->set_bt_compare( db, int_dbt_cmp);
CKERR(r);
r = db->set_dup_compare(db, int_dbt_cmp);
CKERR(r);
char a;
for (a = 'a'; a <= 'z'; a++) init_txn(a);
init_txn('\0');
r = db->open(db, txns[(int)'\0'], "foobar.db", NULL, DB_BTREE, DB_CREATE, 0600);
CKERR(r);
commit_txn('\0');
for (a = 'a'; a <= 'z'; a++) init_dbc(a);
}
static void
close_dbs(void) {
char a;
for (a = 'a'; a <= 'z'; a++) {
if (cursors[(int)a]) close_dbc(a);
if (txns[(int)a]) commit_txn(a);
}
int r;
r = db->close(db, 0);
CKERR(r);
db = NULL;
r = dbenv->close(dbenv, 0);
CKERR(r);
dbenv = NULL;
}
static __attribute__((__unused__))
void
test_abort (u_int32_t dup_flags) {
/* ********************************************************************** */
setup_dbs(dup_flags);
put(TRUE, 'a', 1, 1);
early_abort('a');
cget(TRUE, FALSE, 'b', 1, 1, 0, 0, DB_SET);
close_dbs();
/* ********************************************************************** */
setup_dbs(dup_flags);
cget(TRUE, FALSE, 'a', 1, 1, 0, 0, DB_SET);
cget(TRUE, FALSE, 'b', 1, 1, 0, 0, DB_SET);
put(FALSE, 'a', 1, 1);
early_commit('b');
put(TRUE, 'a', 1, 1);
cget(TRUE, TRUE, 'a', 1, 1, 1, 1, DB_SET);
cget(TRUE, FALSE, 'a', 2, 1, 1, 1, DB_SET);
cget(FALSE, TRUE, 'c', 1, 1, 0, 0, DB_SET);
early_abort('a');
cget(TRUE, FALSE, 'c', 1, 1, 0, 0, DB_SET);
close_dbs();
/* ********************************************************************** */
}
struct dbt_pair {
DBT key;
DBT val;
};
struct int_pair {
int key;
int val;
};
int got_r_h;
static __attribute__((__unused__))
int
f_heavi (DBT const *key, DBT const *val, void *extra_f, int r_h) {
struct int_pair *info = extra_f;
if (r_h==0) got_r_h = 0;
assert(key->size == 4);
assert(val->size == 4);
info->key = *(int*)key->data;
info->val = *(int*)val->data;
int r = 0;
return r;
}
static __attribute__((__unused__))
void
ignore (void *ignore __attribute__((__unused__))) {
}
#define TOKU_IGNORE(x) ignore((void*)x)
static void
cget_heavi (BOOL success, BOOL find, char txn, int _key, int _val,
int _key_expect, int _val_expect, int direction,
int r_h_expect,
int (*h)(const DBT*,const DBT*,void*)) {
#if defined(USE_BDB)
TOKU_IGNORE(success);
TOKU_IGNORE(find);
TOKU_IGNORE((size_t)txn);
TOKU_IGNORE((size_t)_key);
TOKU_IGNORE((size_t)_val);
TOKU_IGNORE((size_t)_key_expect);
TOKU_IGNORE((size_t)_val_expect);
TOKU_IGNORE((size_t)direction);
TOKU_IGNORE(h);
TOKU_IGNORE((size_t)r_h_expect);
return;
#else
assert(txns[(int)txn] && cursors[(int)txn]);
int r;
struct heavi_extra input;
struct int_pair output;
dbt_init(&input.key, &_key, sizeof(int));
dbt_init(&input.val, &_val, sizeof(int));
input.db = db;
output.key = 0;
output.val = 0;
got_r_h = direction;
r = cursors[(int)txn]->c_getf_heaviside(cursors[(int)txn], 0, //No prelocking
f_heavi, &output,
h, &input, direction);
if (!success) {
CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
return;
}
if (!find) {
CKERR2(r, DB_NOTFOUND);
return;
}
CKERR(r);
assert(got_r_h == r_h_expect);
assert(output.key == _key_expect);
assert(output.val == _val_expect);
#endif
}
static void
test_heavi (u_int32_t dup_flags) {
/* ********************************************************************** */
setup_dbs(dup_flags);
cget_heavi(TRUE, FALSE, 'a', 0, 0, 0, 0, 1, 0, heavi_after);
cget_heavi(TRUE, FALSE, 'a', 0, 0, 0, 0, -1, 0, heavi_before);
close_dbs();
/* ********************************************************************** */
//Not found locks left to right (with empty db == entire db)
setup_dbs(dup_flags);
cget_heavi(TRUE, FALSE, 'a', 0, 0, 0, 0, 1, 0, heavi_after);
put(FALSE, 'b', 7, 6);
put(FALSE, 'b', -1, -1);
put(TRUE, 'a', 4, 4);
early_commit('a');
put(TRUE, 'b', 7, 6);
put(TRUE, 'b', -1, -1);
close_dbs();
/* ********************************************************************** */
//Not found locks left to right (with empty db == entire db)
setup_dbs(dup_flags);
cget_heavi(TRUE, FALSE, 'a', 0, 0, 0, 0, -1, 0, heavi_before);
put(FALSE, 'b', 7, 6);
put(FALSE, 'b', -1, -1);
put(TRUE, 'a', 4, 4);
early_commit('a');
put(TRUE, 'b', 7, 6);
put(TRUE, 'b', -1, -1);
close_dbs();
/* ********************************************************************** */
//Duplicate mode behaves differently.
setup_dbs(dup_flags);
int k,v;
for (k = 10; k <= 100; k+= 10) {
v = k+5;
put(TRUE, 'a', k, v);
}
if (dup_flags) {
cget_heavi(TRUE, TRUE, 'a', 100, 0, 100, 105, 1, 0, heavi_after);
}
else {
cget_heavi(TRUE, FALSE, 'a', 100, 0, 0, 0, 1, 0, heavi_after);
}
close_dbs();
/* ********************************************************************** */
//Locks stop at actual elements in the DB.
setup_dbs(dup_flags);
//int k,v;
for (k = 10; k <= 100; k+= 10) {
v = k+5;
put(TRUE, 'a', k, v);
}
cget_heavi(TRUE, FALSE, 'a', 105, 1, 0, 0, 1, 0, heavi_after);
put(FALSE, 'b', 104, 1);
put(FALSE, 'b', 105, 0);
put(FALSE, 'b', 105, 1);
put(FALSE, 'b', 105, 2);
put(FALSE, 'b', 106, 0);
put(TRUE, 'b', 99, 0);
put((BOOL)(dup_flags!=0), 'b', 100, 104);
close_dbs();
/* ********************************************************************** */
// Test behavior of heavi_after
setup_dbs(dup_flags);
//int k,v;
for (k = 10; k <= 100; k+= 10) {
v = k+5;
put(TRUE, 'a', k, v);
}
for (k = 5; k <= 95; k+= 10) {
v = k+5;
cget_heavi(TRUE, TRUE, 'a', k, v, k+5, v+5, 1, 1, heavi_after);
}
put(FALSE, 'b', -1, -2);
put(TRUE, 'b', 200, 201);
cget_heavi(FALSE, FALSE, 'a', 105, 105, 0, 0, 1, 0, heavi_after);
close_dbs();
/* ********************************************************************** */
// Test behavior of heavi_before
setup_dbs(dup_flags);
//int k,v;
for (k = 10; k <= 100; k+= 10) {
v = k+5;
put(TRUE, 'a', k, v);
}
for (k = 105; k >= 15; k-= 10) {
v = k+5;
cget_heavi(TRUE, TRUE, 'a', k, v, k-5, v-5, -1, -1, heavi_before);
}
put(FALSE, 'b', 200, 201);
put(TRUE, 'b', -1, -2);
cget_heavi(FALSE, FALSE, 'a', -5, -5, 0, 0, -1, 0, heavi_after);
close_dbs();
}
static void
test (u_int32_t dup_flags) {
/* ********************************************************************** */
setup_dbs(dup_flags);
close_dbs();
/* ********************************************************************** */
test_heavi(dup_flags);
/* ********************************************************************** */
}
int
test_main(int argc, char *const argv[]) {
parse_args(argc, argv);
if (!IS_TDB) {
if (verbose) {
printf("Warning: " __FILE__" does not work in BDB.\n");
}
} else {
test(0);
test(DB_DUP | DB_DUPSORT);
/*
test_abort(0);
test_abort(DB_DUP | DB_DUPSORT);
*/
}
return 0;
}
/* -*- mode: C; c-basic-offset: 4 -*- */
#include <toku_portability.h>
#ident "Copyright (c) 2007 Tokutek Inc. All rights reserved."
#include <memory.h>
#include <toku_portability.h>
#include <db.h>
#include <errno.h>
#include <sys/stat.h>
#include "test.h"
struct heavi_extra {
DBT key;
DBT val;
DB* db;
};
static int
heavi_after (const DBT *key, const DBT *val, void *extra) {
//Assumes cmp is int_dbt_cmp
struct heavi_extra *info = extra;
int cmp = int_dbt_cmp(info->db, key, &info->key);
if (cmp!=0) return cmp;
if (!val) return 0;
cmp = int_dbt_cmp(info->db, val, &info->val);
return cmp<=0 ? -1 : 0;
//Returns <0 for too small/equal
//Returns 0 for greater, but with the same key
//Returns >0 for greater with different key
}
static int
heavi_before (const DBT *key, const DBT *val, void *extra) {
struct heavi_extra *info = extra;
int cmp = int_dbt_cmp(info->db, key, &info->key);
if (cmp!=0) return cmp;
if (!val) return 0;
cmp = int_dbt_cmp(info->db, val, &info->val);
return cmp>=0 ? 1 : 0;
//Returns >0 for too large/equal
//Returns 0 for smaller with same key
//returns -1 for smaller with different key
}
// ENVDIR is defined in the Makefile
static DB *db;
static DB_TXN* txns[(int)256];
static DB_ENV* dbenv;
static DBC* cursors[(int)256];
static void
put(BOOL success, char txn, int _key, int _data) {
assert(txns[(int)txn]);
int r;
DBT key;
DBT data;
r = db->put(db, txns[(int)txn],
dbt_init(&key, &_key, sizeof(int)),
dbt_init(&data, &_data, sizeof(int)),
DB_YESOVERWRITE);
if (success) CKERR(r);
else CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
}
static void UU()
delboth(BOOL success, char txn, int _key, int _data) {
assert(txns[(int)txn]);
int r;
DBT key;
DBT data;
r = db->delboth(db, txns[(int)txn],
dbt_init(&key, &_key, sizeof(int)),
dbt_init(&data, &_data, sizeof(int)),
DB_DELETE_ANY);
if (success) CKERR(r);
else CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
}
static void
cget(BOOL success, BOOL find, char txn, int _key, int _data,
int _key_expect, int _data_expect, u_int32_t flags) {
assert(txns[(int)txn] && cursors[(int)txn]);
int r;
DBT key;
DBT data;
r = cursors[(int)txn]->c_get(cursors[(int)txn],
dbt_init(&key, &_key, sizeof(int)),
dbt_init(&data, &_data, sizeof(int)),
flags);
if (success) {
if (find) {
CKERR(r);
assert(*(int *)key.data == _key_expect);
assert(*(int *)data.data == _data_expect);
}
else CKERR2(r, DB_NOTFOUND);
}
else CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
}
static void
init_txn (char name) {
int r;
assert(!txns[(int)name]);
r = dbenv->txn_begin(dbenv, NULL, &txns[(int)name], DB_TXN_NOWAIT);
CKERR(r);
assert(txns[(int)name]);
}
static void
init_dbc (char name) {
int r;
assert(!cursors[(int)name] && txns[(int)name]);
r = db->cursor(db, txns[(int)name], &cursors[(int)name], 0);
CKERR(r);
assert(cursors[(int)name]);
}
static void
commit_txn (char name) {
int r;
assert(txns[(int)name] && !cursors[(int)name]);
r = txns[(int)name]->commit(txns[(int)name], 0);
CKERR(r);
txns[(int)name] = NULL;
}
static void
abort_txn (char name) {
int r;
assert(txns[(int)name] && !cursors[(int)name]);
r = txns[(int)name]->abort(txns[(int)name]);
CKERR(r);
txns[(int)name] = NULL;
}
static void
close_dbc (char name) {
int r;
assert(cursors[(int)name]);
r = cursors[(int)name]->c_close(cursors[(int)name]);
CKERR(r);
cursors[(int)name] = NULL;
}
static void
early_commit (char name) {
assert(cursors[(int)name] && txns[(int)name]);
close_dbc(name);
commit_txn(name);
}
static void
early_abort (char name) {
assert(cursors[(int)name] && txns[(int)name]);
close_dbc(name);
abort_txn(name);
}
static void
setup_dbs (u_int32_t dup_flags) {
int r;
r = system("rm -rf " ENVDIR);
CKERR(r);
toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);
dbenv = NULL;
db = NULL;
/* Open/create primary */
r = db_env_create(&dbenv, 0);
CKERR(r);
u_int32_t env_txn_flags = DB_INIT_TXN | DB_INIT_LOCK;
u_int32_t env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL;
r = dbenv->open(dbenv, ENVDIR, env_open_flags | env_txn_flags, 0600);
CKERR(r);
r = db_create(&db, dbenv, 0);
CKERR(r);
if (dup_flags) {
r = db->set_flags(db, dup_flags);
CKERR(r);
}
r = db->set_bt_compare( db, int_dbt_cmp);
CKERR(r);
r = db->set_dup_compare(db, int_dbt_cmp);
CKERR(r);
char a;
for (a = 'a'; a <= 'z'; a++) init_txn(a);
init_txn('\0');
r = db->open(db, txns[(int)'\0'], "foobar.db", NULL, DB_BTREE, DB_CREATE, 0600);
CKERR(r);
commit_txn('\0');
for (a = 'a'; a <= 'z'; a++) init_dbc(a);
}
static void
close_dbs(void) {
char a;
for (a = 'a'; a <= 'z'; a++) {
if (cursors[(int)a]) close_dbc(a);
if (txns[(int)a]) commit_txn(a);
}
int r;
r = db->close(db, 0);
CKERR(r);
db = NULL;
r = dbenv->close(dbenv, 0);
CKERR(r);
dbenv = NULL;
}
static __attribute__((__unused__))
void
test_abort (u_int32_t dup_flags) {
/* ********************************************************************** */
setup_dbs(dup_flags);
put(TRUE, 'a', 1, 1);
early_abort('a');
cget(TRUE, FALSE, 'b', 1, 1, 0, 0, DB_SET);
close_dbs();
/* ********************************************************************** */
setup_dbs(dup_flags);
cget(TRUE, FALSE, 'a', 1, 1, 0, 0, DB_SET);
cget(TRUE, FALSE, 'b', 1, 1, 0, 0, DB_SET);
put(FALSE, 'a', 1, 1);
early_commit('b');
put(TRUE, 'a', 1, 1);
cget(TRUE, TRUE, 'a', 1, 1, 1, 1, DB_SET);
cget(TRUE, FALSE, 'a', 2, 1, 1, 1, DB_SET);
cget(FALSE, TRUE, 'c', 1, 1, 0, 0, DB_SET);
early_abort('a');
cget(TRUE, FALSE, 'c', 1, 1, 0, 0, DB_SET);
close_dbs();
/* ********************************************************************** */
}
struct dbt_pair {
DBT key;
DBT val;
};
struct f_extra{
int key;
int val;
void *h_extra;
int (*h)(const DBT *, const DBT *, void *);
};
int got_r_h;
static __attribute__((__unused__))
int
f_heavi (DBT const *key, DBT const *val, void *extra_f, int r_h) {
struct f_extra *info = extra_f;
{
//Verify sign(r_h) is correct.
int r_h_verify = info->h(key, val, info->h_extra);
if (r_h_verify < 0)
assert(r_h<0);
else if (r_h_verify > 0)
assert(r_h>0);
else // if (r_h_verify == 0)
assert(r_h==0);
}
if (r_h==0) got_r_h = 0;
assert(key->size == 4);
assert(val->size == 4);
info->key = *(int*)key->data;
info->val = *(int*)val->data;
int r = 0;
return r;
}
static __attribute__((__unused__))
void
ignore (void *ignore __attribute__((__unused__))) {
}
#define TOKU_IGNORE(x) ignore((void*)x)
static void
cget_heavi (BOOL success, BOOL find, char txn, int _key, int _val,
int _key_expect, int _val_expect, int direction,
int r_h_expect,
int (*h)(const DBT*,const DBT*,void*)) {
#if defined(USE_BDB)
TOKU_IGNORE(success);
TOKU_IGNORE(find);
TOKU_IGNORE((size_t)txn);
TOKU_IGNORE((size_t)_key);
TOKU_IGNORE((size_t)_val);
TOKU_IGNORE((size_t)_key_expect);
TOKU_IGNORE((size_t)_val_expect);
TOKU_IGNORE((size_t)direction);
TOKU_IGNORE(h);
TOKU_IGNORE((size_t)r_h_expect);
return;
#else
assert(txns[(int)txn] && cursors[(int)txn]);
int r;
struct heavi_extra input;
struct f_extra output;
dbt_init(&input.key, &_key, sizeof(int));
dbt_init(&input.val, &_val, sizeof(int));
input.db = db;
output.key = 0;
output.val = 0;
output.h_extra = &input;
output.h = h;
got_r_h = direction;
r = cursors[(int)txn]->c_getf_heaviside(cursors[(int)txn], 0, //No prelocking
f_heavi, &output,
h, &input, direction);
if (!success) {
CKERR2s(r, DB_LOCK_DEADLOCK, DB_LOCK_NOTGRANTED);
return;
}
if (!find) {
CKERR2(r, DB_NOTFOUND);
return;
}
CKERR(r);
assert(got_r_h == r_h_expect);
assert(output.key == _key_expect);
assert(output.val == _val_expect);
#endif
}
static void
test_heavi (u_int32_t dup_flags) {
/* ********************************************************************** */
// Test behavior of heavi_after with provdels
setup_dbs(dup_flags);
int k,v;
for (k = 10; k <= 100; k+= 10) {
v = k+5;
put(TRUE, 'a', k, v);
}
for (k = 5; k <= 100; k+= 5) {
v = k+5;
if (k % 10 == 5)
cget_heavi(TRUE, TRUE, 'a', k, v, k+5, v+5, 1, 1, heavi_after);
else
cget_heavi(TRUE, TRUE, 'a', k, v-1, k, v, 1, 0, heavi_after);
}
//We want the deletes to make LE_PROVDEL. A delete of a LE_PROVPAIR is a nothing.
//Currently they are LE_PROVPAIR, committing will make them LE_COMMITTED
//A delete of a LE_COMMITTED is a LE_PROVDEL
close_dbc('a');
commit_txn('a');
init_txn('a');
init_dbc('a');
for (k = 5; k <= 95; k+= 5) {
v = k+5;
if (k % 10 == 5)
cget_heavi(TRUE, TRUE, 'a', k, v, k+5, v+5, 1, 1, heavi_after);
else {
delboth(TRUE, 'a', k, v);
cget_heavi(TRUE, TRUE, 'a', k, v-1, k+10, v+10, 1, 1, heavi_after);
}
}
close_dbs();
/* ********************************************************************** */
// Test behavior of heavi_before with provdels
setup_dbs(dup_flags);
//int k,v;
for (k = 10; k <= 100; k+= 10) {
v = k+5;
put(TRUE, 'a', k, v);
}
for (k = 105; k >= 15; k-= 5) {
v = k+5;
if (k % 10 == 5)
cget_heavi(TRUE, TRUE, 'a', k, v, k-5, v-5, -1, -1, heavi_before);
else
cget_heavi(TRUE, TRUE, 'a', k, v+1, k, v, -1, 0, heavi_before);
}
close_dbc('a');
commit_txn('a');
init_txn('a');
init_dbc('a');
for (k = 105; k >= 20; k-= 5) {
v = k+5;
if (k % 10 == 5)
cget_heavi(TRUE, TRUE, 'a', k, v, k-5, v-5, -1, -1, heavi_before);
else {
delboth(TRUE, 'a', k, v);
cget_heavi(TRUE, TRUE, 'a', k, v+1, k-10, v-10, -1, -1, heavi_before);
}
}
close_dbs();
}
static void
test (u_int32_t dup_flags) {
/* ********************************************************************** */
setup_dbs(dup_flags);
close_dbs();
/* ********************************************************************** */
test_heavi(dup_flags);
/* ********************************************************************** */
}
int
test_main(int argc, char *const argv[]) {
parse_args(argc, argv);
if (!IS_TDB) {
if (verbose) {
printf("Warning: " __FILE__" does not work in BDB.\n");
}
} else {
test(0);
test(DB_DUP | DB_DUPSORT);
/*
test_abort(0);
test_abort(DB_DUP | DB_DUPSORT);
*/
}
return 0;
}
/* -*- mode: C; c-basic-offset: 4 -*- */
#include <toku_portability.h>
#ident "Copyright (c) 2007 Tokutek Inc. All rights reserved."
#include <memory.h>
#include <toku_portability.h>
#include <db.h>
#include <errno.h>
#include <sys/stat.h>
#include "test.h"
#define INT_BLOWUP 16
struct heavi_extra {
DBT key;
DBT val;
DB* db;
};
static int
int_ignore_dbt_cmp(DB *db, const DBT *a, const DBT *b) {
assert(db && a && b);
assert(a->size == INT_BLOWUP * sizeof(int));
assert(b->size == INT_BLOWUP * sizeof(int));
int x = *(int *) a->data;
int y = *(int *) b->data;
if (x<y) return -1;
if (x>y) return 1;
return 0;
}
static int
heavi_find (const DBT *key, const DBT *val, void *extra) {
//Assumes cmp is int_dbt_cmp
struct heavi_extra *info = extra;
int cmp = int_ignore_dbt_cmp(info->db, key, &info->key);
if (cmp!=0) return cmp;
if (val) cmp = int_ignore_dbt_cmp(info->db, val, &info->val);
return cmp;
}
// ENVDIR is defined in the Makefile
static DB *db;
static DB_TXN* txns[(int)256];
static DB_ENV* dbenv;
static DBC* cursors[(int)256];
static void
put(char txn, int _key, int _val) {
assert(txns[(int)txn]);
static int waste_key[INT_BLOWUP];
static int waste_val[INT_BLOWUP];
waste_key[0] = _key;
waste_val[0] = _val;
int r;
DBT key;
DBT val;
r = db->put(db, txns[(int)txn],
dbt_init(&key, &waste_key[0], sizeof(waste_key)),
dbt_init(&val, &waste_val[0], sizeof(waste_val)),
DB_YESOVERWRITE);
CKERR(r);
}
static void
init_txn (char name) {
int r;
assert(!txns[(int)name]);
r = dbenv->txn_begin(dbenv, NULL, &txns[(int)name], DB_TXN_NOWAIT);
CKERR(r);
assert(txns[(int)name]);
}
static void
init_dbc (char name) {
int r;
assert(!cursors[(int)name] && txns[(int)name]);
r = db->cursor(db, txns[(int)name], &cursors[(int)name], 0);
CKERR(r);
assert(cursors[(int)name]);
}
static void
commit_txn (char name) {
int r;
assert(txns[(int)name] && !cursors[(int)name]);
r = txns[(int)name]->commit(txns[(int)name], 0);
CKERR(r);
txns[(int)name] = NULL;
}
static void
close_dbc (char name) {
int r;
assert(cursors[(int)name]);
r = cursors[(int)name]->c_close(cursors[(int)name]);
CKERR(r);
cursors[(int)name] = NULL;
}
static void
setup_dbs (u_int32_t dup_flags) {
int r;
r = system("rm -rf " ENVDIR);
CKERR(r);
toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);
dbenv = NULL;
db = NULL;
/* Open/create primary */
r = db_env_create(&dbenv, 0);
CKERR(r);
r = dbenv->set_cachesize(dbenv, 0, 4096, 1);
u_int32_t env_txn_flags = DB_INIT_TXN | DB_INIT_LOCK;
u_int32_t env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL;
r = dbenv->open(dbenv, ENVDIR, env_open_flags | env_txn_flags, 0600);
CKERR(r);
r = db_create(&db, dbenv, 0);
CKERR(r);
if (dup_flags) {
r = db->set_flags(db, dup_flags);
CKERR(r);
}
r = db->set_bt_compare( db, int_ignore_dbt_cmp);
CKERR(r);
r = db->set_dup_compare(db, int_ignore_dbt_cmp);
CKERR(r);
r = db->set_pagesize(db, 4096);
char a;
for (a = 'a'; a <= 'z'; a++) init_txn(a);
init_txn('\0');
r = db->open(db, txns[(int)'\0'], "foobar.db", NULL, DB_BTREE, DB_CREATE, 0600);
CKERR(r);
commit_txn('\0');
for (a = 'a'; a <= 'z'; a++) init_dbc(a);
}
static void
close_dbs(void) {
char a;
for (a = 'a'; a <= 'z'; a++) {
if (cursors[(int)a]) close_dbc(a);
if (txns[(int)a]) commit_txn(a);
}
int r;
r = db->close(db, 0);
CKERR(r);
db = NULL;
r = dbenv->close(dbenv, 0);
CKERR(r);
dbenv = NULL;
}
struct dbt_pair {
DBT key;
DBT val;
};
struct int_pair {
int key;
int val;
};
int got_r_h;
static __attribute__((__unused__))
int
f_heavi (DBT const *key, DBT const *val, void *extra_f, int r_h) {
struct int_pair *info = extra_f;
if (r_h==0) got_r_h = 0;
assert(key->size == INT_BLOWUP * sizeof(int));
assert(val->size == INT_BLOWUP * sizeof(int));
info->key = *(int*)key->data;
info->val = *(int*)val->data;
int r = 0;
return r;
}
static __attribute__((__unused__))
void
ignore (void *ignore __attribute__((__unused__))) {
}
#define TOKU_IGNORE(x) ignore((void*)x)
static void
cget_heavi (char txn, int _key, int _val,
int _key_expect, int _val_expect, int direction,
int r_h_expect) {
assert(txns[(int)txn] && cursors[(int)txn]);
static int waste_key[INT_BLOWUP];
static int waste_val[INT_BLOWUP];
waste_key[0] = _key;
waste_val[0] = _val;
int r;
struct heavi_extra input;
struct int_pair output;
dbt_init(&input.key, &waste_key[0], sizeof(waste_key));
dbt_init(&input.val, &waste_val[0], sizeof(waste_val));
input.db = db;
output.key = 0;
output.val = 0;
got_r_h = direction;
r = cursors[(int)txn]->c_getf_heaviside(cursors[(int)txn], 0, //No prelocking
f_heavi, &output,
heavi_find, &input, direction);
CKERR(r);
assert(got_r_h == r_h_expect);
assert(output.key == _key_expect);
assert(output.val == _val_expect);
}
static void
test(u_int32_t dup_flags) {
/* ********************************************************************** */
int i;
int j;
const int max_inserts = 2*4096/(INT_BLOWUP*sizeof(int));
for (i=1; i <= max_inserts ; i++) {
setup_dbs(dup_flags);
if (verbose) {
printf("%s: put %d\n", __FILE__, i);
fflush(stdout);
}
for (j=0; j < i; j++) {
put('a', j, j);
}
cget_heavi('a', i-1, i-1, i-1, i-1, 1, 0);
close_dbs();
}
}
int
test_main(int argc, char *const argv[]) {
parse_args(argc, argv);
test(0);
test(DB_DUP | DB_DUPSORT);
return 0;
}
......@@ -350,142 +350,6 @@ static int toku_c_getf_get_both(DBC *c, u_int32_t flag, DBT *key, DBT *val, YDB_
static int toku_c_getf_get_both_range(DBC *c, u_int32_t flag, DBT *key, DBT *val, YDB_CALLBACK_FUNCTION f, void *extra);
static int toku_c_getf_get_both_range_reverse(DBC *c, u_int32_t flag, DBT *key, DBT *val, YDB_CALLBACK_FUNCTION f, void *extra);
static int toku_c_getf_heaviside(DBC *c, u_int32_t flags,
YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f,
YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction);
// There is a total order on all key/value pairs in the database.
// In a DB_DUPSORT db, let V_i = (Key,Value) refer to the ith element (0 based indexing).
// In a NODUP db, let V_i = (Key) refer to the ith element (0 based indexing).
// We define V_{-1} = -\infty and
// V_{|V|} = \infty and
// h(-\infty,extra_h) = -1 by definition and
// h( \infty,extra_h) = 1 by definition
// Requires: Direction != 0
// Effect:
// if direction >0 then find the smallest i such that h(V_i,extra_h)>=0.
// if direction <0 then find the largest i such that h(V_i,extra_h)<=0.
// Let signus(r_h) = signus(h(V_i, extra_h))
// If flags&(DB_PRELOCKED|DB_PRELOCKED_WRITE) then skip locking
// That is, we already own the locks
// else
// if direction >0 then readlock [V_{i-1}, V_i]
// if direction <0 then readlock [V_i, V_{i+1}]
// That is, If we search from the right, lock the element we found, up to the
// next element to the right.
// If locking fails, return the locking error code
//
// If (0<=i<|V|) then
// call f(V_i.Key, V_i.Value, extra_f, r_h)
// Note: The lifetime of V_i.Key and V_i.Value is limited: they may only
// be referenced until f returns
// and return 0
// else
// return DB_NOTFOUND
// Rationale: Locking
// If we approach from the left (direction<0) we need to prevent anyone
// from inserting anything to our right that could change our answer,
// so we lock the range from the element found, to the next element to the right.
// The inverse argument applies for approaching from the right.
// Rationale: passing r_h to f
// We want to save the performance hit of requiring f to call h again to
// find out what h's return value was.
// Rationale: separate extra_f, extra_h parameters
// If the same extra parameter is sent to both f and h, then you need a
// special struct for each tuple (f_i, h_i) you use instead of a struct for each
// f_i and each h_i.
// Requires: The signum of h is monotically increasing.
// Requires: f does not create references to key, value, or data within once f
// exits
// Returns
// 0 success
// DB_NOTFOUND i is not in [0,|V|)
// DB_LOCK_NOTGRANTED Failed to obtain a lock.
// On nonzero return, what c points to becomes undefined, That is, c becomes uninitialized
// Performance: ... TODO
// Implementation Notes:
// How do we get the extra locking information efficiently?
// After finding the target, we can copy the cursor, do a DB_NEXT,
// or do a DB_NEXT+DB_PREV (vice versa for direction<0).
// Can we have the BRT provide two key/value pairs instead of one?
// That is, brt_cursor_c_getf_heavi_and_next for direction >0
// and brt_cursor_c_getf_heavi_and_prev for direction <0
// Current suggestion is to make a copy of the cursor, and use the
// copy to find the next(prev) element by using DB_NEXT(DB_PREV).
// This has the overhead of needing to make a copy of the cursor,
// which probably has a memcpy involved.
// The argument against returning two key/value pairs is that
// we should not have to pay to retreive both when we're doing something
// simple like DB_NEXT.
// This could be mitigated by having two BRT functions (or one with a
// BOOL parameter) such that it only returns two values when necessary.
// Parameters
// c The cursor
// flags Additional bool parameters. The current allowed flags are
// DB_PRELOCKED and DB_PRELOCKED_WRITE (bitwise or'd to use both)
// h A heaviside function that, along with direction, defines the query.
// extra_h is passed to h
// For additional information on heaviside functions, see omt.h
// NOTE: In a DB_DUPSORT database, both key and value will be
// passed to h. In a NODUP database, only key will be passed to h.
// f A callback function (i.e. smart dbts) to provide the result of the
// query. key and value are the key/value pair found, extra_f is
// passed to f, r_h is the return value for h for the key and value returned.
// This is used as output. That is, we call f with the outputs of the
// function.
// direction Which direction to search in on the heaviside function. >0
// means from the right, <0 means from the left.
// extra_f Any extra information required for f
// extra_h Any extra information required for h
//
// Example:
// Find the smallest V_i = (key_i,val_i) such that key_i > key_x, assume
// key.data and val.data are c strings, and print them out.
// Create a struct to hold key_x, that is extra_h
// Direction = 1 (We approach from the right, and want the smallest such
// element).
// Construct a heaviside function that returns >=0 if the
// given key > key_x, and -1 otherwise
// That is, call the comparison function on (key, key_x)
// Create a struct to hold key_x, that is extra_f
// construct f to call printf on key_x.data, key_i.data, val_i.data.
// Find the least upper bound (greatest lower bound)
// In this case, h can just return the comparison function's answer.
// direction >0 means upper bound, direction <0 means lower bound.
// (If you want upper/lower bound of the keyvalue pair, you need
// to call the comparison function on the values if the key comparison
// returns 0).
// Handlerton implications:
// The handlerton needs at most one heaviside function per special query type (where a
// special query is one that is not directly supported by the bdb api excluding
// this function).
// It is possible that more than query type can use the same heaviside function
// if the extra_h parameter can be used to change its behavior sufficiently.
//
// That is, part of extra_h can be a boolean strictly_greater
// You can construct a single heaviside function that converts 0 to -1
// (strictly greater) from the comparison function, or one that just returns
// the results of the comparison function (greater or equal).
//
// Implementation Notes:
// The BRT search function supports the following searches:
// SEARCH_LEFT(h(V_i))
// Given a step function b, that goes from 0 to 1
// find the greatest i such that h_b(V_i) == 1
// If it does not exist, return not found
// SEARCH_RIGHT(h(V_i))
// Given a step function b, that goes from 1 to 0
// find the smallest i such that h_b(V_i) == 1
// If it does not exist, return not found
// We can implement c_getf_heavi using these BRT search functions.
// A query of direction<0:
// Create wrapper function B
// return h(V_i) <=0 ? 1 : 0;
// SEARCH_RIGHT(B)
// A query of direction>0:
// Create wrapper function B
// return h(V_i) >=0 ? 1 : 0;
// SEARCH_LEFT(B)
// Effect: Lightweight cursor get
/* cursor methods */
......@@ -3816,185 +3680,6 @@ c_getf_get_both_range_reverse_callback(ITEMLEN keylen, bytevec key, ITEMLEN vall
return r;
}
static int locked_c_getf_heaviside(DBC *c, u_int32_t flags,
YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f,
YDB_HEAVISIDE_FUNCTION h, void *extra_h, int direction) {
toku_ydb_lock(); int r = toku_c_getf_heaviside(c, flags, f, extra_f, h, extra_h, direction); toku_ydb_unlock(); return r;
}
typedef struct {
QUERY_CONTEXT_BASE_S base;
YDB_HEAVISIDE_CALLBACK_FUNCTION f;
HEAVI_WRAPPER wrapper;
} *QUERY_CONTEXT_HEAVISIDE, QUERY_CONTEXT_HEAVISIDE_S;
static void
query_context_heaviside_init(QUERY_CONTEXT_HEAVISIDE context, DBC *c, u_int32_t flag, YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra, HEAVI_WRAPPER wrapper) {
WRITE_OP is_write = {FALSE};
query_context_base_init(&context->base, c, flag, is_write, extra);
context->f = f;
context->wrapper = wrapper;
}
static void
heavi_wrapper_init(HEAVI_WRAPPER wrapper, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction) {
wrapper->h = h;
wrapper->extra_h = extra_h;
wrapper->r_h = direction; //Default value of r_h (may be set to 0 later)->
wrapper->direction = direction;
}
static int c_getf_heaviside_callback(ITEMLEN found_keylen, bytevec found_key, ITEMLEN found_vallen, bytevec found_val,
ITEMLEN next_keylen, bytevec next_key, ITEMLEN next_vallen, bytevec next_val,
void *extra);
static int
toku_c_getf_heaviside(DBC *c, u_int32_t flag,
YDB_HEAVISIDE_CALLBACK_FUNCTION f, void *extra_f,
YDB_HEAVISIDE_FUNCTION h, void *extra_h,
int direction) {
int r;
HANDLE_PANICKED_DB(c->dbp);
HANDLE_CURSOR_ILLEGAL_WORKING_PARENT_TXN(c);
num_point_queries++; // accountability
HEAVI_WRAPPER_S wrapper;
heavi_wrapper_init(&wrapper, h, extra_h, direction);
QUERY_CONTEXT_HEAVISIDE_S context; //Describes the context of this query.
query_context_heaviside_init(&context, c, flag, f, extra_f, &wrapper);
//toku_brt_cursor_heaviside will call c_getf_heaviside_callback(..., context) (if query is successful)
r = toku_brt_cursor_heaviside(dbc_struct_i(c)->c, c_getf_heaviside_callback, &context, &wrapper);
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
return r;
}
//result is the result of the query (i.e. 0 means found, DB_NOTFOUND, etc..)
//bytevec==NULL means not found.
static int c_getf_heaviside_callback(ITEMLEN found_keylen, bytevec found_keyvec, ITEMLEN found_vallen, bytevec found_valvec,
ITEMLEN next_keylen, bytevec next_keyvec, ITEMLEN next_vallen, bytevec next_valvec,
void *extra) {
QUERY_CONTEXT_HEAVISIDE super_context = extra;
QUERY_CONTEXT_BASE context = &super_context->base;
int r;
int r2 = 0;
DBT found_key;
DBT found_val;
toku_fill_dbt(&found_key, found_keyvec, found_keylen);
toku_fill_dbt(&found_val, found_valvec, found_vallen);
if (context->do_locking) {
const DBT *left_key = toku_lt_neg_infinity;
const DBT *left_val = toku_lt_neg_infinity;
const DBT *right_key = toku_lt_infinity;
const DBT *right_val = toku_lt_infinity;
RANGE_LOCK_REQUEST_S request;
#ifdef BRT_LEVEL_STRADDLE_CALLBACK_LOGIC_NOT_READY
//Have cursor (base->c)
//Have txn (base->txn)
//Have db (base->db)
BOOL found = (BOOL)(found_keyvec != NULL);
DBC *tmp_cursor; //Temporary cursor to find 'next_key/next_val'
DBT tmp_key;
DBT tmp_val;
toku_init_dbt(&tmp_key);
toku_init_dbt(&tmp_val);
r = toku_db_cursor(context->db, context->txn, &tmp_cursor, 0, 0);
if (r!=0) goto tmp_cleanup;
//Find the 'next key and next val'
//We will do all relevent range locking, so there is no need for any sub-queries to do locking.
//Pass in DB_PRELOCKED.
if (super_context->wrapper->direction<0) {
if (found) {
//do an 'after'
//call DB_GET_BOTH to set the temp cursor to the 'found' values
//then call 'DB_NEXT' to advance it to the values we want
r = toku_c_getf_get_both(tmp_cursor, DB_PRELOCKED, &found_key, &found_val, ydb_getf_do_nothing, NULL);
if (r==0) {
r = toku_c_get(tmp_cursor, &tmp_key, &tmp_val, DB_NEXT|DB_PRELOCKED);
if (r==DB_NOTFOUND) r = 0;
}
}
else {
//do a 'first'
r = toku_c_get(tmp_cursor, &tmp_key, &tmp_val, DB_FIRST|DB_PRELOCKED);
if (r==DB_NOTFOUND) r = 0;
}
}
else {
if (found) {
//do a 'before'
//call DB_GET_BOTH to set the temp cursor to the 'found' values
//then call 'DB_PREV' to advance it to the values we want
r = toku_c_getf_get_both(tmp_cursor, DB_PRELOCKED, &found_key, &found_val, ydb_getf_do_nothing, NULL);
if (r==0) {
r = toku_c_get(tmp_cursor, &tmp_key, &tmp_val, DB_PREV|DB_PRELOCKED);
if (r==DB_NOTFOUND) r = 0;
}
}
else {
//do a 'last'
r = toku_c_get(tmp_cursor, &tmp_key, &tmp_val, DB_LAST|DB_PRELOCKED);
if (r==DB_NOTFOUND) r = 0;
}
}
if (r==0) {
next_keyvec = tmp_key.data;
next_keylen = tmp_key.size;
next_valvec = tmp_val.data;
next_vallen = tmp_val.size;
}
else goto temp_cursor_cleanup;
#endif
DBT next_key;
DBT next_val;
toku_fill_dbt(&next_key, next_keyvec, next_keylen);
toku_fill_dbt(&next_val, next_valvec, next_vallen);
if (super_context->wrapper->direction<0) {
if (found_keyvec!=NULL) {
left_key = &found_key;
left_val = &found_val;
}
if (next_keyvec!=NULL) {
right_key = &next_key;
right_val = &next_val;
}
}
else {
if (next_keyvec!=NULL) {
left_key = &next_key;
left_val = &next_val;
}
if (found_keyvec!=NULL) {
right_key = &found_key;
right_val = &found_val;
}
}
read_lock_request_init(&request, context->txn, context->db,
left_key, left_val,
right_key, right_val);
r = grab_range_lock(&request);
#ifdef BRT_LEVEL_STRADDLE_CALLBACK_LOGIC_NOT_READY
temp_cursor_cleanup:
r2 = toku_c_close(tmp_cursor);
//cleanup cursor
#endif
}
else r = 0;
//Call application-layer callback if found and locks were successfully obtained.
if (r==0 && found_keyvec!=NULL) {
context->r_user_callback = super_context->f(&found_key, &found_val, context->f_extra, super_context->wrapper->r_h);
if (context->r_user_callback) r = TOKUDB_USER_CALLBACK_ERROR;
}
#ifdef BRT_LEVEL_STRADDLE_CALLBACK_LOGIC_NOT_READY
tmp_cleanup:
#endif
//Give brt-layer an error (if any) to return from toku_brt_cursor_heavi
return r ? r : r2;
}
static int toku_c_close(DBC * c) {
HANDLE_PANICKED_DB(c->dbp);
HANDLE_CURSOR_ILLEGAL_WORKING_PARENT_TXN(c);
......@@ -4239,7 +3924,6 @@ static int toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags, int
SCRS(c_getf_prev_dup);
SCRS(c_getf_current);
SCRS(c_getf_current_binding);
SCRS(c_getf_heaviside);
SCRS(c_getf_set);
SCRS(c_getf_set_range);
SCRS(c_getf_set_range_reverse);
......
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