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

Closes #567

Merge all of ticket 567 into trunk

git-svn-id: file:///svn/tokudb@3134 c7de825b-a66e-492c-adef-691d508d4ae1
parent 57004ac0
......@@ -2,9 +2,11 @@
// FNV Hash: From an idea sent by Glenn Fowler and Phong Vo to the IEEE POSIX 1003.2 committee. Landon Curt Noll improved it.
// See: http://isthe.com/chongo/tech/comp/fnv/
static inline unsigned int hash_key (const unsigned char *key, unsigned long keylen) {
unsigned long i;
unsigned int hash=0;
static inline u_int32_t hash_key_extend(u_int32_t initial_hash,
const unsigned char *key,
size_t keylen) {
size_t i;
u_int32_t hash = initial_hash;
for (i=0; i<keylen; i++, key++) {
hash *= 16777619;
// GCC 4.1.2 -O2 and -O3 translates the following shifts back into the multiply shown on the line above here.
......@@ -15,6 +17,10 @@ static inline unsigned int hash_key (const unsigned char *key, unsigned long key
return hash;
}
static inline u_int32_t hash_key(const unsigned char *key, size_t keylen) {
return hash_key_extend(0, key, keylen);
}
#if 0
static unsigned int hash_key (const char *key, ITEMLEN keylen) {
/* From Sedgewick. There are probably better hash functions. */
......
......@@ -51,7 +51,7 @@ ydb.o: ../include/db.h ../newbrt/cachetable.h ../newbrt/brt.h ../newbrt/log.c
DBBINS = ydb.o errors.o elocks.o ../newbrt/brt.o ../newbrt/brt-serialize.o ../newbrt/brt-verify.o ../newbrt/cachetable.o ../newbrt/fifo.o ../newbrt/key.o ../newbrt/memory.o ../newbrt/mempool.o ../newbrt/pma.o ../newbrt/ybt.o ../newbrt/primes.o ../newbrt/log.o ../newbrt/fingerprint.o ../newbrt/log_code.o ../newbrt/roll.o ../newbrt/toku_assert.o ../newbrt/recover.o
RANGETREE_BINS = range_tree/rangetree.o range_tree/tokuredblack.o
LOCKTREE_BINS = lock_tree/locktree.o lock_tree/rth.o lock_tree/lth.o $(RANGETREE_BINS)
LOCKTREE_BINS = lock_tree/locktree.o lock_tree/rth.o lock_tree/lth.o lock_tree/idlth.o lock_tree/db_id.o $(RANGETREE_BINS)
$(LIBRARY): $(DBBINS) $(LOCKTREE_BINS)
......
......@@ -31,7 +31,7 @@ LT_TLOG = $(LT_NOOVERLAP)
LT_LOG = $(LT_OVERLAP)
LT_BINS=$(LT_OVERLAP) $(LT_NOOVERLAP) locktree.o
BINS=rth.o lth.o
BINS=rth.o lth.o idlth.o db_id.o
.PHONY: install logformat range_tree
install: range_tree $(BINS) $(LT_BINS)
......@@ -45,8 +45,6 @@ clean:
rm -rf *.gcno *.gcda *.gcov
cd tests && make clean
BINS = locktree.o rth.o lth.o
locktree.o: $(LT_TLOG)
cp $< $@
......
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <memory.h>
#include <hashfun.h>
#include "db_id.h"
BOOL toku_db_id_equals(const toku_db_id* a, const toku_db_id* b) {
assert(a && b);
return a == b ||
(a->saved_hash == b->saved_hash &&
!strcmp(a->absolute_path, b->absolute_path) &&
!strcmp(a->sub_database_name, b->sub_database_name));
}
void toku_db_id_add_ref(toku_db_id* db_id) {
assert(db_id);
assert(db_id->ref_count > 0);
db_id->ref_count++;
}
static void toku_db_id_close(toku_db_id* db_id) {
toku_free(db_id->absolute_path);
toku_free(db_id->sub_database_name);
toku_free(db_id);
}
void toku_db_id_remove_ref(toku_db_id* db_id) {
assert(db_id);
assert(db_id->ref_count > 0);
db_id->ref_count--;
if (db_id->ref_count > 0) { return; }
toku_db_id_close(db_id);
}
int toku_db_id_create(toku_db_id** pdbid, const char* path,
const char* sub_database_name) {
int r = ENOSYS;
assert(sub_database_name);
toku_db_id* db_id = NULL;
db_id = (toku_db_id *)toku_malloc(sizeof(*db_id));
if (!db_id) { r = ENOMEM; goto cleanup; }
memset(db_id, 0, sizeof(*db_id));
db_id->absolute_path = (char *)toku_malloc((PATH_MAX + 1) * sizeof(char));
if (!db_id->absolute_path) { r = ENOMEM; goto cleanup; }
/* TODO: BUG! Buffer overflow if the path > PATH_MAX. */
if (realpath(path, db_id->absolute_path) == NULL) {
r = errno;
goto cleanup;
}
char* tmp = (char*)toku_realloc(db_id->absolute_path,
(strlen(db_id->absolute_path) + 1) * sizeof(char));
if (!tmp) { r = ENOMEM; goto cleanup; }
db_id->absolute_path = tmp;
db_id->sub_database_name = toku_strdup(sub_database_name);
if (!db_id->sub_database_name) { r = ENOMEM; goto cleanup; }
db_id->saved_hash = hash_key((unsigned char*)db_id->absolute_path,
strlen(db_id->absolute_path));
db_id->saved_hash = hash_key_extend(db_id->saved_hash,
(unsigned char*)db_id->sub_database_name,
strlen(db_id->sub_database_name));
db_id->ref_count = 1;
*pdbid = db_id;
r = 0;
cleanup:
if (r != 0) {
if (db_id != NULL) {
if (db_id->absolute_path) { toku_free(db_id->absolute_path); }
if (db_id->sub_database_name) { toku_free(db_id->sub_database_name); }
toku_free(db_id);
}
}
return r;
}
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
#include <brttypes.h>
#if !defined(TOKU_DB_ID_H)
#define TOKU_DB_ID_H
typedef struct __toku_db_id {
char* absolute_path;
char* sub_database_name;
u_int32_t saved_hash;
u_int32_t ref_count;
} toku_db_id;
/* db_id methods */
int toku_db_id_create(toku_db_id** pdbid, const char* path,
const char* sub_database_name);
BOOL toku_db_id_equals(const toku_db_id* a, const toku_db_id* b);
void toku_db_id_add_ref(toku_db_id* db_id);
void toku_db_id_remove_ref(toku_db_id* db_id);
#endif /* #if !defined(TOKU_DB_ID_H) */
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
/**
\file hash_idlth.h
\brief Hash idlth
*/
#include <idlth.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
/* TODO: investigate whether we can remove the user_memory functions */
/* TODO: reallocate the hash idlth if it grows too big. Perhaps, use toku_get_prime in newbrt/primes.c */
const u_int32_t __toku_idlth_init_size = 521;
static inline u_int32_t toku__idlth_hash(toku_idlth* idlth, toku_db_id* key) {
size_t tmp = key->saved_hash;
return tmp % idlth->num_buckets;
}
static inline void toku__invalidate_scan(toku_idlth* idlth) {
idlth->iter_is_valid = FALSE;
}
int toku_idlth_create(toku_idlth** pidlth,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) {
int r = ENOSYS;
assert(pidlth && user_malloc && user_free && user_realloc);
toku_idlth* tmp = NULL;
tmp = (toku_idlth*)user_malloc(sizeof(*tmp));
if (!tmp) { r = ENOMEM; goto cleanup; }
memset(tmp, 0, sizeof(*tmp));
tmp->malloc = user_malloc;
tmp->free = user_free;
tmp->realloc = user_realloc;
tmp->num_buckets = __toku_idlth_init_size;
tmp->buckets = (toku_idlth_elt*)
tmp->malloc(tmp->num_buckets * sizeof(*tmp->buckets));
if (!tmp->buckets) { r = ENOMEM; goto cleanup; }
memset(tmp->buckets, 0, tmp->num_buckets * sizeof(*tmp->buckets));
toku__invalidate_scan(tmp);
tmp->iter_head.next_in_iteration = &tmp->iter_head;
tmp->iter_head.prev_in_iteration = &tmp->iter_head;
*pidlth = tmp;
r = 0;
cleanup:
if (r != 0) {
if (tmp) {
if (tmp->buckets) { user_free(tmp->buckets); }
user_free(tmp);
}
}
return r;
}
toku_lt_map* toku_idlth_find(toku_idlth* idlth, toku_db_id* key) {
assert(idlth);
u_int32_t index = toku__idlth_hash(idlth, key);
toku_idlth_elt* head = &idlth->buckets[index];
toku_idlth_elt* current = head->next_in_bucket;
while (current) {
if (toku_db_id_equals(current->value.db_id, key)) { break; }
current = current->next_in_bucket;
}
return current ? &current->value : NULL;
}
void toku_idlth_start_scan(toku_idlth* idlth) {
assert(idlth);
idlth->iter_curr = &idlth->iter_head;
idlth->iter_is_valid = TRUE;
}
static inline toku_idlth_elt* toku__idlth_next(toku_idlth* idlth) {
assert(idlth);
assert(idlth->iter_is_valid);
idlth->iter_curr = idlth->iter_curr->next_in_iteration;
idlth->iter_is_valid = idlth->iter_curr != &idlth->iter_head;
return idlth->iter_curr;
}
toku_lt_map* toku_idlth_next(toku_idlth* idlth) {
assert(idlth);
toku_idlth_elt* next = toku__idlth_next(idlth);
return idlth->iter_curr != &idlth->iter_head ? &next->value : NULL;
}
/* Element MUST exist. */
void toku_idlth_delete(toku_idlth* idlth, toku_db_id* key) {
assert(idlth);
toku__invalidate_scan(idlth);
/* Must have elements. */
assert(idlth->num_keys);
u_int32_t index = toku__idlth_hash(idlth, key);
toku_idlth_elt* head = &idlth->buckets[index];
toku_idlth_elt* prev = head;
toku_idlth_elt* current = prev->next_in_bucket;
while (current != NULL) {
if (toku_db_id_equals(current->value.db_id, key)) { break; }
prev = current;
current = current->next_in_bucket;
}
/* Must be found. */
assert(current);
current->prev_in_iteration->next_in_iteration = current->next_in_iteration;
current->next_in_iteration->prev_in_iteration = current->prev_in_iteration;
prev->next_in_bucket = current->next_in_bucket;
toku_db_id_remove_ref(current->value.db_id);
idlth->free(current);
idlth->num_keys--;
return;
}
/* Will allow you to insert it over and over. You need to keep track. */
int toku_idlth_insert(toku_idlth* idlth, toku_db_id* key) {
int r = ENOSYS;
assert(idlth);
toku__invalidate_scan(idlth);
u_int32_t index = toku__idlth_hash(idlth, key);
/* Allocate a new one. */
toku_idlth_elt* element = (toku_idlth_elt*)idlth->malloc(sizeof(*element));
if (!element) { r = ENOMEM; goto cleanup; }
memset(element, 0, sizeof(*element));
element->value.db_id = key;
toku_db_id_add_ref(element->value.db_id);
element->next_in_iteration = idlth->iter_head.next_in_iteration;
element->prev_in_iteration = &idlth->iter_head;
element->next_in_iteration->prev_in_iteration = element;
element->prev_in_iteration->next_in_iteration = element;
element->next_in_bucket = idlth->buckets[index].next_in_bucket;
idlth->buckets[index].next_in_bucket = element;
idlth->num_keys++;
r = 0;
cleanup:
return r;
}
static inline void toku__idlth_clear(toku_idlth* idlth, BOOL clean) {
assert(idlth);
toku_idlth_elt* element;
toku_idlth_elt* head = &idlth->iter_head;
toku_idlth_elt* next = NULL;
toku_idlth_start_scan(idlth);
next = toku__idlth_next(idlth);
while (next != head) {
element = next;
next = toku__idlth_next(idlth);
toku_db_id_remove_ref(element->value.db_id);
idlth->free(element);
}
/* If clean is true, then we want to restore it to 'just created' status.
If we are closing the tree, we don't need to do that restoration. */
if (!clean) { return; }
memset(idlth->buckets, 0, idlth->num_buckets * sizeof(*idlth->buckets));
toku__invalidate_scan(idlth);
idlth->iter_head.next_in_iteration = &idlth->iter_head;
idlth->iter_head.prev_in_iteration = &idlth->iter_head;
idlth->num_keys = 0;
}
void toku_idlth_clear(toku_idlth* idlth) {
toku__idlth_clear(idlth, TRUE);
}
void toku_idlth_close(toku_idlth* idlth) {
assert(idlth);
toku__idlth_clear(idlth, FALSE);
idlth->free(idlth->buckets);
idlth->free(idlth);
}
BOOL toku_idlth_is_empty(toku_idlth* idlth) {
assert(idlth);
/* Verify consistency. */
assert((idlth->num_keys == 0) ==
(idlth->iter_head.next_in_iteration == &idlth->iter_head));
assert((idlth->num_keys == 0) ==
(idlth->iter_head.prev_in_iteration == &idlth->iter_head));
return idlth->num_keys == 0;
}
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
#if !defined(TOKU_IDLTH_H)
#define TOKU_IDLTH_H
/**
\file hash_table.h
\brief Hash table
*/
//Defines BOOL data type.
#include <db.h>
#include <brttypes.h>
#include <rangetree.h>
#include <db_id.h>
#if !defined(TOKU_LOCKTREE_DEFINE)
#define TOKU_LOCKTREE_DEFINE
typedef struct __toku_lock_tree toku_lock_tree;
#endif
typedef struct __toku_lt_map toku_lt_map;
struct __toku_lt_map {
toku_db_id* db_id;
toku_lock_tree* tree;
};
typedef struct __toku_idlth_elt toku_idlth_elt;
struct __toku_idlth_elt {
toku_lt_map value;
toku_idlth_elt* next_in_bucket;
toku_idlth_elt* next_in_iteration;
toku_idlth_elt* prev_in_iteration;
};
typedef struct __toku_idlth toku_idlth;
struct __toku_idlth {
toku_idlth_elt* buckets;
u_int32_t num_buckets;
u_int32_t num_keys;
toku_idlth_elt iter_head;
toku_idlth_elt* iter_curr;
BOOL iter_is_valid;
/** The user malloc function */
void* (*malloc) (size_t);
/** The user free function */
void (*free) (void*);
/** The user realloc function */
void* (*realloc)(void*, size_t);
};
int toku_idlth_create(toku_idlth** ptable,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t));
toku_lt_map* toku_idlth_find (toku_idlth* table, toku_db_id* key);
void toku_idlth_start_scan (toku_idlth* table);
toku_lt_map* toku_idlth_next (toku_idlth* table);
void toku_idlth_delete (toku_idlth* table, toku_db_id* key);
void toku_idlth_close (toku_idlth* table);
int toku_idlth_insert (toku_idlth* table, toku_db_id* key);
void toku_idlth_clear (toku_idlth* idlth);
BOOL toku_idlth_is_empty (toku_idlth* idlth);
#endif
......@@ -12,6 +12,7 @@
#include <locktree.h>
#include <ydb-internal.h>
#include <brt-internal.h>
#include <stdint.h>
/* TODO: Yoni should check that all asserts make sense instead of panic,
and all early returns make sense instead of panic,
......@@ -32,16 +33,6 @@ static inline int toku__lt_panic(toku_lock_tree *tree, int r) {
return tree->panic(tree->db, r);
}
static inline int toku__lt_add_callback(toku_lock_tree *tree, DB_TXN* txn) {
return tree->lock_add_callback ? tree->lock_add_callback(txn, tree) : 0;
}
static inline void toku__lt_remove_callback(toku_lock_tree *tree, DB_TXN* txn) {
if (tree->lock_remove_callback) {
tree->lock_remove_callback(txn, tree);
}
}
const u_int32_t __toku_default_buflen = 2;
static const DBT __toku_lt_infinity;
......@@ -89,7 +80,7 @@ static inline DBT* toku__recreate_DBT(DBT* dbt, void* payload, u_int32_t length)
return dbt;
}
static inline int toku__lt_txn_cmp(const DB_TXN* a, const DB_TXN* b) {
static inline int toku__lt_txn_cmp(const TXNID a, const TXNID b) {
return a < b ? -1 : (a != b);
}
......@@ -138,10 +129,12 @@ int toku__lt_point_cmp(const toku_point* x, const toku_point* y) {
toku__recreate_DBT(&point_2, y->data_payload, y->data_len));
}
/* Lock tree manager functions begin here */
int toku_ltm_create(toku_ltm** pmgr,
u_int32_t max_locks,
int (*panic)(DB*, int),
toku_dbt_cmp (*get_compare_fun_from_db)(DB*),
toku_dbt_cmp (*get_dup_compare_from_db)(DB*),
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) {
......@@ -151,35 +144,50 @@ int toku_ltm_create(toku_ltm** pmgr,
if (!pmgr || !max_locks || !user_malloc || !user_free || !user_realloc) {
r = EINVAL; goto cleanup;
}
assert(panic && get_compare_fun_from_db && get_dup_compare_from_db);
tmp_mgr = (toku_ltm*)user_malloc(sizeof(*tmp_mgr));
if (!tmp_mgr) { r = ENOMEM; goto cleanup; }
memset(tmp_mgr, 0, sizeof(toku_ltm));
r = toku_ltm_set_max_locks(tmp_mgr, max_locks);
/*
Temporarily set the maximum number of locks per environment to 'infinity'.
See ticket #596 for when this will be reversed.
We will then use 'max_locks' instead of 'UINT32_MAX'.
All of the 'per_db' functions and variables will then be deleted.
*/
r = toku_ltm_set_max_locks(tmp_mgr, UINT32_MAX);
if (r!=0) { goto cleanup; }
tmp_mgr->panic = panic;
tmp_mgr->malloc = user_malloc;
tmp_mgr->free = user_free;
tmp_mgr->realloc = user_realloc;
tmp_mgr->get_compare_fun_from_db = get_compare_fun_from_db;
tmp_mgr->get_dup_compare_from_db = get_dup_compare_from_db;
r = toku_lth_create(&tmp_mgr->lth, user_malloc, user_free, user_realloc);
if (r!=0) { goto cleanup; }
if (!tmp_mgr->lth) { r = ENOMEM; goto cleanup; }
r = toku_idlth_create(&tmp_mgr->idlth, user_malloc, user_free, user_realloc);
if (r!=0) { goto cleanup; }
if (!tmp_mgr->idlth) { r = ENOMEM; goto cleanup; }
r = toku_ltm_set_max_locks_per_db(tmp_mgr, max_locks);
if (r!=0) { goto cleanup; }
r = 0;
*pmgr = tmp_mgr;
cleanup:
if (r!=0) {
if (tmp_mgr) {
if (tmp_mgr->lth) {
toku_lth_close(tmp_mgr->lth);
}
if (tmp_mgr->lth) { toku_lth_close(tmp_mgr->lth); }
if (tmp_mgr->idlth) { toku_idlth_close(tmp_mgr->idlth); }
user_free(tmp_mgr);
}
}
return r;
}
static int toku_lt_close_without_ltm(toku_lock_tree* tree);
int toku_ltm_close(toku_ltm* mgr) {
int r = ENOSYS;
int first_error = 0;
......@@ -189,10 +197,11 @@ int toku_ltm_close(toku_ltm* mgr) {
toku_lth_start_scan(mgr->lth);
toku_lock_tree* lt;
while ((lt = toku_lth_next(mgr->lth)) != NULL) {
r = toku_lt_close_without_ltm(lt);
r = toku_lt_close(lt);
if (r!=0 && first_error==0) { first_error = r; }
}
toku_lth_close(mgr->lth);
toku_idlth_close(mgr->idlth);
mgr->free(mgr);
r = first_error;
......@@ -210,6 +219,16 @@ int toku_ltm_get_max_locks(toku_ltm* mgr, u_int32_t* max_locks) {
return r;
}
int toku_ltm_get_max_locks_per_db(toku_ltm* mgr, u_int32_t* max_locks) {
int r = ENOSYS;
if (!mgr || !max_locks) { r = EINVAL; goto cleanup; }
*max_locks = mgr->max_locks_per_db;
r = 0;
cleanup:
return r;
}
int toku_ltm_set_max_locks(toku_ltm* mgr, u_int32_t max_locks) {
int r = ENOSYS;
if (!mgr || !max_locks) {
......@@ -225,27 +244,69 @@ int toku_ltm_set_max_locks(toku_ltm* mgr, u_int32_t max_locks) {
return r;
}
int toku_ltm_set_max_locks_per_db(toku_ltm* mgr, u_int32_t max_locks) {
int r = ENOSYS;
if (!mgr || !max_locks) {
r = EINVAL; goto cleanup;
}
toku_lth_start_scan(mgr->lth);
toku_lock_tree* lt;
while ((lt = toku_lth_next(mgr->lth)) != NULL) {
if (max_locks < lt->curr_locks) {
r = EDOM; goto cleanup; }
}
toku_lth_start_scan(mgr->lth);
while ((lt = toku_lth_next(mgr->lth)) != NULL) {
lt->max_locks = max_locks;
}
mgr->max_locks_per_db = max_locks;
r = 0;
cleanup:
return r;
}
/* Functions to update the range count and compare it with the
maximum number of ranges */
static inline BOOL toku__mgr_lock_test_incr(toku_ltm* tree_mgr,
#if 0 //See ticket #596
static inline BOOL toku__ltm_lock_test_incr(toku_ltm* tree_mgr,
u_int32_t replace_locks) {
assert(tree_mgr);
assert(replace_locks <= tree_mgr->curr_locks);
return tree_mgr->curr_locks - replace_locks < tree_mgr->max_locks;
}
static inline void toku__mgr_lock_incr(toku_ltm* tree_mgr, u_int32_t replace_locks) {
assert(toku__mgr_lock_test_incr(tree_mgr, replace_locks));
static inline void toku__ltm_lock_incr(toku_ltm* tree_mgr, u_int32_t replace_locks) {
assert(toku__ltm_lock_test_incr(tree_mgr, replace_locks));
tree_mgr->curr_locks -= replace_locks;
tree_mgr->curr_locks += 1;
}
static inline void toku__mgr_lock_decr(toku_ltm* tree_mgr, u_int32_t locks) {
static inline void toku__ltm_lock_decr(toku_ltm* tree_mgr, u_int32_t locks) {
assert(tree_mgr);
assert(tree_mgr->curr_locks >= locks);
tree_mgr->curr_locks -= locks;
}
#endif
/* The following 3 are temporary functions. See #596 */
static inline BOOL toku__lt_lock_test_incr_per_db(toku_lock_tree* tree,
u_int32_t replace_locks) {
assert(tree);
assert(replace_locks <= tree->curr_locks);
return tree->curr_locks - replace_locks < tree->max_locks;
}
static inline void toku__lt_lock_incr_per_db(toku_lock_tree* tree, u_int32_t replace_locks) {
assert(toku__lt_lock_test_incr_per_db(tree, replace_locks));
tree->curr_locks -= replace_locks;
tree->curr_locks += 1;
}
static inline void toku__lt_lock_decr_per_db(toku_lock_tree* tree, u_int32_t locks) {
assert(tree);
assert(tree->curr_locks >= locks);
tree->curr_locks -= locks;
}
static inline void toku__p_free(toku_lock_tree* tree, toku_point* point) {
assert(point);
......@@ -311,8 +372,8 @@ static inline int toku__p_makecopy(toku_lock_tree* tree, toku_point** ppoint) {
/* Provides access to a selfread tree for a particular transaction.
Returns NULL if it does not exist yet. */
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn) {
assert(tree && txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, TXNID txn) {
assert(tree);
toku_rt_forest* forest = toku_rth_find(tree->rth, txn);
return forest ? forest->self_read : NULL;
}
......@@ -320,31 +381,39 @@ toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn) {
/* Provides access to a selfwrite tree for a particular transaction.
Returns NULL if it does not exist yet. */
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree,
DB_TXN* txn) {
assert(tree && txn);
TXNID txn) {
assert(tree);
toku_rt_forest* forest = toku_rth_find(tree->rth, txn);
return forest ? forest->self_write : NULL;
}
static inline int toku__lt_add_locked_txn(toku_lock_tree* tree, TXNID txn) {
int r = ENOSYS;
BOOL half_done = FALSE;
/* Neither selfread nor selfwrite exist. */
r = toku_rth_insert(tree->rth, txn);
if (r!=0) { goto cleanup; }
r = toku_rth_insert(tree->txns_still_locked, txn);
if (r!=0) { half_done = TRUE; goto cleanup; }
r = 0;
cleanup:
if (half_done) { toku_rth_delete(tree->rth, txn); }
return r;
}
/* Provides access to a selfread tree for a particular transaction.
Creates it if it does not exist. */
static inline int toku__lt_selfread(toku_lock_tree* tree, DB_TXN* txn,
static inline int toku__lt_selfread(toku_lock_tree* tree, TXNID txn,
toku_range_tree** pselfread) {
int r;
assert(tree && txn && pselfread);
int r = ENOSYS;
assert(tree && pselfread);
toku_rt_forest* forest = toku_rth_find(tree->rth, txn);
if (!forest) {
/* Let the transaction know about this lock tree. */
r = toku__lt_add_callback(tree, txn);
if (r!=0) return r;
/* Neither selfread nor selfwrite exist. */
r = toku_rth_insert(tree->rth, txn);
if (r!=0) {
toku__lt_remove_callback(tree, txn);
return r;
}
r = toku__lt_add_locked_txn(tree, txn);
if (r!=0) { goto cleanup; }
forest = toku_rth_find(tree->rth, txn);
}
assert(forest);
......@@ -353,32 +422,27 @@ static inline int toku__lt_selfread(toku_lock_tree* tree, DB_TXN* txn,
toku__lt_point_cmp, toku__lt_txn_cmp,
FALSE,
tree->malloc, tree->free, tree->realloc);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
assert(forest->self_read);
}
*pselfread = forest->self_read;
return 0;
r = 0;
cleanup:
return r;
}
/* Provides access to a selfwrite tree for a particular transaction.
Creates it if it does not exist. */
static inline int toku__lt_selfwrite(toku_lock_tree* tree, DB_TXN* txn,
static inline int toku__lt_selfwrite(toku_lock_tree* tree, TXNID txn,
toku_range_tree** pselfwrite) {
int r;
assert(tree && txn && pselfwrite);
int r = ENOSYS;
assert(tree && pselfwrite);
toku_rt_forest* forest = toku_rth_find(tree->rth, txn);
if (!forest) {
/* Let the transaction know about this lock tree. */
r = toku__lt_add_callback(tree, txn);
if (r!=0) return r;
/* Neither selfread nor selfwrite exist. */
r = toku_rth_insert(tree->rth, txn);
if (r!=0) {
toku__lt_remove_callback(tree, txn);
return r;
}
r = toku__lt_add_locked_txn(tree, txn);
if (r!=0) { goto cleanup; }
forest = toku_rth_find(tree->rth, txn);
}
assert(forest);
......@@ -387,15 +451,16 @@ static inline int toku__lt_selfwrite(toku_lock_tree* tree, DB_TXN* txn,
toku__lt_point_cmp, toku__lt_txn_cmp,
FALSE,
tree->malloc, tree->free, tree->realloc);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
assert(forest->self_write);
}
*pselfwrite = forest->self_write;
return 0;
r = 0;
cleanup:
return r;
}
static inline BOOL toku__dominated(toku_range* query, toku_range* by) {
static inline BOOL toku__dominated(toku_interval* query, toku_interval* by) {
assert(query && by);
return (toku__lt_point_cmp(query->left, by->left) >= 0 &&
toku__lt_point_cmp(query->right, by->right) <= 0);
......@@ -406,7 +471,7 @@ static inline BOOL toku__dominated(toku_range* query, toku_range* by) {
Uses the standard definition of dominated from the design document.
Determines whether 'query' is dominated by 'rt'.
*/
static inline int toku__lt_rt_dominates(toku_lock_tree* tree, toku_range* query,
static inline int toku__lt_rt_dominates(toku_lock_tree* tree, toku_interval* query,
toku_range_tree* rt, BOOL* dominated) {
assert(tree && query && dominated);
if (!rt) {
......@@ -434,7 +499,7 @@ static inline int toku__lt_rt_dominates(toku_lock_tree* tree, toku_range* query,
return 0;
}
assert(numfound == 1);
*dominated = toku__dominated(query, &buf[0]);
*dominated = toku__dominated(query, &buf[0].ends);
return 0;
}
......@@ -450,10 +515,10 @@ typedef enum
If exactly one range overlaps and its data != self, there might be a
conflict. We need to check the 'peer'write table to verify.
*/
static inline int toku__lt_borderwrite_conflict(toku_lock_tree* tree, DB_TXN* self,
toku_range* query,
toku_conflict* conflict, DB_TXN** peer) {
assert(tree && self && query && conflict && peer);
static inline int toku__lt_borderwrite_conflict(toku_lock_tree* tree, TXNID self,
toku_interval* query,
toku_conflict* conflict, TXNID* peer) {
assert(tree && query && conflict && peer);
toku_range_tree* rt = tree->borderwrite;
assert(rt);
......@@ -467,7 +532,6 @@ static inline int toku__lt_borderwrite_conflict(toku_lock_tree* tree, DB_TXN* se
r = toku_rt_find(rt, query, query_size, &buf, &buflen, &numfound);
if (r!=0) return r;
assert(numfound <= query_size);
*peer = NULL;
if (numfound == 2) *conflict = TOKU_YES_CONFLICT;
else if (numfound == 0 || buf[0].data == self) *conflict = TOKU_NO_CONFLICT;
else {
......@@ -484,7 +548,7 @@ static inline int toku__lt_borderwrite_conflict(toku_lock_tree* tree, DB_TXN* se
Uses the standard definition of 'query' meets 'tree' at 'data' from the
design document.
*/
static inline int toku__lt_meets(toku_lock_tree* tree, toku_range* query,
static inline int toku__lt_meets(toku_lock_tree* tree, toku_interval* query,
toku_range_tree* rt, BOOL* met) {
assert(tree && query && rt && met);
const u_int32_t query_size = 1;
......@@ -514,9 +578,9 @@ static inline int toku__lt_meets(toku_lock_tree* tree, toku_range* query,
Uses the standard definition of 'query' meets 'tree' at 'data' from the
design document.
*/
static inline int toku__lt_meets_peer(toku_lock_tree* tree, toku_range* query,
static inline int toku__lt_meets_peer(toku_lock_tree* tree, toku_interval* query,
toku_range_tree* rt, BOOL is_homogenous,
DB_TXN* self, BOOL* met) {
TXNID self, BOOL* met) {
assert(tree && query && rt && self && met);
assert(query->left == query->right || is_homogenous);
......@@ -539,10 +603,10 @@ static inline int toku__lt_meets_peer(toku_lock_tree* tree, toku_range* query,
if K meets E at v'!=t and K meets W_v' then return failure.
*/
static inline int toku__lt_check_borderwrite_conflict(toku_lock_tree* tree,
DB_TXN* txn, toku_range* query) {
assert(tree && txn && query);
TXNID txn, toku_interval* query) {
assert(tree && query);
toku_conflict conflict;
DB_TXN* peer;
TXNID peer;
toku_range_tree* peer_selfwrite;
int r;
......@@ -596,37 +660,36 @@ static inline void toku__init_point(toku_point* point, toku_lock_tree* tree,
}
}
static inline void toku__init_query(toku_range* query,
static inline void toku__init_query(toku_interval* query,
toku_point* left, toku_point* right) {
query->left = left;
query->right = right;
query->data = NULL;
}
/*
Memory ownership:
- to_insert we own (it's static)
- to_insert.left, .right are toku_point's, and we own them.
- to_insert.ends.left, .ends.right are toku_point's, and we own them.
If we have consolidated, we own them because we had allocated
them earlier, but
if we have not consolidated we need to gain ownership now:
we will gain ownership by copying all payloads and
allocating the points.
- to_insert.{left,right}.{key_payload, data_payload} are owned by lt,
- to_insert.{ends.left,ends.right}.{key_payload, data_payload} are owned by lt,
we made copies from the DB at consolidation time
*/
static inline void toku__init_insert(toku_range* to_insert,
toku_point* left, toku_point* right,
DB_TXN* txn) {
to_insert->left = left;
to_insert->right = right;
TXNID txn) {
to_insert->ends.left = left;
to_insert->ends.right = right;
to_insert->data = txn;
}
/* Returns whether the point already exists
as an endpoint of the given range. */
static inline BOOL toku__lt_p_independent(toku_point* point, toku_range* range) {
static inline BOOL toku__lt_p_independent(toku_point* point, toku_interval* range) {
assert(point && range);
return point != range->left && point != range->right;
}
......@@ -640,24 +703,24 @@ static inline int toku__lt_extend_extreme(toku_lock_tree* tree,toku_range* to_in
for (i = 0; i < numfound; i++) {
int c;
/* Find the extreme left end-point among overlapping ranges */
if ((c = toku__lt_point_cmp(tree->buf[i].left, to_insert->left))
if ((c = toku__lt_point_cmp(tree->buf[i].ends.left, to_insert->ends.left))
<= 0) {
if ((!*alloc_left && c == 0) ||
!toku__lt_p_independent(tree->buf[i].left, to_insert)) {
!toku__lt_p_independent(tree->buf[i].ends.left, &to_insert->ends)) {
return toku__lt_panic(tree, TOKU_LT_INCONSISTENT); }
*alloc_left = FALSE;
to_insert->left = tree->buf[i].left;
to_insert->ends.left = tree->buf[i].ends.left;
}
/* Find the extreme right end-point */
if ((c = toku__lt_point_cmp(tree->buf[i].right, to_insert->right))
if ((c = toku__lt_point_cmp(tree->buf[i].ends.right, to_insert->ends.right))
>= 0) {
if ((!*alloc_right && c == 0) ||
(tree->buf[i].right == to_insert->left &&
tree->buf[i].left != to_insert->left) ||
tree->buf[i].right == to_insert->right) {
(tree->buf[i].ends.right == to_insert->ends.left &&
tree->buf[i].ends.left != to_insert->ends.left) ||
tree->buf[i].ends.right == to_insert->ends.right) {
return toku__lt_panic(tree, TOKU_LT_INCONSISTENT); }
*alloc_right = FALSE;
to_insert->right = tree->buf[i].right;
to_insert->ends.right = tree->buf[i].ends.right;
}
}
return 0;
......@@ -672,24 +735,24 @@ static inline int toku__lt_alloc_extreme(toku_lock_tree* tree, toku_range* to_in
/* The pointer comparison may speed up the evaluation in some cases,
but it is not strictly needed */
if (alloc_left && alloc_right &&
(to_insert->left == to_insert->right ||
toku__lt_point_cmp(to_insert->left, to_insert->right) == 0)) {
(to_insert->ends.left == to_insert->ends.right ||
toku__lt_point_cmp(to_insert->ends.left, to_insert->ends.right) == 0)) {
*alloc_right = FALSE;
copy_left = TRUE;
}
if (alloc_left) {
r = toku__p_makecopy(tree, &to_insert->left);
r = toku__p_makecopy(tree, &to_insert->ends.left);
if (0) { died1:
if (alloc_left) toku__p_free(tree, to_insert->left); return r; }
if (alloc_left) toku__p_free(tree, to_insert->ends.left); return r; }
if (r!=0) return r;
}
if (*alloc_right) {
assert(!copy_left);
r = toku__p_makecopy(tree, &to_insert->right);
r = toku__p_makecopy(tree, &to_insert->ends.right);
if (r!=0) goto died1;
}
else if (copy_left) to_insert->right = to_insert->left;
else if (copy_left) to_insert->ends.right = to_insert->ends.left;
return 0;
}
......@@ -707,7 +770,7 @@ static inline int toku__lt_delete_overlapping_ranges(toku_lock_tree* tree,
return 0;
}
static inline int toku__lt_free_points(toku_lock_tree* tree, toku_range* to_insert,
static inline int toku__lt_free_points(toku_lock_tree* tree, toku_interval* to_insert,
u_int32_t numfound, toku_range_tree *rt) {
assert(tree && to_insert);
assert(numfound <= tree->buflen);
......@@ -725,12 +788,12 @@ static inline int toku__lt_free_points(toku_lock_tree* tree, toku_range* to_inse
(toku__lt_point_cmp(a, b) == 0 && a.txn == b.txn) => a == b
*/
/* Do not double-free. */
if (tree->buf[i].right != tree->buf[i].left &&
toku__lt_p_independent(tree->buf[i].right, to_insert)) {
toku__p_free(tree, tree->buf[i].right);
if (tree->buf[i].ends.right != tree->buf[i].ends.left &&
toku__lt_p_independent(tree->buf[i].ends.right, to_insert)) {
toku__p_free(tree, tree->buf[i].ends.right);
}
if (toku__lt_p_independent(tree->buf[i].left, to_insert)) {
toku__p_free(tree, tree->buf[i].left);
if (toku__lt_p_independent(tree->buf[i].ends.left, to_insert)) {
toku__p_free(tree, tree->buf[i].ends.left);
}
}
return 0;
......@@ -741,13 +804,13 @@ static inline int toku__lt_free_points(toku_lock_tree* tree, toku_range* to_inse
/* TODO: Toku error codes, i.e. get rid of the extra parameter for (ran out of locks) */
/* Consolidate the new range and all the overlapping ranges */
static inline int toku__consolidate(toku_lock_tree* tree,
toku_range* query, toku_range* to_insert,
DB_TXN* txn, BOOL* out_of_locks) {
toku_interval* query, toku_range* to_insert,
TXNID txn, BOOL* out_of_locks) {
int r;
BOOL alloc_left = TRUE;
BOOL alloc_right = TRUE;
toku_range_tree* selfread;
assert(tree && to_insert && txn && out_of_locks);
assert(tree && to_insert && out_of_locks);
*out_of_locks = FALSE;
#if !defined(TOKU_RT_NOOVERLAPS)
toku_range_tree* mainread = tree->mainread;
......@@ -767,15 +830,15 @@ static inline int toku__consolidate(toku_lock_tree* tree,
r = toku__lt_extend_extreme(tree, to_insert, &alloc_left, &alloc_right,
numfound);
if (r!=0) return r;
if (!toku__mgr_lock_test_incr(tree->mgr, numfound)) {
if (!toku__lt_lock_test_incr_per_db(tree, numfound)) {
*out_of_locks = TRUE;
return 0;
}
/* Allocate the consolidated range */
r = toku__lt_alloc_extreme(tree, to_insert, alloc_left, &alloc_right);
if (0) { died1:
if (alloc_left) toku__p_free(tree, to_insert->left);
if (alloc_right) toku__p_free(tree, to_insert->right); return r; }
if (alloc_left) toku__p_free(tree, to_insert->ends.left);
if (alloc_right) toku__p_free(tree, to_insert->ends.right); return r; }
if (r!=0) return r;
/* From this point on we have to panic if we cannot finish. */
/* Delete overlapping ranges from selfread ... */
......@@ -789,7 +852,7 @@ static inline int toku__consolidate(toku_lock_tree* tree,
if (r!=0) return toku__lt_panic(tree, r);
#endif
/* Free all the points from ranges in tree->buf[0]..tree->buf[numfound-1] */
toku__lt_free_points(tree, to_insert, numfound, NULL);
toku__lt_free_points(tree, &to_insert->ends, numfound, NULL);
/* We don't necessarily need to panic after here unless numfound > 0
Which indicates we deleted something. */
/* Insert extreme range into selfread. */
......@@ -813,11 +876,11 @@ static inline int toku__consolidate(toku_lock_tree* tree,
if (numfound) return toku__lt_panic(tree, TOKU_LT_INCONSISTENT);
goto died2; }
#endif
toku__mgr_lock_incr(tree->mgr, numfound);
toku__lt_lock_incr_per_db(tree, numfound);
return 0;
}
static inline void toku__lt_init_full_query(toku_lock_tree* tree, toku_range* query,
static inline void toku__lt_init_full_query(toku_lock_tree* tree, toku_interval* query,
toku_point* left, toku_point* right) {
toku__init_point(left, tree, (DBT*)toku_lt_neg_infinity,
tree->duplicates ? (DBT*)toku_lt_neg_infinity : NULL);
......@@ -840,11 +903,10 @@ static inline int toku__lt_free_contents(toku_lock_tree* tree, toku_range_tree*
int r2;
BOOL found = FALSE;
toku_range query;
toku_interval query;
toku_point left;
toku_point right;
toku__lt_init_full_query(tree, &query, &left, &right);
toku_rt_start_scan(rt);
while ((r = toku_rt_next(rt, &tree->buf[0], &found)) == 0 && found) {
r = toku__lt_free_points(tree, &query, 1, rtdel);
......@@ -855,7 +917,7 @@ static inline int toku__lt_free_contents(toku_lock_tree* tree, toku_range_tree*
return r;
}
static inline BOOL toku__r_backwards(toku_range* range) {
static inline BOOL toku__r_backwards(toku_interval* range) {
assert(range && range->left && range->right);
toku_point* left = (toku_point*)range->left;
toku_point* right = (toku_point*)range->right;
......@@ -866,39 +928,78 @@ static inline BOOL toku__r_backwards(toku_range* range) {
toku__lt_point_cmp(left, right) > 0;
}
static inline int toku__lt_unlock_deferred_txns(toku_lock_tree* tree);
static inline void toku__lt_set_comparison_functions(toku_lock_tree* tree,
DB* db) {
assert(!tree->db && !tree->compare_fun && !tree->dup_compare);
tree->db = db;
tree->compare_fun = tree->get_compare_fun_from_db(tree->db);
assert(tree->compare_fun);
tree->dup_compare = tree->get_dup_compare_from_db(tree->db);
assert(tree->dup_compare);
}
static inline void toku__lt_clear_comparison_functions(toku_lock_tree* tree) {
assert(tree);
tree->db = NULL;
tree->compare_fun = NULL;
tree->dup_compare = NULL;
}
static inline int toku__lt_preprocess(toku_lock_tree* tree, DB_TXN* txn,
/* Preprocess step for acquire functions. */
static inline int toku__lt_preprocess(toku_lock_tree* tree, DB* db,
__attribute__((unused)) TXNID txn,
const DBT* key_left, const DBT** pdata_left,
const DBT* key_right, const DBT** pdata_right,
toku_point* left, toku_point* right,
toku_range* query, BOOL* out_of_locks) {
toku_interval* query, BOOL* out_of_locks) {
int r = ENOSYS;
assert(pdata_left && pdata_right);
if (!tree || !txn || !key_left || !key_right || !out_of_locks) return EINVAL;
if (!tree || !db ||
!key_left || !key_right || !out_of_locks) {r = EINVAL; goto cleanup; }
if (!tree->duplicates) *pdata_right = *pdata_left = NULL;
const DBT* data_left = *pdata_left;
const DBT* data_right = *pdata_right;
if (tree->duplicates && (!data_left || !data_right)) return EINVAL;
if (tree->duplicates && (!data_left || !data_right)) { r = EINVAL; goto cleanup; }
if (tree->duplicates && key_left != data_left &&
toku__lt_is_infinite(key_left)) return EINVAL;
toku__lt_is_infinite(key_left)) { r = EINVAL; goto cleanup; }
if (tree->duplicates && key_right != data_right &&
toku__lt_is_infinite(key_right)) return EINVAL;
toku__lt_is_infinite(key_right)) { r = EINVAL; goto cleanup; }
int r;
/* Verify that NULL keys have payload and size that are mutually
consistent*/
if ((r = toku__lt_verify_null_key(key_left)) != 0) return r;
if ((r = toku__lt_verify_null_key(data_left)) != 0) return r;
if ((r = toku__lt_verify_null_key(key_right)) != 0) return r;
if ((r = toku__lt_verify_null_key(data_right)) != 0) return r;
if ((r = toku__lt_verify_null_key(key_left)) != 0) { goto cleanup; }
if ((r = toku__lt_verify_null_key(data_left)) != 0) { goto cleanup; }
if ((r = toku__lt_verify_null_key(key_right)) != 0) { goto cleanup; }
if ((r = toku__lt_verify_null_key(data_right)) != 0) { goto cleanup; }
toku__init_point(left, tree, key_left, data_left);
toku__init_point(right, tree, key_right, data_right);
toku__init_query(query, left, right);
/* Verify left <= right, otherwise return EDOM. */
if (toku__r_backwards(query)) return EDOM;
tree->settings_final = TRUE;
return 0;
toku__lt_set_comparison_functions(tree, db);
/* Verify left <= right, otherwise return EDOM. */
if (toku__r_backwards(query)) { r = EDOM; goto cleanup; }
r = 0;
cleanup:
if (r == 0) {
assert(tree->db && tree->compare_fun && tree->dup_compare);
/* Cleanup all existing deleted transactions */
if (!toku_rth_is_empty(tree->txns_to_unlock)) {
r = toku__lt_unlock_deferred_txns(tree);
}
}
return r;
}
/* Postprocess step for acquire functions. */
static inline void toku__lt_postprocess(toku_lock_tree* tree) {
toku__lt_clear_comparison_functions(tree);
}
static inline int toku__lt_get_border(toku_lock_tree* tree, BOOL in_borderwrite,
......@@ -911,9 +1012,9 @@ static inline int toku__lt_get_border(toku_lock_tree* tree, BOOL in_borderwrite,
rt = in_borderwrite ? tree->borderwrite :
toku__lt_ifexist_selfwrite(tree, tree->buf[0].data);
if (!rt) return toku__lt_panic(tree, TOKU_LT_INCONSISTENT);
r = toku_rt_predecessor(rt, to_insert->left, pred, found_p);
r = toku_rt_predecessor(rt, to_insert->ends.left, pred, found_p);
if (r!=0) return r;
r = toku_rt_successor (rt, to_insert->right, succ, found_s);
r = toku_rt_successor (rt, to_insert->ends.right, succ, found_s);
if (r!=0) return r;
return 0;
}
......@@ -926,12 +1027,12 @@ static inline int toku__lt_expand_border(toku_lock_tree* tree, toku_range* to_in
if (found_p && pred->data == to_insert->data) {
r = toku_rt_delete(tree->borderwrite, pred);
if (r!=0) return r;
to_insert->left = pred->left;
to_insert->ends.left = pred->ends.left;
}
else if (found_s && succ->data == to_insert->data) {
r = toku_rt_delete(tree->borderwrite, succ);
if (r!=0) return r;
to_insert->right = succ->right;
to_insert->ends.right = succ->ends.right;
}
return 0;
}
......@@ -947,9 +1048,9 @@ static inline int toku__lt_split_border(toku_lock_tree* tree, toku_range* to_ins
r = toku_rt_delete(tree->borderwrite, &tree->buf[0]);
if (r!=0) return toku__lt_panic(tree, r);
pred->left = tree->buf[0].left;
succ->right = tree->buf[0].right;
if (toku__r_backwards(pred) || toku__r_backwards(succ)) {
pred->ends.left = tree->buf[0].ends.left;
succ->ends.right = tree->buf[0].ends.right;
if (toku__r_backwards(&pred->ends) || toku__r_backwards(&succ->ends)) {
return toku__lt_panic(tree, TOKU_LT_INCONSISTENT);}
r = toku_rt_insert(tree->borderwrite, pred);
......@@ -967,7 +1068,7 @@ static inline int toku__lt_split_border(toku_lock_tree* tree, toku_range* to_ins
if both found
assert(predecessor.data != successor.data)
if predecessor found, and pred.data == my.data
'merge' (extend to) predecessor.left
'merge' (extend to) predecessor.ends.left
To do this, delete predecessor,
insert combined me and predecessor.
then done/return
......@@ -979,17 +1080,17 @@ static inline int toku__lt_split_border(toku_lock_tree* tree, toku_range* to_ins
Get the selfwrite for the peer.
Get successor of my point in peer_selfwrite
get pred of my point in peer_selfwrite.
Old range = O.left, O.right
Old range = O.ends.left, O.ends.right
delete old range,
insert O.left, pred.right
insert succ.left, O.right
insert O.ends.left, pred.ends.right
insert succ.ends.left, O.ends.right
NO MEMORY GETS FREED!!!!!!!!!!, it all is tied to selfwrites.
insert point,point into borderwrite
done with borderwrite.
insert point,point into selfwrite.
*/
static inline int toku__lt_borderwrite_insert(toku_lock_tree* tree,
toku_range* query,
toku_interval* query,
toku_range* to_insert) {
assert(tree && query && to_insert);
int r;
......@@ -1032,66 +1133,156 @@ static inline int toku__lt_borderwrite_insert(toku_lock_tree* tree,
return 0;
}
int toku_lt_create(toku_lock_tree** ptree, DB* db, BOOL duplicates,
/* TODO: Investigate better way of passing comparison functions. */
int toku_lt_create(toku_lock_tree** ptree, BOOL duplicates,
int (*panic)(DB*, int),
toku_ltm* mgr,
int (*compare_fun)(DB*,const DBT*,const DBT*),
int (*dup_compare)(DB*,const DBT*,const DBT*),
toku_dbt_cmp (*get_compare_fun_from_db)(DB*),
toku_dbt_cmp (*get_dup_compare_from_db)(DB*),
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) {
if (!ptree || !db || !mgr || !compare_fun || !dup_compare || !panic ||
!user_malloc || !user_free || !user_realloc) { return EINVAL; }
int r;
int r = ENOSYS;
toku_lock_tree* tmp_tree = NULL;
if (!ptree || !mgr ||
!get_compare_fun_from_db || !get_dup_compare_from_db || !panic ||
!user_malloc || !user_free || !user_realloc) {
r = EINVAL; goto cleanup;
}
toku_lock_tree* tmp_tree = (toku_lock_tree*)user_malloc(sizeof(*tmp_tree));
if (0) { died1: user_free(tmp_tree); return r; }
if (!tmp_tree) return errno;
tmp_tree = (toku_lock_tree*)user_malloc(sizeof(*tmp_tree));
if (!tmp_tree) { r = ENOMEM; goto cleanup; }
memset(tmp_tree, 0, sizeof(toku_lock_tree));
tmp_tree->db = db;
tmp_tree->duplicates = duplicates;
tmp_tree->panic = panic;
tmp_tree->mgr = mgr;
tmp_tree->compare_fun = compare_fun;
tmp_tree->dup_compare = dup_compare;
tmp_tree->malloc = user_malloc;
tmp_tree->free = user_free;
tmp_tree->realloc = user_realloc;
#if defined(TOKU_RT_NOOVERLAPS)
if (0) { died2: goto died1; }
#else
tmp_tree->get_compare_fun_from_db = get_compare_fun_from_db;
tmp_tree->get_dup_compare_from_db = get_dup_compare_from_db;
tmp_tree->lock_escalation_allowed = TRUE;
r = toku_ltm_get_max_locks_per_db(mgr, &tmp_tree->max_locks);
if (r!=0) { goto cleanup; }
#if !defined(TOKU_RT_NOOVERLAPS)
r = toku_rt_create(&tmp_tree->mainread,
toku__lt_point_cmp, toku__lt_txn_cmp, TRUE,
user_malloc, user_free, user_realloc);
if (0) { died2: toku_rt_close(tmp_tree->mainread); goto died1; }
if (r!=0) goto died1;
if (r!=0) { goto cleanup; }
#endif
r = toku_rt_create(&tmp_tree->borderwrite,
toku__lt_point_cmp, toku__lt_txn_cmp, FALSE,
user_malloc, user_free, user_realloc);
if (0) { died3: toku_rt_close(tmp_tree->borderwrite); goto died2; }
if (r!=0) goto died2;
if (r!=0) { goto cleanup; }
r = toku_rth_create(&tmp_tree->rth, user_malloc, user_free, user_realloc);
if (0) { died4: toku_rth_close(tmp_tree->rth); goto died3; }
if (r!=0) goto died3;
if (r!=0) { goto cleanup; }
r = toku_rth_create(&tmp_tree->txns_to_unlock, user_malloc, user_free, user_realloc);
if (r!=0) { goto cleanup; }
r = toku_rth_create(&tmp_tree->txns_still_locked, user_malloc, user_free, user_realloc);
if (r!=0) { goto cleanup; }
tmp_tree->buflen = __toku_default_buflen;
tmp_tree->buf = (toku_range*)
user_malloc(tmp_tree->buflen * sizeof(toku_range));
if (0) { died5: toku_free(tmp_tree->buf); goto died4; }
if (!tmp_tree->buf) { r = errno; goto died4; }
/* We have not failed lock escalation, so we allow escalation if we run
out of locks. */
tmp_tree->lock_escalation_allowed = TRUE;
r = toku_ltm_add_lt(tmp_tree->mgr, tmp_tree);
if (r!=0) { goto died5; }
if (!tmp_tree->buf) { r = ENOMEM; goto cleanup; }
tmp_tree->ref_count = 1;
*ptree = tmp_tree;
return 0;
r = 0;
cleanup:
if (r!=0) {
if (tmp_tree) {
assert(user_free);
if (tmp_tree->mainread) { toku_rt_close(tmp_tree->mainread); }
if (tmp_tree->borderwrite) { toku_rt_close(tmp_tree->borderwrite); }
if (tmp_tree->rth) { toku_rth_close(tmp_tree->rth); }
if (tmp_tree->txns_to_unlock) { toku_rth_close(tmp_tree->rth); }
if (tmp_tree->buf) { user_free(tmp_tree->buf); }
user_free(tmp_tree);
}
}
return r;
}
void toku_ltm_invalidate_lt(toku_ltm* mgr, toku_db_id* db_id) {
assert(mgr && db_id);
toku_lt_map* map = NULL;
map = toku_idlth_find(mgr->idlth, db_id);
if (!map) { return; }
toku_idlth_delete(mgr->idlth, db_id);
}
static inline void toku_lt_set_db_id(toku_lock_tree* lt, toku_db_id* db_id) {
assert(lt && db_id);
assert(!lt->settings_final);
lt->db_id = db_id;
toku_db_id_add_ref(db_id);
}
static inline BOOL toku_lt_get_dups(toku_lock_tree* lt) {
assert(lt);
return lt->duplicates;
}
int toku_ltm_get_lt(toku_ltm* mgr, toku_lock_tree** ptree,
BOOL duplicates, toku_db_id* db_id) {
/* first look in hash table to see if lock tree exists for that db,
if so return it */
int r = ENOSYS;
toku_lt_map* map = NULL;
toku_lock_tree* tree = NULL;
BOOL added_to_ltm = FALSE;
BOOL added_to_idlth = FALSE;
map = toku_idlth_find(mgr->idlth, db_id);
if (map != NULL) {
/* Load already existing lock tree. */
assert (map->tree != NULL);
*ptree = map->tree;
assert(duplicates == toku_lt_get_dups(map->tree));
toku_lt_add_ref(*ptree);
r = 0;
goto cleanup;
}
/* Must create new lock tree for this db_id*/
r = toku_lt_create(&tree, duplicates, mgr->panic, mgr,
mgr->get_compare_fun_from_db,
mgr->get_dup_compare_from_db,
mgr->malloc, mgr->free, mgr->realloc);
if (r != 0) { goto cleanup; }
toku_lt_set_db_id(tree, db_id);
/* add tree to ltm */
r = toku_ltm_add_lt(mgr, tree);
if (r!=0) { goto cleanup; }
added_to_ltm = TRUE;
/* add mapping to idlth*/
r = toku_idlth_insert(mgr->idlth, db_id);
if (r != 0) { goto cleanup; }
added_to_idlth = TRUE;
map = toku_idlth_find(mgr->idlth, db_id);
assert(map);
map->tree = tree;
/* No add ref needed because ref count was set to 1 in toku_lt_create */
*ptree = tree;
r = 0;
cleanup:
if (r != 0) {
if (tree != NULL) {
if (added_to_ltm) { toku_ltm_remove_lt(mgr, tree); }
if (added_to_idlth) { toku_idlth_delete(mgr->idlth, db_id); }
toku_lt_close(tree);
}
}
return r;
}
static int toku_lt_close_without_ltm(toku_lock_tree* tree) {
int toku_lt_close(toku_lock_tree* tree) {
int r = ENOSYS;
int first_error = 0;
if (!tree) { r = ENOSYS; goto cleanup; }
if (!tree) { r = EINVAL; goto cleanup; }
#if !defined(TOKU_RT_NOOVERLAPS)
r = toku_rt_close(tree->mainread);
if (!first_error && r!=0) { first_error = r; }
......@@ -1103,53 +1294,43 @@ static int toku_lt_close_without_ltm(toku_lock_tree* tree) {
toku_rt_forest* forest;
while ((forest = toku_rth_next(tree->rth)) != NULL) {
toku__lt_remove_callback(tree, forest->hash_key);
r = toku__lt_free_contents(tree, forest->self_read, NULL);
if (!first_error && r!=0) { first_error = r; }
r = toku__lt_free_contents(tree, forest->self_write, NULL);
if (!first_error && r!=0) { first_error = r; }
}
toku_rth_close(tree->rth);
toku_rth_close(tree->txns_to_unlock);
toku_rth_close(tree->txns_still_locked);
tree->free(tree->buf);
if (tree->db_id) { toku_db_id_remove_ref(tree->db_id); }
tree->free(tree);
r = first_error;
cleanup:
return r;
}
int toku_lt_close(toku_lock_tree* tree) {
int r = ENOSYS;
int first_error = 0;
if (!tree) { r = EINVAL; goto cleanup; }
toku_ltm_remove_lt(tree->mgr, tree);
r = toku_lt_close_without_ltm(tree);
if (r!=0 && first_error==0) { first_error = r; }
r = first_error;
cleanup:
return r;
}
int toku_lt_acquire_read_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_read_lock(toku_lock_tree* tree,
DB* db, TXNID txn,
const DBT* key, const DBT* data) {
return toku_lt_acquire_range_read_lock(tree, txn, key, data, key, data);
return toku_lt_acquire_range_read_lock(tree, db, txn, key, data, key, data);
}
static int toku__lt_try_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
static int toku__lt_try_acquire_range_read_lock(toku_lock_tree* tree,
DB* db, TXNID txn,
const DBT* key_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right,
BOOL* out_of_locks) {
int r;
toku_point left;
toku_point right;
toku_range query;
toku_interval query;
BOOL dominated;
if (!out_of_locks) { return EINVAL; }
r = toku__lt_preprocess(tree, txn,
r = toku__lt_preprocess(tree, db, txn,
key_left, &data_left,
key_right, &data_right,
&left, &right,
......@@ -1157,7 +1338,7 @@ static int toku__lt_try_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* tx
if (r!=0) { goto cleanup; }
/*
For transaction 'txn' to acquire a read-lock on range 'K'=['left','right']:
For transaction 'txn' to acquire a read-lock on range 'K'=['ends.left','ends.right']:
if 'K' is dominated by selfwrite('txn') then return success.
else if 'K' is dominated by selfread('txn') then return success.
else if 'K' meets borderwrite at 'peer' ('peer'!='txn') &&
......@@ -1191,13 +1372,14 @@ static int toku__lt_try_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* tx
r = 0;
cleanup:
if (tree) { toku__lt_postprocess(tree); }
return r;
}
/* Checks for if a write range conflicts with reads.
Supports ranges. */
static inline int toku__lt_write_range_conflicts_reads(toku_lock_tree* tree,
DB_TXN* txn, toku_range* query) {
TXNID txn, toku_interval* query) {
int r = 0;
BOOL met = FALSE;
toku_rth_start_scan(tree->rth);
......@@ -1205,7 +1387,7 @@ static inline int toku__lt_write_range_conflicts_reads(toku_lock_tree* tree,
while ((forest = toku_rth_next(tree->rth)) != NULL) {
if (forest->self_read != NULL && forest->hash_key != txn) {
r = toku__lt_meets_peer(tree, query, forest->self_read, TRUE, txn,///
r = toku__lt_meets_peer(tree, query, forest->self_read, TRUE, txn,
&met);
if (r!=0) { goto cleanup; }
if (met) { r = DB_LOCK_NOTGRANTED; goto cleanup; }
......@@ -1226,8 +1408,7 @@ static inline int toku__border_escalation_trivial(toku_lock_tree* tree,
assert(tree && border_range && trivial);
int r = ENOSYS;
toku_range query = *border_range;
query.data = NULL;
toku_interval query = border_range->ends;
r = toku__lt_write_range_conflicts_reads(tree, border_range->data, &query);
if (r == DB_LOCK_NOTGRANTED || r == DB_LOCK_DEADLOCK) { *trivial = FALSE; }
......@@ -1244,12 +1425,11 @@ static inline int toku__escalate_writes_from_border_range(toku_lock_tree* tree,
toku_range* border_range) {
int r = ENOSYS;
if (!tree || !border_range) { r = EINVAL; goto cleanup; }
DB_TXN* txn = border_range->data;
TXNID txn = border_range->data;
toku_range_tree* self_write = toku__lt_ifexist_selfwrite(tree, txn);
assert(self_write);
toku_range query = *border_range;
toku_interval query = border_range->ends;
u_int32_t numfound = 0;
query.data = NULL;
/*
* Delete all overlapping ranges
......@@ -1263,13 +1443,13 @@ static inline int toku__escalate_writes_from_border_range(toku_lock_tree* tree,
/*
* Clean up memory that is not referenced by border_range.
*/
if (tree->buf[i].left != tree->buf[i].right &&
toku__lt_p_independent(tree->buf[i].left, border_range)) {
if (tree->buf[i].ends.left != tree->buf[i].ends.right &&
toku__lt_p_independent(tree->buf[i].ends.left, &border_range->ends)) {
/* Do not double free if left and right are same point. */
toku__p_free(tree, tree->buf[i].left);
toku__p_free(tree, tree->buf[i].ends.left);
}
if (toku__lt_p_independent(tree->buf[i].right, border_range)) {
toku__p_free(tree, tree->buf[i].right);
if (toku__lt_p_independent(tree->buf[i].ends.right, &border_range->ends)) {
toku__p_free(tree, tree->buf[i].ends.right);
}
}
......@@ -1279,7 +1459,7 @@ static inline int toku__escalate_writes_from_border_range(toku_lock_tree* tree,
r = toku_rt_insert(self_write, border_range);
if (r != 0) { r = toku__lt_panic(tree, r); goto cleanup; }
toku__mgr_lock_incr(tree->mgr, numfound);
toku__lt_lock_incr_per_db(tree, numfound);
r = 0;
cleanup:
return r;
......@@ -1289,12 +1469,11 @@ static inline int toku__escalate_reads_from_border_range(toku_lock_tree* tree,
toku_range* border_range) {
int r = ENOSYS;
if (!tree || !border_range) { r = EINVAL; goto cleanup; }
DB_TXN* txn = border_range->data;
TXNID txn = border_range->data;
toku_range_tree* self_read = toku__lt_ifexist_selfread(tree, txn);
if (self_read == NULL) { r = 0; goto cleanup; }
toku_range query = *border_range;
toku_interval query = border_range->ends;
u_int32_t numfound = 0;
query.data = NULL;
/*
* Delete all overlapping ranges
......@@ -1304,7 +1483,7 @@ static inline int toku__escalate_reads_from_border_range(toku_lock_tree* tree,
u_int32_t i;
u_int32_t removed = 0;
for (i = 0; i < numfound; i++) {
if (!toku__dominated(&tree->buf[i], border_range)) { continue; }
if (!toku__dominated(&tree->buf[i].ends, &border_range->ends)) { continue; }
r = toku_rt_delete(self_read, &tree->buf[i]);
if (r != 0) { r = toku__lt_panic(tree, r); goto cleanup; }
#if !defined(TOKU_RT_NOOVERLAPS)
......@@ -1315,23 +1494,22 @@ static inline int toku__escalate_reads_from_border_range(toku_lock_tree* tree,
/*
* Clean up memory that is not referenced by border_range.
*/
if (tree->buf[i].left != tree->buf[i].right &&
toku__lt_p_independent(tree->buf[i].left, border_range)) {
if (tree->buf[i].ends.left != tree->buf[i].ends.right &&
toku__lt_p_independent(tree->buf[i].ends.left, &border_range->ends)) {
/* Do not double free if left and right are same point. */
toku__p_free(tree, tree->buf[i].left);
toku__p_free(tree, tree->buf[i].ends.left);
}
if (toku__lt_p_independent(tree->buf[i].right, border_range)) {
toku__p_free(tree, tree->buf[i].right);
if (toku__lt_p_independent(tree->buf[i].ends.right, &border_range->ends)) {
toku__p_free(tree, tree->buf[i].ends.right);
}
}
toku__mgr_lock_decr(tree->mgr, removed);
toku__lt_lock_decr_per_db(tree, removed);
r = 0;
cleanup:
return r;
}
/*
* For each range in BorderWrite:
* Check to see if range conflicts any read lock held by other transactions
......@@ -1368,6 +1546,7 @@ static int toku__lt_do_escalation(toku_lock_tree* tree) {
}
/* TODO: Different error code for escalation failed vs not even happened. */
#if 0 //See ticket #596
static int toku__ltm_do_escalation(toku_ltm* mgr, BOOL* locks_available) {
assert(mgr && locks_available);
int r = ENOSYS;
......@@ -1379,18 +1558,35 @@ static int toku__ltm_do_escalation(toku_ltm* mgr, BOOL* locks_available) {
if (r!=0) { goto cleanup; }
}
*locks_available = toku__mgr_lock_test_incr(mgr, 0);
*locks_available = toku__ltm_lock_test_incr(mgr, 0);
r = 0;
cleanup:
return r;
}
#endif
static int toku__lt_do_escalation_per_db(toku_lock_tree* lt, DB* db, BOOL* locks_available) {
assert(lt && locks_available);
int r = ENOSYS;
toku__lt_set_comparison_functions(lt, db);
int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
r = toku__lt_do_escalation(lt);
if (r!=0) { goto cleanup; }
*locks_available = toku__lt_lock_test_incr_per_db(lt, 0);
r = 0;
cleanup:
toku__lt_clear_comparison_functions(lt);
return r;
}
int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right) {
BOOL out_of_locks = FALSE;
int r = ENOSYS;
r = toku__lt_try_acquire_range_read_lock(tree, txn,
r = toku__lt_try_acquire_range_read_lock(tree, db, txn,
key_left, data_left,
key_right, data_right,
&out_of_locks);
......@@ -1398,7 +1594,7 @@ int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
if (out_of_locks) {
BOOL locks_available = FALSE;
r = toku__ltm_do_escalation(tree->mgr, &locks_available);
r = toku__lt_do_escalation_per_db(tree, db, &locks_available);
if (r != 0) { goto cleanup; }
if (!locks_available) {
......@@ -1406,7 +1602,7 @@ int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
goto cleanup;
}
r = toku__lt_try_acquire_range_read_lock(tree, txn,
r = toku__lt_try_acquire_range_read_lock(tree, db, txn,
key_left, data_left,
key_right, data_right,
&out_of_locks);
......@@ -1428,7 +1624,7 @@ int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
Does not support write ranges.
*/
static int toku__lt_write_point_conflicts_reads(toku_lock_tree* tree,
DB_TXN* txn, toku_range* query) {
TXNID txn, toku_interval* query) {
int r = 0;
#if defined(TOKU_RT_NOOVERLAPS)
r = toku__lt_write_range_conflicts_reads(tree, txn, query);
......@@ -1445,35 +1641,37 @@ static int toku__lt_write_point_conflicts_reads(toku_lock_tree* tree,
return r;
}
static int toku__lt_try_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
static int toku__lt_try_acquire_write_lock(toku_lock_tree* tree,
DB* db, TXNID txn,
const DBT* key, const DBT* data,
BOOL* out_of_locks) {
int r;
int r = ENOSYS;
toku_point endpoint;
toku_range query;
toku_interval query;
BOOL dominated;
BOOL free_left = FALSE;
r = toku__lt_preprocess(tree, txn,
r = toku__lt_preprocess(tree, db, txn,
key, &data,
key, &data,
&endpoint, &endpoint,
&query, out_of_locks);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
*out_of_locks = FALSE;
/* if 'K' is dominated by selfwrite('txn') then return success. */
r = toku__lt_rt_dominates(tree, &query,
toku__lt_ifexist_selfwrite(tree, txn), &dominated);
if (r || dominated) return r;
if (r || dominated) { goto cleanup; }
/* else if K meets mainread at 'txn2' then return failure */
r = toku__lt_write_point_conflicts_reads(tree, txn, &query);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
/*
else if 'K' meets borderwrite at 'peer' ('peer'!='txn') &&
'K' meets selfwrite('peer') then return failure.
*/
r = toku__lt_check_borderwrite_conflict(tree, txn, &query);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
/* Now need to copy the memory and insert.
No merging required in selfwrite.
This is a point, and if merging was possible it would have been
......@@ -1481,40 +1679,48 @@ static int toku__lt_try_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
*/
toku_range to_insert;
toku__init_insert(&to_insert, &endpoint, &endpoint, txn);
if (!toku__mgr_lock_test_incr(tree->mgr, 0)) {
*out_of_locks = TRUE; return 0;
if (!toku__lt_lock_test_incr_per_db(tree, 0)) {
*out_of_locks = TRUE; r = 0; goto cleanup;
}
BOOL dummy = TRUE;
r = toku__lt_alloc_extreme(tree, &to_insert, TRUE, &dummy);
if (0) { died1: toku__p_free(tree, to_insert.left); return r; }
if (r!=0) return r;
if (r!=0) { goto cleanup; }
toku_range_tree* selfwrite;
r = toku__lt_selfwrite(tree, txn, &selfwrite);
if (r!=0) goto died1;
if (r!=0) { free_left = TRUE; goto cleanup; }
assert(selfwrite);
r = toku_rt_insert(selfwrite, &to_insert);
if (r!=0) goto died1;
if (r!=0) { free_left = TRUE; goto cleanup; }
/* Need to update borderwrite. */
r = toku__lt_borderwrite_insert(tree, &query, &to_insert);
if (r!=0) return toku__lt_panic(tree, r);
toku__mgr_lock_incr(tree->mgr, 0);
return 0;
if (r!=0) { r = toku__lt_panic(tree, r); goto cleanup; }
toku__lt_lock_incr_per_db(tree, 0);
r = 0;
cleanup:
if (r!=0) {
if (free_left) {
toku__p_free(tree, to_insert.ends.left);
}
}
if (tree) { toku__lt_postprocess(tree); }
return r;
}
int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key, const DBT* data) {
BOOL out_of_locks = FALSE;
int r = ENOSYS;
r = toku__lt_try_acquire_write_lock (tree, txn,
r = toku__lt_try_acquire_write_lock(tree, db, txn,
key, data,
&out_of_locks);
if (r != 0) { goto cleanup; }
if (out_of_locks) {
BOOL locks_available = FALSE;
r = toku__ltm_do_escalation(tree->mgr, &locks_available);
r = toku__lt_do_escalation_per_db(tree, db, &locks_available);
if (r != 0) { goto cleanup; }
if (!locks_available) {
......@@ -1522,7 +1728,7 @@ int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
goto cleanup;
}
r = toku__lt_try_acquire_write_lock (tree, txn,
r = toku__lt_try_acquire_write_lock(tree, db, txn,
key, data,
&out_of_locks);
if (r != 0) { goto cleanup; }
......@@ -1537,42 +1743,47 @@ int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
return r;
}
static int toku__lt_try_acquire_range_write_lock(toku_lock_tree* tree, DB_TXN* txn,
static int toku__lt_try_acquire_range_write_lock(toku_lock_tree* tree,
DB* db, TXNID txn,
const DBT* key_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right,
BOOL* out_of_locks) {
int r;
toku_point left;
toku_point right;
toku_range query;
toku_interval query;
if (key_left == key_right &&
(data_left == data_right || (tree && !tree->duplicates))) {
return toku__lt_try_acquire_write_lock(tree, txn,
return toku__lt_try_acquire_write_lock(tree, db, txn,
key_left, data_left,
out_of_locks);
}
r = toku__lt_preprocess(tree, txn,
r = toku__lt_preprocess(tree, db, txn,
key_left, &data_left,
key_right, &data_right,
&left, &right,
&query, out_of_locks);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
*out_of_locks = FALSE;
return ENOSYS;
//We are not ready for this.
//Not needed for Feb 1 release.
r = ENOSYS;
cleanup:
if (tree) { toku__lt_postprocess(tree); }
return r;
}
int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right) {
BOOL out_of_locks = FALSE;
int r = ENOSYS;
r = toku__lt_try_acquire_range_write_lock (tree, txn,
r = toku__lt_try_acquire_range_write_lock(tree, db, txn,
key_left, data_left,
key_right, data_right,
&out_of_locks);
......@@ -1580,7 +1791,7 @@ int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB_TXN* txn,
if (out_of_locks) {
BOOL locks_available = FALSE;
r = toku__ltm_do_escalation(tree->mgr, &locks_available);
r = toku__lt_do_escalation_per_db(tree, db, &locks_available);
if (r != 0) { goto cleanup; }
if (!locks_available) {
......@@ -1588,7 +1799,7 @@ int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB_TXN* txn,
goto cleanup;
}
r = toku__lt_try_acquire_range_write_lock (tree, txn,
r = toku__lt_try_acquire_range_write_lock(tree, db, txn,
key_left, data_left,
key_right, data_right,
&out_of_locks);
......@@ -1617,8 +1828,7 @@ static inline int toku__sweep_border(toku_lock_tree* tree, toku_range* range) {
toku_range* buf = &buffer[0];
u_int32_t numfound;
toku_range query = *range;
query.data = NULL;
toku_interval query = range->ends;
r = toku_rt_find(borderwrite, &query, query_size, &buf, &buflen, &numfound);
if (r!=0) return r;
assert(numfound <= query_size);
......@@ -1632,7 +1842,7 @@ static inline int toku__sweep_border(toku_lock_tree* tree, toku_range* range) {
r = toku_rt_delete(borderwrite, &buf[0]);
if (r!=0) return r;
/* Find pred(s.left), and succ(s.right) */
/* Find pred(s.ends.left), and succ(s.ends.right) */
toku_range pred;
toku_range succ;
BOOL found_p;
......@@ -1654,7 +1864,7 @@ static inline int toku__sweep_border(toku_lock_tree* tree, toku_range* range) {
r = toku_rt_delete(borderwrite, &succ);
if (r!=0) return r;
pred.right = succ.right;
pred.ends.right = succ.ends.right;
r = toku_rt_insert(borderwrite, &pred);
if (r!=0) return r;
......@@ -1668,7 +1878,7 @@ static inline int toku__sweep_border(toku_lock_tree* tree, toku_range* range) {
If none exists or data is not ours (we have already deleted the real
overlapping range), continue
Delete s from borderwrite
Find pred(s.left), and succ(s.right)
Find pred(s.ends.left), and succ(s.ends.right)
If both found and pred.data=succ.data, merge pred and succ (expand?)
free_points
*/
......@@ -1678,7 +1888,7 @@ static inline int toku__lt_border_delete(toku_lock_tree* tree, toku_range_tree*
if (!rt) return 0;
/* Find the ranges in rt */
toku_range query;
toku_interval query;
toku_point left;
toku_point right;
toku__lt_init_full_query(tree, &query, &left, &right);
......@@ -1697,8 +1907,24 @@ static inline int toku__lt_border_delete(toku_lock_tree* tree, toku_range_tree*
return 0;
}
int toku_lt_unlock(toku_lock_tree* tree, DB_TXN* txn) {
if (!tree || !txn) return EINVAL;
static inline int toku__lt_defer_unlocking_txn(toku_lock_tree* tree, TXNID txnid) {
int r = ENOSYS;
toku_rt_forest* forest = toku_rth_find(tree->txns_to_unlock, txnid);
/* Should not be unlocking a transaction twice. */
assert(!forest);
r = toku_rth_insert(tree->txns_to_unlock, txnid);
if (r!=0) { goto cleanup; }
if (toku_rth_find(tree->txns_still_locked, txnid) != NULL) {
toku_rth_delete(tree->txns_still_locked, txnid);
}
r = 0;
cleanup:
return r;
}
static inline int toku__lt_unlock_txn(toku_lock_tree* tree, TXNID txn) {
if (!tree) return EINVAL;
int r;
toku_range_tree *selfwrite = toku__lt_ifexist_selfwrite(tree, txn);
toku_range_tree *selfread = toku__lt_ifexist_selfread (tree, txn);
......@@ -1727,40 +1953,99 @@ int toku_lt_unlock(toku_lock_tree* tree, DB_TXN* txn) {
if (selfread || selfwrite) toku_rth_delete(tree->rth, txn);
toku__mgr_lock_decr(tree->mgr, ranges);
toku__lt_lock_decr_per_db(tree, ranges);
return 0;
}
int toku_lt_set_dups(toku_lock_tree* tree, BOOL duplicates) {
static inline int toku__lt_unlock_deferred_txns(toku_lock_tree* tree) {
int r = ENOSYS;
if (!tree) { r = EINVAL; goto cleanup; }
if (tree->settings_final) { r = EDOM; goto cleanup; }
tree->duplicates = duplicates;
toku_rth_start_scan(tree->txns_to_unlock);
toku_rt_forest* forest = NULL;
while ((forest = toku_rth_next(tree->txns_to_unlock)) != NULL) {
/* This can only fail with a panic so it is fine to quit immediately. */
r = toku__lt_unlock_txn(tree, forest->hash_key);
if (r!=0) { goto cleanup; }
}
toku_rth_clear(tree->txns_to_unlock);
r = 0;
cleanup:
return r;
}
int toku_lt_set_txn_add_lt_callback(toku_lock_tree* tree,
int (*add_callback)(DB_TXN*, toku_lock_tree*)) {
static inline void toku__lt_clear(toku_lock_tree* tree) {
int r;
assert(tree);
#if !defined(TOKU_RT_NOOVERLAPS)
toku_rt_clear(tree->mainread);
#endif
toku_rt_clear(tree->borderwrite);
toku_rth_start_scan(tree->rth);
toku_rt_forest* forest;
u_int32_t ranges = 0;
while ((forest = toku_rth_next(tree->rth)) != NULL) {
u_int32_t size;
if (forest->self_read) {
r = toku_rt_get_size(forest->self_read, &size);
assert(r==0);
ranges += size;
r = toku__lt_free_contents(tree, forest->self_read, NULL);
assert(r==0);
}
if (forest->self_write) {
r = toku_rt_get_size(forest->self_write, &size);
assert(r==0);
ranges += size;
r = toku__lt_free_contents(tree, forest->self_write, NULL);
assert(r==0);
}
}
toku_rth_clear(tree->rth);
toku_rth_clear(tree->txns_to_unlock);
/* tree->txns_still_locked is already empty, so we do not clear it. */
toku__lt_lock_decr_per_db(tree, ranges);
}
int toku_lt_unlock(toku_lock_tree* tree, TXNID txn) {
int r = ENOSYS;
if (!tree || !add_callback) { r = EINVAL; goto cleanup; }
if (tree->settings_final) { r = EDOM; goto cleanup; }
tree->lock_add_callback = add_callback;
if (!tree) { r = EINVAL; goto cleanup; }
r = toku__lt_defer_unlocking_txn(tree, txn);
if (r!=0) { goto cleanup; }
if (toku_rth_is_empty(tree->txns_still_locked)) { toku__lt_clear(tree); }
r = 0;
cleanup:
return r;
}
int toku_lt_set_txn_remove_lt_callback(toku_lock_tree* tree,
void (*remove_callback)(DB_TXN*, toku_lock_tree*)) {
void toku_lt_add_ref(toku_lock_tree* tree) {
assert(tree);
assert(tree->ref_count > 0);
tree->ref_count++;
}
static void toku_ltm_stop_managing_lt(toku_ltm* mgr, toku_lock_tree* tree) {
toku_ltm_remove_lt(mgr, tree);
toku_lt_map* map = toku_idlth_find(mgr->idlth, tree->db_id);
if (map && map->tree == tree) {
toku_idlth_delete(mgr->idlth, tree->db_id);
}
}
int toku_lt_remove_ref(toku_lock_tree* tree) {
int r = ENOSYS;
if (!tree || !remove_callback) { r = EINVAL; goto cleanup; }
if (tree->settings_final) { r = EDOM; goto cleanup; }
tree->lock_remove_callback = remove_callback;
assert(tree);
assert(tree->ref_count > 0);
tree->ref_count--;
if (tree->ref_count > 0) { r = 0; goto cleanup; }
assert(tree->db_id);
toku_ltm_stop_managing_lt(tree->mgr, tree);
r = toku_lt_close(tree);
if (r!=0) { goto cleanup; }
r = 0;
cleanup:
return r;
}
......@@ -24,6 +24,7 @@
#include <rangetree.h>
#include <lth.h>
#include <rth.h>
#include <idlth.h>
/** Errors returned by lock trees */
typedef enum {
......@@ -31,6 +32,8 @@ typedef enum {
state */
} TOKU_LT_ERROR;
typedef int (*toku_dbt_cmp)(DB*,const DBT*,const DBT*);
/** Convert error codes into a human-readable error message */
char* toku_lt_strerror(TOKU_LT_ERROR r /**< Error code */)
__attribute__((const,pure));
......@@ -58,7 +61,20 @@ struct __toku_lock_tree {
BOOL settings_final;
toku_range_tree* mainread; /**< See design document */
toku_range_tree* borderwrite; /**< See design document */
toku_rth* rth;
toku_rth* rth; /**< Stores local(read|write)set tables */
/**
Stores a list of transactions to unlock when it is safe.
When we get a PUT or a GET, the comparison function is valid
and we can delete locks held in txns_to_unlock, even if txns_still_locked
is nonempty.
*/
toku_rth* txns_to_unlock;
/** Stores a list of transactions that hold locks. txns_still_locked = rth - txns_to_unlock
rth != txns_still_locked + txns_to_unlock, we may get an unlock call for a txn that has
no locks in rth.
When txns_still_locked becomes empty, we can throw away the contents of the lock tree
quickly. */
toku_rth* txns_still_locked;
/** A temporary area where we store the results of various find on
the range trees that this lock tree owns
......@@ -81,10 +97,10 @@ struct __toku_lock_tree {
BOOL lock_escalation_allowed;
/** Lock tree manager */
toku_ltm* mgr;
/** The callback function to let a transaction add a new lock tree. */
int (*lock_add_callback)(DB_TXN*, toku_lock_tree*);
/** The callback function to let a transaction forget a lock tree. */
void (*lock_remove_callback)(DB_TXN*, toku_lock_tree*);
/** Function to retrieve the key compare function from the database. */
toku_dbt_cmp (*get_compare_fun_from_db)(DB*);
/** Function to retrieve the data compare function from the database. */
toku_dbt_cmp (*get_dup_compare_from_db)(DB*);
/** The key compare function */
int (*compare_fun)(DB*,const DBT*,const DBT*);
/** The data compare function */
......@@ -97,6 +113,14 @@ struct __toku_lock_tree {
void (*free) (void*);
/** The user realloc function */
void* (*realloc)(void*, size_t);
/** The maximum number of locks allowed for this lock tree. */
u_int32_t max_locks;
/** The current number of locks for this lock tree. */
u_int32_t curr_locks;
/** The number of references held by DB instances and transactions to this lock tree*/
u_int32_t ref_count;
/** db_id associated with the lock tree */
toku_db_id* db_id;
};
struct __toku_ltm {
......@@ -104,8 +128,21 @@ struct __toku_ltm {
u_int32_t max_locks;
/** The current number of locks for the environment. */
u_int32_t curr_locks;
/** The maximum number of locks allowed for the environment. */
u_int32_t max_locks_per_db;
/** The list of lock trees it manages. */
toku_lth* lth;
/** List of lock-tree DB mappings. Upon a request for a lock tree given
a DB, if an object for that DB exists in this list, then the lock tree
is retrieved from this list, otherwise, a new lock tree is created
and the new mapping of DB and Lock tree is stored here */
toku_idlth* idlth;
/** Function to retrieve the key compare function from the database. */
toku_dbt_cmp (*get_compare_fun_from_db)(DB*);
/** Function to retrieve the data compare function from the database. */
toku_dbt_cmp (*get_dup_compare_from_db)(DB*);
/** The panic function */
int (*panic)(DB*, int);
/** The user malloc function */
void* (*malloc) (size_t);
/** The user free function */
......@@ -147,11 +184,9 @@ typedef struct __toku_point toku_point;
Create a lock tree. Should be called only inside DB->open.
\param ptree We set *ptree to the newly allocated tree.
\param db This is the db that the lock tree will be performing
locking for.
\param duplicates Whether the db supports duplicates.
\param compare_fun The key compare function.
\param dup_compare The data compare function.
\param get_compare_fun_from_db Accessor for the key compare function.
\param get_dup_compare_from_db Accessor for the data compare function.
\param panic The function to cause the db to panic.
i.e., godzilla_rampage()
\param payload_capacity The maximum amount of memory to use for dbt payloads.
......@@ -172,26 +207,22 @@ typedef struct __toku_point toku_point;
If this library is ever exported to users, we will use error datas
instead.
*/
int toku_lt_create(toku_lock_tree** ptree, DB* db, BOOL duplicates,
int toku_lt_create(toku_lock_tree** ptree, BOOL duplicates,
int (*panic)(DB*, int),
toku_ltm* mgr,
int (*compare_fun)(DB*,const DBT*,const DBT*),
int (*dup_compare)(DB*,const DBT*,const DBT*),
toku_dbt_cmp (*get_compare_fun_from_db)(DB*),
toku_dbt_cmp (*get_dup_compare_from_db)(DB*),
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t));
/**
Set whether duplicates are allowed.
This can be called after create, but NOT after any locks or unlocks have
occurred.
\return
- 0 on success.
- EINVAL if tree is NULL
- EDOM if it is too late to change.
Gets a lock tree for a given DB with id db_id
*/
int toku_lt_set_dups(toku_lock_tree* tree, BOOL duplicates);
int toku_ltm_get_lt(toku_ltm* mgr, toku_lock_tree** ptree,
BOOL duplicates, toku_db_id* db_id);
void toku_ltm_invalidate_lt(toku_ltm* mgr, toku_db_id* db_id);
/**
Closes and frees a lock tree.
......@@ -234,14 +265,14 @@ int toku_lt_close(toku_lock_tree* tree);
(tree->db is dupsort && data == NULL) or
(tree->db is dupsort && key != data &&
(key == toku_lt_infinity ||
(toku_lock_tree* tree, DB_TXN* txn, const DBT* key, const DBT* data);
(toku_lock_tree* tree, TXNID txn, const DBT* key, const DBT* data);
If this library is ever exported to users, we will use EINVAL instead.
In BDB, txn can actually be NULL (mixed operations with transactions and
no transactions). This can cause conflicts, nobody was able (so far)
to verify that MySQL does or does not use this.
*/
int toku_lt_acquire_read_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_read_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key, const DBT* data);
/*
......@@ -288,7 +319,7 @@ int toku_lt_acquire_read_lock(toku_lock_tree* tree, DB_TXN* txn,
no transactions). This can cause conflicts, nobody was able (so far)
to verify that MySQL does or does not use this.
*/
int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right);
......@@ -321,7 +352,7 @@ int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
If the lock tree needs to hold onto the key or data, it will make copies
to its local memory.
*/
int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key, const DBT* data);
//In BDB, txn can actually be NULL (mixed operations with transactions and no transactions).
......@@ -373,7 +404,7 @@ int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
* to its local memory.
* *** Note that txn == NULL is not supported at this time.
*/
int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB_TXN* txn,
int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right);
......@@ -393,43 +424,7 @@ int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB_TXN* txn,
- EINVAL If (tree == NULL || txn == NULL).
- EINVAL If panicking.
*/
int toku_lt_unlock(toku_lock_tree* tree, DB_TXN* txn);
/**
Set a add_callback function to run after parameter checking but before
any locks.
This can be called after create, but NOT after any locks or unlocks have
occurred.
\param tree The tree on whick to set the add_callback function
\param add_callback The add_callback function
\return
- 0 on success.
- EINVAL if tree is NULL
- EDOM if it is too late to change.
*/
int toku_lt_set_txn_add_lt_callback(toku_lock_tree* tree,
int (*add_callback)(DB_TXN*, toku_lock_tree*));
/**
Set a remove_callback function to run after parameter checking but before
any locks.
This can be called after create, but NOT after any locks or unlocks have
occurred.
\param tree The tree on whick to set the remove_callback function
\param remove_callback The remove_callback function
\return
- 0 on success.
- EINVAL if tree is NULL
- EDOM if it is too late to change.
*/
int toku_lt_set_txn_remove_lt_callback(toku_lock_tree* tree,
void (*remove_callback)(DB_TXN*, toku_lock_tree*));
int toku_lt_unlock(toku_lock_tree* tree, TXNID txn);
/* Lock tree manager functions begin here */
/**
......@@ -448,6 +443,9 @@ int toku_lt_set_txn_remove_lt_callback(toku_lock_tree* tree,
*/
int toku_ltm_create(toku_ltm** pmgr,
u_int32_t max_locks,
int (*panic)(DB*, int),
toku_dbt_cmp (*get_compare_fun_from_db)(DB*),
toku_dbt_cmp (*get_dup_compare_from_db)(DB*),
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t));
......@@ -478,6 +476,22 @@ int toku_ltm_close(toku_ltm* mgr);
*/
int toku_ltm_set_max_locks(toku_ltm* mgr, u_int32_t max_locks);
/**
Sets the maximum number of locks for each lock tree.
This is a temporary function until we can complete ticket #596.
This will be used instead of toku_ltm_set_max_locks.
\param mgr The lock tree manager to which to set max_locks.
\param max_locks The new maximum number of locks.
\return
- 0 on success.
- EINVAL if tree is NULL or max_locks is 0
- EDOM if max_locks is less than the number of locks held by any lock tree
held by the manager
*/
int toku_ltm_set_max_locks_per_db(toku_ltm* mgr, u_int32_t max_locks);
/**
Sets the maximum number of locks on the lock tree manager.
......@@ -490,5 +504,10 @@ int toku_ltm_set_max_locks(toku_ltm* mgr, u_int32_t max_locks);
*/
int toku_ltm_get_max_locks(toku_ltm* mgr, u_int32_t* max_locks);
int toku_ltm_get_max_locks_per_db(toku_ltm* mgr, u_int32_t* max_locks);
void toku_lt_add_ref(toku_lock_tree* tree);
int toku_lt_remove_ref(toku_lock_tree* tree);
#endif
......@@ -15,9 +15,9 @@
#include <string.h>
/* TODO: reallocate the hash lth if it grows too big. Perhaps, use toku_get_prime in newbrt/primes.c */
const uint32 __toku_lth_init_size = 521;
const u_int32_t __toku_lth_init_size = 521;
static inline uint32 toku__lth_hash(toku_lth* lth, toku_lock_tree* key) {
static inline u_int32_t toku__lth_hash(toku_lth* lth, toku_lock_tree* key) {
size_t tmp = (size_t)key;
return tmp % lth->num_buckets;
}
......@@ -64,7 +64,7 @@ int toku_lth_create(toku_lth** plth,
toku_lock_tree* toku_lth_find(toku_lth* lth, toku_lock_tree* key) {
assert(lth && key);
uint32 index = toku__lth_hash(lth, key);
u_int32_t index = toku__lth_hash(lth, key);
toku_lth_elt* head = &lth->buckets[index];
toku_lth_elt* current = head->next_in_bucket;
while (current) {
......@@ -103,7 +103,7 @@ void toku_lth_delete(toku_lth* lth, toku_lock_tree* key) {
/* Must have elements. */
assert(lth->num_keys);
uint32 index = toku__lth_hash(lth, key);
u_int32_t index = toku__lth_hash(lth, key);
toku_lth_elt* head = &lth->buckets[index];
toku_lth_elt* prev = head;
toku_lth_elt* current = prev->next_in_bucket;
......@@ -129,7 +129,7 @@ int toku_lth_insert(toku_lth* lth, toku_lock_tree* key) {
assert(lth && key);
toku__invalidate_scan(lth);
uint32 index = toku__lth_hash(lth, key);
u_int32_t index = toku__lth_hash(lth, key);
/* Allocate a new one. */
toku_lth_elt* element = (toku_lth_elt*)lth->malloc(sizeof(*element));
......
......@@ -15,9 +15,9 @@
#include <string.h>
/* TODO: reallocate the hash rth if it grows too big. Perhaps, use toku_get_prime in newbrt/primes.c */
const uint32 __toku_rth_init_size = 521;
const u_int32_t __toku_rth_init_size = 521;
static inline uint32 toku__rth_hash(toku_rth* rth, DB_TXN* key) {
static inline u_int32_t toku__rth_hash(toku_rth* rth, TXNID key) {
size_t tmp = (size_t)key;
return tmp % rth->num_buckets;
}
......@@ -61,10 +61,10 @@ int toku_rth_create(toku_rth** prth,
return r;
}
toku_rt_forest* toku_rth_find(toku_rth* rth, DB_TXN* key) {
assert(rth && key);
toku_rt_forest* toku_rth_find(toku_rth* rth, TXNID key) {
assert(rth);
uint32 index = toku__rth_hash(rth, key);
u_int32_t index = toku__rth_hash(rth, key);
toku_rth_elt* head = &rth->buckets[index];
toku_rth_elt* current = head->next_in_bucket;
while (current) {
......@@ -96,14 +96,14 @@ toku_rt_forest* toku_rth_next(toku_rth* rth) {
}
/* Element MUST exist. */
void toku_rth_delete(toku_rth* rth, DB_TXN* key) {
assert(rth && key);
void toku_rth_delete(toku_rth* rth, TXNID key) {
assert(rth);
toku__invalidate_scan(rth);
/* Must have elements. */
assert(rth->num_keys);
uint32 index = toku__rth_hash(rth, key);
u_int32_t index = toku__rth_hash(rth, key);
toku_rth_elt* head = &rth->buckets[index];
toku_rth_elt* prev = head;
toku_rth_elt* current = prev->next_in_bucket;
......@@ -124,12 +124,12 @@ void toku_rth_delete(toku_rth* rth, DB_TXN* key) {
}
/* Will allow you to insert it over and over. You need to keep track. */
int toku_rth_insert(toku_rth* rth, DB_TXN* key) {
int toku_rth_insert(toku_rth* rth, TXNID key) {
int r = ENOSYS;
assert(rth && key);
assert(rth);
toku__invalidate_scan(rth);
uint32 index = toku__rth_hash(rth, key);
u_int32_t index = toku__rth_hash(rth, key);
/* Allocate a new one. */
toku_rth_elt* element = (toku_rth_elt*)rth->malloc(sizeof(*element));
......@@ -150,12 +150,12 @@ int toku_rth_insert(toku_rth* rth, DB_TXN* key) {
return r;
}
void toku_rth_close(toku_rth* rth) {
static inline void toku__rth_clear(toku_rth* rth, BOOL clean) {
assert(rth);
toku_rth_elt* element;
toku_rth_elt* head = &rth->iter_head;
toku_rth_elt* next = NULL;
toku_rth_start_scan(rth);
next = toku__rth_next(rth);
while (next != head) {
......@@ -163,7 +163,34 @@ void toku_rth_close(toku_rth* rth) {
next = toku__rth_next(rth);
rth->free(element);
}
/* If clean is true, then we want to restore it to 'just created' status.
If we are closing the tree, we don't need to do that restoration. */
if (!clean) { return; }
memset(rth->buckets, 0, rth->num_buckets * sizeof(*rth->buckets));
toku__invalidate_scan(rth);
rth->iter_head.next_in_iteration = &rth->iter_head;
rth->iter_head.prev_in_iteration = &rth->iter_head;
rth->num_keys = 0;
}
void toku_rth_clear(toku_rth* rth) {
toku__rth_clear(rth, TRUE);
}
void toku_rth_close(toku_rth* rth) {
assert(rth);
toku__rth_clear(rth, FALSE);
rth->free(rth->buckets);
rth->free(rth);
}
BOOL toku_rth_is_empty(toku_rth* rth) {
assert(rth);
/* Verify consistency. */
assert((rth->num_keys == 0) ==
(rth->iter_head.next_in_iteration == &rth->iter_head));
assert((rth->num_keys == 0) ==
(rth->iter_head.prev_in_iteration == &rth->iter_head));
return rth->num_keys == 0;
}
......@@ -16,11 +16,9 @@
#include <brttypes.h>
#include <rangetree.h>
typedef u_int32_t uint32;
typedef struct __toku_rt_forest toku_rt_forest;
struct __toku_rt_forest {
DB_TXN* hash_key;
TXNID hash_key;
toku_range_tree* self_read;
toku_range_tree* self_write;
};
......@@ -36,8 +34,8 @@ struct __toku_rth_elt {
typedef struct __toku_rth toku_rth;
struct __toku_rth {
toku_rth_elt* buckets;
uint32 num_buckets;
uint32 num_keys;
u_int32_t num_buckets;
u_int32_t num_keys;
toku_rth_elt iter_head;
toku_rth_elt* iter_curr;
BOOL iter_is_valid;
......@@ -54,15 +52,20 @@ int toku_rth_create(toku_rth** ptable,
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t));
toku_rt_forest* toku_rth_find (toku_rth* table, DB_TXN* key);
toku_rt_forest* toku_rth_find (toku_rth* table, TXNID key);
void toku_rth_start_scan (toku_rth* table);
toku_rt_forest* toku_rth_next (toku_rth* table);
void toku_rth_delete (toku_rth* table, DB_TXN* key);
void toku_rth_delete (toku_rth* table, TXNID key);
void toku_rth_close (toku_rth* table);
int toku_rth_insert (toku_rth* table, DB_TXN* key);
int toku_rth_insert (toku_rth* table, TXNID key);
void toku_rth_clear (toku_rth* rth);
BOOL toku_rth_is_empty (toku_rth* rth);
#endif
......@@ -107,7 +107,7 @@ RT_TLINEAR_BINS = ../../range_tree/linear.o
RT_TLOG_BINS = ../../range_tree/log_nooverlap.o ../../range_tree/tokuredblack.o
RT_LOG_BINS = ../../range_tree/log.o
LT_BINS = ../lth.o ../rth.o
LT_BINS = ../lth.o ../rth.o ../idlth.o ../db_id.o
LT_OVERLAP = ../locktree_global_readset.o
LT_NOOVERLAP = ../locktree_no_global_readset.o
LT_LINEAR = $(LT_OVERLAP) $(LT_BINS) $(RT_LINEAR_BINS)
......
......@@ -8,7 +8,10 @@
#include <assert.h>
#include <errno.h>
int verbose=0;
#include <db_id.h>
#include <lth.h>
#include <sys/types.h>
#include <sys/stat.h>
BOOL want_panic = FALSE;
......@@ -46,6 +49,17 @@ int dbcmp (DB *db __attribute__((__unused__)), const DBT *a, const DBT*b) {
return toku_keycompare(a->data, a->size, b->data, b->size);
}
toku_dbt_cmp compare_fun = dbcmp;
toku_dbt_cmp dup_compare = dbcmp;
toku_dbt_cmp get_compare_fun_from_db(__attribute__((unused)) DB* db) {
return compare_fun;
}
toku_dbt_cmp get_dup_compare_from_db(__attribute__((unused)) DB* db) {
return dup_compare;
}
BOOL panicked = FALSE;
int dbpanic(DB* db, int r) {
......@@ -134,3 +148,10 @@ void* fail_malloc(size_t size) {
}
return malloc(size);
}
char *toku_strdup (const char *s) {
size_t len = strlen(s) + 1;
void * r = toku_malloc(len);
memcpy(r, s, len);
return r;
}
......@@ -4,16 +4,18 @@ int main() {
int r;
toku_lock_tree* lt = NULL;
toku_ltm* mgr = NULL;
DB* db = (DB*)1;
u_int32_t max_locks = 1000;
BOOL duplicates;
r = toku_ltm_create(&mgr, max_locks, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(&mgr, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
for (duplicates = 0; duplicates < 2; duplicates++) {
r = toku_lt_create(&lt, db, duplicates, dbpanic, mgr,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, mgr,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
r = toku_lt_close(lt);
......
......@@ -9,13 +9,13 @@ DBT* data;
u_int32_t max_locks = 1000;
toku_ltm* ltm = NULL;
static void do_range_test(int (*acquire)(toku_lock_tree*, DB_TXN*,
static void do_range_test(int (*acquire)(toku_lock_tree*, DB*, TXNID,
const DBT*, const DBT*,
const DBT*, const DBT*)) {
int r;
toku_lock_tree* lt = NULL;
DB* db = (DB*)1;
DB_TXN* txn = (DB_TXN*)1; // Fake.
TXNID txn = (TXNID)1; // Fake.
BOOL duplicates = FALSE;
DBT _key_l = _key;
DBT _key_r = _key;
......@@ -40,63 +40,61 @@ static void do_range_test(int (*acquire)(toku_lock_tree*, DB_TXN*,
reverse_data_l = &_data_l;
reverse_data_r = &_data_r;
}
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
if (acquire == toku_lt_acquire_range_write_lock) {
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
key_r, data_r);
CKERR2(r, ENOSYS);
}
r = acquire(NULL, txn, key_l, data_l,
r = acquire(NULL, db, txn, key_l, data_l,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, NULL, key_l, data_l,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, NULL, data_l,
r = acquire(lt, db, txn, NULL, data_l,
key_r, data_r);
CKERR2(r, EINVAL);
if (duplicates) {
r = acquire(lt, txn, key_l, reverse_data_l,
r = acquire(lt, db, txn, key_l, reverse_data_l,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
key_r, reverse_data_r);
CKERR2(r, EINVAL);
}
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
NULL, data_r);
CKERR2(r, EINVAL);
/* Infinite tests. */
if (duplicates) {
r = acquire(lt, txn, toku_lt_infinity, data_l,
r = acquire(lt, db, txn, toku_lt_infinity, data_l,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, toku_lt_neg_infinity, data_l,
r = acquire(lt, db, txn, toku_lt_neg_infinity, data_l,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
toku_lt_infinity, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
toku_lt_neg_infinity, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, toku_lt_infinity, toku_lt_neg_infinity,
r = acquire(lt, db, txn, toku_lt_infinity, toku_lt_neg_infinity,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, toku_lt_neg_infinity, toku_lt_infinity,
r = acquire(lt, db, txn, toku_lt_neg_infinity, toku_lt_infinity,
key_r, data_r);
CKERR2(r, EINVAL);
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
toku_lt_infinity, toku_lt_neg_infinity);
CKERR2(r, EINVAL);
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
toku_lt_neg_infinity, toku_lt_infinity);
CKERR2(r, EINVAL);
}
......@@ -105,13 +103,13 @@ static void do_range_test(int (*acquire)(toku_lock_tree*, DB_TXN*,
const DBT* inf = toku_lt_infinity;
const DBT* d_ninf = duplicates ? toku_lt_neg_infinity : NULL;
const DBT* ninf = toku_lt_neg_infinity;
r = acquire(lt, txn, inf, d_inf,
r = acquire(lt, db, txn, inf, d_inf,
key_r, data_r);
CKERR2(r, EDOM);
r = acquire(lt, txn, key_l, data_l,
r = acquire(lt, db, txn, key_l, data_l,
ninf, d_ninf);
CKERR2(r, EDOM);
r = acquire(lt, txn, inf, d_inf,
r = acquire(lt, db, txn, inf, d_inf,
ninf, d_ninf);
CKERR2(r, EDOM);
......@@ -123,12 +121,12 @@ static void do_range_test(int (*acquire)(toku_lock_tree*, DB_TXN*,
}
}
static void do_point_test(int (*acquire)(toku_lock_tree*, DB_TXN*,
static void do_point_test(int (*acquire)(toku_lock_tree*, DB*, TXNID,
const DBT*, const DBT*)) {
int r;
toku_lock_tree* lt = NULL;
DB* db = (DB*)1;
DB_TXN* txn = (DB_TXN*)1; // Fake.
TXNID txn = (TXNID)1; // Fake.
DB* db = (DB*)0x1;
BOOL duplicates = FALSE;
lt = NULL;
......@@ -145,40 +143,35 @@ static void do_point_test(int (*acquire)(toku_lock_tree*, DB_TXN*,
reverse_data = &_data;
data = NULL;
}
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
r = toku_lt_unlock(NULL, (DB_TXN*)1);
CKERR2(r, EINVAL);
r = toku_lt_unlock(lt, NULL);
r = toku_lt_unlock(NULL, (TXNID)1);
CKERR2(r, EINVAL);
r = acquire(NULL, txn, key, data);
r = acquire(NULL, db, txn, key, data);
CKERR2(r, EINVAL);
r = acquire(lt, NULL, key, data);
CKERR2(r, EINVAL);
r = acquire(lt, txn, NULL, data);
r = acquire(lt, db, txn, NULL, data);
CKERR2(r, EINVAL);
if (duplicates) {
r = acquire(lt, txn, key, reverse_data);
r = acquire(lt, db, txn, key, reverse_data);
CKERR2(r, EINVAL);
}
/* Infinite tests. */
if (duplicates) {
r = acquire(lt, txn, toku_lt_infinity, data);
r = acquire(lt, db, txn, toku_lt_infinity, data);
CKERR2(r, EINVAL);
r = acquire(lt, txn, toku_lt_neg_infinity, data);
r = acquire(lt, db, txn, toku_lt_neg_infinity, data);
CKERR2(r, EINVAL);
r = acquire(lt, txn, toku_lt_infinity, toku_lt_neg_infinity);
r = acquire(lt, db, txn, toku_lt_infinity, toku_lt_neg_infinity);
CKERR2(r, EINVAL);
r = acquire(lt, txn, toku_lt_neg_infinity, toku_lt_infinity);
r = acquire(lt, db, txn, toku_lt_neg_infinity, toku_lt_infinity);
CKERR2(r, EINVAL);
}
......@@ -195,27 +188,38 @@ int main(int argc, const char *argv[]) {
int r;
toku_lock_tree* lt = NULL;
DB* db = (DB*)1;
BOOL duplicates = FALSE;
r = toku_ltm_create(NULL, max_locks, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(NULL, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
assert(ltm == NULL);
r = toku_ltm_create(&ltm, 0, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(&ltm, 0, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
assert(ltm == NULL);
r = toku_ltm_create(&ltm, max_locks, NULL, toku_free, toku_realloc);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
NULL, toku_free, toku_realloc);
CKERR2(r, EINVAL);
assert(ltm == NULL);
r = toku_ltm_create(&ltm, max_locks, toku_malloc, NULL, toku_realloc);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, NULL, toku_realloc);
CKERR2(r, EINVAL);
assert(ltm == NULL);
r = toku_ltm_create(&ltm, max_locks, toku_malloc, toku_free, NULL);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, NULL);
CKERR2(r, EINVAL);
assert(ltm == NULL);
/* Actually create it. */
r = toku_ltm_create(&ltm, max_locks, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
......@@ -239,37 +243,41 @@ int main(int argc, const char *argv[]) {
/* create tests. */
for (duplicates = 0; duplicates < 2; duplicates++) {
r = toku_lt_create(NULL, db, duplicates, dbpanic, ltm,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, NULL, duplicates, dbpanic, ltm,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(NULL, duplicates, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, NULL, ltm,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, NULL, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, dbpanic, NULL,
dbcmp, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, NULL,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
NULL, dbcmp, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
NULL, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
dbcmp, NULL, toku_malloc, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
get_compare_fun_from_db, NULL,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
dbcmp, dbcmp, NULL, toku_free, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
NULL, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
dbcmp, dbcmp, toku_malloc, NULL, toku_realloc);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, NULL, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, db, duplicates, dbpanic, ltm,
dbcmp, dbcmp, toku_malloc, toku_free, NULL);
r = toku_lt_create(&lt, duplicates, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, NULL);
CKERR2(r, EINVAL);
}
......
......@@ -2,14 +2,14 @@
#include "test.h"
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, TXNID txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, TXNID txn);
int r;
toku_lock_tree* lt = NULL;
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
DB_TXN* txn = (DB_TXN*)1;
TXNID txn = (TXNID)1;
u_int32_t max_locks = 1000;
BOOL duplicates = FALSE;
int nums[100];
......@@ -24,7 +24,7 @@ DBT* data_left [2] ;
DBT* data_right[2] ;
toku_point qleft, qright;
toku_range query;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
......@@ -48,10 +48,13 @@ void init_query(BOOL dups) {
void setup_tree(BOOL dups) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, db, dups, dbpanic, ltm, dbcmp, dbcmp,
r = toku_lt_create(&lt, dups, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
......@@ -104,7 +107,7 @@ void lt_insert(BOOL dups, int key_l, int data_l, int key_r, int data_r) {
assert(key_right && !data_right);
}
r = toku_lt_acquire_range_read_lock(lt, txn, key_left, data_left,
r = toku_lt_acquire_range_read_lock(lt, db, txn, key_left, data_left,
key_right, data_right);
CKERR(r);
}
......@@ -125,11 +128,25 @@ void setup_payload_len(void** payload, u_int32_t* len, int val) {
}
}
void temporarily_fake_comparison_functions(void) {
assert(!lt->db && !lt->compare_fun && !lt->dup_compare);
lt->db = db;
lt->compare_fun = get_compare_fun_from_db(db);
lt->dup_compare = get_dup_compare_from_db(db);
}
void stop_fake_comparison_functions(void) {
assert(lt->db && lt->compare_fun && lt->dup_compare);
lt->db = NULL;
lt->compare_fun = NULL;
lt->dup_compare = NULL;
}
void lt_find(BOOL dups, toku_range_tree* rt,
unsigned k, int key_l, int data_l,
int key_r, int data_r,
DB_TXN* find_txn) {
TXNID find_txn) {
temporarily_fake_comparison_functions();
r = toku_rt_find(rt, &query, 0, &buf, &buflen, &numfound);
CKERR(r);
assert(numfound==k);
......@@ -149,11 +166,13 @@ void lt_find(BOOL dups, toku_range_tree* rt,
}
unsigned i;
for (i = 0; i < numfound; i++) {
if (toku__lt_point_cmp(buf[i].left, &left ) == 0 &&
toku__lt_point_cmp(buf[i].right, &right) == 0 &&
buf[i].data == find_txn) return;
if (toku__lt_point_cmp(buf[i].ends.left, &left ) == 0 &&
toku__lt_point_cmp(buf[i].ends.right, &right) == 0 &&
buf[i].data == find_txn) { goto cleanup; }
}
assert(FALSE); //Crash since we didn't find it.
cleanup:
stop_fake_comparison_functions();
}
......@@ -181,13 +200,13 @@ void insert_1(BOOL dups, int key_l, int key_r, int data_l, int data_r,
setup_tree(dups);
r = toku_lt_acquire_range_read_lock(lt, txn, key_left, data_left,
r = toku_lt_acquire_range_read_lock(lt, db, txn, key_left, data_left,
key_right, data_right);
CKERR(r);
close_tree();
setup_tree(dups);
r = toku_lt_acquire_read_lock(lt, txn, key_left, data_left);
r = toku_lt_acquire_read_lock(lt, db, txn, key_left, data_left);
CKERR(r);
close_tree();
}
......@@ -220,7 +239,7 @@ void insert_2_noclose(BOOL dups, int key_l[2], int key_r[2],
if (kl[i]) key_left[i] = (DBT*)kl[i];
if (kr[i]) key_right[i] = (DBT*)kr[i];
r = toku_lt_acquire_range_read_lock(lt, txn, key_left[i], data_left[i],
r = toku_lt_acquire_range_read_lock(lt, db, txn, key_left[i], data_left[i],
key_right[i], data_right[i]);
CKERR(r);
......@@ -263,7 +282,6 @@ void runtest(BOOL dups) {
lt_insert(dups,
dups ? 3 : 4, 4,
dups ? 3 : 5, 5);
rt = toku__lt_ifexist_selfread(lt, txn);
assert(rt);
......
......@@ -8,6 +8,7 @@ int main(int argc, const char *argv[]) {
int r;
parse_args(argc, argv);
/* ********************************************************************** */
rth = NULL;
for (failon = 1; failon <= 2; failon++) {
......@@ -22,6 +23,8 @@ int main(int argc, const char *argv[]) {
toku_rth_close(rth);
rth = NULL;
/* ********************************************************************** */
size_t i;
size_t iterations = 512 << 2;
......@@ -29,41 +32,44 @@ int main(int argc, const char *argv[]) {
CKERR(r);
assert(rth);
for (i = 1; i < iterations; i++) {
r = toku_rth_insert(rth, (DB_TXN*)i);
r = toku_rth_insert(rth, (TXNID)i);
CKERR(r);
}
toku_rt_forest* f;
for (i = 1; i < iterations; i++) {
f = toku_rth_find(rth, (DB_TXN*)i);
f = toku_rth_find(rth, (TXNID)i);
assert(f);
}
f = toku_rth_find(rth, (DB_TXN*)i);
f = toku_rth_find(rth, (TXNID)i);
assert(!f);
for (i = iterations - 1; i >= 1; i--) {
toku_rth_delete(rth, (DB_TXN*)i);
toku_rth_delete(rth, (TXNID)i);
}
toku_rth_close(rth);
rth = NULL;
/* ********************************************************************** */
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
for (i = 1; i < iterations; i++) {
r = toku_rth_insert(rth, (DB_TXN*)i);
r = toku_rth_insert(rth, (TXNID)i);
CKERR(r);
}
for (i = 1; i < iterations; i++) {
toku_rth_delete(rth, (DB_TXN*)i);
toku_rth_delete(rth, (TXNID)i);
}
toku_rth_close(rth);
rth = NULL;
/* ********************************************************************** */
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
for (i = iterations - 1; i >= 1; i--) {
r = toku_rth_insert(rth, (DB_TXN*)i);
r = toku_rth_insert(rth, (TXNID)i);
CKERR(r);
}
toku_rth_close(rth);
......@@ -74,9 +80,23 @@ int main(int argc, const char *argv[]) {
r = toku_rth_create(&rth, fail_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
r = toku_rth_insert(rth, (DB_TXN*)1);
r = toku_rth_insert(rth, (TXNID)1);
CKERR2(r, ENOMEM);
toku_rth_close(rth);
rth = NULL;
/* ********************************************************************** */
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
for (i = iterations - 1; i >= 1; i--) {
r = toku_rth_insert(rth, (TXNID)i);
CKERR(r);
}
toku_rth_clear(rth);
assert(toku_rth_is_empty(rth));
rth = NULL;
return 0;
}
......@@ -2,8 +2,8 @@
#include "test.h"
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, TXNID txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, TXNID txn);
int r;
toku_lock_tree* lt = NULL;
......@@ -17,13 +17,13 @@ DBT _key_left[2];
DBT _key_right[2];
DBT _data_left[2];
DBT _data_right[2];
DBT* key_left[2] ;
DBT* key_right[2] ;
DBT* data_left [2] ;
DBT* data_right[2] ;
DBT* key_left[2];
DBT* key_right[2];
DBT* data_left [2];
DBT* data_right[2];
toku_point qleft, qright;
toku_range query;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
......@@ -47,10 +47,13 @@ void init_query(BOOL dups) {
void setup_tree(BOOL dups) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, db, dups, dbpanic, ltm, dbcmp, dbcmp,
r = toku_lt_create(&lt, dups, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
......@@ -104,13 +107,14 @@ void lt_insert(BOOL dups, int r_expect, char txn, int key_l, int data_l,
assert(!read_flag || (key_right && !data_right));
}
DB_TXN* local_txn = (DB_TXN*) (size_t) txn;
TXNID local_txn = (TXNID) (size_t) txn;
if (read_flag)
r = toku_lt_acquire_range_read_lock(lt, local_txn, key_left, data_left,
r = toku_lt_acquire_range_read_lock(lt, db, local_txn,
key_left, data_left,
key_right, data_right);
else
r = toku_lt_acquire_write_lock(lt, local_txn, key_left, data_left);
r = toku_lt_acquire_write_lock(lt, db, local_txn, key_left, data_left);
CKERR2(r, r_expect);
}
......@@ -149,7 +153,7 @@ void lt_find(BOOL dups, toku_range_tree* rt,
CKERR(r);
assert(numfound==k);
DB_TXN* find_txn = (DB_TXN *) (size_t) char_txn;
TXNID find_txn = (TXNID) (size_t) char_txn;
toku_point left, right;
init_point(&left, lt);
......@@ -166,8 +170,8 @@ void lt_find(BOOL dups, toku_range_tree* rt,
}
unsigned i;
for (i = 0; i < numfound; i++) {
if (toku__lt_point_cmp(buf[i].left, &left ) == 0 &&
toku__lt_point_cmp(buf[i].right, &right) == 0 &&
if (toku__lt_point_cmp(buf[i].ends.left, &left ) == 0 &&
toku__lt_point_cmp(buf[i].ends.right, &right) == 0 &&
buf[i].data == find_txn) return;
}
assert(FALSE); //Crash since we didn't find it.
......@@ -175,7 +179,7 @@ void lt_find(BOOL dups, toku_range_tree* rt,
void lt_unlock(char ctxn) {
int r;
r = toku_lt_unlock(lt, (DB_TXN *) (size_t) ctxn);
r = toku_lt_unlock(lt, (TXNID) (size_t) ctxn);
CKERR(r);
}
......
......@@ -2,8 +2,8 @@
#include "test.h"
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, TXNID txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, TXNID txn);
int r;
toku_lock_tree* lt = NULL;
......@@ -23,7 +23,7 @@ DBT* data_left [2] ;
DBT* data_right[2] ;
toku_point qleft, qright;
toku_range query;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
......@@ -47,10 +47,13 @@ void init_query(BOOL dups) {
void setup_tree(BOOL dups) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, toku_malloc, toku_free, toku_realloc);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, db, dups, dbpanic, ltm, intcmp, intcmp,
r = toku_lt_create(&lt, dups, dbpanic, ltm,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
......@@ -104,13 +107,14 @@ void lt_insert(BOOL dups, int r_expect, char txn, int key_l, int data_l,
assert(!read_flag || (key_right && !data_right));
}
DB_TXN* local_txn = (DB_TXN*) (size_t) txn;
TXNID local_txn = (TXNID) (size_t) txn;
if (read_flag)
r = toku_lt_acquire_range_read_lock(lt, local_txn, key_left, data_left,
r = toku_lt_acquire_range_read_lock(lt, db, local_txn,
key_left, data_left,
key_right, data_right);
else
r = toku_lt_acquire_write_lock(lt, local_txn, key_left, data_left);
r = toku_lt_acquire_write_lock(lt, db, local_txn, key_left, data_left);
CKERR2(r, r_expect);
}
......@@ -140,16 +144,30 @@ void setup_payload_len(void** payload, u_int32_t* len, int val) {
}
}
void temporarily_fake_comparison_functions(void) {
assert(!lt->db && !lt->compare_fun && !lt->dup_compare);
lt->db = db;
lt->compare_fun = get_compare_fun_from_db(db);
lt->dup_compare = get_dup_compare_from_db(db);
}
void stop_fake_comparison_functions(void) {
assert(lt->db && lt->compare_fun && lt->dup_compare);
lt->db = NULL;
lt->compare_fun = NULL;
lt->dup_compare = NULL;
}
void lt_find(BOOL dups, toku_range_tree* rt,
unsigned k, int key_l, int data_l,
int key_r, int data_r,
char char_txn) {
temporarily_fake_comparison_functions();
r = toku_rt_find(rt, &query, 0, &buf, &buflen, &numfound);
CKERR(r);
assert(numfound==k);
DB_TXN* find_txn = (DB_TXN *) (size_t) char_txn;
TXNID find_txn = (TXNID) (size_t) char_txn;
toku_point left, right;
init_point(&left, lt);
......@@ -166,16 +184,18 @@ void lt_find(BOOL dups, toku_range_tree* rt,
}
unsigned i;
for (i = 0; i < numfound; i++) {
if (toku__lt_point_cmp(buf[i].left, &left ) == 0 &&
toku__lt_point_cmp(buf[i].right, &right) == 0 &&
buf[i].data == find_txn) return;
if (toku__lt_point_cmp(buf[i].ends.left, &left ) == 0 &&
toku__lt_point_cmp(buf[i].ends.right, &right) == 0 &&
buf[i].data == find_txn) { goto cleanup; }
}
assert(FALSE); //Crash since we didn't find it.
cleanup:
stop_fake_comparison_functions();
}
void lt_unlock(char ctxn) {
int r;
r = toku_lt_unlock(lt, (DB_TXN *) (size_t) ctxn);
r = toku_lt_unlock(lt, (TXNID) (size_t) ctxn);
CKERR(r);
}
......@@ -507,6 +527,8 @@ void init_test(void) {
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
compare_fun = intcmp;
dup_compare = intcmp;
}
......
......@@ -7,40 +7,86 @@ toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn);
int r;
toku_lock_tree* lt = NULL;
toku_lock_tree* lt [10] = {0};
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
u_int32_t max_locks = 10;
BOOL duplicates = FALSE;
int nums[10000];
void setup_tree(BOOL dups) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, toku_malloc, toku_free, toku_realloc);
void setup_ltm(void) {
assert(!ltm);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, db, dups, dbpanic, ltm, intcmp, intcmp,
toku_malloc, toku_free, toku_realloc);
}
void setup_tree(BOOL dups, size_t index, toku_db_id* db_id) {
assert(!lt[index] && ltm);
r = toku_ltm_get_lt(ltm, &lt[index], dups, db_id);
CKERR(r);
assert(lt);
assert(lt[index]);
}
void close_ltm(void) {
assert(lt && ltm);
assert(ltm);
r = toku_ltm_close(ltm);
CKERR(r);
lt = NULL;
u_int32_t i = 0;
for (i = 0; i < sizeof(lt)/sizeof(*lt); i++) { lt[i] = NULL; }
ltm = NULL;
}
void run_test(BOOL dups) {
setup_tree(dups);
toku_db_id* db_id = NULL;
r = toku_db_id_create(&db_id, DIR, "subdb");
CKERR(r);
assert(db_id);
toku_db_id* db_id2 = NULL;
r = toku_db_id_create(&db_id2, DIR, "subdb2");
CKERR(r);
assert(db_id);
toku_db_id* db_id3 = NULL;
r = toku_db_id_create(&db_id3, DIR, "subdb");
CKERR(r);
assert(db_id);
setup_ltm();
setup_tree(dups, 0, db_id);
setup_tree(dups, 1, db_id);
assert(lt[0] == lt[1]);
setup_tree(dups, 2, db_id2);
assert(lt[0] != lt[2]);
setup_tree(dups, 3, db_id3);
assert(lt[0] == lt[3]);
toku_ltm_invalidate_lt(ltm, db_id);
setup_tree(dups, 4, db_id);
assert(lt[0] != lt[4]);
setup_tree(dups, 5, db_id);
assert(lt[0] != lt[5]);
assert(lt[4] == lt[5]);
close_ltm();
toku_db_id_remove_ref(db_id);
toku_db_id_remove_ref(db_id2);
toku_db_id_remove_ref(db_id3);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
compare_fun = intcmp;
dup_compare = intcmp;
system("rm -rf " DIR);
mkdir(DIR, 0777);
run_test(FALSE);
run_test(TRUE);
......
/* Test for a memory leak from just closing the lock tree manager (should close
all lock trees. */
#include "test.h"
toku_range_tree* toku__lt_ifexist_selfwrite(toku_lock_tree* tree, DB_TXN* txn);
toku_range_tree* toku__lt_ifexist_selfread(toku_lock_tree* tree, DB_TXN* txn);
void initial_setup(void);
static int r;
static u_int32_t lt_refs[100];
static toku_lock_tree* lts [100];
static toku_ltm* ltm = NULL;
static toku_db_id* db_ids[100];
static char subdb [100][5];
static u_int32_t max_locks = 10;
int nums[10000];
void setup_ltm(void) {
assert(!ltm);
r = toku_ltm_create(&ltm, max_locks, dbpanic,
get_compare_fun_from_db, get_dup_compare_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
}
void db_open_tree(BOOL dups, size_t index, size_t db_id_index) {
assert((lt_refs[index] == 0 && !lts[index]) ||
(lt_refs[index] > 0 && lts[index]));
assert(ltm);
lt_refs[index]++;
r = toku_ltm_get_lt(ltm, &lts[index], dups, db_ids[db_id_index]);
CKERR(r);
assert(lts[index]);
}
void db_close_tree(size_t index) {
assert(lts[index] && ltm && lt_refs[index] > 0);
r = toku_lt_remove_ref(lts[index]); CKERR(r);
lt_refs[index]--;
if (lt_refs[index] == 0) { lts[index] = NULL; }
}
void txn_open_tree(size_t index) {
assert(lts[index] && ltm && lt_refs[index] > 0);
toku_lt_add_ref(lts[index]);
lt_refs[index]++;
}
void txn_close_tree(size_t index) {
assert(lts[index] && ltm && lt_refs[index] > 0);
r = toku_lt_remove_ref(lts[index]); CKERR(r);
lt_refs[index]--;
if (lt_refs[index] == 0) { lts[index] = NULL; }
}
void close_ltm(void) {
assert(ltm);
r = toku_ltm_close(ltm);
CKERR(r);
initial_setup();
ltm = NULL;
}
void run_test(BOOL dups) {
setup_ltm();
//Start:
/* ********************************************************************** */
//Open and close.
db_open_tree(dups, 0, 0);
db_close_tree(0);
/* ********************************************************************** */
//Open with db and transaction, db closes first.
db_open_tree(dups, 0, 0);
txn_open_tree(0);
db_close_tree(0);
txn_close_tree(0);
/* ********************************************************************** */
//Open with db and transaction, txn closes first.
db_open_tree(dups, 0, 0);
txn_open_tree(0);
txn_close_tree(0);
db_close_tree(0);
/* ********************************************************************** */
//Open with multiple db handles.
db_open_tree(dups, 0, 0);
db_open_tree(dups, 0, 0);
db_close_tree(0);
db_close_tree(0);
/* ********************************************************************** */
//Open with multiple db handles and txns.
db_open_tree(dups, 0, 0);
txn_open_tree(0);
db_open_tree(dups, 0, 0);
db_close_tree(0);
db_close_tree(0);
txn_close_tree(0);
/* ********************************************************************** */
//Open with multiple db handles and txns.
db_open_tree(dups, 0, 0);
db_open_tree(dups, 0, 0);
txn_open_tree(0);
db_close_tree(0);
db_close_tree(0);
txn_close_tree(0);
/* ********************************************************************** */
//End:
close_ltm();
}
void initial_setup(void) {
u_int32_t i;
ltm = NULL;
assert(sizeof(db_ids) / sizeof(db_ids[0]) == sizeof(lts) / sizeof(lts[0]));
assert(sizeof(subdb) / sizeof(subdb[0]) == sizeof(lts) / sizeof(lts[0]));
for (i = 0; i < sizeof(lts) / sizeof(lts[0]); i++) {
lts[i] = NULL;
sprintf(subdb[i], "%05x", i);
if (!db_ids[i]) toku_db_id_create(&db_ids[i], DIR, subdb[i]);
assert(db_ids[i]);
lt_refs[i] = 0;
}
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
compare_fun = intcmp;
dup_compare = intcmp;
system("rm -rf " DIR);
mkdir(DIR, 0777);
initial_setup();
run_test(FALSE);
run_test(TRUE);
return 0;
}
......@@ -70,7 +70,7 @@ static inline int toku__rt_increase_capacity(toku_range_tree* tree,
}
static inline BOOL toku__rt_overlap(toku_range_tree* tree,
toku_range* a, toku_range* b) {
toku_interval* a, toku_interval* b) {
assert(tree);
assert(a);
assert(b);
......@@ -85,14 +85,14 @@ static inline BOOL toku__rt_exact(toku_range_tree* tree,
assert(a);
assert(b);
return (tree->end_cmp (a->left, b->left) == 0 &&
tree->end_cmp (a->right, b->right) == 0 &&
return (tree->end_cmp (a->ends.left, b->ends.left) == 0 &&
tree->end_cmp (a->ends.right, b->ends.right) == 0 &&
tree->data_cmp(a->data, b->data) == 0);
}
int toku_rt_create(toku_range_tree** ptree,
int (*end_cmp)(const toku_point*,const toku_point*),
int (*data_cmp)(const DB_TXN*,const DB_TXN*),
int (*data_cmp)(const TXNID,const TXNID),
BOOL allow_overlaps,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
......@@ -122,6 +122,13 @@ int toku_rt_create(toku_range_tree** ptree,
return 0;
}
void toku_rt_clear(toku_range_tree* tree) {
assert(tree);
toku__rt_decrease_capacity(tree, 0);
toku_rt_invalidate_iteration(tree);
tree->numelements = 0;
}
int toku_rt_close(toku_range_tree* tree) {
if (!tree) return EINVAL;
tree->free(tree->i.ranges);
......@@ -129,10 +136,9 @@ int toku_rt_close(toku_range_tree* tree) {
return 0;
}
int toku_rt_find(toku_range_tree* tree, toku_range* query, u_int32_t k,
int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
if (!tree || !query || !buf || !buflen || !numfound) return EINVAL;
if (query->data != NULL) return EINVAL;
if (*buflen == 0) return EINVAL;
u_int32_t temp_numfound = 0;
......@@ -140,7 +146,7 @@ int toku_rt_find(toku_range_tree* tree, toku_range* query, u_int32_t k,
u_int32_t i;
for (i = 0; i < tree->numelements; i++) {
if (toku__rt_overlap(tree, query, &tree->i.ranges[i])) {
if (toku__rt_overlap(tree, query, &tree->i.ranges[i].ends)) {
r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1);
if (r != 0) return r;
(*buf)[temp_numfound++] = tree->i.ranges[i];
......@@ -166,7 +172,7 @@ int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
}
else {
for (i = 0; i < tree->numelements; i++) {
if (toku__rt_overlap(tree, range, &tree->i.ranges[i])) return EDOM;
if (toku__rt_overlap(tree, &range->ends, &tree->i.ranges[i].ends)) return EDOM;
}
}
r = toku__rt_increase_capacity(tree, tree->numelements + 1);
......@@ -202,8 +208,8 @@ int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
u_int32_t i;
for (i = 0; i < tree->numelements; i++) {
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i]) > 0 &&
(!best || tree->end_cmp(best->left, tree->i.ranges[i].left) < 0)) {
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i].ends) > 0 &&
(!best || tree->end_cmp(best->ends.left, tree->i.ranges[i].ends.left) < 0)) {
best = &tree->i.ranges[i];
}
}
......@@ -220,8 +226,8 @@ int toku_rt_successor (toku_range_tree* tree, toku_point* point,
u_int32_t i;
for (i = 0; i < tree->numelements; i++) {
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i]) < 0 &&
(!best || tree->end_cmp(best->left, tree->i.ranges[i].left) > 0)) {
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i].ends) < 0 &&
(!best || tree->end_cmp(best->ends.left, tree->i.ranges[i].ends.left) > 0)) {
best = &tree->i.ranges[i];
}
}
......
......@@ -61,7 +61,7 @@ static inline void toku_rt_invalidate_iteration(toku_range_tree* tree) {
//FIRST PASS
int toku_rt_create(toku_range_tree** ptree,
int (*end_cmp)(const toku_point*,const toku_point*),
int (*data_cmp)(const DB_TXN*,const DB_TXN*),
int (*data_cmp)(const TXNID,const TXNID),
BOOL allow_overlaps,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
......@@ -100,6 +100,13 @@ int toku_rt_close(toku_range_tree* tree) {
return 0;
}
void toku_rt_clear(toku_range_tree* tree) {
assert(tree);
toku_rbt_clear(tree->i.rbt);
toku_rt_invalidate_iteration(tree);
tree->numelements = 0;
}
/*
5- FindOverlaps
O(lg N+1) CMPs Do a lookup (<=) (out found, out elementpointer)
......@@ -115,12 +122,11 @@ int toku_rt_close(toku_range_tree* tree) {
add found to buffer
(0) CMPs do a finger_successor(elementpointer) (out found, out elementpointer)
*/
int toku_rt_find(toku_range_tree* tree, toku_range* query, u_int32_t k,
int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
int r = ENOSYS;
if (!tree || !query || !buf || !buflen || !numfound ||
query->data != NULL || *buflen == 0) {
if (!tree || !query || !buf || !buflen || !numfound || *buflen == 0) {
r = EINVAL; goto cleanup;
}
assert(!tree->allow_overlaps);
......@@ -136,7 +142,7 @@ int toku_rt_find(toku_range_tree* tree, toku_range* query, u_int32_t k,
r = toku_rbt_lookup(RB_LULTEQ, query, tree->i.rbt, &ignore_insert, &succ_finger, &data);
if (r!=0) { goto cleanup; }
if (data != NULL) {
if (tree->end_cmp(data->right, query->left) >= 0) {
if (tree->end_cmp(data->ends.right, query->left) >= 0) {
r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1);
if (r!=0) { goto cleanup; }
(*buf)[temp_numfound++] = *data;
......@@ -152,7 +158,7 @@ int toku_rt_find(toku_range_tree* tree, toku_range* query, u_int32_t k,
}
while (temp_numfound < k && data != NULL) {
if (tree->end_cmp(data->left, query->right) > 0) { break; }
if (tree->end_cmp(data->ends.left, query->right) > 0) { break; }
r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1);
if (r!=0) { goto cleanup; }
(*buf)[temp_numfound++] = *data;
......@@ -188,10 +194,10 @@ int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
struct toku_rbt_node* succ_finger = NULL;
toku_range* data = NULL;
r = toku_rbt_lookup(RB_LULTEQ, range, tree->i.rbt, &insert_finger, &succ_finger, &data);
r = toku_rbt_lookup(RB_LULTEQ, &range->ends, tree->i.rbt, &insert_finger, &succ_finger, &data);
if (r!=0) { goto cleanup; }
if (data != NULL) {
if (tree->end_cmp(data->right, range->left) >= 0) {
if (tree->end_cmp(data->ends.right, range->ends.left) >= 0) {
r = EDOM; goto cleanup;
}
r = toku_rbt_finger_successor(&succ_finger, &data);
......@@ -201,7 +207,7 @@ int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
r = toku_rbt_lookup(RB_LUFIRST, NULL, tree->i.rbt, &ignore_insert, &succ_finger, &data);
if (r!=0) { goto cleanup; }
}
if (data != NULL && tree->end_cmp(data->left, range->right) <= 0) {
if (data != NULL && tree->end_cmp(data->ends.left, range->ends.right) <= 0) {
r = EDOM; goto cleanup;
}
r = toku_rbt_finger_insert(range, tree->i.rbt, insert_finger);
......@@ -237,12 +243,12 @@ int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
struct toku_rbt_node* delete_finger = NULL;
toku_range* data = NULL;
r = toku_rbt_lookup(RB_LUEQUAL, range, tree->i.rbt,
r = toku_rbt_lookup(RB_LUEQUAL, &range->ends, tree->i.rbt,
&ignore_insert, &delete_finger, &data);
if (r!=0) { goto cleanup; }
if (!data ||
tree->data_cmp(data->data, range->data) != 0 ||
tree->end_cmp(data->right, range->right) != 0) {
tree->end_cmp(data->ends.right, range->ends.right) != 0) {
r = EDOM; goto cleanup;
}
......@@ -279,12 +285,11 @@ int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
struct toku_rbt_node* ignore_insert = NULL;
struct toku_rbt_node* pred_finger = NULL;
toku_range* data = NULL;
toku_range range;
range.left = point;
range.right = point;
range.data = NULL;
toku_interval query;
query.left = point;
query.right = point;
r = toku_rbt_lookup(RB_LULESS, &range, tree->i.rbt, &ignore_insert, &pred_finger, &data);
r = toku_rbt_lookup(RB_LULESS, &query, tree->i.rbt, &ignore_insert, &pred_finger, &data);
if (r!=0) { goto cleanup; }
if (!data) {
......@@ -292,7 +297,7 @@ int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
r = 0;
goto cleanup;
}
if (tree->end_cmp(data->right, point) < 0) {
if (tree->end_cmp(data->ends.right, point) < 0) {
*wasfound = TRUE;
*pred = *data;
r = 0;
......@@ -329,12 +334,11 @@ int toku_rt_successor (toku_range_tree* tree, toku_point* point,
struct toku_rbt_node* ignore_insert = NULL;
struct toku_rbt_node* succ_finger = NULL;
toku_range* data = NULL;
toku_range range;
range.left = point;
range.right = point;
range.data = NULL;
toku_interval query;
query.left = point;
query.right = point;
r = toku_rbt_lookup(RB_LUGREAT, &range, tree->i.rbt, &ignore_insert, &succ_finger, &data);
r = toku_rbt_lookup(RB_LUGREAT, &query, tree->i.rbt, &ignore_insert, &succ_finger, &data);
if (r!=0) { goto cleanup; }
if (!data) {
......
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved."
......@@ -23,7 +24,7 @@ struct __toku_range_tree {
int (*end_cmp)(const toku_point*,const toku_point*);
/** A comparison function, as in bsearch(3), to compare the data associated
with a range */
int (*data_cmp)(const DB_TXN*,const DB_TXN*);
int (*data_cmp)(const TXNID,const TXNID);
/** Whether this tree allows ranges to overlap */
BOOL allow_overlaps;
/** The number of ranges in the range tree */
......@@ -45,9 +46,9 @@ struct __toku_range_tree {
* > 0: Point strictly greater than the range.
*/
static inline int toku__rt_p_cmp(toku_range_tree* tree,
toku_point* point, toku_range* range) {
if (tree->end_cmp(point, range->left) < 0) return -1;
if (tree->end_cmp(point, range->right) > 0) return 1;
toku_point* point, toku_interval* interval) {
if (tree->end_cmp(point, interval->left) < 0) return -1;
if (tree->end_cmp(point, interval->right) > 0) return 1;
return 0;
}
......@@ -70,7 +71,7 @@ static inline int toku__rt_increase_buffer(toku_range_tree* tree, toku_range** b
static inline int toku_rt_super_create(toku_range_tree** upperptree,
toku_range_tree** ptree,
int (*end_cmp)(const toku_point*,const toku_point*),
int (*data_cmp)(const DB_TXN*,const DB_TXN*),
int (*data_cmp)(const TXNID,const TXNID),
BOOL allow_overlaps,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
......
......@@ -34,9 +34,12 @@ typedef struct __toku_point toku_point;
typedef struct {
toku_point* left; /**< Left end-point */
toku_point* right; /**< Right end-point */
DB_TXN* data; /**< Data associated with the range */
} toku_range;
} toku_interval;
typedef struct {
toku_interval ends;
TXNID data; /**< Data associated with the range */
} toku_range;
/** Export the internal representation to a sensible name */
/* These lines will remain. */
......@@ -84,7 +87,7 @@ int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed);
- Other exit codes may be forwarded from underlying system calls. */
int toku_rt_create(toku_range_tree** ptree,
int (*end_cmp)(const toku_point*,const toku_point*),
int (*data_cmp)(const DB_TXN*,const DB_TXN*),
int (*data_cmp)(const TXNID,const TXNID),
BOOL allow_overlaps,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
......@@ -101,6 +104,13 @@ int toku_rt_create(toku_range_tree** ptree,
*/
int toku_rt_close(toku_range_tree* tree);
/**
Deletes all elements of a range tree.
\param tree The range tree to clear.
*/
void toku_rt_clear(toku_range_tree* tree);
/**
Finds ranges in the range tree that overlap a query range.
......@@ -133,7 +143,7 @@ int toku_rt_close(toku_range_tree* tree);
parameter to specify whether more elements exist in the tree that overlap
(in excess of the requested limit of k).
*/
int toku_rt_find(toku_range_tree* tree,toku_range* query, u_int32_t k,
int toku_rt_find(toku_range_tree* tree,toku_interval* query, u_int32_t k,
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound);
......
......@@ -45,7 +45,7 @@ int dummy_cmp(const toku_point *a __attribute__((__unused__)),
return 0;
}
int ptr_cmp(const DB_TXN* a, const DB_TXN* b) {
int TXNID_cmp(const TXNID a, const TXNID b) {
return a < b ? -1 : (a != b); /* \marginpar{!?} */
}
......@@ -55,9 +55,9 @@ int int_cmp(const toku_point* a, const toku_point*b) {
return x -y;
}
int char_cmp(const DB_TXN *a, const DB_TXN *b) {
int x = *(char*)a;
int y = *(char*)b;
int char_cmp(const TXNID a, const TXNID b) {
int x = (char)a;
int y = (char)b;
return x -y;
}
......@@ -83,3 +83,14 @@ void* fail_malloc(size_t size) {
}
return malloc(size);
}
void verify_all_overlap(toku_interval* query, toku_range* list, unsigned listlen) {
unsigned i;
for (i = 0; i < listlen; i++) {
/* Range A and B overlap iff A.left <= B.right && B.left <= A.right */
assert(int_cmp(query->left, list[i].ends.right) <= 0 &&
int_cmp(list[i].ends.left, query->right) <= 0);
}
}
......@@ -10,10 +10,10 @@ int main(int argc, const char *argv[]) {
parse_args(argc, argv);
/* Create tests */
r = toku_rt_create(NULL, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(NULL, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, NULL, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, NULL, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR2(r, EINVAL);
assert(tree == NULL);
......@@ -21,13 +21,13 @@ int main(int argc, const char *argv[]) {
r = toku_rt_create(&tree, int_cmp, NULL, FALSE, malloc, free, realloc);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, NULL, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, NULL, free, realloc);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, NULL, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, NULL, realloc);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, NULL);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, NULL);
CKERR2(r, EINVAL);
assert(tree == NULL);
......@@ -40,7 +40,7 @@ int main(int argc, const char *argv[]) {
r = toku_rt_insert(NULL, &range);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......@@ -53,7 +53,7 @@ int main(int argc, const char *argv[]) {
r = toku_rt_delete(NULL, &range);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......@@ -66,38 +66,33 @@ int main(int argc, const char *argv[]) {
unsigned found;
int stuff[3] = {0,1,2};
range.left = (toku_point*)&stuff[0];
range.right = (toku_point*)&stuff[1];
range.data = NULL;
range.ends.left = (toku_point*)&stuff[0];
range.ends.right = (toku_point*)&stuff[1];
range.data = 0;
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
r = toku_rt_find(NULL, &range, 2, &buf, &bufsize, &found);
r = toku_rt_find(NULL, &range.ends, 2, &buf, &bufsize, &found);
CKERR2(r, EINVAL);
r = toku_rt_find(tree, NULL, 2, &buf, &bufsize, &found);
CKERR2(r, EINVAL);
range.data = (DB_TXN*)&stuff[2];
r = toku_rt_find(tree, &range, 2, &buf, &bufsize, &found);
r = toku_rt_find(tree, &range.ends, 2, NULL, &bufsize, &found);
CKERR2(r, EINVAL);
range.data = NULL;
r = toku_rt_find(tree, &range, 2, NULL, &bufsize, &found);
CKERR2(r, EINVAL);
r = toku_rt_find(tree, &range, 2, &buf, NULL, &found);
r = toku_rt_find(tree, &range.ends, 2, &buf, NULL, &found);
CKERR2(r, EINVAL);
unsigned oldbufsize = bufsize;
bufsize = 0;
r = toku_rt_find(tree, &range, 2, &buf, &bufsize, &found);
r = toku_rt_find(tree, &range.ends, 2, &buf, &bufsize, &found);
CKERR2(r, EINVAL);
bufsize = oldbufsize;
r = toku_rt_find(tree, &range, 2, &buf, &bufsize, NULL);
r = toku_rt_find(tree, &range.ends, 2, &buf, &bufsize, NULL);
CKERR2(r, EINVAL);
r = toku_rt_close(tree); CKERR(r);
......@@ -105,7 +100,7 @@ int main(int argc, const char *argv[]) {
/* Predecessor tests */
toku_point* foo = (toku_point*)&stuff[0];
BOOL wasfound;
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......@@ -124,7 +119,7 @@ int main(int argc, const char *argv[]) {
r = toku_rt_close(tree); CKERR(r);
#ifndef TOKU_RT_NOOVERLAPS
r = toku_rt_create(&tree, int_cmp, ptr_cmp, TRUE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, TRUE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......@@ -138,7 +133,7 @@ int main(int argc, const char *argv[]) {
/* Successor tests */
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......@@ -157,7 +152,7 @@ int main(int argc, const char *argv[]) {
r = toku_rt_close(tree); CKERR(r);
#ifndef TOKU_RT_NOOVERLAPS
r = toku_rt_create(&tree, int_cmp, ptr_cmp, TRUE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, TRUE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......@@ -174,7 +169,7 @@ int main(int argc, const char *argv[]) {
r = toku_rt_get_allow_overlaps(NULL, &allowed);
CKERR2(r, EINVAL);
r = toku_rt_create(&tree, int_cmp, ptr_cmp, FALSE, malloc, free, realloc);
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, malloc, free, realloc);
CKERR(r);
assert(tree != NULL);
......
......@@ -25,80 +25,80 @@ int main(int argc, const char *argv[]) {
CKERR(r);
/* Verify we can insert a trivial range and lose it. */
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[1];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[1];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
u_int32_t num_in_range;
r = toku_rt_get_size(tree, &num_in_range); CKERR(r);
assert(num_in_range == 1);
r = toku_rt_delete(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[5];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[5];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
/* Try and fail to insert exact same thing. */
r = toku_rt_insert(tree, &range); CKERR2(r,EDOM);
/* Try and succeed to insert (and delete) similar yet different things */
range.right = (toku_point*)&nums[6];
range.ends.right = (toku_point*)&nums[6];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_delete(tree, &range); CKERR(r);
range.right = (toku_point*)&nums[5];
range.data = (DB_TXN*)&letters[1];
range.ends.right = (toku_point*)&nums[5];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_delete(tree, &range); CKERR(r);
range.data = (DB_TXN*)&letters[0];
range.data = (TXNID)letters[0];
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[3];
range.right = (toku_point*)&nums[7];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[3];
range.ends.right = (toku_point*)&nums[7];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
/* Try to delete again, make sure it fails. (Not there anymore) */
r = toku_rt_delete(tree, &range); CKERR2(r,EDOM);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_delete(tree, &range); CKERR(r);
/* Clean up. */
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[5];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[5];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[3];
range.right = (toku_point*)&nums[7];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[3];
range.ends.right = (toku_point*)&nums[7];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
/* Done */
......@@ -116,60 +116,60 @@ int main(int argc, const char *argv[]) {
CKERR(r);
/* Verify we can insert a trivial range and lose it. */
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[1];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[1];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_delete(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[3];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[3];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
/* Try and fail to insert exact same thing. */
r = toku_rt_insert(tree, &range); CKERR2(r,EDOM);
/* Try (and fail) to insert an overlapping range in a nooverlap tree. */
range.left = (toku_point*)&nums[0];
range.right = (toku_point*)&nums[4];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[0];
range.ends.right = (toku_point*)&nums[4];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR2(r,EDOM);
/* Try (and fail) to insert an overlapping range (different data) in a
nooverlap tree. */
range.left = (toku_point*)&nums[0];
range.right = (toku_point*)&nums[4];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[0];
range.ends.right = (toku_point*)&nums[4];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR2(r,EDOM);
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_delete(tree, &range); CKERR(r);
/* Try to delete again, make sure it fails. (Not there anymore) */
r = toku_rt_delete(tree, &range); CKERR2(r,EDOM);
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[3];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[3];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
/* Clean up. */
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_delete(tree, &range); CKERR(r);
/* Done */
......
......@@ -35,18 +35,18 @@ void RunTest (BOOL f_overlaps_allowed) {
/* Insert lots of ranges */
for (i = 0; i < 512; i++) {
j = i + i;
range.left = (toku_point*)&nums[j];
range.right = (toku_point*)&nums[j+1];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[j];
range.ends.right = (toku_point*)&nums[j+1];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
}
/* Decrease lots of ranges */
for (i = 0; i < 512; i++) {
j = i + i;
range.left = (toku_point*)&nums[j];
range.right = (toku_point*)&nums[j+1];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[j];
range.ends.right = (toku_point*)&nums[j+1];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
}
......
......@@ -27,9 +27,9 @@ void run_test (BOOL overlap_allowed) {
);
CKERR(r);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[5];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[5];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_close(tree); CKERR(r);
......
......@@ -2,22 +2,12 @@
#include "test.h"
void verify_all_overlap(toku_range* query, toku_range* list, unsigned listlen) {
unsigned i;
for (i = 0; i < listlen; i++) {
/* Range A and B overlap iff A.left <= B.right && B.left <= A.right */
assert(int_cmp(query->left, list[i].right) <= 0 &&
int_cmp(list[i].left, query->right) <= 0);
}
}
int main(int argc, const char *argv[]) {
int r;
toku_range_tree *tree = NULL;
toku_range range;
toku_range find_range;
toku_range find_all_range;
toku_interval find_range;
toku_interval find_all_range;
int nums[1000];
char letters[2] = {'A','B'};
unsigned found;
......@@ -34,11 +24,9 @@ int main(int argc, const char *argv[]) {
find_range.left = (toku_point*)&nums[4];
find_range.right = (toku_point*)&nums[4];
find_range.data = NULL;
find_all_range.left = (toku_point*)&nums[0];
find_all_range.right = (toku_point*)&nums[sizeof(nums)/sizeof(nums[0]) - 1];
find_all_range.data = NULL;
#ifndef TOKU_RT_NOOVERLAPS
bufsize = 2;
......@@ -59,9 +47,9 @@ int main(int argc, const char *argv[]) {
assert(found == 0);
assert(bufsize == 2);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[5];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[5];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -69,9 +57,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize == 2);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -79,9 +67,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize == 2);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[3];
range.right = (toku_point*)&nums[7];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[3];
range.ends.right = (toku_point*)&nums[7];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
/* Now that we find 3, we are testing that realloc works. */
......@@ -90,9 +78,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= 3);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -101,9 +89,9 @@ int main(int argc, const char *argv[]) {
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -113,14 +101,14 @@ int main(int argc, const char *argv[]) {
/* Verify the right one is still there, and the wrong one is not there. */
for (i = 0; i < found; i++) {
assert(*(int*)buf[i].left != 2 ||
*(int*)buf[i].right != 6 ||
*(char*)buf[i].data == letters[1]);
assert(*(int*)buf[i].ends.left != 2 ||
*(int*)buf[i].ends.right != 6 ||
(char)buf[i].data == letters[1]);
}
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -128,9 +116,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= 4);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -140,15 +128,15 @@ int main(int argc, const char *argv[]) {
/* Verify the right one is still there, and the wrong one is not there. */
for (i = 0; i < found; i++) {
assert(*(int*)buf[i].left != 2 ||
*(int*)buf[i].right != 6 ||
*(char*)buf[i].data == letters[0]);
assert(*(int*)buf[i].ends.left != 2 ||
*(int*)buf[i].ends.right != 6 ||
(char)buf[i].data == letters[0]);
}
/* Clean up. */
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[5];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[5];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -156,9 +144,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= 4);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[2];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[2];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -167,13 +155,13 @@ int main(int argc, const char *argv[]) {
verify_all_overlap(&find_range, buf, found);
/* Verify the right one is still there, and the wrong one is not there. */
assert(*(int*)buf[0].left == 3 &&
*(int*)buf[0].right == 7 &&
*(char*)buf[0].data == letters[0]);
assert(*(int*)buf[0].ends.left == 3 &&
*(int*)buf[0].ends.right == 7 &&
(char)buf[0].data == letters[0]);
range.left = (toku_point*)&nums[3];
range.right = (toku_point*)&nums[7];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[3];
range.ends.right = (toku_point*)&nums[7];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -201,7 +189,6 @@ int main(int argc, const char *argv[]) {
*/
find_range.left = (toku_point*)&nums[3];
find_range.right = (toku_point*)&nums[4];
find_range.data = NULL;
r = toku_rt_create(&tree, int_cmp, char_cmp, FALSE, malloc, free, realloc);
CKERR(r);
......@@ -211,9 +198,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= 2);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[3];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[3];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -221,9 +208,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= 2);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -235,9 +222,9 @@ int main(int argc, const char *argv[]) {
const uint32_t start_loop = 100;
const uint32_t end_loop = 200;
for (i = start_loop; i < end_loop; i += 4) {
range.left = (toku_point*)&nums[i];
range.right = (toku_point*)&nums[i+2];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[i];
range.ends.right = (toku_point*)&nums[i+2];
range.data = (TXNID)letters[0];
r = toku_rt_insert(tree, &range); CKERR(r);
inserted++;
......@@ -246,17 +233,17 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= inserted);
}
for (i = start_loop; i < end_loop; i += 4) {
range.left = (toku_point*)&nums[i];
range.right = (toku_point*)&nums[i+2];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[i];
range.ends.right = (toku_point*)&nums[i+2];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
}
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -265,13 +252,13 @@ int main(int argc, const char *argv[]) {
verify_all_overlap(&find_range, buf, found);
/* Verify the right one is still there, and the wrong one is not there. */
assert(*(int*)buf[0].left == 1 &&
*(int*)buf[0].right == 3 &&
*(char*)buf[0].data == letters[0]);
assert(*(int*)buf[0].ends.left == 1 &&
*(int*)buf[0].ends.right == 3 &&
(char)buf[0].data == letters[0]);
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_insert(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -279,9 +266,9 @@ int main(int argc, const char *argv[]) {
assert(bufsize >= inserted);
verify_all_overlap(&find_range, buf, found);
range.left = (toku_point*)&nums[1];
range.right = (toku_point*)&nums[3];
range.data = (DB_TXN*)&letters[0];
range.ends.left = (toku_point*)&nums[1];
range.ends.right = (toku_point*)&nums[3];
range.data = (TXNID)letters[0];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......@@ -290,14 +277,14 @@ int main(int argc, const char *argv[]) {
verify_all_overlap(&find_range, buf, found);
/* Verify the right one is still there, and the wrong one is not there. */
assert(*(int*)buf[0].left == 4 &&
*(int*)buf[0].right == 6 &&
*(char*)buf[0].data == letters[1]);
assert(*(int*)buf[0].ends.left == 4 &&
*(int*)buf[0].ends.right == 6 &&
(char)buf[0].data == letters[1]);
/* Clean up. */
range.left = (toku_point*)&nums[4];
range.right = (toku_point*)&nums[6];
range.data = (DB_TXN*)&letters[1];
range.ends.left = (toku_point*)&nums[4];
range.ends.right = (toku_point*)&nums[6];
range.data = (TXNID)letters[1];
r = toku_rt_delete(tree, &range); CKERR(r);
r = toku_rt_find(tree, &find_range, 4, &buf, &bufsize, &found); CKERR(r);
......
......@@ -2,16 +2,6 @@
#include "test.h"
void verify_all_overlap(toku_range* query, toku_range* list, unsigned listlen) {
unsigned i;
for (i = 0; i < listlen; i++) {
/* Range A and B overlap iff A.left <= B.right && B.left <= A.right */
assert(int_cmp(query->left, list[i].right) <= 0 &&
int_cmp(list[i].left, query->right) <= 0);
}
}
int nums[200];
char letters[2] = {'A','B'};
......@@ -19,11 +9,16 @@ toku_range_tree *tree;
toku_range* buf;
unsigned buflen;
toku_range* init_range(toku_range* range, int left, int right, int data) {
toku_interval* init_query(toku_interval* range, int left, int right) {
range->left = (toku_point*)&nums[left];
range->right = (toku_point*)&nums[right];
if (data < 0) range->data = NULL;
else range->data = (DB_TXN*)&letters[data];
return range;
}
toku_range* init_range(toku_range* range, int left, int right, int data) {
init_query(&range->ends, left, right);
if (data < 0) range->data = 0;
else range->data = (TXNID)letters[data];
return range;
}
......@@ -43,7 +38,7 @@ void close_tree(void) {
r = toku_rt_close(tree); CKERR(r);
}
void runsearch(int rexpect, toku_range* query, toku_range* expect) {
void runsearch(int rexpect, toku_interval* query, toku_range* expect) {
int r;
unsigned found;
r = toku_rt_find(tree, query, 0, &buf, &buflen, &found);
......@@ -51,8 +46,8 @@ void runsearch(int rexpect, toku_range* query, toku_range* expect) {
if (rexpect != 0) return;
assert(found == 1);
assert(int_cmp(buf[0].left, expect->left) == 0 &&
int_cmp(buf[0].right, expect->right) == 0 &&
assert(int_cmp(buf[0].ends.left, expect->ends.left) == 0 &&
int_cmp(buf[0].ends.right, expect->ends.right) == 0 &&
char_cmp(buf[0].data, expect->data) == 0);
}
......@@ -62,7 +57,7 @@ void runinsert(int rexpect, toku_range* toinsert) {
CKERR2(r, rexpect);
}
void runlimitsearch(toku_range* query, unsigned limit, unsigned findexpect) {
void runlimitsearch(toku_interval* query, unsigned limit, unsigned findexpect) {
int r;
unsigned found;
r=toku_rt_find(tree, query, limit, &buf, &buflen, &found); CKERR(r);
......@@ -72,7 +67,7 @@ void runlimitsearch(toku_range* query, unsigned limit, unsigned findexpect) {
}
void tests(BOOL allow_overlaps) {
toku_range query;
toku_interval query;
toku_range insert;
/*
Limited/Unlimited Queries
......@@ -88,30 +83,30 @@ void tests(BOOL allow_overlaps) {
runinsert(0, init_range(&insert, 6, 7, 0));
runinsert(0, init_range(&insert, 8, 9, 0));
runlimitsearch(init_range(&query, 2, 7, -1), 0, 3);
runlimitsearch(init_range(&query, 2, 7, -1), 1, 1);
runlimitsearch(init_range(&query, 2, 7, -1), 2, 2);
runlimitsearch(init_range(&query, 2, 7, -1), 3, 3);
runlimitsearch(init_range(&query, 2, 7, -1), 4, 3);
runlimitsearch(init_query(&query, 2, 7), 0, 3);
runlimitsearch(init_query(&query, 2, 7), 1, 1);
runlimitsearch(init_query(&query, 2, 7), 2, 2);
runlimitsearch(init_query(&query, 2, 7), 3, 3);
runlimitsearch(init_query(&query, 2, 7), 4, 3);
close_tree();
/* Tree is empty (return none) */
setup_tree(allow_overlaps, FALSE, 0, 0, 0);
runlimitsearch(init_range(&query, 0, 0, -1), 0, 0);
runlimitsearch(init_query(&query, 0, 0), 0, 0);
close_tree();
/* Tree contains only elements to the left. */
setup_tree(allow_overlaps, FALSE, 0, 0, 0);
runinsert(0, init_range(&insert, 1, 2, 0));
runinsert(0, init_range(&insert, 3, 4, 0));
runlimitsearch(init_range(&query, 8, 30, -1), 0, 0);
runlimitsearch(init_query(&query, 8, 30), 0, 0);
close_tree();
/* Tree contains only elements to the right. */
setup_tree(allow_overlaps, FALSE, 0, 0, 0);
runinsert(0, init_range(&insert, 10, 20, 0));
runinsert(0, init_range(&insert, 30, 40, 0));
runlimitsearch(init_range(&query, 5, 7, -1), 0, 0);
runlimitsearch(init_query(&query, 5, 7), 0, 0);
close_tree();
/* Tree contains only elements to the left and to the right. */
......@@ -120,7 +115,7 @@ void tests(BOOL allow_overlaps) {
runinsert(0, init_range(&insert, 30, 40, 0));
runinsert(0, init_range(&insert, 70, 80, 0));
runinsert(0, init_range(&insert, 90, 100, 0));
runlimitsearch(init_range(&query, 60, 65, -1), 0, 0);
runlimitsearch(init_query(&query, 60, 65), 0, 0);
close_tree();
/* Tree contains overlaps and elements to the left. */
......@@ -129,7 +124,7 @@ void tests(BOOL allow_overlaps) {
runinsert(0, init_range(&insert, 30, 40, 0));
runinsert(0, init_range(&insert, 60, 80, 0));
runinsert(0, init_range(&insert, 90, 100, 0));
runlimitsearch(init_range(&query, 70, 95, -1), 0, 2);
runlimitsearch(init_query(&query, 70, 95), 0, 2);
close_tree();
/* Tree contains overlaps and elements to the right. */
......@@ -138,7 +133,7 @@ void tests(BOOL allow_overlaps) {
runinsert(0, init_range(&insert, 130, 140, 0));
runinsert(0, init_range(&insert, 60, 80, 0));
runinsert(0, init_range(&insert, 90, 100, 0));
runlimitsearch(init_range(&query, 70, 95, -1), 0, 2);
runlimitsearch(init_query(&query, 70, 95), 0, 2);
close_tree();
/* Tree contains overlaps and elements to the left and to the right. */
......@@ -149,7 +144,7 @@ void tests(BOOL allow_overlaps) {
runinsert(0, init_range(&insert, 130, 140, 0));
runinsert(0, init_range(&insert, 60, 80, 0));
runinsert(0, init_range(&insert, 90, 100, 0));
runlimitsearch(init_range(&query, 70, 95, -1), 0, 2);
runlimitsearch(init_query(&query, 70, 95), 0, 2);
close_tree();
}
......
......@@ -2,16 +2,6 @@
#include "test.h"
void verify_all_overlap(toku_range* query, toku_range* list, unsigned listlen) {
unsigned i;
for (i = 0; i < listlen; i++) {
/* Range A and B overlap iff A.left <= B.right && B.left <= A.right */
assert(int_cmp(query->left, list[i].right) <= 0 &&
int_cmp(list[i].left, query->right) <= 0);
}
}
int nums[8] = {0,1,2,3,4,5,6,7};
char letters[2] = {'A','B'};
......@@ -19,11 +9,16 @@ toku_range_tree *tree;
toku_range* buf;
unsigned buflen;
toku_range* init_range(toku_range* range, int left, int right, int data) {
toku_interval* init_query(toku_interval* range, int left, int right) {
range->left = (toku_point*)&nums[left];
range->right = (toku_point*)&nums[right];
if (data < 0) range->data = NULL;
else range->data = (DB_TXN*)&letters[data];
return range;
}
toku_range* init_range(toku_range* range, int left, int right, int data) {
init_query(&range->ends, left, right);
if (data < 0) range->data = 0;
else range->data = (TXNID)letters[data];
return range;
}
......@@ -40,7 +35,7 @@ void close_tree(void) {
r = toku_rt_close(tree); CKERR(r);
}
void runsearch(int rexpect, toku_range* query, toku_range* expect) {
void runsearch(int rexpect, toku_interval* query, toku_range* expect) {
int r;
unsigned found;
r = toku_rt_find(tree, query, 0, &buf, &buflen, &found);
......@@ -48,8 +43,8 @@ void runsearch(int rexpect, toku_range* query, toku_range* expect) {
if (rexpect != 0) return;
assert(found == 1);
assert(int_cmp(buf[0].left, expect->left) == 0 &&
int_cmp(buf[0].right, expect->right) == 0 &&
assert(int_cmp(buf[0].ends.left, expect->ends.left) == 0 &&
int_cmp(buf[0].ends.right, expect->ends.right) == 0 &&
char_cmp(buf[0].data, expect->data) == 0);
}
......@@ -71,7 +66,7 @@ void verify_overlap(BOOL allow_overlaps) {
void tests(BOOL allow_overlaps) {
toku_range expect;
toku_range query;
toku_interval query;
toku_range toinsert;
/*
......@@ -88,12 +83,12 @@ void tests(BOOL allow_overlaps) {
is set appropriately. */
setup_tree(allow_overlaps, 0, 1, 0);
verify_overlap(allow_overlaps);
runsearch(0, init_range(&query, 1, 2, -1), init_range(&expect, 0, 1, 0));
runsearch(0, init_query(&query, 1, 2), init_range(&expect, 0, 1, 0));
close_tree();
/* Tree: {|1-2|}, query of |0-1| returns |1-2| */
setup_tree(allow_overlaps, 1, 2, 0);
runsearch(0, init_range(&query, 0, 1, -1), init_range(&expect, 1, 2, 0));
runsearch(0, init_query(&query, 0, 1), init_range(&expect, 1, 2, 0));
close_tree();
/* Tree: {|1-2|}, insert of of |0-1| success == allow_overlaps */
......@@ -117,12 +112,12 @@ void tests(BOOL allow_overlaps) {
/* Tree: {|0-3|}, query of |1-2| returns |0-3| */
setup_tree(allow_overlaps, 0, 3, 0);
runsearch(0, init_range(&query, 1, 2, -1), init_range(&expect, 0, 3, 0));
runsearch(0, init_query(&query, 1, 2), init_range(&expect, 0, 3, 0));
close_tree();
/* Tree: {|1-2|}, query of |0-3| returns |1-2| */
setup_tree(allow_overlaps, 1, 2, 0);
runsearch(0, init_range(&query, 0, 3, -1), init_range(&expect, 1, 2, 0));
runsearch(0, init_query(&query, 0, 3), init_range(&expect, 1, 2, 0));
close_tree();
/* Tree: {|1-2|}, insert of of |0-3| success == allow_overlaps */
......@@ -144,7 +139,7 @@ void tests(BOOL allow_overlaps) {
/* Tree: {|0-3|}, query of |0-3| returns |0-3| */
setup_tree(allow_overlaps, 0, 3, 0);
runsearch(0, init_range(&query, 0, 3, -1), init_range(&expect, 0, 3, 0));
runsearch(0, init_query(&query, 0, 3), init_range(&expect, 0, 3, 0));
close_tree();
/* Tree: {(|0-3|,0)}, insert of of (|0-3|,1) success == allow_overlaps */
......
......@@ -2,16 +2,6 @@
#include "test.h"
void verify_all_overlap(toku_range* query, toku_range* list, unsigned listlen) {
unsigned i;
for (i = 0; i < listlen; i++) {
/* Range A and B overlap iff A.left <= B.right && B.left <= A.right */
assert(int_cmp(query->left, list[i].right) <= 0 &&
int_cmp(list[i].left, query->right) <= 0);
}
}
int nums[64 << 3];
const size_t numlen = sizeof(nums) / sizeof(nums[0]);
char letters[2] = {'A','B'};
......@@ -20,12 +10,16 @@ toku_range_tree *tree;
toku_range* buf;
unsigned buflen;
toku_range* init_range(toku_range* range, unsigned left, unsigned right,
int data) {
toku_interval* init_query(toku_interval* range, unsigned left, unsigned right) {
range->left = (toku_point*)&nums[left];
range->right = (toku_point*)&nums[right];
if (data < 0) range->data = NULL;
else range->data = (DB_TXN*)&letters[data];
return range;
}
toku_range* init_range(toku_range* range, unsigned left, unsigned right, int data) {
init_query(&range->ends, left, right);
if (data < 0) range->data = 0;
else range->data = (TXNID)letters[data];
return range;
}
......@@ -46,7 +40,7 @@ void close_tree(void) {
r = toku_rt_close(tree); CKERR(r);
}
void runsearch(int rexpect, toku_range* query, toku_range* expect) {
void runsearch(int rexpect, toku_interval* query, toku_range* expect) {
int r;
unsigned found;
r = toku_rt_find(tree, query, 0, &buf, &buflen, &found);
......@@ -54,8 +48,8 @@ void runsearch(int rexpect, toku_range* query, toku_range* expect) {
if (rexpect != 0) return;
assert(found == 1);
assert(int_cmp(buf[0].left, expect->left) == 0 &&
int_cmp(buf[0].right, expect->right) == 0 &&
assert(int_cmp(buf[0].ends.left, expect->ends.left) == 0 &&
int_cmp(buf[0].ends.right, expect->ends.right) == 0 &&
char_cmp(buf[0].data, expect->data) == 0);
}
......@@ -71,7 +65,7 @@ void rundelete(int rexpect, toku_range* todelete) {
CKERR2(r, rexpect);
}
void runlimitsearch(toku_range* query, unsigned limit, unsigned findexpect) {
void runlimitsearch(toku_interval* query, unsigned limit, unsigned findexpect) {
int r;
unsigned found;
r=toku_rt_find(tree, query, limit, &buf, &buflen, &found); CKERR(r);
......
#include "test.h"
void verify_all_overlap(toku_range* query, toku_range* list, unsigned listlen) {
unsigned i;
for (i = 0; i < listlen; i++) {
/* Range A and B overlap iff A.left <= B.right && B.left <= A.right */
assert(int_cmp(query->left, list[i].right) <= 0 &&
int_cmp(list[i].left, query->right) <= 0);
}
}
int nums[200];
char letters[2] = {'A','B'};
......@@ -17,11 +7,16 @@ toku_range_tree *tree;
toku_range* buf;
unsigned buflen;
toku_range* init_range(toku_range* range, int left, int right, int data) {
toku_interval* init_query(toku_interval* range, int left, int right) {
range->left = (toku_point*)&nums[left];
range->right = (toku_point*)&nums[right];
if (data < 0) range->data = NULL;
else range->data = (DB_TXN*)&letters[data];
return range;
}
toku_range* init_range(toku_range* range, int left, int right, int data) {
init_query(&range->ends, left, right);
if (data < 0) range->data = 0;
else range->data = (TXNID)letters[data];
return range;
}
......@@ -46,7 +41,7 @@ void close_tree(void) {
r = toku_rt_close(tree); CKERR(r);
}
void runsearch(int rexpect, toku_range* query, toku_range* expect) {
void runsearch(int rexpect, toku_interval* query, toku_range* expect) {
int r;
unsigned found;
r = toku_rt_find(tree, query, 0, &buf, &buflen, &found);
......@@ -54,8 +49,8 @@ void runsearch(int rexpect, toku_range* query, toku_range* expect) {
if (rexpect != 0) return;
assert(found == 1);
assert(int_cmp(buf[0].left, expect->left) == 0 &&
int_cmp(buf[0].right, expect->right) == 0 &&
assert(int_cmp(buf[0].ends.left, expect->ends.left) == 0 &&
int_cmp(buf[0].ends.right, expect->ends.right) == 0 &&
char_cmp(buf[0].data, expect->data) == 0);
}
......@@ -65,7 +60,7 @@ void runinsert(int rexpect, toku_range* toinsert) {
CKERR2(r, rexpect);
}
void runlimitsearch(toku_range* query, unsigned limit, unsigned findexpect) {
void runlimitsearch(toku_interval* query, unsigned limit, unsigned findexpect) {
int r;
unsigned found;
r=toku_rt_find(tree, query, limit, &buf, &buflen, &found); CKERR(r);
......@@ -75,7 +70,7 @@ void runlimitsearch(toku_range* query, unsigned limit, unsigned findexpect) {
}
typedef enum {PRED=0, SUCC=1} predsucc;
void runtest(predsucc testtype, void* query, BOOL findexpect,
void runtest(predsucc testtype, toku_point* query, BOOL findexpect,
unsigned left, unsigned right, unsigned data) {
int r;
BOOL found;
......@@ -94,9 +89,9 @@ void runtest(predsucc testtype, void* query, BOOL findexpect,
CKERR(r);
assert(found == findexpect);
if (findexpect) {
assert(int_cmp(out.left, (toku_point*)&nums[left]) == 0);
assert(int_cmp(out.right, (toku_point*)&nums[right]) == 0);
assert(char_cmp(out.data, (DB_TXN*)&letters[data]) == 0);
assert(int_cmp(out.ends.left, (toku_point*)&nums[left]) == 0);
assert(int_cmp(out.ends.right, (toku_point*)&nums[right]) == 0);
assert(char_cmp(out.data, (TXNID)letters[data]) == 0);
}
}
......
......@@ -57,7 +57,7 @@ static struct toku_rbt_node* toku_rbt__insert(
struct toku_rbt_node* parent
);
static struct toku_rbt_node *toku_rbt__lookup(int, const toku_range * , struct toku_rbt_tree *, struct toku_rbt_node**);
static struct toku_rbt_node *toku_rbt__lookup(int, const toku_interval * , struct toku_rbt_tree *, struct toku_rbt_node**);
static void toku_rbt__destroy(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *);
......@@ -126,15 +126,14 @@ int toku_rbt_init (
return r;
}
void
toku_rbt_destroy(struct toku_rbt_tree *rbinfo)
{
if (rbinfo==NULL)
return;
if (rbinfo->rb_root!=RBNULL)
toku_rbt__destroy(rbinfo, rbinfo->rb_root);
void toku_rbt_clear(struct toku_rbt_tree *rbinfo) {
assert(rbinfo);
if (rbinfo->rb_root!=RBNULL) { toku_rbt__destroy(rbinfo, rbinfo->rb_root); }
rbinfo->rb_root = RBNULL;
}
void toku_rbt_destroy(struct toku_rbt_tree *rbinfo) {
toku_rbt_clear(rbinfo);
rbinfo->rb_free(rbinfo);
}
......@@ -150,7 +149,7 @@ int toku_rbt_finger_delete(struct toku_rbt_node* node, struct toku_rbt_tree *rbi
int toku_rbt_lookup(
int mode,
const toku_range* key,
const toku_interval* key,
struct toku_rbt_tree* rbinfo,
struct toku_rbt_node** pinsert_finger,
struct toku_rbt_node** pelement_finger,
......@@ -194,7 +193,7 @@ toku_rbt__traverse(int insert, const toku_range *key, struct toku_rbt_tree *rbin
{
y=x;
/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
cmp=rbinfo->rb_cmp(key->left, x->key.left);
cmp=rbinfo->rb_cmp(key->ends.left, x->key.ends.left);
if (cmp<0)
x=x->left;
......@@ -240,7 +239,7 @@ static struct toku_rbt_node* toku_rbt__insert(
}
else
{
cmp=rbinfo->rb_cmp(z->key.left, y->key.left);
cmp=rbinfo->rb_cmp(z->key.ends.left, y->key.ends.left);
if (cmp<0)
y->left=z;
else
......@@ -339,7 +338,7 @@ static struct toku_rbt_node* toku_rbt__insert(
/* Search for a key according to mode (see redblack.h)
*/
static struct toku_rbt_node *
toku_rbt__lookup(int mode, const toku_range *key, struct toku_rbt_tree *rbinfo, struct toku_rbt_node** pinsert_finger)
toku_rbt__lookup(int mode, const toku_interval *key, struct toku_rbt_tree *rbinfo, struct toku_rbt_node** pinsert_finger)
{
struct toku_rbt_node *x,*y;
int cmp = 0;
......@@ -376,7 +375,7 @@ toku_rbt__lookup(int mode, const toku_range *key, struct toku_rbt_tree *rbinfo,
{
y=x;
/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
cmp=rbinfo->rb_cmp(key->left, x->key.left);
cmp=rbinfo->rb_cmp(key->left, x->key.ends.left);
if (cmp<0)
......
......@@ -61,7 +61,7 @@ int toku_rbt_init (
/* Sets *pdata to NULL if not found. (unless error) */
int toku_rbt_lookup(
int mode,
const toku_range* key,
const toku_interval* key,
struct toku_rbt_tree* rbinfo,
struct toku_rbt_node** pinsert_finger,
struct toku_rbt_node** pelement_finger,
......@@ -82,6 +82,8 @@ int toku_rbt_finger_successor(struct toku_rbt_node** pfinger, toku_range** psucc
void toku_rbt_destroy(struct toku_rbt_tree *);
void toku_rbt_clear(struct toku_rbt_tree *);
enum nodecolour { BLACK, RED };
struct toku_rbt_node
......
......@@ -8,6 +8,9 @@
#include "../newbrt/brt.h"
#include "../newbrt/list.h"
#include "./lock_tree/locktree.h"
#include "./lock_tree/db_id.h"
#include "./lock_tree/idlth.h"
#include <limits.h>
struct db_header {
int n_databases; // Or there can be >=1 named databases. This is the count.
......@@ -34,6 +37,7 @@ struct __toku_db_internal {
int(*associate_callback)(DB*, const DBT*, const DBT*, DBT*); // For secondary, the callback function for associate. NULL if not secondary
int associate_is_immutable; // If this DB is a secondary then this field indicates that the index never changes due to updates.
struct __toku_lock_tree* lt;
toku_db_id* db_id;
};
#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1
......
......@@ -29,7 +29,6 @@ const char *toku_copyright_string = "Copyright (c) 2007, 2008 Tokutek Inc. All
#include "log.h"
#include "memory.h"
/** The default maximum number of persistent locks in a lock tree */
const u_int32_t __toku_env_default_max_locks = 1000;
......@@ -541,7 +540,7 @@ static int toku_env_set_lk_max_locks(DB_ENV *dbenv, u_int32_t max) {
int r = ENOSYS;
HANDLE_PANICKED_ENV(dbenv);
if (env_opened(dbenv)) { return EINVAL; }
r = toku_ltm_set_max_locks(dbenv->i->ltm, max);
r = toku_ltm_set_max_locks_per_db(dbenv->i->ltm, max);
return r;
}
......@@ -557,7 +556,7 @@ static int locked_env_set_lk_max(DB_ENV * env, u_int32_t lk_max) {
static int toku_env_get_lk_max_locks(DB_ENV *dbenv, u_int32_t *lk_maxp) {
HANDLE_PANICKED_ENV(dbenv);
return toku_ltm_get_max_locks(dbenv->i->ltm, lk_maxp);
return toku_ltm_get_max_locks_per_db(dbenv->i->ltm, lk_maxp);
}
static int locked_env_set_lk_max_locks(DB_ENV *dbenv, u_int32_t max) {
......@@ -679,6 +678,12 @@ static int locked_env_txn_stat(DB_ENV * env, DB_TXN_STAT ** statp, u_int32_t fla
static int locked_txn_begin(DB_ENV * env, DB_TXN * stxn, DB_TXN ** txn, u_int32_t flags);
static int toku_db_lt_panic(DB* db, int r);
static toku_dbt_cmp toku_db_get_compare_fun(DB* db);
static toku_dbt_cmp toku_db_get_dup_compare(DB* db);
static int toku_env_create(DB_ENV ** envp, u_int32_t flags) {
int r = ENOSYS;
DB_ENV* result = NULL;
......@@ -728,6 +733,8 @@ static int toku_env_create(DB_ENV ** envp, u_int32_t flags) {
result->i->errfile = 0;
r = toku_ltm_create(&result->i->ltm, __toku_env_default_max_locks,
toku_db_lt_panic,
toku_db_get_compare_fun, toku_db_get_dup_compare,
toku_malloc, toku_free, toku_realloc);
if (r!=0) { goto cleanup; }
......@@ -763,19 +770,25 @@ static int toku_txn_release_locks(DB_TXN* txn) {
assert(txn);
toku_lth* lth = txn->i->lth;
int r = 0;
int r = ENOSYS;
int first_error = 0;
if (lth) {
toku_lth_start_scan(lth);
toku_lock_tree* next = toku_lth_next(lth);
int r2;
while (next) {
r2 = toku_lt_unlock(next, txn);
if (r2!=0 && !r) r = r2;
r = toku_lt_unlock(next, toku_txn_get_txnid(txn->i->tokutxn));
if (!first_error && r!=0) { first_error = r; }
if (r == 0) {
r = toku_lt_remove_ref(next);
if (!first_error && r!=0) { first_error = r; }
}
next = toku_lth_next(lth);
}
toku_lth_close(lth);
txn->i->lth = NULL;
}
r = first_error;
return r;
}
......@@ -786,6 +799,7 @@ static int toku_txn_commit(DB_TXN * txn, u_int32_t flags) {
int nosync = (flags & DB_TXN_NOSYNC)!=0;
flags &= ~DB_TXN_NOSYNC;
if (flags!=0) {
//TODO: Release locks perhaps?
if (txn->i) {
if (txn->i->tokutxn)
toku_free(txn->i->tokutxn);
......@@ -794,8 +808,8 @@ static int toku_txn_commit(DB_TXN * txn, u_int32_t flags) {
toku_free(txn);
return EINVAL;
}
int r2 = toku_txn_release_locks(txn);
int r = toku_logger_commit(txn->i->tokutxn, nosync); // frees the tokutxn
int r2 = toku_txn_release_locks(txn); // release the locks after the commit (otherwise, what if we abort)
// the toxutxn is freed, and we must free the rest. */
if (txn->i)
toku_free(txn->i);
......@@ -812,12 +826,12 @@ static u_int32_t toku_txn_id(DB_TXN * txn) {
static int toku_txn_abort(DB_TXN * txn) {
HANDLE_PANICKED_ENV(txn->mgrp);
int r2 = toku_txn_release_locks(txn);
int r = toku_logger_abort(txn->i->tokutxn);
toku_txn_release_locks(txn);
toku_free(txn->i);
toku_free(txn);
return r;
return r ? r : r2;
}
static int toku_txn_begin(DB_ENV *env, DB_TXN * stxn, DB_TXN ** txn, u_int32_t flags);
......@@ -956,11 +970,11 @@ static int toku_db_close(DB * db, u_int32_t flags) {
// It is a primary. Unlink all the secondaries. */
while (!list_empty(&db->i->associated)) {
assert(list_struct(list_head(&db->i->associated),
struct __toku_db_internal,
associated)->primary==db);
struct __toku_db_internal, associated)->primary==db);
list_remove(list_head(&db->i->associated));
}
} else {
}
else {
// It is a secondary. Remove it from the list, (which it must be in .*/
if (!list_empty(&db->i->associated)) {
list_remove(&db->i->associated);
......@@ -970,9 +984,10 @@ static int toku_db_close(DB * db, u_int32_t flags) {
int r = toku_close_brt(db->i->brt);
if (r != 0)
return r;
if (db->i->db_id) { toku_db_id_remove_ref(db->i->db_id); }
if (db->i->lt) {
r = toku_lt_close(db->i->lt);
if (r!=0) return r;
r = toku_lt_remove_ref(db->i->lt);
if (r!=0) { return r; }
}
// printf("%s:%d %d=__toku_db_close(%p)\n", __FILE__, __LINE__, r, db);
// Even if panicked, let's close as much as we can.
......@@ -1077,9 +1092,12 @@ static inline int toku_uninitialized_swap(DBC* c, DBT* key, DBT* data,
*/
static inline DB_TXN* toku_txn_ancestor(DB_TXN* txn) {
while (txn && txn->i->parent) txn = txn->i->parent;
return txn;
}
static int toku_txn_add_lt(DB_TXN* txn, toku_lock_tree* lt);
static int toku_c_get_pre_lock(DBC* c, DBT* key, DBT* data, u_int32_t* flag,
DBT* saved_key, DBT* saved_data) {
assert(saved_key && saved_data && flag);
......@@ -1093,6 +1111,8 @@ static int toku_c_get_pre_lock(DBC* c, DBT* key, DBT* data, u_int32_t* flag,
unsigned int brtflags;
toku_brt_get_flags(db->i->brt, &brtflags);
BOOL duplicates = (brtflags & TOKU_DB_DUPSORT) != 0;
DB_TXN* txn_anc = NULL;
TXNID id_anc = 0;
int r = 0;
switch (get_flag) {
......@@ -1105,8 +1125,11 @@ static int toku_c_get_pre_lock(DBC* c, DBT* key, DBT* data, u_int32_t* flag,
}
case (DB_GET_BOTH): {
get_both:
r = toku_lt_acquire_read_lock(db->i->lt, toku_txn_ancestor(txn),
key, data);
txn_anc = toku_txn_ancestor(txn);
r = toku_txn_add_lt(txn_anc, db->i->lt);
if (r!=0) return r;
id_anc = toku_txn_get_txnid(txn_anc->i->tokutxn);
r = toku_lt_acquire_read_lock(db->i->lt, db, id_anc, key, data);
break;
}
case (DB_SET_RANGE): {
......@@ -1256,10 +1279,15 @@ static int toku_c_get_post_lock(DBC* c, DBT* key, DBT* data, u_int32_t flag,
break;
}
}
if (lock) r = toku_lt_acquire_range_read_lock(db->i->lt,
toku_txn_ancestor(txn),
if (lock) {
DB_TXN* txn_anc = toku_txn_ancestor(txn);
r = toku_txn_add_lt(txn_anc, db->i->lt);
if (r!=0) { goto cleanup; }
TXNID id_anc = toku_txn_get_txnid(txn_anc->i->tokutxn);
r = toku_lt_acquire_range_read_lock(db->i->lt, db, id_anc,
key_l, data_l,
key_r, data_r);
}
cleanup:
if (saved_key->data) toku_free(saved_key->data);
if (saved_data->data) toku_free(saved_data->data);
......@@ -1293,7 +1321,11 @@ static int toku_c_del_noassociate(DBC * c, u_int32_t flags) {
DBT saved_data;
r = toku_c_get_current_unconditional(c, &saved_key, &saved_data);
if (r!=0) return r;
r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(c->i->txn),
DB_TXN* txn_anc = toku_txn_ancestor(c->i->txn);
r = toku_txn_add_lt(txn_anc, db->i->lt);
if (r!=0) { return r; }
TXNID id_anc = toku_txn_get_txnid(txn_anc->i->tokutxn);
r = toku_lt_acquire_write_lock(db->i->lt, db, id_anc,
&saved_key, &saved_data);
if (saved_key.data) toku_free(saved_key.data);
if (saved_data.data) toku_free(saved_data.data);
......@@ -1516,7 +1548,11 @@ static int toku_db_del_noassociate(DB * db, DB_TXN * txn, DBT * key, u_int32_t f
}
//Do the actual deleting.
if (db->i->lt) {
r = toku_lt_acquire_range_write_lock(db->i->lt, toku_txn_ancestor(txn),
DB_TXN* txn_anc = toku_txn_ancestor(txn);
r = toku_txn_add_lt(txn_anc, db->i->lt);
if (r!=0) { return r; }
TXNID id_anc = toku_txn_get_txnid(txn_anc->i->tokutxn);
r = toku_lt_acquire_range_write_lock(db->i->lt, db, id_anc,
key, toku_lt_neg_infinity,
key, toku_lt_infinity);
if (r!=0) return r;
......@@ -1646,10 +1682,14 @@ static int toku_c_put(DBC *dbc, DBT *key, DBT *data, u_int32_t flags) {
//Remove old pair.
if (db->i->lt) {
/* Acquire all write locks before */
r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(txn),
DB_TXN* txn_anc = toku_txn_ancestor(txn);
r = toku_txn_add_lt(txn_anc, db->i->lt);
if (r!=0) { return r; }
TXNID id_anc = toku_txn_get_txnid(txn_anc->i->tokutxn);
r = toku_lt_acquire_write_lock(db->i->lt, db, id_anc,
&key_local, &data_local);
if (r!=0) goto cleanup;
r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(txn),
r = toku_lt_acquire_write_lock(db->i->lt, db, id_anc,
&key_local, data);
if (r!=0) goto cleanup;
}
......@@ -1954,6 +1994,7 @@ static int toku_db_lt_panic(DB* db, int r) {
}
static int toku_txn_add_lt(DB_TXN* txn, toku_lock_tree* lt) {
int r = ENOSYS;
assert(txn && lt);
toku_lth* lth = txn->i->lth;
assert(lth);
......@@ -1961,22 +2002,24 @@ static int toku_txn_add_lt(DB_TXN* txn, toku_lock_tree* lt) {
toku_lock_tree* find = toku_lth_find(lth, lt);
if (find) {
assert(find == lt);
return 0;
r = 0;
goto cleanup;
}
int r = toku_lth_insert(lth, lt);
r = toku_lth_insert(lth, lt);
if (r != 0) { goto cleanup; }
toku_lt_add_ref(lt);
r = 0;
cleanup:
return r;
}
static void toku_txn_remove_lt(DB_TXN* txn, toku_lock_tree* lt) {
assert(txn && lt);
toku_lth* lth = txn->i->lth;
assert(lth);
static toku_dbt_cmp toku_db_get_compare_fun(DB* db) {
return db->i->brt->compare_fun;
}
toku_lock_tree* find = toku_lth_find(lth, lt);
if (find) {
assert(find == lt);
toku_lth_delete(lth, lt);
}
static toku_dbt_cmp toku_db_get_dup_compare(DB* db) {
return db->i->brt->dup_compare;
}
static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *dbname, DBTYPE dbtype, u_int32_t flags, int mode) {
......@@ -2044,20 +2087,6 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
db->i->open_flags = flags;
db->i->open_mode = mode;
if (need_locktree) {
r = toku_lt_create(&db->i->lt, db, FALSE,
toku_db_lt_panic, db->dbenv->i->ltm,
db->i->brt->compare_fun, db->i->brt->dup_compare,
toku_malloc, toku_free, toku_realloc);
if (r!=0) goto error_cleanup;
r = toku_lt_set_txn_add_lt_callback(db->i->lt, toku_txn_add_lt);
if (r!=0) fprintf(stderr, "%s:%d r=%d (%s)\n", __FILE__, __LINE__, r, strerror(r));
assert(r==0);
r = toku_lt_set_txn_remove_lt_callback(db->i->lt, toku_txn_remove_lt);
assert(r==0);
}
r = toku_brt_open(db->i->brt, db->i->full_fname, fname, dbname,
is_db_create, is_db_excl, is_db_unknown,
......@@ -2067,20 +2096,26 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
if (r != 0)
goto error_cleanup;
if (db->i->lt) {
if (need_locktree) {
unsigned int brtflags;
BOOL dups;
/* Whether we have dups is only known starting now. */
toku_brt_get_flags(db->i->brt, &brtflags);
dups = (brtflags & TOKU_DB_DUPSORT || brtflags & TOKU_DB_DUP);
r = toku_lt_set_dups(db->i->lt, dups);
/* toku_lt_set_dups cannot return an error here. */
assert(r==0);
r = toku_db_id_create(&db->i->db_id, db->i->full_fname,
db->i->database_name);
if (r!=0) { goto error_cleanup; }
r = toku_ltm_get_lt(db->dbenv->i->ltm, &db->i->lt, dups, db->i->db_id);
if (r!=0) { goto error_cleanup; }
}
return 0;
error_cleanup:
if (db->i->db_id) {
toku_db_id_remove_ref(db->i->db_id);
db->i->db_id = NULL;
}
if (db->i->database_name) {
toku_free(db->i->database_name);
db->i->database_name = NULL;
......@@ -2090,7 +2125,7 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
db->i->full_fname = NULL;
}
if (db->i->lt) {
toku_lt_close(db->i->lt);
toku_lt_remove_ref(db->i->lt);
db->i->lt = NULL;
}
return r;
......@@ -2142,8 +2177,11 @@ static int toku_db_put_noassociate(DB * db, DB_TXN * txn, DBT * key, DBT * data,
}
}
if (db->i->lt) {
r = toku_lt_acquire_write_lock(db->i->lt, toku_txn_ancestor(txn),
key, data);
DB_TXN* txn_anc = toku_txn_ancestor(txn);
r = toku_txn_add_lt(txn_anc, db->i->lt);
if (r!=0) { return r; }
TXNID id_anc = toku_txn_get_txnid(txn_anc->i->tokutxn);
r = toku_lt_acquire_write_lock(db->i->lt, db, id_anc, key, data);
if (r!=0) return r;
}
r = toku_brt_insert(db->i->brt, key, data, txn ? txn->i->tokutxn : 0);
......@@ -2194,33 +2232,63 @@ static int toku_db_put(DB * db, DB_TXN * txn, DBT * key, DBT * data, u_int32_t f
static int toku_db_remove(DB * db, const char *fname, const char *dbname, u_int32_t flags) {
HANDLE_PANICKED_DB(db);
int r;
int r2;
char *full_name;
int r = ENOSYS;
int r2 = 0;
toku_db_id* db_id = NULL;
BOOL need_close = TRUE;
char* full_name = NULL;
toku_ltm* ltm = NULL;
//TODO: Verify DB* db not yet opened
//TODO: Verify db file not in use. (all dbs in the file must be unused)
r = toku_db_open(db, NULL, fname, dbname, DB_BTREE, 0, 0777);
if (r!=0) { goto cleanup; }
if (db->i->lt) {
/* Lock tree exists, therefore:
* Non-private environment (since we are using transactions)
* Environment will exist after db->close */
if (db->i->db_id) {
/* 'copy' the db_id */
db_id = db->i->db_id;
toku_db_id_add_ref(db_id);
}
if (db->dbenv->i->ltm) { ltm = db->dbenv->i->ltm; }
}
if (dbname) {
//TODO: Verify the target db is not open
//TODO: Use master database (instead of manual edit) when implemented.
if ((r = toku_db_open(db, NULL, fname, dbname, DB_BTREE, 0, 0777)) != 0) goto cleanup;
r = toku_brt_remove_subdb(db->i->brt, dbname, flags);
cleanup:
r2 = toku_db_close(db, 0);
return r ? r : r2;
if (r!=0) { goto cleanup; }
}
//TODO: Verify db file not in use. (all dbs in the file must be unused)
r = toku_db_close(db, 0);
need_close = FALSE;
if (r!=0) { goto cleanup; }
if (!dbname) {
r = find_db_file(db->dbenv, fname, &full_name);
if (r!=0) return r;
if (r!=0) { goto cleanup; }
assert(full_name);
r2 = toku_db_close(db, 0);
if (r == 0 && r2 == 0) {
if (unlink(full_name) != 0) r = errno;
if (unlink(full_name) != 0) { r = errno; goto cleanup; }
}
toku_free(full_name);
if (ltm && db_id) { toku_ltm_invalidate_lt(ltm, db_id); }
r = 0;
cleanup:
if (need_close) { r2 = toku_db_close(db, 0); }
if (full_name) { toku_free(full_name); }
if (db_id) { toku_db_id_remove_ref(db_id); }
return r ? r : r2;
}
/* TODO: Either
-find a way for the DB_ID to survive this rename (i.e. be
the same before and after
or
-Go through all DB_IDs in the ltm, and rename them so we
have the correct unique ids.
TODO: Verify the DB file is not in use (either a single db file or
a file with multi-databases).
*/
static int toku_db_rename(DB * db, const char *namea, const char *nameb, const char *namec, u_int32_t flags) {
HANDLE_PANICKED_DB(db);
if (flags!=0) return EINVAL;
......@@ -2578,3 +2646,4 @@ const char *db_version(int *major, int *minor, int *patch) {
int db_env_set_func_fsync (int (*fsync_function)(int)) {
return toku_set_func_fsync(fsync_function);
}
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