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

Addresses #993

Merge branch 993 back into main.

git-svn-id: file:///svn/tokudb@5141 c7de825b-a66e-492c-adef-691d508d4ae1
parent 6e4e5048
......@@ -251,7 +251,8 @@ struct __toku_dbc {
int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
void* __toku_dummy0[10];
int (*c_getf_heavi)(DBC *, u_int32_t, void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction);
void* __toku_dummy0[9];
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 */
......
......@@ -267,7 +267,8 @@ struct __toku_dbc {
int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
void* __toku_dummy0[8];
int (*c_getf_heavi)(DBC *, u_int32_t, void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction);
void* __toku_dummy0[7];
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 */
......
......@@ -272,7 +272,8 @@ struct __toku_dbc {
int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
void* __toku_dummy0[10];
int (*c_getf_heavi)(DBC *, u_int32_t, void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction);
void* __toku_dummy0[9];
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 */
......
......@@ -271,7 +271,8 @@ struct __toku_dbc {
int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
void* __toku_dummy0[14];
int (*c_getf_heavi)(DBC *, u_int32_t, void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction);
void* __toku_dummy0[13];
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 */
......
......@@ -11,9 +11,9 @@ extern "C" {
#define TOKUDB 1
#define DB_VERSION_MAJOR 4
#define DB_VERSION_MINOR 6
#define DB_VERSION_PATCH 21
#define DB_VERSION_PATCH 19
#ifndef _TOKUDB_WRAP_H
#define DB_VERSION_STRING "Tokutek: TokuDB 4.6.21"
#define DB_VERSION_STRING "Tokutek: TokuDB 4.6.19"
#else
#define DB_VERSION_STRING_ydb "Tokutek: TokuDB (wrapped bdb)"
#endif
......@@ -276,7 +276,8 @@ struct __toku_dbc {
int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
void* __toku_dummy0[24];
int (*c_getf_heavi)(DBC *, u_int32_t, void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction);
void* __toku_dummy0[23];
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 */
......
......@@ -330,6 +330,9 @@ int main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__un
"int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *)",
"int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *)",
"int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *)",
"int (*c_getf_heavi)(DBC *, u_int32_t, "
"void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, "
"int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction)",
NULL};
assert(sizeof(dbc_fields32)==sizeof(dbc_fields64));
print_struct("dbc", 1, dbc_fields32, dbc_fields64, sizeof(dbc_fields32)/sizeof(dbc_fields32[0]), extra);
......
......@@ -272,7 +272,8 @@ struct __toku_dbc {
int (*c_getf_current)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_first)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
int (*c_getf_last)(DBC *, u_int32_t, void(*)(DBT const *, DBT const *, void *), void *);
void* __toku_dummy0[10];
int (*c_getf_heavi)(DBC *, u_int32_t, void(*f)(DBT const *, DBT const *, void *, int), void *extra_f, int (*h)(const DBT *key, const DBT *value, void *extra_h), void *extra_h, int direction);
void* __toku_dummy0[9];
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 */
......
......@@ -3322,6 +3322,64 @@ get_next:;
return -1;
}
int toku_brt_cursor_peek_prev(BRT_CURSOR cursor, DBT *outkey, DBT *outval) {
if (toku_omt_cursor_is_valid(cursor->omtcursor)) {
{
int rr = toku_read_and_pin_brt_header(cursor->brt->cf, &cursor->brt->h);
if (rr!=0) return rr;
uint64_t h_counter = cursor->brt->h->root_put_counter;
rr = toku_unpin_brt_header(cursor->brt);
assert(rr==0);
if (h_counter != cursor->root_put_counter) return -1;
}
OMTVALUE le;
u_int32_t index = 0;
int r = toku_omt_cursor_current_index(cursor->omtcursor, &index);
assert(r==0);
OMT omt = toku_omt_cursor_get_omt(cursor->omtcursor);
get_prev:;
if (index>0) {
r = toku_omt_fetch(omt, --index, &le, NULL);
if (r==0) {
if (le_is_provdel(le)) goto get_prev;
toku_fill_dbt(outkey, le_latest_key(le), le_latest_keylen(le));
toku_fill_dbt(outval, le_latest_val(le), le_latest_vallen(le));
return 0;
}
}
}
return -1;
}
int toku_brt_cursor_peek_next(BRT_CURSOR cursor, DBT *outkey, DBT *outval) {
if (toku_omt_cursor_is_valid(cursor->omtcursor)) {
{
int rr = toku_read_and_pin_brt_header(cursor->brt->cf, &cursor->brt->h);
if (rr!=0) return rr;
uint64_t h_counter = cursor->brt->h->root_put_counter;
rr = toku_unpin_brt_header(cursor->brt);
assert(rr==0);
if (h_counter != cursor->root_put_counter) return -1;
}
OMTVALUE le;
u_int32_t index = UINT32_MAX;
int r = toku_omt_cursor_current_index(cursor->omtcursor, &index);
assert(r==0);
OMT omt = toku_omt_cursor_get_omt(cursor->omtcursor);
get_next:;
if (++index<toku_omt_size(omt)) {
r = toku_omt_fetch(omt, index, &le, NULL);
if (r==0) {
if (le_is_provdel(le)) goto get_next;
toku_fill_dbt(outkey, le_latest_key(le), le_latest_keylen(le));
toku_fill_dbt(outval, le_latest_val(le), le_latest_vallen(le));
return 0;
}
}
}
return -1;
}
static int brt_cursor_next(BRT_CURSOR cursor, DBT *outkey, DBT *outval, TOKULOGGER logger) {
if (0!=(cursor->brt->flags & TOKU_DB_DUP) &&
brt_cursor_next_shortcut(cursor, outkey, outval)==0)
......@@ -3330,6 +3388,12 @@ static int brt_cursor_next(BRT_CURSOR cursor, DBT *outkey, DBT *outval, TOKULOGG
return brt_cursor_search(cursor, &search, outkey, outval, logger);
}
int toku_brt_cursor_after(BRT_CURSOR cursor, DBT *key, DBT *val, DBT *outkey, DBT *outval, TOKUTXN txn) {
TOKULOGGER logger = toku_txn_logger(txn);
brt_search_t search; brt_search_init(&search, brt_cursor_compare_next, BRT_SEARCH_LEFT, key, val, cursor->brt);
return brt_cursor_search(cursor, &search, outkey, outval, logger);
}
static int brt_cursor_compare_next_nodup(brt_search_t *search, DBT *x, DBT *y) {
BRT brt = search->context; y = y;
return compare_k_x(brt, search->k, x) < 0; /* return min x: k < x */
......@@ -3413,6 +3477,12 @@ get_prev:;
return -1;
}
int toku_brt_cursor_before(BRT_CURSOR cursor, DBT *key, DBT *val, DBT *outkey, DBT *outval, TOKUTXN txn) {
TOKULOGGER logger = toku_txn_logger(txn);
brt_search_t search; brt_search_init(&search, brt_cursor_compare_prev, BRT_SEARCH_RIGHT, key, val, cursor->brt);
return brt_cursor_search(cursor, &search, outkey, outval, logger);
}
static int brt_cursor_prev(BRT_CURSOR cursor, DBT *outkey, DBT *outval, TOKULOGGER logger) {
if (0!=(cursor->brt->flags & TOKU_DB_DUP) &&
brt_cursor_prev_shortcut(cursor, outkey, outval)==0)
......@@ -3543,6 +3613,34 @@ int toku_brt_cursor_get (BRT_CURSOR cursor, DBT *key, DBT *val, int get_flags, T
return r;
}
static int brt_cursor_compare_heavi(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;
return (search->direction&BRT_SEARCH_LEFT) ? r>=0 : r<=0;
}
//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,
//the actual 'extra' information for the heaviside function is inside the
//wrapper.
static const DBT __toku_dbt_fake;
static const DBT* const toku_dbt_fake = &__toku_dbt_fake;
int toku_brt_cursor_get_heavi (BRT_CURSOR cursor, DBT *outkey, DBT *outval, TOKUTXN txn, int direction, HEAVI_WRAPPER wrapper) {
TOKULOGGER logger = toku_txn_logger(txn);
brt_search_t search; brt_search_init(&search, brt_cursor_compare_heavi,
direction < 0 ? BRT_SEARCH_RIGHT : BRT_SEARCH_LEFT,
(DBT*)toku_dbt_fake,
cursor->brt->flags & TOKU_DB_DUPSORT ? (DBT*)toku_dbt_fake : NULL,
wrapper);
return brt_cursor_search(cursor, &search, outkey, outval, logger);
}
static void toku_brt_keyrange_internal (BRT brt, CACHEKEY nodename, u_int32_t fullhash, DBT *key, u_int64_t *less, u_int64_t *equal, u_int64_t *greater) {
BRTNODE node;
{
......
......@@ -49,6 +49,17 @@ int toku_verify_brt (BRT brt);
typedef struct brt_cursor *BRT_CURSOR;
int toku_brt_cursor (BRT, BRT_CURSOR*, int is_temporary_cursor);
int toku_brt_cursor_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int brtc_flags, TOKUTXN);
struct heavi_wrapper {
int (*h)(const DBT *key, const DBT *value, void *extra_h);
void *extra_h;
int r_h;
};
typedef struct heavi_wrapper *HEAVI_WRAPPER;
int toku_brt_cursor_get_heavi (BRT_CURSOR cursor, DBT *outkey, DBT *outval, TOKUTXN txn, int direction, HEAVI_WRAPPER wrapper);
int toku_brt_cursor_peek_prev(BRT_CURSOR cursor, DBT *outkey, DBT *outval);
int toku_brt_cursor_peek_next(BRT_CURSOR cursor, DBT *outkey, DBT *outval);
int toku_brt_cursor_before(BRT_CURSOR cursor, DBT *key, DBT *val, DBT *outkey, DBT *outval, TOKUTXN txn);
int toku_brt_cursor_after(BRT_CURSOR cursor, DBT *key, DBT *val, DBT *outkey, DBT *outval, TOKUTXN txn);
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);
......
......@@ -80,6 +80,10 @@ int toku_omt_cursor_create (OMTCURSOR *omtcp) {
return 0;
}
OMT toku_omt_cursor_get_omt(OMTCURSOR c) {
return c->omt;
}
void toku_omt_cursor_invalidate (OMTCURSOR c) {
if (c==NULL || c->omt==NULL) return;
if (c->next == c) {
......@@ -625,6 +629,12 @@ int toku_omt_cursor_current (OMTCURSOR c, OMTVALUE *v) {
return r;
}
int toku_omt_cursor_current_index(OMTCURSOR c, u_int32_t *index) {
if (c->omt == NULL) return EINVAL;
*index = c->index;
return 0;
}
//TODO: Put all omt API functions here.
int toku_omt_create (OMT *omtp) {
return omt_create_internal(omtp, 2);
......
......@@ -417,6 +417,19 @@ int toku_omt_cursor_next (OMTCURSOR c, OMTVALUE *v);
// Performance: time=O(log N) worst case, expected time=O(1) for a randomly
// chosen initial position.
int toku_omt_cursor_current_index(OMTCURSOR c, u_int32_t *index);
// Effect: Stores c's offset in *index.
// Requires: index != NULL
// Returns
// 0 success
// EINVAL c is invalid
// On nonzero return, *index is unchanged and c is unchanged.
// Performance: time=O(1)
OMT toku_omt_cursor_get_omt(OMTCURSOR c);
// Effect: returns the associated omt or NULL if not associated.
// Performance: time=O(1)
int toku_omt_cursor_current (OMTCURSOR c, OMTVALUE *v);
// Effect: Store in v the value pointed by c's abstract offset
// Requires: v != NULL
......
......@@ -9,6 +9,37 @@
#include "test.h"
struct heavi_extra {
DBT key;
DBT val;
DB* db;
};
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
}
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
int dbtcmp(DBT *dbt1, DBT *dbt2) {
......@@ -593,6 +624,162 @@ void test_current(u_int32_t dup_flags) {
close_dbs();
}
struct dbt_pair {
DBT key;
DBT val;
};
struct int_pair {
int key;
int val;
};
int got_r_h;
void 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;
}
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)
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_heavi(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) {
CKERR2s(r, DB_NOTFOUND, DB_KEYEMPTY);
return;
}
CKERR(r);
assert(got_r_h == r_h_expect);
assert(output.key == _key_expect);
assert(output.val == _val_expect);
#endif
}
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(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();
}
void test(u_int32_t dup_flags) {
/* ********************************************************************** */
setup_dbs(dup_flags);
......@@ -637,6 +824,9 @@ void test(u_int32_t dup_flags) {
test_dbdel(dup_flags);
/* ********************************************************************** */
test_current(dup_flags);
/* ********************************************************************** */
test_heavi(dup_flags);
/* ********************************************************************** */
}
......
This diff is collapsed.
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