Commit 2ef26e00 authored by Yoni Fogel's avatar Yoni Fogel

Converted all dos files to unix format (endlines only changed)

git-svn-id: file:///svn/tokudb@4327 c7de825b-a66e-492c-adef-691d508d4ae1
parent 6f7da789
/* -*- mode: C; c-basic-offset: 4 -*- */ /* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved." #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." #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 <errno.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <memory.h> #include <memory.h>
#include <hashfun.h> #include <hashfun.h>
#include "db_id.h" #include "db_id.h"
BOOL toku_db_id_equals(const toku_db_id* a, const toku_db_id* b) { BOOL toku_db_id_equals(const toku_db_id* a, const toku_db_id* b) {
assert(a && b); assert(a && b);
return a == b || return a == b ||
(a->saved_hash == b->saved_hash && (a->saved_hash == b->saved_hash &&
!strcmp(a->absolute_path, b->absolute_path) && !strcmp(a->absolute_path, b->absolute_path) &&
!strcmp(a->sub_database_name, b->sub_database_name)); !strcmp(a->sub_database_name, b->sub_database_name));
} }
void toku_db_id_add_ref(toku_db_id* db_id) { void toku_db_id_add_ref(toku_db_id* db_id) {
assert(db_id); assert(db_id);
assert(db_id->ref_count > 0); assert(db_id->ref_count > 0);
db_id->ref_count++; db_id->ref_count++;
} }
static void toku_db_id_close(toku_db_id* db_id) { static void toku_db_id_close(toku_db_id* db_id) {
toku_free(db_id->absolute_path); toku_free(db_id->absolute_path);
toku_free(db_id->sub_database_name); toku_free(db_id->sub_database_name);
toku_free(db_id); toku_free(db_id);
} }
void toku_db_id_remove_ref(toku_db_id* db_id) { void toku_db_id_remove_ref(toku_db_id* db_id) {
assert(db_id); assert(db_id);
assert(db_id->ref_count > 0); assert(db_id->ref_count > 0);
db_id->ref_count--; db_id->ref_count--;
if (db_id->ref_count > 0) { return; } if (db_id->ref_count > 0) { return; }
toku_db_id_close(db_id); toku_db_id_close(db_id);
} }
int toku_db_id_create(toku_db_id** pdbid, const char* path, int toku_db_id_create(toku_db_id** pdbid, const char* path,
const char* sub_database_name) { const char* sub_database_name) {
int r = ENOSYS; int r = ENOSYS;
assert(sub_database_name); assert(sub_database_name);
toku_db_id* db_id = NULL; toku_db_id* db_id = NULL;
db_id = (toku_db_id *)toku_malloc(sizeof(*db_id)); db_id = (toku_db_id *)toku_malloc(sizeof(*db_id));
if (!db_id) { r = ENOMEM; goto cleanup; } if (!db_id) { r = ENOMEM; goto cleanup; }
memset(db_id, 0, sizeof(*db_id)); memset(db_id, 0, sizeof(*db_id));
db_id->absolute_path = (char *)toku_malloc((PATH_MAX + 1) * sizeof(char)); db_id->absolute_path = (char *)toku_malloc((PATH_MAX + 1) * sizeof(char));
if (!db_id->absolute_path) { r = ENOMEM; goto cleanup; } if (!db_id->absolute_path) { r = ENOMEM; goto cleanup; }
/* TODO: BUG! Buffer overflow if the path > PATH_MAX. */ /* TODO: BUG! Buffer overflow if the path > PATH_MAX. */
if (realpath(path, db_id->absolute_path) == NULL) { if (realpath(path, db_id->absolute_path) == NULL) {
r = errno; r = errno;
goto cleanup; goto cleanup;
} }
char* tmp = (char*)toku_realloc(db_id->absolute_path, char* tmp = (char*)toku_realloc(db_id->absolute_path,
(strlen(db_id->absolute_path) + 1) * sizeof(char)); (strlen(db_id->absolute_path) + 1) * sizeof(char));
if (!tmp) { r = ENOMEM; goto cleanup; } if (!tmp) { r = ENOMEM; goto cleanup; }
db_id->absolute_path = tmp; db_id->absolute_path = tmp;
db_id->sub_database_name = toku_strdup(sub_database_name); db_id->sub_database_name = toku_strdup(sub_database_name);
if (!db_id->sub_database_name) { r = ENOMEM; goto cleanup; } if (!db_id->sub_database_name) { r = ENOMEM; goto cleanup; }
db_id->saved_hash = hash_key((unsigned char*)db_id->absolute_path, db_id->saved_hash = hash_key((unsigned char*)db_id->absolute_path,
strlen(db_id->absolute_path)); strlen(db_id->absolute_path));
db_id->saved_hash = hash_key_extend(db_id->saved_hash, db_id->saved_hash = hash_key_extend(db_id->saved_hash,
(unsigned char*)db_id->sub_database_name, (unsigned char*)db_id->sub_database_name,
strlen(db_id->sub_database_name)); strlen(db_id->sub_database_name));
db_id->ref_count = 1; db_id->ref_count = 1;
*pdbid = db_id; *pdbid = db_id;
r = 0; r = 0;
cleanup: cleanup:
if (r != 0) { if (r != 0) {
if (db_id != NULL) { if (db_id != NULL) {
if (db_id->absolute_path) { toku_free(db_id->absolute_path); } if (db_id->absolute_path) { toku_free(db_id->absolute_path); }
if (db_id->sub_database_name) { toku_free(db_id->sub_database_name); } if (db_id->sub_database_name) { toku_free(db_id->sub_database_name); }
toku_free(db_id); toku_free(db_id);
} }
} }
return r; return r;
} }
/* -*- mode: C; c-basic-offset: 4 -*- */ /* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved." #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." #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> #include <brttypes.h>
#if !defined(TOKU_DB_ID_H) #if !defined(TOKU_DB_ID_H)
#define TOKU_DB_ID_H #define TOKU_DB_ID_H
typedef struct __toku_db_id { typedef struct __toku_db_id {
char* absolute_path; char* absolute_path;
char* sub_database_name; char* sub_database_name;
u_int32_t saved_hash; u_int32_t saved_hash;
u_int32_t ref_count; u_int32_t ref_count;
} toku_db_id; } toku_db_id;
/* db_id methods */ /* db_id methods */
int toku_db_id_create(toku_db_id** pdbid, const char* path, int toku_db_id_create(toku_db_id** pdbid, const char* path,
const char* sub_database_name); const char* sub_database_name);
BOOL toku_db_id_equals(const toku_db_id* a, const toku_db_id* b); 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_add_ref(toku_db_id* db_id);
void toku_db_id_remove_ref(toku_db_id* db_id); void toku_db_id_remove_ref(toku_db_id* db_id);
#endif /* #if !defined(TOKU_DB_ID_H) */ #endif /* #if !defined(TOKU_DB_ID_H) */
This source diff could not be displayed because it is too large. You can view the blob instead.
/* -*- mode: C; c-basic-offset: 4 -*- */ /* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved." #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." #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_LOCKTREE_H) #if !defined(TOKU_LOCKTREE_H)
#define TOKU_LOCKTREE_H #define TOKU_LOCKTREE_H
/** /**
\file locktree.h \file locktree.h
\brief Lock trees: header and comments \brief Lock trees: header and comments
Lock trees are toku-struct's for granting long-lived locks to transactions. Lock trees are toku-struct's for granting long-lived locks to transactions.
See more details on the design document. See more details on the design document.
TODO: If the various range trees are inconsistent with TODO: If the various range trees are inconsistent with
each other, due to some system error like failed malloc, each other, due to some system error like failed malloc,
we defer to the db panic handler. Pass in another parameter to do this. we defer to the db panic handler. Pass in another parameter to do this.
*/ */
#include <db.h> #include <db.h>
#include <brttypes.h> #include <brttypes.h>
#include <rangetree.h> #include <rangetree.h>
#include <lth.h> #include <lth.h>
#include <rth.h> #include <rth.h>
#include <idlth.h> #include <idlth.h>
#include "toku_assert.h" #include "toku_assert.h"
/** Errors returned by lock trees */ /** Errors returned by lock trees */
typedef enum { typedef enum {
TOKU_LT_INCONSISTENT=-1, /**< The member data are in an inconsistent TOKU_LT_INCONSISTENT=-1, /**< The member data are in an inconsistent
state */ state */
} TOKU_LT_ERROR; } TOKU_LT_ERROR;
typedef int (*toku_dbt_cmp)(DB*,const DBT*,const DBT*); typedef int (*toku_dbt_cmp)(DB*,const DBT*,const DBT*);
/** Convert error codes into a human-readable error message */ /** Convert error codes into a human-readable error message */
char* toku_lt_strerror(TOKU_LT_ERROR r /**< Error code */) char* toku_lt_strerror(TOKU_LT_ERROR r /**< Error code */)
__attribute__((const,pure)); __attribute__((const,pure));
#if !defined(TOKU_LOCKTREE_DEFINE) #if !defined(TOKU_LOCKTREE_DEFINE)
#define TOKU_LOCKTREE_DEFINE #define TOKU_LOCKTREE_DEFINE
typedef struct __toku_lock_tree toku_lock_tree; typedef struct __toku_lock_tree toku_lock_tree;
#endif #endif
#if !defined(TOKU_LTH_DEFINE) #if !defined(TOKU_LTH_DEFINE)
#define TOKU_LTH_DEFINE #define TOKU_LTH_DEFINE
typedef struct __toku_lth toku_lth; typedef struct __toku_lth toku_lth;
#endif #endif
typedef struct __toku_ltm toku_ltm; typedef struct __toku_ltm toku_ltm;
/** \brief The lock tree structure */ /** \brief The lock tree structure */
struct __toku_lock_tree { struct __toku_lock_tree {
/** The database for which this locktree will be handling locks */ /** The database for which this locktree will be handling locks */
DB* db; DB* db;
/** Whether the db supports duplicate */ /** Whether the db supports duplicate */
BOOL duplicates; BOOL duplicates;
/** Whether the duplicates flag can no longer be changed. */ /** Whether the duplicates flag can no longer be changed. */
BOOL settings_final; BOOL settings_final;
toku_range_tree* mainread; /**< See design document */ toku_range_tree* mainread; /**< See design document */
toku_range_tree* borderwrite; /**< See design document */ toku_range_tree* borderwrite; /**< See design document */
toku_rth* rth; /**< Stores local(read|write)set tables */ toku_rth* rth; /**< Stores local(read|write)set tables */
/** /**
Stores a list of transactions to unlock when it is safe. Stores a list of transactions to unlock when it is safe.
When we get a PUT or a GET, the comparison function is valid 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 and we can delete locks held in txns_to_unlock, even if txns_still_locked
is nonempty. is nonempty.
*/ */
toku_rth* txns_to_unlock; toku_rth* txns_to_unlock;
/** Stores a list of transactions that hold locks. txns_still_locked = 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 rth != txns_still_locked + txns_to_unlock, we may get an unlock call for a txn that has
no locks in rth. no locks in rth.
When txns_still_locked becomes empty, we can throw away the contents of the lock tree When txns_still_locked becomes empty, we can throw away the contents of the lock tree
quickly. */ quickly. */
toku_rth* txns_still_locked; toku_rth* txns_still_locked;
/** A temporary area where we store the results of various find on /** A temporary area where we store the results of various find on
the range trees that this lock tree owns the range trees that this lock tree owns
Memory ownership: Memory ownership:
- tree->buf is an array of toku_range's, which the lt owns - tree->buf is an array of toku_range's, which the lt owns
The contents of tree->buf are volatile (this is a buffer space The contents of tree->buf are volatile (this is a buffer space
that we pass around to various functions, and every time we that we pass around to various functions, and every time we
invoke a new function, its previous contents may become invoke a new function, its previous contents may become
meaningless) meaningless)
- tree->buf[i].left, .right are toku_points (ultimately a struct), - tree->buf[i].left, .right are toku_points (ultimately a struct),
also owned by lt. We gave a pointer only to this memory to the also owned by lt. We gave a pointer only to this memory to the
range tree earlier when we inserted a range, but the range tree range tree earlier when we inserted a range, but the range tree
does not own it! does not own it!
- tree->buf[i].{left,right}.{key_payload,data_payload} is owned by - tree->buf[i].{left,right}.{key_payload,data_payload} is owned by
the lt, we made copies from the DB at some point the lt, we made copies from the DB at some point
*/ */
toku_range* buf; toku_range* buf;
u_int32_t buflen; /**< The length of buf */ u_int32_t buflen; /**< The length of buf */
/** Whether lock escalation is allowed. */ /** Whether lock escalation is allowed. */
BOOL lock_escalation_allowed; BOOL lock_escalation_allowed;
/** Lock tree manager */ /** Lock tree manager */
toku_ltm* mgr; toku_ltm* mgr;
/** Function to retrieve the key compare function from the database. */ /** Function to retrieve the key compare function from the database. */
toku_dbt_cmp (*get_compare_fun_from_db)(DB*); toku_dbt_cmp (*get_compare_fun_from_db)(DB*);
/** Function to retrieve the data compare function from the database. */ /** Function to retrieve the data compare function from the database. */
toku_dbt_cmp (*get_dup_compare_from_db)(DB*); toku_dbt_cmp (*get_dup_compare_from_db)(DB*);
/** The key compare function */ /** The key compare function */
int (*compare_fun)(DB*,const DBT*,const DBT*); int (*compare_fun)(DB*,const DBT*,const DBT*);
/** The data compare function */ /** The data compare function */
int (*dup_compare)(DB*,const DBT*,const DBT*); int (*dup_compare)(DB*,const DBT*,const DBT*);
/** The panic function */ /** The panic function */
int (*panic)(DB*, int); int (*panic)(DB*, int);
/** The user malloc function */ /** The user malloc function */
void* (*malloc) (size_t); void* (*malloc) (size_t);
/** The user free function */ /** The user free function */
void (*free) (void*); void (*free) (void*);
/** The user realloc function */ /** The user realloc function */
void* (*realloc)(void*, size_t); void* (*realloc)(void*, size_t);
/** The maximum number of locks allowed for this lock tree. */ /** The maximum number of locks allowed for this lock tree. */
u_int32_t max_locks; u_int32_t max_locks;
/** The current number of locks for this lock tree. */ /** The current number of locks for this lock tree. */
u_int32_t curr_locks; u_int32_t curr_locks;
/** The number of references held by DB instances and transactions to this lock tree*/ /** The number of references held by DB instances and transactions to this lock tree*/
u_int32_t ref_count; u_int32_t ref_count;
/** db_id associated with the lock tree */ /** db_id associated with the lock tree */
toku_db_id* db_id; toku_db_id* db_id;
}; };
struct __toku_ltm { struct __toku_ltm {
/** The maximum number of locks allowed for the environment. */ /** The maximum number of locks allowed for the environment. */
u_int32_t max_locks; u_int32_t max_locks;
/** The current number of locks for the environment. */ /** The current number of locks for the environment. */
u_int32_t curr_locks; u_int32_t curr_locks;
/** The maximum number of locks allowed for the environment. */ /** The maximum number of locks allowed for the environment. */
u_int32_t max_locks_per_db; u_int32_t max_locks_per_db;
/** The list of lock trees it manages. */ /** The list of lock trees it manages. */
toku_lth* lth; toku_lth* lth;
/** List of lock-tree DB mappings. Upon a request for a lock tree given /** 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 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 is retrieved from this list, otherwise, a new lock tree is created
and the new mapping of DB and Lock tree is stored here */ and the new mapping of DB and Lock tree is stored here */
toku_idlth* idlth; toku_idlth* idlth;
/** Function to retrieve the key compare function from the database. */ /** Function to retrieve the key compare function from the database. */
toku_dbt_cmp (*get_compare_fun_from_db)(DB*); toku_dbt_cmp (*get_compare_fun_from_db)(DB*);
/** Function to retrieve the data compare function from the database. */ /** Function to retrieve the data compare function from the database. */
toku_dbt_cmp (*get_dup_compare_from_db)(DB*); toku_dbt_cmp (*get_dup_compare_from_db)(DB*);
/** The panic function */ /** The panic function */
int (*panic)(DB*, int); int (*panic)(DB*, int);
/** The user malloc function */ /** The user malloc function */
void* (*malloc) (size_t); void* (*malloc) (size_t);
/** The user free function */ /** The user free function */
void (*free) (void*); void (*free) (void*);
/** The user realloc function */ /** The user realloc function */
void* (*realloc)(void*, size_t); void* (*realloc)(void*, size_t);
}; };
extern const DBT* const toku_lt_infinity; /**< Special value denoting extern const DBT* const toku_lt_infinity; /**< Special value denoting
+infty */ +infty */
extern const DBT* const toku_lt_neg_infinity; /**< Special value denoting extern const DBT* const toku_lt_neg_infinity; /**< Special value denoting
-infty */ -infty */
/** /**
\brief A 2D BDB-inspired point. \brief A 2D BDB-inspired point.
Observe the toku_point, and marvel! Observe the toku_point, and marvel!
It makes the pair (key, data) into a 1-dimensional point, It makes the pair (key, data) into a 1-dimensional point,
on which a total order is defined by toku_lt_point_cmp. on which a total order is defined by toku_lt_point_cmp.
Additionally, we have points at +infty and -infty as Additionally, we have points at +infty and -infty as
key_payload = (void*) toku_lt_infinity or key_payload = (void*) toku_lt_infinity or
key_payload = (void*) toku_lt_neg infinity key_payload = (void*) toku_lt_neg infinity
*/ */
struct __toku_point { struct __toku_point {
toku_lock_tree* lt; /**< The lock tree, where toku_lt_point_cmp toku_lock_tree* lt; /**< The lock tree, where toku_lt_point_cmp
is defined */ is defined */
void* key_payload; /**< The key ... */ void* key_payload; /**< The key ... */
u_int32_t key_len; /**< and its length */ u_int32_t key_len; /**< and its length */
void* data_payload; /**< The data ... */ void* data_payload; /**< The data ... */
u_int32_t data_len; /**< and its length */ u_int32_t data_len; /**< and its length */
}; };
#if !defined(__TOKU_POINT) #if !defined(__TOKU_POINT)
#define __TOKU_POINT #define __TOKU_POINT
typedef struct __toku_point toku_point; typedef struct __toku_point toku_point;
#endif #endif
/** /**
Create a lock tree. Should be called only inside DB->open. Create a lock tree. Should be called only inside DB->open.
\param ptree We set *ptree to the newly allocated tree. \param ptree We set *ptree to the newly allocated tree.
\param duplicates Whether the db supports duplicates. \param duplicates Whether the db supports duplicates.
\param get_compare_fun_from_db Accessor for the key 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 get_dup_compare_from_db Accessor for the data compare function.
\param panic The function to cause the db to panic. \param panic The function to cause the db to panic.
i.e., godzilla_rampage() i.e., godzilla_rampage()
\param payload_capacity The maximum amount of memory to use for dbt payloads. \param payload_capacity The maximum amount of memory to use for dbt payloads.
\param user_malloc A user provided malloc(3) function. \param user_malloc A user provided malloc(3) function.
\param user_free A user provided free(3) function. \param user_free A user provided free(3) function.
\param user_realloc A user provided realloc(3) function. \param user_realloc A user provided realloc(3) function.
\return \return
- 0 Success - 0 Success
- EINVAL If any pointer or function argument is NULL. - EINVAL If any pointer or function argument is NULL.
- EINVAL If payload_capacity is 0. - EINVAL If payload_capacity is 0.
- May return other errors due to system calls. - May return other errors due to system calls.
A pre-condition is that no pointer parameter can be NULL; A pre-condition is that no pointer parameter can be NULL;
this pre-condition is assert(3)'ed. this pre-condition is assert(3)'ed.
A future check is that it should return EINVAL for already opened db A future check is that it should return EINVAL for already opened db
or already closed db. or already closed db.
If this library is ever exported to users, we will use error datas If this library is ever exported to users, we will use error datas
instead. instead.
*/ */
int toku_lt_create(toku_lock_tree** ptree, BOOL duplicates, int toku_lt_create(toku_lock_tree** ptree, BOOL duplicates,
int (*panic)(DB*, int), int (*panic)(DB*, int),
toku_ltm* mgr, toku_ltm* mgr,
toku_dbt_cmp (*get_compare_fun_from_db)(DB*), toku_dbt_cmp (*get_compare_fun_from_db)(DB*),
toku_dbt_cmp (*get_dup_compare_from_db)(DB*), toku_dbt_cmp (*get_dup_compare_from_db)(DB*),
void* (*user_malloc) (size_t), void* (*user_malloc) (size_t),
void (*user_free) (void*), void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)); void* (*user_realloc)(void*, size_t));
/** /**
Gets a lock tree for a given DB with id db_id Gets a lock tree for a given DB with id db_id
*/ */
int toku_ltm_get_lt(toku_ltm* mgr, toku_lock_tree** ptree, int toku_ltm_get_lt(toku_ltm* mgr, toku_lock_tree** ptree,
BOOL duplicates, toku_db_id* db_id); BOOL duplicates, toku_db_id* db_id);
void toku_ltm_invalidate_lt(toku_ltm* mgr, toku_db_id* db_id); void toku_ltm_invalidate_lt(toku_ltm* mgr, toku_db_id* db_id);
/** /**
Closes and frees a lock tree. Closes and frees a lock tree.
It will free memory used by the tree, and all keys/datas It will free memory used by the tree, and all keys/datas
from all internal structures. from all internal structures.
It handles the case of transactions that are still active It handles the case of transactions that are still active
when lt_close is invoked: it can throw away other tables, but when lt_close is invoked: it can throw away other tables, but
it keeps lists of selfread and selfwrite, and frees the memory it keeps lists of selfread and selfwrite, and frees the memory
pointed to by the DBTs contained in the selfread and selfwrite. pointed to by the DBTs contained in the selfread and selfwrite.
\param tree The tree to free. \param tree The tree to free.
\return \return
- 0 Success. - 0 Success.
It asserts that the tree != NULL. It asserts that the tree != NULL.
If this library is ever exported to users, we will use error datas instead. If this library is ever exported to users, we will use error datas instead.
*/ */
int toku_lt_close(toku_lock_tree* tree); int toku_lt_close(toku_lock_tree* tree);
/** /**
Acquires a read lock on a single key (or key/data). Acquires a read lock on a single key (or key/data).
\param tree The lock tree for the db. \param tree The lock tree for the db.
\param txn The TOKU Transaction this lock is for. \param txn The TOKU Transaction this lock is for.
\param key The key this lock is for. \param key The key this lock is for.
\param data The data this lock is for. \param data The data this lock is for.
\return \return
- 0 Success. - 0 Success.
- DB_LOCK_NOTGRANTED If there is a conflict in getting the lock. - DB_LOCK_NOTGRANTED If there is a conflict in getting the lock.
This can only happen if some other transaction has This can only happen if some other transaction has
a write lock that overlaps this point. a write lock that overlaps this point.
- ENOMEM If adding the lock would exceed the maximum - ENOMEM If adding the lock would exceed the maximum
memory allowed for payloads. memory allowed for payloads.
The following is asserted: The following is asserted:
(tree == NULL || txn == NULL || key == NULL) or (tree == NULL || txn == NULL || key == NULL) or
(tree->db is dupsort && data == NULL) or (tree->db is dupsort && data == NULL) or
(tree->db is dupsort && key != data && (tree->db is dupsort && key != data &&
(key == toku_lt_infinity || (key == toku_lt_infinity ||
(toku_lock_tree* tree, TXNID 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. 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 In BDB, txn can actually be NULL (mixed operations with transactions and
no transactions). This can cause conflicts, nobody was able (so far) no transactions). This can cause conflicts, nobody was able (so far)
to verify that MySQL does or does not use this. to verify that MySQL does or does not use this.
*/ */
int toku_lt_acquire_read_lock(toku_lock_tree* tree, DB* db, TXNID txn, int toku_lt_acquire_read_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key, const DBT* data); const DBT* key, const DBT* data);
/* /*
Acquires a read lock on a key range (or key/data range). (Closed range). Acquires a read lock on a key range (or key/data range). (Closed range).
\param tree The lock tree for the db. \param tree The lock tree for the db.
\param txn The TOKU Transaction this lock is for. \param txn The TOKU Transaction this lock is for.
Note that txn == NULL is not supported at this time. Note that txn == NULL is not supported at this time.
\param key_left The left end key of the range. \param key_left The left end key of the range.
\param data_left The left end data of the range. \param data_left The left end data of the range.
\param key_right The right end key of the range. \param key_right The right end key of the range.
\param data_right The right end data of the range. \param data_right The right end data of the range.
\return \return
- 0 Success. - 0 Success.
- DB_LOCK_NOTGRANTED If there is a conflict in getting the lock. - DB_LOCK_NOTGRANTED If there is a conflict in getting the lock.
This can only happen if some other transaction has This can only happen if some other transaction has
a write lock that overlaps this range. a write lock that overlaps this range.
- EDOM In a DB_DUPSORT db: - EDOM In a DB_DUPSORT db:
If (key_left, data_left) > (key_right, data_right) or If (key_left, data_left) > (key_right, data_right) or
In a nodup db: if (key_left) > (key_right) In a nodup db: if (key_left) > (key_right)
(According to the db's comparison functions.) (According to the db's comparison functions.)
- ENOMEM If adding the lock would exceed the maximum - ENOMEM If adding the lock would exceed the maximum
memory allowed for payloads. memory allowed for payloads.
The following is asserted, but if this library is ever exported to users, The following is asserted, but if this library is ever exported to users,
EINVAL should be used instead: EINVAL should be used instead:
If (tree == NULL || txn == NULL || If (tree == NULL || txn == NULL ||
key_left == NULL || key_right == NULL) or key_left == NULL || key_right == NULL) or
(tree->db is dupsort && (tree->db is dupsort &&
(data_left == NULL || data_right == NULL)) or (data_left == NULL || data_right == NULL)) or
(tree->db is dupsort && key_left != data_left && (tree->db is dupsort && key_left != data_left &&
(key_left == toku_lt_infinity || (key_left == toku_lt_infinity ||
key_left == toku_lt_neg_infinity)) or key_left == toku_lt_neg_infinity)) or
(tree->db is dupsort && key_right != data_right && (tree->db is dupsort && key_right != data_right &&
(key_right == toku_lt_infinity || (key_right == toku_lt_infinity ||
key_right == toku_lt_neg_infinity)) key_right == toku_lt_neg_infinity))
Memory: It is safe to free keys and datas after this call. Memory: It is safe to free keys and datas after this call.
If the lock tree needs to hold onto the key or data, it will make copies If the lock tree needs to hold onto the key or data, it will make copies
to its local memory. to its local memory.
In BDB, txn can actually be NULL (mixed operations with transactions and In BDB, txn can actually be NULL (mixed operations with transactions and
no transactions). This can cause conflicts, nobody was able (so far) no transactions). This can cause conflicts, nobody was able (so far)
to verify that MySQL does or does not use this. to verify that MySQL does or does not use this.
*/ */
int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB* db, TXNID 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_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right); const DBT* key_right, const DBT* data_right);
/** /**
Acquires a write lock on a single key (or key/data). Acquires a write lock on a single key (or key/data).
\param tree The lock tree for the db. \param tree The lock tree for the db.
\param txn The TOKU Transaction this lock is for. \param txn The TOKU Transaction this lock is for.
Note that txn == NULL is not supported at this time. Note that txn == NULL is not supported at this time.
\param key The key this lock is for. \param key The key this lock is for.
\param data The data this lock is for. \param data The data this lock is for.
\return \return
- 0 Success. - 0 Success.
- DB_LOCK_NOTGRANTED If there is a conflict in getting the lock. - DB_LOCK_NOTGRANTED If there is a conflict in getting the lock.
This can only happen if some other transaction has This can only happen if some other transaction has
a write (or read) lock that overlaps this point. a write (or read) lock that overlaps this point.
- ENOMEM If adding the lock would exceed the maximum - ENOMEM If adding the lock would exceed the maximum
memory allowed for payloads. memory allowed for payloads.
The following is asserted, but if this library is ever exported to users, The following is asserted, but if this library is ever exported to users,
EINVAL should be used instead: EINVAL should be used instead:
If (tree == NULL || txn == NULL || key == NULL) or If (tree == NULL || txn == NULL || key == NULL) or
(tree->db is dupsort && data == NULL) or (tree->db is dupsort && data == NULL) or
(tree->db is dupsort && key != data && (tree->db is dupsort && key != data &&
(key == toku_lt_infinity || key == toku_lt_neg_infinity)) (key == toku_lt_infinity || key == toku_lt_neg_infinity))
Memory: Memory:
It is safe to free keys and datas after this call. It is safe to free keys and datas after this call.
If the lock tree needs to hold onto the key or data, it will make copies If the lock tree needs to hold onto the key or data, it will make copies
to its local memory. to its local memory.
*/ */
int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB* db, TXNID txn, int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB* db, TXNID txn,
const DBT* key, const DBT* data); const DBT* key, const DBT* data);
//In BDB, txn can actually be NULL (mixed operations with transactions and no transactions). //In BDB, txn can actually be NULL (mixed operations with transactions and no transactions).
//This can cause conflicts, I was unable (so far) to verify that MySQL does or does not use //This can cause conflicts, I was unable (so far) to verify that MySQL does or does not use
//this. //this.
/* /*
* ***************NOTE: This will not be implemented before Feb 1st because * ***************NOTE: This will not be implemented before Feb 1st because
* *************** MySQL does not use DB->del on DB_DUPSORT dbs. * *************** MySQL does not use DB->del on DB_DUPSORT dbs.
* *************** The only operation that requires a write range lock is * *************** The only operation that requires a write range lock is
* *************** DB->del on DB_DUPSORT dbs. * *************** DB->del on DB_DUPSORT dbs.
* Acquires a write lock on a key range (or key/data range). (Closed range). * Acquires a write lock on a key range (or key/data range). (Closed range).
* Params: * Params:
* tree The lock tree for the db. * tree The lock tree for the db.
* txn The TOKU Transaction this lock is for. * txn The TOKU Transaction this lock is for.
* key_left The left end key of the range. * key_left The left end key of the range.
* key_right The right end key of the range. * key_right The right end key of the range.
* data_left The left end data of the range. * data_left The left end data of the range.
* data_right The right end data of the range. * data_right The right end data of the range.
* Returns: * Returns:
* 0 Success. * 0 Success.
* DB_LOCK_NOTGRANTED If there is a conflict in getting the lock. * DB_LOCK_NOTGRANTED If there is a conflict in getting the lock.
* This can only happen if some other transaction has * This can only happen if some other transaction has
* a write (or read) lock that overlaps this range. * a write (or read) lock that overlaps this range.
* EINVAL If (tree == NULL || txn == NULL || * EINVAL If (tree == NULL || txn == NULL ||
* key_left == NULL || key_right == NULL) or * key_left == NULL || key_right == NULL) or
* (tree->db is dupsort && * (tree->db is dupsort &&
* (data_left == NULL || data_right == NULL)) or * (data_left == NULL || data_right == NULL)) or
or or
* (tree->db is dupsort && key_left != data_left && * (tree->db is dupsort && key_left != data_left &&
* (key_left == toku_lt_infinity || * (key_left == toku_lt_infinity ||
* key_left == toku_lt_neg_infinity)) or * key_left == toku_lt_neg_infinity)) or
* (tree->db is dupsort && key_right != data_right && * (tree->db is dupsort && key_right != data_right &&
* (key_right == toku_lt_infinity || * (key_right == toku_lt_infinity ||
* key_right == toku_lt_neg_infinity)) * key_right == toku_lt_neg_infinity))
* ERANGE In a DB_DUPSORT db: * ERANGE In a DB_DUPSORT db:
* If (key_left, data_left) > (key_right, data_right) or * If (key_left, data_left) > (key_right, data_right) or
* In a nodup db: if (key_left) > (key_right) * In a nodup db: if (key_left) > (key_right)
* (According to the db's comparison functions. * (According to the db's comparison functions.
* ENOSYS THis is not yet implemented. Till it is, it will return ENOSYS, * ENOSYS THis is not yet implemented. Till it is, it will return ENOSYS,
* if other errors do not occur first. * if other errors do not occur first.
* ENOMEM If adding the lock would exceed the maximum * ENOMEM If adding the lock would exceed the maximum
* memory allowed for payloads. * memory allowed for payloads.
* Asserts: * Asserts:
* The EINVAL and ERANGE cases described will use assert to abort instead of returning errors. * The EINVAL and ERANGE cases described will use assert to abort instead of returning errors.
* If this library is ever exported to users, we will use error datas instead. * If this library is ever exported to users, we will use error datas instead.
* Memory: * Memory:
* It is safe to free keys and datas after this call. * It is safe to free keys and datas after this call.
* If the lock tree needs to hold onto the key or data, it will make copies * If the lock tree needs to hold onto the key or data, it will make copies
* to its local memory. * to its local memory.
* *** Note that txn == NULL is not supported at this time. * *** Note that txn == NULL is not supported at this time.
*/ */
int toku_lt_acquire_range_write_lock(toku_lock_tree* tree, DB* db, TXNID 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_left, const DBT* data_left,
const DBT* key_right, const DBT* data_right); const DBT* key_right, const DBT* data_right);
//In BDB, txn can actually be NULL (mixed operations with transactions and no transactions). //In BDB, txn can actually be NULL (mixed operations with transactions and no transactions).
//This can cause conflicts, I was unable (so far) to verify that MySQL does or does not use //This can cause conflicts, I was unable (so far) to verify that MySQL does or does not use
//this. //this.
/** /**
Releases all the locks owned by a transaction. Releases all the locks owned by a transaction.
This is used when a transaction aborts/rolls back/commits. This is used when a transaction aborts/rolls back/commits.
\param tree The lock tree for the db. \param tree The lock tree for the db.
\param txn The transaction to release all locks for. \param txn The transaction to release all locks for.
Note that txn == NULL is not supported at this time. Note that txn == NULL is not supported at this time.
\return \return
- 0 Success. - 0 Success.
- EINVAL If (tree == NULL || txn == NULL). - EINVAL If (tree == NULL || txn == NULL).
- EINVAL If panicking. - EINVAL If panicking.
*/ */
int toku_lt_unlock(toku_lock_tree* tree, TXNID txn); int toku_lt_unlock(toku_lock_tree* tree, TXNID txn);
/* Lock tree manager functions begin here */ /* Lock tree manager functions begin here */
/** /**
Creates a lock tree manager.. Creates a lock tree manager..
\param pmgr A buffer for the new lock tree manager. \param pmgr A buffer for the new lock tree manager.
\param max_locks The maximum number of locks. \param max_locks The maximum number of locks.
\param user_malloc A user provided malloc(3) function. \param user_malloc A user provided malloc(3) function.
\param user_free A user provided free(3) function. \param user_free A user provided free(3) function.
\param user_realloc A user provided realloc(3) function. \param user_realloc A user provided realloc(3) function.
\return \return
- 0 on success. - 0 on success.
- EINVAL if any pointer parameter is NULL. - EINVAL if any pointer parameter is NULL.
- May return other errors due to system calls. - May return other errors due to system calls.
*/ */
int toku_ltm_create(toku_ltm** pmgr, int toku_ltm_create(toku_ltm** pmgr,
u_int32_t max_locks, u_int32_t max_locks,
int (*panic)(DB*, int), int (*panic)(DB*, int),
toku_dbt_cmp (*get_compare_fun_from_db)(DB*), toku_dbt_cmp (*get_compare_fun_from_db)(DB*),
toku_dbt_cmp (*get_dup_compare_from_db)(DB*), toku_dbt_cmp (*get_dup_compare_from_db)(DB*),
void* (*user_malloc) (size_t), void* (*user_malloc) (size_t),
void (*user_free) (void*), void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)); void* (*user_realloc)(void*, size_t));
/** /**
Closes and frees a lock tree manager.. Closes and frees a lock tree manager..
\param mgr The lock tree manager. \param mgr The lock tree manager.
\return \return
- 0 on success. - 0 on success.
- EINVAL if any pointer parameter is NULL. - EINVAL if any pointer parameter is NULL.
- May return other errors due to system calls. - May return other errors due to system calls.
*/ */
int toku_ltm_close(toku_ltm* mgr); int toku_ltm_close(toku_ltm* mgr);
/** /**
Sets the maximum number of locks on the lock tree manager. Sets the maximum number of locks on the lock tree manager.
\param mgr The lock tree manager to which to set max_locks. \param mgr The lock tree manager to which to set max_locks.
\param max_locks The new maximum number of locks. \param max_locks The new maximum number of locks.
\return \return
- 0 on success. - 0 on success.
- EINVAL if tree is NULL or max_locks is 0 - 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 - EDOM if max_locks is less than the number of locks held by any lock tree
held by the manager held by the manager
*/ */
int toku_ltm_set_max_locks(toku_ltm* mgr, u_int32_t max_locks); int toku_ltm_set_max_locks(toku_ltm* mgr, u_int32_t max_locks);
/** /**
Sets the maximum number of locks for each lock tree. Sets the maximum number of locks for each lock tree.
This is a temporary function until we can complete ticket #596. This is a temporary function until we can complete ticket #596.
This will be used instead of toku_ltm_set_max_locks. This will be used instead of toku_ltm_set_max_locks.
\param mgr The lock tree manager to which to set max_locks. \param mgr The lock tree manager to which to set max_locks.
\param max_locks The new maximum number of locks. \param max_locks The new maximum number of locks.
\return \return
- 0 on success. - 0 on success.
- EINVAL if tree is NULL or max_locks is 0 - 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 - EDOM if max_locks is less than the number of locks held by any lock tree
held by the manager held by the manager
*/ */
int toku_ltm_set_max_locks_per_db(toku_ltm* mgr, u_int32_t max_locks); 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. Sets the maximum number of locks on the lock tree manager.
\param mgr The lock tree manager to which to set max_locks. \param mgr The lock tree manager to which to set max_locks.
\param max_locks A buffer to return the number of max locks. \param max_locks A buffer to return the number of max locks.
\return \return
- 0 on success. - 0 on success.
- EINVAL if any parameter is NULL. - EINVAL if any parameter is NULL.
*/ */
int toku_ltm_get_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); 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); void toku_lt_add_ref(toku_lock_tree* tree);
int toku_lt_remove_ref(toku_lock_tree* tree); int toku_lt_remove_ref(toku_lock_tree* tree);
#endif #endif
/* -*- mode: C; c-basic-offset: 4 -*- */ /* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved." #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." #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 linear.c \file linear.c
\brief Range tree implementation \brief Range tree implementation
See rangetree.h for documentation on the following. */ See rangetree.h for documentation on the following. */
//Currently this is a stub implementation just so we can write and compile tests //Currently this is a stub implementation just so we can write and compile tests
//before actually implementing the range tree. //before actually implementing the range tree.
#include <rangetree.h> #include <rangetree.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct __toku_range_tree_local { struct __toku_range_tree_local {
//Linear version only fields: //Linear version only fields:
toku_range* ranges; toku_range* ranges;
u_int32_t ranges_len; u_int32_t ranges_len;
}; };
#include <rangetree-internal.h> #include <rangetree-internal.h>
static const u_int32_t minlen = 64; static const u_int32_t minlen = 64;
static inline int toku__rt_decrease_capacity(toku_range_tree* tree, static inline int toku__rt_decrease_capacity(toku_range_tree* tree,
u_int32_t _num) { u_int32_t _num) {
//TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(tree); //TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(tree);
u_int32_t num = _num < minlen ? minlen : _num; u_int32_t num = _num < minlen ? minlen : _num;
if (tree->i.ranges_len >= num * 2) { if (tree->i.ranges_len >= num * 2) {
u_int32_t temp_len = tree->i.ranges_len; u_int32_t temp_len = tree->i.ranges_len;
while (temp_len >= num * 2) temp_len /= 2; while (temp_len >= num * 2) temp_len /= 2;
assert(temp_len >= _num); //Sanity check. assert(temp_len >= _num); //Sanity check.
toku_range* temp_ranges = toku_range* temp_ranges =
tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range)); tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range));
if (!temp_ranges) return errno; if (!temp_ranges) return errno;
tree->i.ranges = temp_ranges; tree->i.ranges = temp_ranges;
tree->i.ranges_len = temp_len; tree->i.ranges_len = temp_len;
} }
return 0; return 0;
} }
static inline int toku__rt_increase_capacity(toku_range_tree* tree, static inline int toku__rt_increase_capacity(toku_range_tree* tree,
u_int32_t num) { u_int32_t num) {
//TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(tree); //TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(tree);
if (tree->i.ranges_len < num) { if (tree->i.ranges_len < num) {
u_int32_t temp_len = tree->i.ranges_len; u_int32_t temp_len = tree->i.ranges_len;
while (temp_len < num) temp_len *= 2; while (temp_len < num) temp_len *= 2;
toku_range* temp_ranges = toku_range* temp_ranges =
tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range)); tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range));
if (!temp_ranges) return errno; if (!temp_ranges) return errno;
tree->i.ranges = temp_ranges; tree->i.ranges = temp_ranges;
tree->i.ranges_len = temp_len; tree->i.ranges_len = temp_len;
} }
return 0; return 0;
} }
static inline BOOL toku__rt_overlap(toku_range_tree* tree, static inline BOOL toku__rt_overlap(toku_range_tree* tree,
toku_interval* a, toku_interval* b) { toku_interval* a, toku_interval* b) {
assert(tree); assert(tree);
assert(a); assert(a);
assert(b); assert(b);
//a->left <= b->right && b->left <= a->right //a->left <= b->right && b->left <= a->right
return (tree->end_cmp(a->left, b->right) <= 0 && return (tree->end_cmp(a->left, b->right) <= 0 &&
tree->end_cmp(b->left, a->right) <= 0); tree->end_cmp(b->left, a->right) <= 0);
} }
static inline BOOL toku__rt_exact(toku_range_tree* tree, static inline BOOL toku__rt_exact(toku_range_tree* tree,
toku_range* a, toku_range* b) { toku_range* a, toku_range* b) {
assert(tree); assert(tree);
assert(a); assert(a);
assert(b); assert(b);
return (tree->end_cmp (a->ends.left, b->ends.left) == 0 && return (tree->end_cmp (a->ends.left, b->ends.left) == 0 &&
tree->end_cmp (a->ends.right, b->ends.right) == 0 && tree->end_cmp (a->ends.right, b->ends.right) == 0 &&
tree->data_cmp(a->data, b->data) == 0); tree->data_cmp(a->data, b->data) == 0);
} }
static inline int toku__rt_cmp(toku_range_tree* tree, static inline int toku__rt_cmp(toku_range_tree* tree,
toku_range* a, toku_range* b) { toku_range* a, toku_range* b) {
int cmp = 0; int cmp = 0;
assert(tree); assert(tree);
assert(a); assert(a);
assert(b); assert(b);
cmp = tree->end_cmp(a->ends.left, b->ends.left); cmp = tree->end_cmp(a->ends.left, b->ends.left);
if (cmp!=0) { goto cleanup; } if (cmp!=0) { goto cleanup; }
cmp = tree->end_cmp(a->ends.right, b->ends.right); cmp = tree->end_cmp(a->ends.right, b->ends.right);
if (cmp!=0) { goto cleanup; } if (cmp!=0) { goto cleanup; }
cmp = tree->data_cmp(a->data, b->data); cmp = tree->data_cmp(a->data, b->data);
if (cmp!=0) { goto cleanup; } if (cmp!=0) { goto cleanup; }
cmp = 0; cmp = 0;
cleanup: cleanup:
return cmp; return cmp;
} }
int toku_rt_create(toku_range_tree** ptree, int toku_rt_create(toku_range_tree** ptree,
int (*end_cmp)(const toku_point*,const toku_point*), int (*end_cmp)(const toku_point*,const toku_point*),
int (*data_cmp)(const TXNID,const TXNID), int (*data_cmp)(const TXNID,const TXNID),
BOOL allow_overlaps, BOOL allow_overlaps,
void* (*user_malloc) (size_t), void* (*user_malloc) (size_t),
void (*user_free) (void*), void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) { void* (*user_realloc)(void*, size_t)) {
int r; int r;
toku_range_tree* tmptree; toku_range_tree* tmptree;
if (!ptree) return EINVAL; if (!ptree) return EINVAL;
r = toku_rt_super_create(ptree, &tmptree, end_cmp, data_cmp, allow_overlaps, r = toku_rt_super_create(ptree, &tmptree, end_cmp, data_cmp, allow_overlaps,
user_malloc, user_free, user_realloc); user_malloc, user_free, user_realloc);
if (0) { if (0) {
died1: died1:
user_free(tmptree); user_free(tmptree);
return r; return r;
} }
if (r!=0) return r; if (r!=0) return r;
//Any local initializers go here. //Any local initializers go here.
tmptree->i.ranges_len = minlen; tmptree->i.ranges_len = minlen;
tmptree->i.ranges = (toku_range*) tmptree->i.ranges = (toku_range*)
user_malloc(tmptree->i.ranges_len * sizeof(toku_range)); user_malloc(tmptree->i.ranges_len * sizeof(toku_range));
if (!tmptree->i.ranges) { r = errno; goto died1; } if (!tmptree->i.ranges) { r = errno; goto died1; }
*ptree = tmptree; *ptree = tmptree;
return 0; return 0;
} }
void toku_rt_clear(toku_range_tree* tree) { void toku_rt_clear(toku_range_tree* tree) {
assert(tree); assert(tree);
toku__rt_decrease_capacity(tree, 0); toku__rt_decrease_capacity(tree, 0);
tree->numelements = 0; tree->numelements = 0;
} }
int toku_rt_close(toku_range_tree* tree) { int toku_rt_close(toku_range_tree* tree) {
if (!tree) return EINVAL; if (!tree) return EINVAL;
tree->free(tree->i.ranges); tree->free(tree->i.ranges);
tree->free(tree); tree->free(tree);
return 0; return 0;
} }
int toku_rt_find(toku_range_tree* tree, toku_interval* 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) { toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
if (!tree || !query || !buf || !buflen || !numfound) return EINVAL; if (!tree || !query || !buf || !buflen || !numfound) return EINVAL;
if (*buflen == 0) return EINVAL; if (*buflen == 0) return EINVAL;
u_int32_t temp_numfound = 0; u_int32_t temp_numfound = 0;
int r; int r;
u_int32_t i; u_int32_t i;
for (i = 0; i < tree->numelements; i++) { for (i = 0; i < tree->numelements; i++) {
if (toku__rt_overlap(tree, query, &tree->i.ranges[i].ends)) { if (toku__rt_overlap(tree, query, &tree->i.ranges[i].ends)) {
r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1); r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1);
if (r != 0) return r; if (r != 0) return r;
(*buf)[temp_numfound++] = tree->i.ranges[i]; (*buf)[temp_numfound++] = tree->i.ranges[i];
//k == 0 means limit of infinity, this is not a bug. //k == 0 means limit of infinity, this is not a bug.
if (temp_numfound == k) break; if (temp_numfound == k) break;
} }
} }
*numfound = temp_numfound; *numfound = temp_numfound;
return 0; return 0;
} }
int toku_rt_insert(toku_range_tree* tree, toku_range* range) { int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
if (!tree || !range) return EINVAL; if (!tree || !range) return EINVAL;
u_int32_t i; u_int32_t i;
u_int32_t move; u_int32_t move;
int r; int r;
//EDOM cases //EDOM cases
if (tree->allow_overlaps) { if (tree->allow_overlaps) {
for (i = 0; i < tree->numelements; i++) { for (i = 0; i < tree->numelements; i++) {
if (toku__rt_exact (tree, range, &tree->i.ranges[i])) return EDOM; if (toku__rt_exact (tree, range, &tree->i.ranges[i])) return EDOM;
} }
} }
else { else {
for (i = 0; i < tree->numelements; i++) { for (i = 0; i < tree->numelements; i++) {
if (toku__rt_overlap(tree, &range->ends, &tree->i.ranges[i].ends)) return EDOM; if (toku__rt_overlap(tree, &range->ends, &tree->i.ranges[i].ends)) return EDOM;
} }
} }
for (i = 0; i < tree->numelements; i++) { for (i = 0; i < tree->numelements; i++) {
if (toku__rt_cmp(tree, range, &tree->i.ranges[i]) > 0) { break; } if (toku__rt_cmp(tree, range, &tree->i.ranges[i]) > 0) { break; }
} }
/* Goes in slot 'i' */ /* Goes in slot 'i' */
r = toku__rt_increase_capacity(tree, tree->numelements + 1); r = toku__rt_increase_capacity(tree, tree->numelements + 1);
if (r != 0) return r; if (r != 0) return r;
tree->numelements++; tree->numelements++;
/* Shift to make room. */ /* Shift to make room. */
for (move = tree->numelements - 1; move > i; move--) { for (move = tree->numelements - 1; move > i; move--) {
tree->i.ranges[move] = tree->i.ranges[move - 1]; tree->i.ranges[move] = tree->i.ranges[move - 1];
} }
tree->i.ranges[i] = *range; tree->i.ranges[i] = *range;
return 0; return 0;
} }
int toku_rt_delete(toku_range_tree* tree, toku_range* range) { int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
if (!tree || !range) return EINVAL; if (!tree || !range) return EINVAL;
u_int32_t i; u_int32_t i;
u_int32_t move; u_int32_t move;
for (i = 0; for (i = 0;
i < tree->numelements && i < tree->numelements &&
!toku__rt_exact(tree, range, &(tree->i.ranges[i])); !toku__rt_exact(tree, range, &(tree->i.ranges[i]));
i++) {} i++) {}
//EDOM case: Not Found //EDOM case: Not Found
if (i == tree->numelements) return EDOM; if (i == tree->numelements) return EDOM;
/* Shift left. */ /* Shift left. */
for (move = i; move < tree->numelements - 1; move++) { for (move = i; move < tree->numelements - 1; move++) {
tree->i.ranges[move] = tree->i.ranges[move + 1]; tree->i.ranges[move] = tree->i.ranges[move + 1];
} }
toku__rt_decrease_capacity(tree, --tree->numelements); toku__rt_decrease_capacity(tree, --tree->numelements);
return 0; return 0;
} }
int toku_rt_predecessor (toku_range_tree* tree, toku_point* point, int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
toku_range* pred, BOOL* wasfound) { toku_range* pred, BOOL* wasfound) {
if (!tree || !point || !pred || !wasfound) return EINVAL; if (!tree || !point || !pred || !wasfound) return EINVAL;
if (tree->allow_overlaps) return EINVAL; if (tree->allow_overlaps) return EINVAL;
toku_range* best = NULL; toku_range* best = NULL;
u_int32_t i; u_int32_t i;
for (i = 0; i < tree->numelements; i++) { for (i = 0; i < tree->numelements; i++) {
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i].ends) > 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->end_cmp(best->ends.left, tree->i.ranges[i].ends.left) < 0)) {
best = &tree->i.ranges[i]; best = &tree->i.ranges[i];
} }
} }
*wasfound = best != NULL; *wasfound = best != NULL;
if (best) *pred = *best; if (best) *pred = *best;
return 0; return 0;
} }
int toku_rt_successor (toku_range_tree* tree, toku_point* point, int toku_rt_successor (toku_range_tree* tree, toku_point* point,
toku_range* succ, BOOL* wasfound) { toku_range* succ, BOOL* wasfound) {
if (!tree || !point || !succ || !wasfound) return EINVAL; if (!tree || !point || !succ || !wasfound) return EINVAL;
if (tree->allow_overlaps) return EINVAL; if (tree->allow_overlaps) return EINVAL;
toku_range* best = NULL; toku_range* best = NULL;
u_int32_t i; u_int32_t i;
for (i = 0; i < tree->numelements; i++) { for (i = 0; i < tree->numelements; i++) {
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i].ends) < 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->end_cmp(best->ends.left, tree->i.ranges[i].ends.left) > 0)) {
best = &tree->i.ranges[i]; best = &tree->i.ranges[i];
} }
} }
*wasfound = best != NULL; *wasfound = best != NULL;
if (best) *succ = *best; if (best) *succ = *best;
return 0; return 0;
} }
int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) { int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) {
if (!tree || !allowed) return EINVAL; if (!tree || !allowed) return EINVAL;
*allowed = tree->allow_overlaps; *allowed = tree->allow_overlaps;
return 0; return 0;
} }
int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) { int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) {
if (!tree || !size) return EINVAL; if (!tree || !size) return EINVAL;
*size = tree->numelements; *size = tree->numelements;
return 0; return 0;
} }
int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) { int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) {
u_int32_t index; u_int32_t index;
int r = ENOSYS; int r = ENOSYS;
for (index = 0; index < tree->numelements; index++) { for (index = 0; index < tree->numelements; index++) {
if ((r = f(&tree->i.ranges[index], extra))) goto cleanup; if ((r = f(&tree->i.ranges[index], extra))) goto cleanup;
} }
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
/* -*- mode: C; c-basic-offset: 4 -*- */ /* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007-8 Tokutek Inc. All rights reserved." #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." #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 linear.c \file linear.c
\brief Range tree implementation \brief Range tree implementation
See rangetree.h for documentation on the following. */ See rangetree.h for documentation on the following. */
//Currently this is a stub implementation just so we can write and compile tests //Currently this is a stub implementation just so we can write and compile tests
//before actually implementing the range tree. //before actually implementing the range tree.
#include <rangetree.h> #include <rangetree.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
typedef toku_range *OMTVALUE; typedef toku_range *OMTVALUE;
#include "../../newbrt/omt.h" #include "../../newbrt/omt.h"
struct __toku_range_tree_local { struct __toku_range_tree_local {
//Logarithmic non-overlapping version only fields: //Logarithmic non-overlapping version only fields:
OMT omt; OMT omt;
}; };
#include <rangetree-internal.h> #include <rangetree-internal.h>
int toku_rt_create(toku_range_tree** ptree, int toku_rt_create(toku_range_tree** ptree,
int (*end_cmp)(const toku_point*,const toku_point*), int (*end_cmp)(const toku_point*,const toku_point*),
int (*data_cmp)(const TXNID,const TXNID), int (*data_cmp)(const TXNID,const TXNID),
BOOL allow_overlaps, BOOL allow_overlaps,
void* (*user_malloc) (size_t), void* (*user_malloc) (size_t),
void (*user_free) (void*), void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) { void* (*user_realloc)(void*, size_t)) {
int r = ENOSYS; int r = ENOSYS;
toku_range_tree* temptree = NULL; toku_range_tree* temptree = NULL;
if (allow_overlaps) return EINVAL; if (allow_overlaps) return EINVAL;
r = toku_rt_super_create(ptree, &temptree, end_cmp, data_cmp, allow_overlaps, r = toku_rt_super_create(ptree, &temptree, end_cmp, data_cmp, allow_overlaps,
user_malloc, user_free, user_realloc); user_malloc, user_free, user_realloc);
if (r!=0) { goto cleanup; } if (r!=0) { goto cleanup; }
//Any local initializers go here. //Any local initializers go here.
r = toku_omt_create(&temptree->i.omt); r = toku_omt_create(&temptree->i.omt);
if (r!=0) { goto cleanup; } if (r!=0) { goto cleanup; }
*ptree = temptree; *ptree = temptree;
r = 0; r = 0;
cleanup: cleanup:
if (r!=0) { if (r!=0) {
if (temptree) user_free(temptree); if (temptree) user_free(temptree);
} }
return r; return r;
} }
static int rt_clear_helper(OMTVALUE value, u_int32_t UU(index), void* extra) { static int rt_clear_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
void (*user_free)(void*) = extra; void (*user_free)(void*) = extra;
user_free(value); user_free(value);
return 0; return 0;
} }
int toku_rt_close(toku_range_tree* tree) { int toku_rt_close(toku_range_tree* tree) {
if (!tree) { return EINVAL; } if (!tree) { return EINVAL; }
int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free); int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free);
assert(r==0); assert(r==0);
toku_omt_destroy(&tree->i.omt); toku_omt_destroy(&tree->i.omt);
tree->free(tree); tree->free(tree);
return 0; return 0;
} }
void toku_rt_clear(toku_range_tree* tree) { void toku_rt_clear(toku_range_tree* tree) {
assert(tree); assert(tree);
int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free); int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free);
assert(r==0); assert(r==0);
toku_omt_clear(tree->i.omt); toku_omt_clear(tree->i.omt);
tree->numelements = 0; tree->numelements = 0;
} }
typedef struct { typedef struct {
int (*end_cmp)(const toku_point*,const toku_point*); int (*end_cmp)(const toku_point*,const toku_point*);
toku_interval query; toku_interval query;
} rt_heavi_extra; } rt_heavi_extra;
static int rt_heaviside(OMTVALUE candidate, void* extra) { static int rt_heaviside(OMTVALUE candidate, void* extra) {
toku_range* range_candidate = candidate; toku_range* range_candidate = candidate;
rt_heavi_extra* info = extra; rt_heavi_extra* info = extra;
if (info->end_cmp(range_candidate->ends.right, info->query.left) < 0) return -1; if (info->end_cmp(range_candidate->ends.right, info->query.left) < 0) return -1;
if (info->end_cmp(range_candidate->ends.left, info->query.right) > 0) return 1; if (info->end_cmp(range_candidate->ends.left, info->query.right) > 0) return 1;
return 0; return 0;
} }
typedef struct { typedef struct {
int (*end_cmp)(const toku_point*,const toku_point*); int (*end_cmp)(const toku_point*,const toku_point*);
toku_interval query; toku_interval query;
u_int32_t k; u_int32_t k;
u_int32_t numfound; u_int32_t numfound;
toku_range_tree* rt; toku_range_tree* rt;
toku_range** buf; toku_range** buf;
u_int32_t* buflen; u_int32_t* buflen;
} rt_find_info; } rt_find_info;
static int rt_find_helper(OMTVALUE value, u_int32_t UU(index), void* extra) { static int rt_find_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
rt_find_info* info = extra; rt_find_info* info = extra;
toku_range* range = value; toku_range* range = value;
int r = ENOSYS; int r = ENOSYS;
if (info->end_cmp(range->ends.left, info->query.right) > 0) { if (info->end_cmp(range->ends.left, info->query.right) > 0) {
r = TOKUDB_SUCCEEDED_EARLY; r = TOKUDB_SUCCEEDED_EARLY;
goto cleanup; goto cleanup;
} }
r = toku__rt_increase_buffer(info->rt, info->buf, info->buflen, info->numfound + 1); r = toku__rt_increase_buffer(info->rt, info->buf, info->buflen, info->numfound + 1);
if (r!=0) goto cleanup; if (r!=0) goto cleanup;
(*info->buf)[info->numfound++] = *range; (*info->buf)[info->numfound++] = *range;
if (info->numfound>=info->k) { if (info->numfound>=info->k) {
r = TOKUDB_SUCCEEDED_EARLY; r = TOKUDB_SUCCEEDED_EARLY;
goto cleanup; goto cleanup;
} }
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
int toku_rt_find(toku_range_tree* tree, toku_interval* 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) { toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
int r = ENOSYS; int r = ENOSYS;
if (!tree || !query || !buf || !buflen || !numfound || *buflen == 0) { if (!tree || !query || !buf || !buflen || !numfound || *buflen == 0) {
r = EINVAL; goto cleanup; r = EINVAL; goto cleanup;
} }
assert(!tree->allow_overlaps); assert(!tree->allow_overlaps);
/* k = 0 means return ALL. (infinity) */ /* k = 0 means return ALL. (infinity) */
if (k == 0) { k = UINT32_MAX; } if (k == 0) { k = UINT32_MAX; }
u_int32_t leftmost; u_int32_t leftmost;
u_int32_t rightmost = toku_omt_size(tree->i.omt); u_int32_t rightmost = toku_omt_size(tree->i.omt);
rt_heavi_extra extra; rt_heavi_extra extra;
extra.end_cmp = tree->end_cmp; extra.end_cmp = tree->end_cmp;
extra.query = *query; extra.query = *query;
r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &leftmost, NULL); r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &leftmost, NULL);
if (r==DB_NOTFOUND) { if (r==DB_NOTFOUND) {
/* Nothing overlaps. */ /* Nothing overlaps. */
*numfound = 0; *numfound = 0;
r = 0; r = 0;
goto cleanup; goto cleanup;
} }
if (r!=0) goto cleanup; if (r!=0) goto cleanup;
rt_find_info info; rt_find_info info;
info.end_cmp = tree->end_cmp; info.end_cmp = tree->end_cmp;
info.query = *query; info.query = *query;
info.k = k; info.k = k;
info.numfound = 0; info.numfound = 0;
info.rt = tree; info.rt = tree;
info.buf = buf; info.buf = buf;
info.buflen = buflen; info.buflen = buflen;
r = toku_omt_iterate_on_range(tree->i.omt, leftmost, rightmost, rt_find_helper, &info); r = toku_omt_iterate_on_range(tree->i.omt, leftmost, rightmost, rt_find_helper, &info);
if (r==TOKUDB_SUCCEEDED_EARLY) r=0; if (r==TOKUDB_SUCCEEDED_EARLY) r=0;
if (r!=0) goto cleanup; if (r!=0) goto cleanup;
*numfound = info.numfound; *numfound = info.numfound;
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
int toku_rt_insert(toku_range_tree* tree, toku_range* range) { int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
int r = ENOSYS; int r = ENOSYS;
toku_range* insert_range = NULL; toku_range* insert_range = NULL;
if (!tree || !range) { r = EINVAL; goto cleanup; } if (!tree || !range) { r = EINVAL; goto cleanup; }
assert(!tree->allow_overlaps); assert(!tree->allow_overlaps);
u_int32_t index; u_int32_t index;
rt_heavi_extra extra; rt_heavi_extra extra;
extra.end_cmp = tree->end_cmp; extra.end_cmp = tree->end_cmp;
extra.query = range->ends; extra.query = range->ends;
r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &index, NULL); r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &index, NULL);
if (r==0) { r = EDOM; goto cleanup; } if (r==0) { r = EDOM; goto cleanup; }
if (r!=DB_NOTFOUND) goto cleanup; if (r!=DB_NOTFOUND) goto cleanup;
insert_range = tree->malloc(sizeof(*insert_range)); insert_range = tree->malloc(sizeof(*insert_range));
*insert_range = *range; *insert_range = *range;
if ((r = toku_omt_insert_at(tree->i.omt, insert_range, index))) goto cleanup; if ((r = toku_omt_insert_at(tree->i.omt, insert_range, index))) goto cleanup;
tree->numelements++; tree->numelements++;
r = 0; r = 0;
cleanup: cleanup:
if (r!=0) { if (r!=0) {
if (insert_range) tree->free(insert_range); if (insert_range) tree->free(insert_range);
} }
return r; return r;
} }
int toku_rt_delete(toku_range_tree* tree, toku_range* range) { int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
int r = ENOSYS; int r = ENOSYS;
if (!tree || !range) { r = EINVAL; goto cleanup; } if (!tree || !range) { r = EINVAL; goto cleanup; }
assert(!tree->allow_overlaps); assert(!tree->allow_overlaps);
OMTVALUE value = NULL; OMTVALUE value = NULL;
u_int32_t index; u_int32_t index;
rt_heavi_extra extra; rt_heavi_extra extra;
extra.end_cmp = tree->end_cmp; extra.end_cmp = tree->end_cmp;
extra.query = range->ends; extra.query = range->ends;
r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, &value, &index, NULL); r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, &value, &index, NULL);
if (r!=0) { r = EDOM; goto cleanup; } if (r!=0) { r = EDOM; goto cleanup; }
assert(value); assert(value);
toku_range* data = value; toku_range* data = value;
if (tree->end_cmp(data->ends.left, range->ends.left) || if (tree->end_cmp(data->ends.left, range->ends.left) ||
tree->end_cmp(data->ends.right, range->ends.right) || tree->end_cmp(data->ends.right, range->ends.right) ||
tree->data_cmp(data->data, range->data)) { tree->data_cmp(data->data, range->data)) {
r = EDOM; r = EDOM;
goto cleanup; goto cleanup;
} }
if ((r = toku_omt_delete_at(tree->i.omt, index))) goto cleanup; if ((r = toku_omt_delete_at(tree->i.omt, index))) goto cleanup;
tree->free(data); tree->free(data);
tree->numelements--; tree->numelements--;
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
static inline int rt_neightbor(toku_range_tree* tree, toku_point* point, static inline int rt_neightbor(toku_range_tree* tree, toku_point* point,
toku_range* neighbor, BOOL* wasfound, int direction) { toku_range* neighbor, BOOL* wasfound, int direction) {
int r = ENOSYS; int r = ENOSYS;
if (!tree || !point || !neighbor || !wasfound || tree->allow_overlaps) { if (!tree || !point || !neighbor || !wasfound || tree->allow_overlaps) {
r = EINVAL; goto cleanup; r = EINVAL; goto cleanup;
} }
u_int32_t index; u_int32_t index;
OMTVALUE value = NULL; OMTVALUE value = NULL;
rt_heavi_extra extra; rt_heavi_extra extra;
extra.end_cmp = tree->end_cmp; extra.end_cmp = tree->end_cmp;
extra.query.left = point; extra.query.left = point;
extra.query.right = point; extra.query.right = point;
assert(direction==1 || direction==-1); assert(direction==1 || direction==-1);
r = toku_omt_find(tree->i.omt, rt_heaviside, &extra, direction, &value, &index, NULL); r = toku_omt_find(tree->i.omt, rt_heaviside, &extra, direction, &value, &index, NULL);
if (r==DB_NOTFOUND) { if (r==DB_NOTFOUND) {
*wasfound = FALSE; *wasfound = FALSE;
r = 0; r = 0;
goto cleanup; goto cleanup;
} }
if (r!=0) goto cleanup; if (r!=0) goto cleanup;
assert(value); assert(value);
toku_range* data = value; toku_range* data = value;
*wasfound = TRUE; *wasfound = TRUE;
*neighbor = *data; *neighbor = *data;
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
int toku_rt_predecessor (toku_range_tree* tree, toku_point* point, int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
toku_range* pred, BOOL* wasfound) { toku_range* pred, BOOL* wasfound) {
return rt_neightbor(tree, point, pred, wasfound, -1); return rt_neightbor(tree, point, pred, wasfound, -1);
} }
int toku_rt_successor (toku_range_tree* tree, toku_point* point, int toku_rt_successor (toku_range_tree* tree, toku_point* point,
toku_range* succ, BOOL* wasfound) { toku_range* succ, BOOL* wasfound) {
return rt_neightbor(tree, point, succ, wasfound, 1); return rt_neightbor(tree, point, succ, wasfound, 1);
} }
int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) { int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) {
if (!tree || !allowed) return EINVAL; if (!tree || !allowed) return EINVAL;
assert(!tree->allow_overlaps); assert(!tree->allow_overlaps);
*allowed = tree->allow_overlaps; *allowed = tree->allow_overlaps;
return 0; return 0;
} }
int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) { int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) {
if (!tree || !size) return EINVAL; if (!tree || !size) return EINVAL;
*size = tree->numelements; *size = tree->numelements;
return 0; return 0;
} }
typedef struct { typedef struct {
int (*f)(toku_range*,void*); int (*f)(toku_range*,void*);
void* extra; void* extra;
} rt_iter_info; } rt_iter_info;
static int rt_iterate_helper(OMTVALUE value, u_int32_t UU(index), void* extra) { static int rt_iterate_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
rt_iter_info* info = extra; rt_iter_info* info = extra;
return info->f(value, info->extra); return info->f(value, info->extra);
} }
int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) { int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) {
rt_iter_info info; rt_iter_info info;
info.f = f; info.f = f;
info.extra = extra; info.extra = extra;
return toku_omt_iterate(tree->i.omt, rt_iterate_helper, &info); return toku_omt_iterate(tree->i.omt, rt_iterate_helper, &info);
} }
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