mirror of
https://github.com/MariaDB/server.git
synced 2025-01-22 06:44:16 +01:00
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
This commit is contained in:
parent
74565b165a
commit
684da3b6ba
16 changed files with 7 additions and 1590 deletions
|
@ -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 *);
|
||||
|
|
86
newbrt/brt.c
86
newbrt/brt.c
|
@ -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 \
|
||||
|
|
|
@ -1,443 +0,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 -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;
|
||||
}
|
|
@ -1,444 +0,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;
|
||||
}
|
|
@ -1,259 +0,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;
|
||||
}
|
316
src/ydb.c
316
src/ydb.c
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue