Commit 14085672 authored by John Esmet's avatar John Esmet

fixes #192 Remove legacy OMT API. Some of it survives in omt-test.cc to

simplify things. New OMTs will use the new templated API, or, when
performance is not critical, use something simple like a std::map
parent 1f07a7d1
...@@ -53,7 +53,6 @@ set(FT_SOURCES ...@@ -53,7 +53,6 @@ set(FT_SOURCES
logger logger
log_upgrade log_upgrade
minicron minicron
omt
pqueue pqueue
queue queue
quicklz quicklz
......
...@@ -743,8 +743,6 @@ exit: ...@@ -743,8 +743,6 @@ exit:
return; return;
} }
// TODO: (Zardosht) possibly get rid of this function and use toku_omt_split_at in
// ftleaf_split
static void static void
move_leafentries( move_leafentries(
BASEMENTNODE dest_bn, BASEMENTNODE dest_bn,
......
...@@ -4438,7 +4438,7 @@ int iterate_do_bn_apply_msg(const int32_t &offset, const uint32_t UU(idx), struc ...@@ -4438,7 +4438,7 @@ int iterate_do_bn_apply_msg(const int32_t &offset, const uint32_t UU(idx), struc
* found. The pivot_bounds are the lower bound exclusive and upper bound * found. The pivot_bounds are the lower bound exclusive and upper bound
* inclusive, because they come from pivot keys in the tree. We want OMT * inclusive, because they come from pivot keys in the tree. We want OMT
* indices, which must have the lower bound be inclusive and the upper * indices, which must have the lower bound be inclusive and the upper
* bound exclusive. We will get these by telling toku_omt_find to look * bound exclusive. We will get these by telling omt::find to look
* for something strictly bigger than each of our pivot bounds. * for something strictly bigger than each of our pivot bounds.
* *
* Outputs the OMT indices in lbi (lower bound inclusive) and ube (upper * Outputs the OMT indices in lbi (lower bound inclusive) and ube (upper
...@@ -4511,7 +4511,7 @@ find_bounds_within_message_tree( ...@@ -4511,7 +4511,7 @@ find_bounds_within_message_tree(
// Again, we use an msn of MAX_MSN and a direction of +1 to get // Again, we use an msn of MAX_MSN and a direction of +1 to get
// the first thing bigger than the upper_bound_inclusive key. // the first thing bigger than the upper_bound_inclusive key.
// This is therefore the smallest thing we don't want to apply, // This is therefore the smallest thing we don't want to apply,
// and toku_omt_iterate_on_range will not examine it. // and omt::iterate_on_range will not examine it.
struct toku_fifo_entry_key_msn_heaviside_extra ube_extra; struct toku_fifo_entry_key_msn_heaviside_extra ube_extra;
ZERO_STRUCT(ube_extra); ZERO_STRUCT(ube_extra);
ube_extra.desc = desc; ube_extra.desc = desc;
......
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
/*
COPYING CONDITIONS NOTICE:
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation, and provided that the
following conditions are met:
* Redistributions of source code must retain this COPYING
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
GRANT (below).
* Redistributions in binary form must reproduce this COPYING
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
GRANT (below) in the documentation and/or other materials
provided with the distribution.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
COPYRIGHT NOTICE:
TokuDB, Tokutek Fractal Tree Indexing Library.
Copyright (C) 2007-2013 Tokutek, Inc.
DISCLAIMER:
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
UNIVERSITY PATENT NOTICE:
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.
PATENT MARKING NOTICE:
This software is covered by US Patent No. 8,185,551.
This software is covered by US Patent No. 8,489,638.
PATENT RIGHTS GRANT:
"THIS IMPLEMENTATION" means the copyrightable works distributed by
Tokutek as part of the Fractal Tree project.
"PATENT CLAIMS" means the claims of patents that are owned or
licensable by Tokutek, both currently or in the future; and that in
the absence of this license would be infringed by THIS
IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
"PATENT CHALLENGE" shall mean a challenge to the validity,
patentability, enforceability and/or non-infringement of any of the
PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
Tokutek hereby grants to you, for the term and geographical scope of
the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to
make, have made, use, offer to sell, sell, import, transfer, and
otherwise run, modify, and propagate the contents of THIS
IMPLEMENTATION, where such license applies only to the PATENT
CLAIMS. This grant does not include claims that would be infringed
only as a consequence of further modifications of THIS
IMPLEMENTATION. If you or your agent or licensee institute or order
or agree to the institution of patent litigation against any entity
(including a cross-claim or counterclaim in a lawsuit) alleging that
THIS IMPLEMENTATION constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any rights
granted to you under this License shall terminate as of the date
such litigation is filed. If you or your agent or exclusive
licensee institute or order or agree to the institution of a PATENT
CHALLENGE, then Tokutek may terminate any rights granted to you
under this License.
*/
#ident "Copyright (c) 2007-2013 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 <toku_portability.h>
#include <memory.h>
#include <string.h>
#include <db.h>
#include "omt.h"
int
toku_omt_create_steal_sorted_array(OMT *omtp, OMTVALUE **valuesp, uint32_t numvalues, uint32_t capacity) {
OMT XMALLOC(omt);
omt->create_steal_sorted_array(valuesp, numvalues, capacity);
*omtp = omt;
return 0;
}
//TODO: Put all omt API functions here.
int toku_omt_create (OMT *omtp) {
OMT XMALLOC(omt);
omt->create();
*omtp = omt;
return 0;
}
void toku_omt_destroy(OMT *omtp) {
OMT omt=*omtp;
omt->destroy();
toku_free(omt);
*omtp=NULL;
}
uint32_t toku_omt_size(OMT V) {
return V->size();
}
int toku_omt_create_from_sorted_array(OMT *omtp, OMTVALUE *values, uint32_t numvalues) {
OMT XMALLOC(omt);
omt->create_from_sorted_array(values, numvalues);
*omtp=omt;
return 0;
}
int toku_omt_insert_at(OMT omt, OMTVALUE value, uint32_t index) {
return omt->insert_at(value, index);
}
int toku_omt_set_at (OMT omt, OMTVALUE value, uint32_t index) {
return omt->set_at(value, index);
}
int toku_omt_delete_at(OMT omt, uint32_t index) {
return omt->delete_at(index);
}
int toku_omt_fetch(OMT omt, uint32_t i, OMTVALUE *v) {
return omt->fetch(i, v);
}
struct functor {
int (*f)(OMTVALUE, uint32_t, void *);
void *v;
};
static_assert(std::is_pod<functor>::value, "not POD");
int call_functor(const OMTVALUE &v, uint32_t idx, functor *const ftor);
int call_functor(const OMTVALUE &v, uint32_t idx, functor *const ftor) {
return ftor->f(const_cast<OMTVALUE>(v), idx, ftor->v);
}
int toku_omt_iterate(OMT omt, int (*f)(OMTVALUE, uint32_t, void*), void*v) {
struct functor ftor = { .f = f, .v = v };
return omt->iterate<functor, call_functor>(&ftor);
}
int toku_omt_iterate_on_range(OMT omt, uint32_t left, uint32_t right, int (*f)(OMTVALUE, uint32_t, void*), void*v) {
struct functor ftor = { .f = f, .v = v };
return omt->iterate_on_range<functor, call_functor>(left, right, &ftor);
}
struct heftor {
int (*h)(OMTVALUE, void *v);
void *v;
};
static_assert(std::is_pod<heftor>::value, "not POD");
int call_heftor(const OMTVALUE &v, const heftor &htor);
int call_heftor(const OMTVALUE &v, const heftor &htor) {
return htor.h(const_cast<OMTVALUE>(v), htor.v);
}
int toku_omt_insert(OMT omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, uint32_t *index) {
struct heftor htor = { .h = h, .v = v };
return omt->insert<heftor, call_heftor>(value, htor, index);
}
int toku_omt_find_zero(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
return V->find_zero<heftor, call_heftor>(htor, value, index);
}
int toku_omt_find(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, int direction, OMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
return V->find<heftor, call_heftor>(htor, direction, value, index);
}
int toku_omt_split_at(OMT omt, OMT *newomtp, uint32_t index) {
OMT XMALLOC(newomt);
int r = omt->split_at(newomt, index);
if (r != 0) {
toku_free(newomt);
} else {
*newomtp = newomt;
}
return r;
}
int toku_omt_merge(OMT leftomt, OMT rightomt, OMT *newomtp) {
OMT XMALLOC(newomt);
newomt->merge(leftomt, rightomt);
toku_free(leftomt);
toku_free(rightomt);
*newomtp = newomt;
return 0;
}
int toku_omt_clone_noptr(OMT *dest, OMT src) {
OMT XMALLOC(omt);
omt->clone(*src);
*dest = omt;
return 0;
}
void toku_omt_clear(OMT omt) {
omt->clear();
}
size_t toku_omt_memory_size (OMT omt) {
return omt->memory_size();
}
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#if !defined(TOKU_OMT_H)
#define TOKU_OMT_H
#ident "$Id$"
/*
COPYING CONDITIONS NOTICE:
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation, and provided that the
following conditions are met:
* Redistributions of source code must retain this COPYING
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
GRANT (below).
* Redistributions in binary form must reproduce this COPYING
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
GRANT (below) in the documentation and/or other materials
provided with the distribution.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
COPYRIGHT NOTICE:
TokuDB, Tokutek Fractal Tree Indexing Library.
Copyright (C) 2007-2013 Tokutek, Inc.
DISCLAIMER:
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
UNIVERSITY PATENT NOTICE:
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.
PATENT MARKING NOTICE:
This software is covered by US Patent No. 8,185,551.
This software is covered by US Patent No. 8,489,638.
PATENT RIGHTS GRANT:
"THIS IMPLEMENTATION" means the copyrightable works distributed by
Tokutek as part of the Fractal Tree project.
"PATENT CLAIMS" means the claims of patents that are owned or
licensable by Tokutek, both currently or in the future; and that in
the absence of this license would be infringed by THIS
IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
"PATENT CHALLENGE" shall mean a challenge to the validity,
patentability, enforceability and/or non-infringement of any of the
PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
Tokutek hereby grants to you, for the term and geographical scope of
the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to
make, have made, use, offer to sell, sell, import, transfer, and
otherwise run, modify, and propagate the contents of THIS
IMPLEMENTATION, where such license applies only to the PATENT
CLAIMS. This grant does not include claims that would be infringed
only as a consequence of further modifications of THIS
IMPLEMENTATION. If you or your agent or licensee institute or order
or agree to the institution of patent litigation against any entity
(including a cross-claim or counterclaim in a lawsuit) alleging that
THIS IMPLEMENTATION constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any rights
granted to you under this License shall terminate as of the date
such litigation is filed. If you or your agent or exclusive
licensee institute or order or agree to the institution of a PATENT
CHALLENGE, then Tokutek may terminate any rights granted to you
under this License.
*/
#ident "Copyright (c) 2007-2013 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."
// Order Maintenance Tree (OMT)
//
// Maintains a collection of totally ordered values, where each value has an integer weight.
// The OMT is a mutable datatype.
//
// The Abstraction:
//
// An OMT is a vector of values, $V$, where $|V|$ is the length of the vector.
// The vector is numbered from $0$ to $|V|-1$.
// Each value has a weight. The weight of the $i$th element is denoted $w(V_i)$.
//
// We can create a new OMT, which is the empty vector.
//
// We can insert a new element $x$ into slot $i$, changing $V$ into $V'$ where
// $|V'|=1+|V|$ and
//
// V'_j = V_j if $j<i$
// x if $j=i$
// V_{j-1} if $j>i$.
//
// We can specify $i$ using a kind of function instead of as an integer.
// Let $b$ be a function mapping from values to nonzero integers, such that
// the signum of $b$ is monotically increasing.
// We can specify $i$ as the minimum integer such that $b(V_i)>0$.
//
// We look up a value using its index, or using a Heaviside function.
// For lookups, we allow $b$ to be zero for some values, and again the signum of $b$ must be monotonically increasing.
// When lookup up values, we can look up
// $V_i$ where $i$ is the minimum integer such that $b(V_i)=0$. (With a special return code if no such value exists.)
// (Rationale: Ordinarily we want $i$ to be unique. But for various reasons we want to allow multiple zeros, and we want the smallest $i$ in that case.)
// $V_i$ where $i$ is the minimum integer such that $b(V_i)>0$. (Or an indication that no such value exists.)
// $V_i$ where $i$ is the maximum integer such that $b(V_i)<0$. (Or an indication that no such value exists.)
//
// When looking up a value using a Heaviside function, we get the value and its index.
//
// We can also split an OMT into two OMTs, splitting the weight of the values evenly.
// Find a value $j$ such that the values to the left of $j$ have about the same total weight as the values to the right of $j$.
// The resulting two OMTs contain the values to the left of $j$ and the values to the right of $j$ respectively.
// All of the values from the original OMT go into one of the new OMTs.
// If the weights of the values don't split exactly evenly, then the implementation has the freedom to choose whether
// the new left OMT or the new right OMT is larger.
//
// Performance:
// Insertion and deletion should run with $O(\log |V|)$ time and $O(\log |V|)$ calls to the Heaviside function.
// The memory required is O(|V|).
//
// The programming API:
//typedef struct value *OMTVALUE; // A slight improvement over using void*.
#include <util/omt.h>
typedef void *OMTVALUE;
typedef toku::omt<OMTVALUE> *OMT;
int toku_omt_create (OMT *omtp);
// Effect: Create an empty OMT. Stores it in *omtp.
// Requires: omtp != NULL
// Returns:
// 0 success
// ENOMEM out of memory (and doesn't modify *omtp)
// Performance: constant time.
int toku_omt_create_from_sorted_array(OMT *omtp, OMTVALUE *values, uint32_t numvalues);
// Effect: Create a OMT containing values. The number of values is in numvalues.
// Stores the new OMT in *omtp.
// Requires: omtp != NULL
// Requires: values != NULL
// Requires: values is sorted
// Returns:
// 0 success
// ENOMEM out of memory (and doesn't modify *omtp)
// Performance: time=O(numvalues)
// Rational: Normally to insert N values takes O(N lg N) amortized time.
// If the N values are known in advance, are sorted, and
// the structure is empty, we can batch insert them much faster.
int toku_omt_create_steal_sorted_array(OMT *omtp, OMTVALUE **valuesp, uint32_t numvalues, uint32_t steal_capacity);
// Effect: Create an OMT containing values. The number of values is in numvalues.
// On success the OMT takes ownership of *valuesp array, and sets valuesp=NULL.
// Requires: omtp != NULL
// Requires: valuesp != NULL
// Requires: *valuesp is sorted
// Requires: *valuesp was allocated with toku_malloc
// Requires: Capacity of the *valuesp array is <= steal_capacity
// Requires: On success, *valuesp may not be accessed again by the caller.
// Returns:
// 0 success
// ENOMEM out of memory (and doesn't modify *omtp)
// EINVAL *valuesp == NULL or numvalues > capacity
// Performance: time=O(1)
// Rational: toku_omt_create_from_sorted_array takes O(numvalues) time.
// By taking ownership of the array, we save a malloc and memcpy,
// and possibly a free (if the caller is done with the array).
void toku_omt_destroy(OMT *omtp);
// Effect: Destroy an OMT, freeing all its memory.
// Does not free the OMTVALUEs stored in the OMT.
// Those values may be freed before or after calling toku_omt_destroy.
// Also sets *omtp=NULL.
// Requires: omtp != NULL
// Requires: *omtp != NULL
// Rationale: The usage is to do something like
// toku_omt_destroy(&s->omt);
// and now s->omt will have a NULL pointer instead of a dangling freed pointer.
// Rationale: Returns no values since free() cannot fail.
// Rationale: Does not free the OMTVALUEs to reduce complexity.
// Performance: time=O(toku_omt_size(*omtp))
uint32_t toku_omt_size(OMT V);
// Effect: return |V|.
// Requires: V != NULL
// Performance: time=O(1)
int toku_omt_iterate_on_range(OMT omt, uint32_t left, uint32_t right, int (*f)(OMTVALUE, uint32_t, void*), void*v);
// Effect: Iterate over the values of the omt, from left to right, calling f on each value.
// The second argument passed to f is the index of the value.
// The third argument passed to f is v.
// The indices run from 0 (inclusive) to toku_omt_size(omt) (exclusive).
// We will iterate only over [left,right)
//
// Requires: omt != NULL
// left <= right
// Requires: f != NULL
// Returns:
// If f ever returns nonzero, then the iteration stops, and the value returned by f is returned by toku_omt_iterate.
// If f always returns zero, then toku_omt_iterate returns 0.
// Requires: Don't modify omt while running. (E.g., f may not insert or delete values form omt.)
// Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in omt.
// Rational: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read.
int toku_omt_iterate(OMT omt, int (*f)(OMTVALUE, uint32_t, void*), void*v);
// Effect: Iterate over the values of the omt, from left to right, calling f on each value.
// The second argument passed to f is the index of the value.
// The third argument passed to f is v.
// The indices run from 0 (inclusive) to toku_omt_size(omt) (exclusive).
// Requires: omt != NULL
// Requires: f != NULL
// Returns:
// If f ever returns nonzero, then the iteration stops, and the value returned by f is returned by toku_omt_iterate.
// If f always returns zero, then toku_omt_iterate returns 0.
// Requires: Don't modify omt while running. (E.g., f may not insert or delete values form omt.)
// Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in omt.
// Rational: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read.
int toku_omt_insert_at(OMT omt, OMTVALUE value, uint32_t idx);
// Effect: Increases indexes of all items at slot >= index by 1.
// Insert value into the position at index.
//
// Returns:
// 0 success
// EINVAL if index>toku_omt_size(omt)
// ENOMEM
// On error, omt is unchanged.
// Performance: time=O(\log N) amortized time.
// Rationale: Some future implementation may be O(\log N) worst-case time, but O(\log N) amortized is good enough for now.
int toku_omt_set_at (OMT omt, OMTVALUE value, uint32_t idx);
// Effect: Replaces the item at index with value.
// Returns:
// 0 success
// EINVAL if index>=toku_omt_size(omt)
// On error, omt i sunchanged.
// Performance: time=O(\log N)
// Rationale: The BRT needs to be able to replace a value with another copy of the same value (allocated in a different location)
int toku_omt_insert(OMT omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, uint32_t *idx);
// Effect: Insert value into the OMT.
// If there is some i such that $h(V_i, v)=0$ then returns DB_KEYEXIST.
// Otherwise, let i be the minimum value such that $h(V_i, v)>0$.
// If no such i exists, then let i be |V|
// Then this has the same effect as
// omt_insert_at(tree, value, i);
// If index!=NULL then i is stored in *index
// Requires: The signum of h must be monotonically increasing.
// Returns:
// 0 success
// DB_KEYEXIST the key is present (h was equal to zero for some value)
// ENOMEM
// On nonzero return, omt is unchanged.
// On nonzero non-DB_KEYEXIST return, *index is unchanged.
// Performance: time=O(\log N) amortized.
// Rationale: Some future implementation may be O(\log N) worst-case time, but O(\log N) amortized is good enough for now.
int toku_omt_delete_at(OMT omt, uint32_t idx);
// Effect: Delete the item in slot index.
// Decreases indexes of all items at slot >= index by 1.
// Returns
// 0 success
// EINVAL if index>=toku_omt_size(omt)
// On error, omt is unchanged.
// Rationale: To delete an item, first find its index using toku_omt_find, then delete it.
// Performance: time=O(\log N) amortized.
int toku_omt_fetch (OMT V, uint32_t i, OMTVALUE *v);
// Effect: Set *v=V_i
// If c!=NULL then set c's abstract offset to i.
// Requires: v != NULL
// Returns
// 0 success
// EINVAL if index>=toku_omt_size(omt)
// On nonzero return, *v is unchanged, and c (if nonnull) is either
// invalidated or unchanged.
// Performance: time=O(\log N)
// Implementation Notes: It is possible that c was previously valid and was
// associated with a different OMT. If c is changed by this
// function, the function must remove c's association with the old
// OMT, and associate it with the new OMT.
int toku_omt_find_zero(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, uint32_t *idx);
// Effect: Find the smallest i such that h(V_i, extra)>=0
// If there is such an i and h(V_i,extra)==0 then set *index=i and return 0.
// If there is such an i and h(V_i,extra)>0 then set *index=i and return DB_NOTFOUND.
// If there is no such i then set *index=toku_omt_size(V) and return DB_NOTFOUND.
// Requires: index!=NULL
int toku_omt_find(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, int direction, OMTVALUE *value, uint32_t *idx);
// Effect:
// If direction >0 then find the smallest i such that h(V_i,extra)>0.
// If direction <0 then find the largest i such that h(V_i,extra)<0.
// (Direction may not be equal to zero.)
// If value!=NULL then store V_i in *value
// If index!=NULL then store i in *index.
// Requires: The signum of h is monotically increasing.
// Returns
// 0 success
// DB_NOTFOUND no such value is found.
// On nonzero return, *value and *index are unchanged, and c (if nonnull) is either invalidated
// or unchanged.
// Performance: time=O(\log N)
// Rationale:
// Here's how to use the find function to find various things
// Cases for find:
// find first value: ( h(v)=+1, direction=+1 )
// find last value ( h(v)=-1, direction=-1 )
// find first X ( h(v)=(v< x) ? -1 : 1 direction=+1 )
// find last X ( h(v)=(v<=x) ? -1 : 1 direction=-1 )
// find X or successor to X ( same as find first X. )
//
// Rationale: To help understand heaviside functions and behavor of find:
// There are 7 kinds of heaviside functions.
// The signus of the h must be monotonically increasing.
// Given a function of the following form, A is the element
// returned for direction>0, B is the element returned
// for direction<0, C is the element returned for
// direction==0 (see find_zero) (with a return of 0), and D is the element
// returned for direction==0 (see find_zero) with a return of DB_NOTFOUND.
// If any of A, B, or C are not found, then asking for the
// associated direction will return DB_NOTFOUND.
// See find_zero for more information.
//
// Let the following represent the signus of the heaviside function.
//
// -...-
// A
// D
//
// +...+
// B
// D
//
// 0...0
// C
//
// -...-0...0
// AC
//
// 0...0+...+
// C B
//
// -...-+...+
// AB
// D
//
// -...-0...0+...+
// AC B
int toku_omt_split_at(OMT omt, OMT *newomt, uint32_t idx);
// Effect: Create a new OMT, storing it in *newomt.
// The values to the right of index (starting at index) are moved to *newomt.
// Requires: omt != NULL
// Requires: newomt != NULL
// Returns
// 0 success,
// EINVAL if index > toku_omt_size(omt)
// ENOMEM
// On nonzero return, omt and *newomt are unmodified.
// Performance: time=O(n)
// Rationale: We don't need a split-evenly operation. We need to split items so that their total sizes
// are even, and other similar splitting criteria. It's easy to split evenly by calling toku_omt_size(), and dividing by two.
int toku_omt_merge(OMT leftomt, OMT rightomt, OMT *newomt);
// Effect: Appends leftomt and rightomt to produce a new omt.
// Sets *newomt to the new omt.
// On success, leftomt and rightomt destroyed,.
// Returns 0 on success
// ENOMEM on out of memory.
// On error, nothing is modified.
// Performance: time=O(n) is acceptable, but one can imagine implementations that are O(\log n) worst-case.
int toku_omt_clone_noptr(OMT *dest, OMT src);
// Effect: Creates a copy of an omt.
// Sets *dest to the clone
// Each element is assumed to be stored directly in the omt, that is, the OMTVALUEs are not pointers, they are data. Thus no extra memory allocation is required.
// Returns 0 on success
// ENOMEM on out of memory.
// On error, nothing is modified.
// Performance: time between O(n) and O(n log n), depending how long it
// takes to traverse src.
void toku_omt_clear(OMT omt);
// Effect: Set the tree to be empty.
// Note: Will not reallocate or resize any memory, since returning void precludes calling malloc.
// Performance: time=O(1)
size_t toku_omt_memory_size (OMT omt);
// Effect: Return the size (in bytes) of the omt, as it resides in main memory. Don't include any of the OMTVALUES.
#endif /* #ifndef TOKU_OMT_H */
...@@ -97,7 +97,8 @@ PATENT RIGHTS GRANT: ...@@ -97,7 +97,8 @@ PATENT RIGHTS GRANT:
#include "cachetable.h" #include "cachetable.h"
#include "checkpoint.h" #include "checkpoint.h"
#include "txn_manager.h" #include "txn_manager.h"
#include "omt.h"
#include <util/omt.h>
int tokudb_recovery_trace = 0; // turn on recovery tracing, default off. int tokudb_recovery_trace = 0; // turn on recovery tracing, default off.
...@@ -174,7 +175,7 @@ static void file_map_tuple_destroy(struct file_map_tuple *tuple) { ...@@ -174,7 +175,7 @@ static void file_map_tuple_destroy(struct file_map_tuple *tuple) {
// Map filenum to ft_handle // Map filenum to ft_handle
struct file_map { struct file_map {
OMT filenums; toku::omt<struct file_map_tuple *> *filenums;
}; };
// The recovery environment // The recovery environment
...@@ -200,31 +201,33 @@ typedef struct recover_env *RECOVER_ENV; ...@@ -200,31 +201,33 @@ typedef struct recover_env *RECOVER_ENV;
static void file_map_init(struct file_map *fmap) { static void file_map_init(struct file_map *fmap) {
int r = toku_omt_create(&fmap->filenums); XMALLOC(fmap->filenums);
assert(r == 0); fmap->filenums->create();
} }
static void file_map_destroy(struct file_map *fmap) { static void file_map_destroy(struct file_map *fmap) {
toku_omt_destroy(&fmap->filenums); fmap->filenums->destroy();
toku_free(fmap->filenums);
fmap->filenums = nullptr;
} }
static uint32_t file_map_get_num_dictionaries(struct file_map *fmap) { static uint32_t file_map_get_num_dictionaries(struct file_map *fmap) {
return toku_omt_size(fmap->filenums); return fmap->filenums->size();
} }
static void file_map_close_dictionaries(struct file_map *fmap, LSN oplsn) { static void file_map_close_dictionaries(struct file_map *fmap, LSN oplsn) {
int r; int r;
while (1) { while (1) {
uint32_t n = toku_omt_size(fmap->filenums); uint32_t n = fmap->filenums->size();
if (n == 0) if (n == 0) {
break; break;
OMTVALUE v; }
r = toku_omt_fetch(fmap->filenums, n-1, &v); struct file_map_tuple *tuple;
r = fmap->filenums->fetch(n - 1, &tuple);
assert(r == 0); assert(r == 0);
r = toku_omt_delete_at(fmap->filenums, n-1); r = fmap->filenums->delete_at(n - 1);
assert(r == 0); assert(r == 0);
struct file_map_tuple *CAST_FROM_VOIDP(tuple, v);
assert(tuple->ft_handle); assert(tuple->ft_handle);
// Logging is on again, but we must pass the right LSN into close. // Logging is on again, but we must pass the right LSN into close.
if (tuple->ft_handle) { // it's a DB, not a rollback file if (tuple->ft_handle) { // it's a DB, not a rollback file
...@@ -235,27 +238,29 @@ static void file_map_close_dictionaries(struct file_map *fmap, LSN oplsn) { ...@@ -235,27 +238,29 @@ static void file_map_close_dictionaries(struct file_map *fmap, LSN oplsn) {
} }
} }
static int file_map_h(OMTVALUE omtv, void *v) { static int file_map_h(struct file_map_tuple *const &a, const FILENUM &b) {
struct file_map_tuple *CAST_FROM_VOIDP(a, omtv); if (a->filenum.fileid < b.fileid) {
FILENUM *CAST_FROM_VOIDP(b, v); return -1;
if (a->filenum.fileid < b->fileid) return -1; } else if (a->filenum.fileid > b.fileid) {
if (a->filenum.fileid > b->fileid) return +1; return 1;
} else {
return 0; return 0;
}
} }
static int file_map_insert (struct file_map *fmap, FILENUM fnum, FT_HANDLE ft_handle, char *iname) { static int file_map_insert (struct file_map *fmap, FILENUM fnum, FT_HANDLE ft_handle, char *iname) {
struct file_map_tuple *XMALLOC(tuple); struct file_map_tuple *XMALLOC(tuple);
file_map_tuple_init(tuple, fnum, ft_handle, iname); file_map_tuple_init(tuple, fnum, ft_handle, iname);
int r = toku_omt_insert(fmap->filenums, tuple, file_map_h, &fnum, NULL); int r = fmap->filenums->insert<FILENUM, file_map_h>(tuple, fnum, nullptr);
return r; return r;
} }
static void file_map_remove(struct file_map *fmap, FILENUM fnum) { static void file_map_remove(struct file_map *fmap, FILENUM fnum) {
OMTVALUE v; uint32_t idx; uint32_t idx;
int r = toku_omt_find_zero(fmap->filenums, file_map_h, &fnum, &v, &idx); struct file_map_tuple *tuple;
int r = fmap->filenums->find_zero<FILENUM, file_map_h>(fnum, &tuple, &idx);
if (r == 0) { if (r == 0) {
struct file_map_tuple *CAST_FROM_VOIDP(tuple, v); r = fmap->filenums->delete_at(idx);
r = toku_omt_delete_at(fmap->filenums, idx);
file_map_tuple_destroy(tuple); file_map_tuple_destroy(tuple);
toku_free(tuple); toku_free(tuple);
} }
...@@ -263,14 +268,15 @@ static void file_map_remove(struct file_map *fmap, FILENUM fnum) { ...@@ -263,14 +268,15 @@ static void file_map_remove(struct file_map *fmap, FILENUM fnum) {
// Look up file info: given FILENUM, return file_map_tuple (or DB_NOTFOUND) // Look up file info: given FILENUM, return file_map_tuple (or DB_NOTFOUND)
static int file_map_find(struct file_map *fmap, FILENUM fnum, struct file_map_tuple **file_map_tuple) { static int file_map_find(struct file_map *fmap, FILENUM fnum, struct file_map_tuple **file_map_tuple) {
OMTVALUE v; uint32_t idx; uint32_t idx;
int r = toku_omt_find_zero(fmap->filenums, file_map_h, &fnum, &v, &idx); struct file_map_tuple *tuple;
int r = fmap->filenums->find_zero<FILENUM, file_map_h>(fnum, &tuple, &idx);
if (r == 0) { if (r == 0) {
struct file_map_tuple *CAST_FROM_VOIDP(tuple, v);
assert(tuple->filenum.fileid == fnum.fileid); assert(tuple->filenum.fileid == fnum.fileid);
*file_map_tuple = tuple; *file_map_tuple = tuple;
} else {
assert(r == DB_NOTFOUND);
} }
else assert(r==DB_NOTFOUND);
return r; return r;
} }
...@@ -320,7 +326,7 @@ static int recover_env_init (RECOVER_ENV renv, ...@@ -320,7 +326,7 @@ static int recover_env_init (RECOVER_ENV renv,
static void recover_env_cleanup (RECOVER_ENV renv) { static void recover_env_cleanup (RECOVER_ENV renv) {
int r; int r;
assert(toku_omt_size(renv->fmap.filenums)==0); invariant_zero(renv->fmap.filenums->size());
file_map_destroy(&renv->fmap); file_map_destroy(&renv->fmap);
if (renv->destroy_logger_at_end) { if (renv->destroy_logger_at_end) {
......
...@@ -350,27 +350,6 @@ find_by_xid (const TOKUTXN &txn, const TXNID &txnidfind) { ...@@ -350,27 +350,6 @@ find_by_xid (const TOKUTXN &txn, const TXNID &txnidfind) {
return 0; return 0;
} }
#if 0
static void
omt_insert_at_end_unless_recovery(OMT omt, int (*h)(OMTVALUE, void*extra), TOKUTXN txn, OMTVALUE v, bool for_recovery)
// Effect: insert v into omt that is sorted by xid gotten from txn.
// Rationale:
// During recovery, we get txns in the order that they did their first
// write operation, which is not necessarily monotonically increasing.
// During normal operation, txns are created with strictly increasing
// txnids, so we can always insert at the end.
{
int r;
uint32_t idx = toku_omt_size(omt);
if (for_recovery) {
r = toku_omt_find_zero(omt, h, (void *) txn->txnid64, NULL, &idx);
invariant(r==DB_NOTFOUND);
}
r = toku_omt_insert_at(omt, v, idx);
lazy_assert_zero(r);
}
#endif
static TXNID static TXNID
max_xid(TXNID a, TXNID b) { max_xid(TXNID a, TXNID b) {
return a < b ? b : a; return a < b ? b : a;
......
...@@ -726,16 +726,18 @@ if __name__ == '__main__': ...@@ -726,16 +726,18 @@ if __name__ == '__main__':
parser.add_option_group(test_group) parser.add_option_group(test_group)
default_testnames = ['test_stress0.tdb', default_testnames = ['recover-test_stress2.tdb',
'test_stress1.tdb', #'test_stress0.tdb',
'test_stress2.tdb', #'test_stress1.tdb',
'test_stress3.tdb', #'test_stress2.tdb',
'test_stress4.tdb', #'test_stress3.tdb',
'test_stress5.tdb', #'test_stress4.tdb',
'test_stress6.tdb', #'test_stress5.tdb',
'test_stress7.tdb', #'test_stress6.tdb',
'test_stress_hot_indexing.tdb', #'test_stress7.tdb',
'test_stress_openclose.tdb'] #'test_stress_hot_indexing.tdb',
#'test_stress_openclose.tdb']
]
default_recover_testnames = ['recover-test_stress1.tdb', default_recover_testnames = ['recover-test_stress1.tdb',
'recover-test_stress2.tdb', 'recover-test_stress2.tdb',
'recover-test_stress3.tdb', 'recover-test_stress3.tdb',
......
...@@ -97,14 +97,14 @@ PATENT RIGHTS GRANT: ...@@ -97,14 +97,14 @@ PATENT RIGHTS GRANT:
#include <ft/tokuconst.h> #include <ft/tokuconst.h>
#include <ft/fttypes.h> #include <ft/fttypes.h>
#include <ft/omt.h>
#include <ft/leafentry.h> #include <ft/leafentry.h>
#include <ft/ule.h> #include <ft/ule.h>
#include <ft/ule-internal.h> #include <ft/ule-internal.h>
#include <ft/le-cursor.h> #include <ft/le-cursor.h>
#include "indexer-internal.h"
#include <ft/xids-internal.h> #include <ft/xids-internal.h>
#include "indexer-internal.h"
struct txn { struct txn {
TXNID xid; TXNID xid;
TOKUTXN_STATE state; TOKUTXN_STATE state;
......
...@@ -97,8 +97,6 @@ PATENT RIGHTS GRANT: ...@@ -97,8 +97,6 @@ PATENT RIGHTS GRANT:
#include <ft/fttypes.h> #include <ft/fttypes.h>
#include <ft/ft-ops.h> #include <ft/ft-ops.h>
#include <ft/minicron.h> #include <ft/minicron.h>
// TODO: remove vanilla omt in favor of templated one
#include <ft/omt.h>
#include <util/growable_array.h> #include <util/growable_array.h>
#include <util/omt.h> #include <util/omt.h>
...@@ -157,9 +155,8 @@ struct __toku_db_env_internal { ...@@ -157,9 +155,8 @@ struct __toku_db_env_internal {
DB *directory; // Maps dnames to inames DB *directory; // Maps dnames to inames
DB *persistent_environment; // Stores environment settings, can be used for upgrade DB *persistent_environment; // Stores environment settings, can be used for upgrade
// TODO: toku::omt<DB *> toku::omt<DB *> *open_dbs_by_dname; // Stores open db handles, sorted first by dname and then by numerical value of pointer to the db (arbitrarily assigned memory location)
OMT open_dbs_by_dname; // Stores open db handles, sorted first by dname and then by numerical value of pointer to the db (arbitrarily assigned memory location) toku::omt<DB *> *open_dbs_by_dict_id; // Stores open db handles, sorted by dictionary id and then by numerical value of pointer to the db (arbitrarily assigned memory location)
OMT open_dbs_by_dict_id; // Stores open db handles, sorted by dictionary id and then by numerical value of pointer to the db (arbitrarily assigned memory location)
toku_pthread_rwlock_t open_dbs_rwlock; // rwlock that protects the OMT of open dbs. toku_pthread_rwlock_t open_dbs_rwlock; // rwlock that protects the OMT of open dbs.
char *real_data_dir; // data dir used when the env is opened (relative to cwd, or absolute with leading /) char *real_data_dir; // data dir used when the env is opened (relative to cwd, or absolute with leading /)
......
...@@ -1137,7 +1137,7 @@ env_close(DB_ENV * env, uint32_t flags) { ...@@ -1137,7 +1137,7 @@ env_close(DB_ENV * env, uint32_t flags) {
goto panic_and_quit_early; goto panic_and_quit_early;
} }
if (env->i->open_dbs_by_dname) { //Verify that there are no open dbs. if (env->i->open_dbs_by_dname) { //Verify that there are no open dbs.
if (toku_omt_size(env->i->open_dbs_by_dname) > 0) { if (env->i->open_dbs_by_dname->size() > 0) {
err_msg = "Cannot close environment due to open DBs\n"; err_msg = "Cannot close environment due to open DBs\n";
r = toku_ydb_do_error(env, EINVAL, "%s", err_msg); r = toku_ydb_do_error(env, EINVAL, "%s", err_msg);
goto panic_and_quit_early; goto panic_and_quit_early;
...@@ -1213,10 +1213,14 @@ env_close(DB_ENV * env, uint32_t flags) { ...@@ -1213,10 +1213,14 @@ env_close(DB_ENV * env, uint32_t flags) {
toku_free(env->i->real_log_dir); toku_free(env->i->real_log_dir);
if (env->i->real_tmp_dir) if (env->i->real_tmp_dir)
toku_free(env->i->real_tmp_dir); toku_free(env->i->real_tmp_dir);
if (env->i->open_dbs_by_dname) if (env->i->open_dbs_by_dname) {
toku_omt_destroy(&env->i->open_dbs_by_dname); env->i->open_dbs_by_dname->destroy();
if (env->i->open_dbs_by_dict_id) toku_free(env->i->open_dbs_by_dname);
toku_omt_destroy(&env->i->open_dbs_by_dict_id); }
if (env->i->open_dbs_by_dict_id) {
env->i->open_dbs_by_dict_id->destroy();
toku_free(env->i->open_dbs_by_dict_id);
}
if (env->i->dir) if (env->i->dir)
toku_free(env->i->dir); toku_free(env->i->dir);
toku_pthread_rwlock_destroy(&env->i->open_dbs_rwlock); toku_pthread_rwlock_destroy(&env->i->open_dbs_rwlock);
...@@ -2298,10 +2302,8 @@ struct ltm_iterate_requests_callback_extra { ...@@ -2298,10 +2302,8 @@ struct ltm_iterate_requests_callback_extra {
}; };
static int static int
find_db_by_dict_id(OMTVALUE v, void *dict_id_v) { find_db_by_dict_id(DB *const &db, const DICTIONARY_ID &dict_id_find) {
DB *db = (DB *) v;
DICTIONARY_ID dict_id = db->i->dict_id; DICTIONARY_ID dict_id = db->i->dict_id;
DICTIONARY_ID dict_id_find = *(DICTIONARY_ID *) dict_id_v;
if (dict_id.dictid < dict_id_find.dictid) { if (dict_id.dictid < dict_id_find.dictid) {
return -1; return -1;
} else if (dict_id.dictid > dict_id_find.dictid) { } else if (dict_id.dictid > dict_id_find.dictid) {
...@@ -2313,10 +2315,9 @@ find_db_by_dict_id(OMTVALUE v, void *dict_id_v) { ...@@ -2313,10 +2315,9 @@ find_db_by_dict_id(OMTVALUE v, void *dict_id_v) {
static DB * static DB *
locked_get_db_by_dict_id(DB_ENV *env, DICTIONARY_ID dict_id) { locked_get_db_by_dict_id(DB_ENV *env, DICTIONARY_ID dict_id) {
OMTVALUE dbv; DB *db;
int r = toku_omt_find_zero(env->i->open_dbs_by_dict_id, find_db_by_dict_id, int r = env->i->open_dbs_by_dict_id->find_zero<DICTIONARY_ID, find_db_by_dict_id>(dict_id, &db, nullptr);
(void *) &dict_id, &dbv, nullptr); return r == 0 ? db : nullptr;
return r == 0 ? (DB *) dbv : nullptr;
} }
static int ltm_iterate_requests_callback(DICTIONARY_ID dict_id, TXNID txnid, static int ltm_iterate_requests_callback(DICTIONARY_ID dict_id, TXNID txnid,
...@@ -2578,10 +2579,10 @@ toku_env_create(DB_ENV ** envp, uint32_t flags) { ...@@ -2578,10 +2579,10 @@ toku_env_create(DB_ENV ** envp, uint32_t flags) {
// The escalate callback will need it to translate txnids to DB_TXNs // The escalate callback will need it to translate txnids to DB_TXNs
result->i->ltm.create(toku_db_lt_on_create_callback, toku_db_lt_on_destroy_callback, toku_db_txn_escalate_callback, result); result->i->ltm.create(toku_db_lt_on_create_callback, toku_db_lt_on_destroy_callback, toku_db_txn_escalate_callback, result);
r = toku_omt_create(&result->i->open_dbs_by_dname); XMALLOC(result->i->open_dbs_by_dname);
assert_zero(r); result->i->open_dbs_by_dname->create();
r = toku_omt_create(&result->i->open_dbs_by_dict_id); XMALLOC(result->i->open_dbs_by_dict_id);
assert_zero(r); result->i->open_dbs_by_dict_id->create();
toku_pthread_rwlock_init(&result->i->open_dbs_rwlock, NULL); toku_pthread_rwlock_init(&result->i->open_dbs_rwlock, NULL);
*envp = result; *envp = result;
...@@ -2607,9 +2608,7 @@ DB_ENV_CREATE_FUN (DB_ENV ** envp, uint32_t flags) { ...@@ -2607,9 +2608,7 @@ DB_ENV_CREATE_FUN (DB_ENV ** envp, uint32_t flags) {
// return <0 if v is earlier in omt than dbv // return <0 if v is earlier in omt than dbv
// return >0 if v is later in omt than dbv // return >0 if v is later in omt than dbv
static int static int
find_db_by_db_dname(OMTVALUE v, void *dbv) { find_db_by_db_dname(DB *const &db, DB *const &dbfind) {
DB *db = (DB *) v; // DB* that is stored in the omt
DB *dbfind = (DB *) dbv; // extra, to be compared to v
int cmp; int cmp;
const char *dname = db->i->dname; const char *dname = db->i->dname;
const char *dnamefind = dbfind->i->dname; const char *dnamefind = dbfind->i->dname;
...@@ -2621,9 +2620,7 @@ find_db_by_db_dname(OMTVALUE v, void *dbv) { ...@@ -2621,9 +2620,7 @@ find_db_by_db_dname(OMTVALUE v, void *dbv) {
} }
static int static int
find_db_by_db_dict_id(OMTVALUE v, void *dbv) { find_db_by_db_dict_id(DB *const &db, DB *const &dbfind) {
DB *db = (DB *) v;
DB *dbfind = (DB *) dbv;
DICTIONARY_ID dict_id = db->i->dict_id; DICTIONARY_ID dict_id = db->i->dict_id;
DICTIONARY_ID dict_id_find = dbfind->i->dict_id; DICTIONARY_ID dict_id_find = dbfind->i->dict_id;
if (dict_id.dictid < dict_id_find.dictid) { if (dict_id.dictid < dict_id_find.dictid) {
...@@ -2646,20 +2643,18 @@ env_note_db_opened(DB_ENV *env, DB *db) { ...@@ -2646,20 +2643,18 @@ env_note_db_opened(DB_ENV *env, DB *db) {
assert(db->i->dname); // internal (non-user) dictionary has no dname assert(db->i->dname); // internal (non-user) dictionary has no dname
int r; int r;
OMTVALUE v;
uint32_t idx; uint32_t idx;
r = toku_omt_find_zero(env->i->open_dbs_by_dname, find_db_by_db_dname,
db, &v, &idx); r = env->i->open_dbs_by_dname->find_zero<DB *, find_db_by_db_dname>(db, nullptr, &idx);
assert(r == DB_NOTFOUND); assert(r == DB_NOTFOUND);
r = toku_omt_insert_at(env->i->open_dbs_by_dname, db, idx); r = env->i->open_dbs_by_dname->insert_at(db, idx);
assert_zero(r); assert_zero(r);
r = toku_omt_find_zero(env->i->open_dbs_by_dict_id, find_db_by_db_dict_id, r = env->i->open_dbs_by_dict_id->find_zero<DB *, find_db_by_db_dict_id>(db, nullptr, &idx);
db, &v, &idx);
assert(r == DB_NOTFOUND); assert(r == DB_NOTFOUND);
r = toku_omt_insert_at(env->i->open_dbs_by_dict_id, db, idx); r = env->i->open_dbs_by_dict_id->insert_at(db, idx);
assert_zero(r); assert_zero(r);
STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS) = toku_omt_size(env->i->open_dbs_by_dname); STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS) = env->i->open_dbs_by_dname->size();
STATUS_VALUE(YDB_LAYER_NUM_DB_OPEN)++; STATUS_VALUE(YDB_LAYER_NUM_DB_OPEN)++;
if (STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS) > STATUS_VALUE(YDB_LAYER_MAX_OPEN_DBS)) { if (STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS) > STATUS_VALUE(YDB_LAYER_MAX_OPEN_DBS)) {
STATUS_VALUE(YDB_LAYER_MAX_OPEN_DBS) = STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS); STATUS_VALUE(YDB_LAYER_MAX_OPEN_DBS) = STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS);
...@@ -2672,58 +2667,44 @@ void ...@@ -2672,58 +2667,44 @@ void
env_note_db_closed(DB_ENV *env, DB *db) { env_note_db_closed(DB_ENV *env, DB *db) {
toku_pthread_rwlock_wrlock(&env->i->open_dbs_rwlock); toku_pthread_rwlock_wrlock(&env->i->open_dbs_rwlock);
assert(db->i->dname); // internal (non-user) dictionary has no dname assert(db->i->dname); // internal (non-user) dictionary has no dname
assert(toku_omt_size(env->i->open_dbs_by_dname) > 0); assert(env->i->open_dbs_by_dname->size() > 0);
assert(toku_omt_size(env->i->open_dbs_by_dict_id) > 0); assert(env->i->open_dbs_by_dict_id->size() > 0);
int r; int r;
OMTVALUE v;
uint32_t idx; uint32_t idx;
r = toku_omt_find_zero(env->i->open_dbs_by_dname, find_db_by_db_dname,
db, &v, &idx); r = env->i->open_dbs_by_dname->find_zero<DB *, find_db_by_db_dname>(db, nullptr, &idx);
assert_zero(r); assert_zero(r);
r = toku_omt_delete_at(env->i->open_dbs_by_dname, idx); r = env->i->open_dbs_by_dname->delete_at(idx);
assert_zero(r); assert_zero(r);
r = toku_omt_find_zero(env->i->open_dbs_by_dict_id, find_db_by_db_dict_id, r = env->i->open_dbs_by_dict_id->find_zero<DB *, find_db_by_db_dict_id>(db, nullptr, &idx);
db, &v, &idx);
assert_zero(r); assert_zero(r);
r = toku_omt_delete_at(env->i->open_dbs_by_dict_id, idx); r = env->i->open_dbs_by_dict_id->delete_at(idx);
assert_zero(r); assert_zero(r);
STATUS_VALUE(YDB_LAYER_NUM_DB_CLOSE)++; STATUS_VALUE(YDB_LAYER_NUM_DB_CLOSE)++;
STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS) = toku_omt_size(env->i->open_dbs_by_dname); STATUS_VALUE(YDB_LAYER_NUM_OPEN_DBS) = env->i->open_dbs_by_dname->size();
toku_pthread_rwlock_wrunlock(&env->i->open_dbs_rwlock); toku_pthread_rwlock_wrunlock(&env->i->open_dbs_rwlock);
} }
static int static int
find_open_db_by_dname (OMTVALUE v, void *dnamev) { find_open_db_by_dname(DB *const &db, const char *const &dnamefind) {
DB *db = (DB *) v; // DB* that is stored in the omt return strcmp(db->i->dname, dnamefind);
int cmp;
const char *dname = db->i->dname;
const char *dnamefind = (char *) dnamev;
cmp = strcmp(dname, dnamefind);
return cmp;
} }
// return true if there is any db open with the given dname // return true if there is any db open with the given dname
static bool static bool
env_is_db_with_dname_open(DB_ENV *env, const char *dname) { env_is_db_with_dname_open(DB_ENV *env, const char *dname) {
int r; DB *db;
bool rval;
OMTVALUE dbv;
uint32_t idx;
toku_pthread_rwlock_rdlock(&env->i->open_dbs_rwlock); toku_pthread_rwlock_rdlock(&env->i->open_dbs_rwlock);
r = toku_omt_find_zero(env->i->open_dbs_by_dname, find_open_db_by_dname, (void*)dname, &dbv, &idx); int r = env->i->open_dbs_by_dname->find_zero<const char *, find_open_db_by_dname>(dname, &db, nullptr);
if (r==0) { if (r == 0) {
DB *db = (DB *) dbv; invariant(strcmp(dname, db->i->dname) == 0);
assert(strcmp(dname, db->i->dname) == 0); } else {
rval = true; invariant(r == DB_NOTFOUND);
}
else {
assert(r==DB_NOTFOUND);
rval = false;
} }
toku_pthread_rwlock_rdunlock(&env->i->open_dbs_rwlock); toku_pthread_rwlock_rdunlock(&env->i->open_dbs_rwlock);
return rval; return r == 0 ? true : false;
} }
//We do not (yet?) support deleting subdbs by deleting the enclosing 'fname' //We do not (yet?) support deleting subdbs by deleting the enclosing 'fname'
......
#ifndef FMUTEX_H
#define FMUTEX_H
// fair mutex
struct fmutex {
pthread_mutex_t mutex;
int mutex_held;
int num_want_mutex;
struct queue_item *wait_head;
struct queue_item *wait_tail;
};
// item on the queue
struct queue_item {
pthread_cond_t *cond;
struct queue_item *next;
};
static void enq_item(struct fmutex *fm, struct queue_item *const item) {
assert(item->next == NULL);
if (fm->wait_tail != NULL) {
fm->wait_tail->next = item;
} else {
assert(fm->wait_head == NULL);
fm->wait_head = item;
}
fm->wait_tail = item;
}
static pthread_cond_t *deq_item(struct fmutex *fm) {
assert(fm->wait_head != NULL);
assert(fm->wait_tail != NULL);
struct queue_item *item = fm->wait_head;
fm->wait_head = fm->wait_head->next;
if (fm->wait_tail == item) {
fm->wait_tail = NULL;
}
return item->cond;
}
void fmutex_create(struct fmutex *fm) {
pthread_mutex_init(&fm->mutex, NULL);
fm->mutex_held = 0;
fm->num_want_mutex = 0;
fm->wait_head = NULL;
fm->wait_tail = NULL;
}
void fmutex_destroy(struct fmutex *fm) {
pthread_mutex_destroy(&fm->mutex);
}
// Prerequisite: Holds m_mutex.
void fmutex_lock(struct fmutex *fm) {
pthread_mutex_lock(&fm->mutex);
if (fm->mutex_held == 0 || fm->num_want_mutex == 0) {
// No one holds the lock. Grant the write lock.
fm->mutex_held = 1;
return;
}
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
struct queue_item item = { .cond = &cond, .next = NULL };
enq_item(fm, &item);
// Wait for our turn.
++fm->num_want_mutex;
pthread_cond_wait(&cond, &fm->mutex);
pthread_cond_destroy(&cond);
// Now it's our turn.
assert(fm->num_want_mutex > 0);
assert(fm->mutex_held == 0);
// Not waiting anymore; grab the lock.
--fm->num_want_mutex;
fm->mutex_held = 1;
pthread_mutex_unlock();
}
void fmutex_mutex_unlock(struct fmutex *fm) {
pthread_mutex_lock();
fm->mutex_held = 0;
if (fm->wait_head == NULL) {
assert(fm->num_want_mutex == 0);
return;
}
assert(fm->num_want_mutex > 0);
// Grant lock to the next waiter
pthread_cond_t *cond = deq_item(fm);
pthread_cond_signal(cond);
pthread_mutex_unlock();
}
int fmutex_users(struct fmutex *fm) const {
return fm->mutex_held + fm->num_want_mutex;
}
int fmutex_blocked_users(struct fmutex *fm) const {
return fm->num_want_mutex;
}
#endif // FMUTEX_H
...@@ -90,11 +90,8 @@ PATENT RIGHTS GRANT: ...@@ -90,11 +90,8 @@ PATENT RIGHTS GRANT:
#include "test.h" #include "test.h"
#include "omt.h"
#include <util/omt.h> #include <util/omt.h>
typedef OMTVALUE TESTVALUE;
static void static void
parse_args (int argc, const char *argv[]) { parse_args (int argc, const char *argv[]) {
const char *argv0=argv[0]; const char *argv0=argv[0];
...@@ -140,19 +137,73 @@ enum create_type { ...@@ -140,19 +137,73 @@ enum create_type {
}; };
/* Globals */ /* Globals */
OMT global_omt; typedef void *OMTVALUE;
TESTVALUE* values = NULL; toku::omt<OMTVALUE> *global_omt;
struct value* nums = NULL; OMTVALUE* global_values = NULL;
uint32_t length; struct value* global_nums = NULL;
uint32_t global_length;
static void static void
cleanup_globals (void) { cleanup_globals (void) {
assert(values); assert(global_values);
toku_free(values); toku_free(global_values);
values = NULL; global_values = NULL;
assert(nums); assert(global_nums);
toku_free(nums); toku_free(global_nums);
nums = NULL; global_nums = NULL;
}
/* Some test wrappers */
struct functor {
int (*f)(OMTVALUE, uint32_t, void *);
void *v;
};
int call_functor(const OMTVALUE &v, uint32_t idx, functor *const ftor);
int call_functor(const OMTVALUE &v, uint32_t idx, functor *const ftor) {
return ftor->f(const_cast<OMTVALUE>(v), idx, ftor->v);
}
static int omt_iterate(toku::omt<void *> *omt, int (*f)(OMTVALUE, uint32_t, void*), void*v) {
struct functor ftor = { .f = f, .v = v };
return omt->iterate<functor, call_functor>(&ftor);
}
struct heftor {
int (*h)(OMTVALUE, void *v);
void *v;
};
int call_heftor(const OMTVALUE &v, const heftor &htor);
int call_heftor(const OMTVALUE &v, const heftor &htor) {
return htor.h(const_cast<OMTVALUE>(v), htor.v);
}
static int omt_insert(toku::omt<void *> *omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, uint32_t *index) {
struct heftor htor = { .h = h, .v = v };
return omt->insert<heftor, call_heftor>(value, htor, index);
}
static int omt_find_zero(toku::omt<void *> *V, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
return V->find_zero<heftor, call_heftor>(htor, value, index);
}
static int omt_find(toku::omt<void *> *V, int (*h)(OMTVALUE, void*extra), void*extra, int direction, OMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
return V->find<heftor, call_heftor>(htor, direction, value, index);
}
static int omt_split_at(toku::omt<void *> *omt, toku::omt<void *> **newomtp, uint32_t index) {
toku::omt<void *> *XMALLOC(newomt);
int r = omt->split_at(newomt, index);
if (r != 0) {
toku_free(newomt);
} else {
*newomtp = newomt;
}
return r;
}
static int omt_merge(toku::omt<void *> *leftomt, toku::omt<void *> *rightomt, toku::omt<void *> **newomtp) {
toku::omt<void *> *XMALLOC(newomt);
newomt->merge(leftomt, rightomt);
toku_free(leftomt);
toku_free(rightomt);
*newomtp = newomt;
return 0;
} }
const unsigned int random_seed = 0xFEADACBA; const unsigned int random_seed = 0xFEADACBA;
...@@ -163,11 +214,9 @@ init_init_values (unsigned int seed, uint32_t num_elements) { ...@@ -163,11 +214,9 @@ init_init_values (unsigned int seed, uint32_t num_elements) {
cleanup_globals(); cleanup_globals();
MALLOC_N(num_elements, values); XMALLOC_N(num_elements, global_values);
assert(values); XMALLOC_N(num_elements, global_nums);
MALLOC_N(num_elements, nums); global_length = num_elements;
assert(nums);
length = num_elements;
} }
static void static void
...@@ -176,9 +225,9 @@ init_identity_values (unsigned int seed, uint32_t num_elements) { ...@@ -176,9 +225,9 @@ init_identity_values (unsigned int seed, uint32_t num_elements) {
init_init_values(seed, num_elements); init_init_values(seed, num_elements);
for (i = 0; i < length; i++) { for (i = 0; i < global_length; i++) {
nums[i].number = i; global_nums[i].number = i;
values[i] = (TESTVALUE)&nums[i]; global_values[i] = (OMTVALUE)&global_nums[i];
} }
} }
...@@ -190,10 +239,10 @@ init_distinct_sorted_values (unsigned int seed, uint32_t num_elements) { ...@@ -190,10 +239,10 @@ init_distinct_sorted_values (unsigned int seed, uint32_t num_elements) {
uint32_t number = 0; uint32_t number = 0;
for (i = 0; i < length; i++) { for (i = 0; i < global_length; i++) {
number += (uint32_t)(random() % 32) + 1; number += (uint32_t)(random() % 32) + 1;
nums[i].number = number; global_nums[i].number = number;
values[i] = (TESTVALUE)&nums[i]; global_values[i] = (OMTVALUE)&global_nums[i];
} }
} }
...@@ -205,49 +254,45 @@ init_distinct_random_values (unsigned int seed, uint32_t num_elements) { ...@@ -205,49 +254,45 @@ init_distinct_random_values (unsigned int seed, uint32_t num_elements) {
uint32_t choice; uint32_t choice;
uint32_t choices; uint32_t choices;
struct value temp; struct value temp;
for (i = 0; i < length - 1; i++) { for (i = 0; i < global_length - 1; i++) {
choices = length - i; choices = global_length - i;
choice = random() % choices; choice = random() % choices;
if (choice != i) { if (choice != i) {
temp = nums[i]; temp = global_nums[i];
nums[i] = nums[choice]; global_nums[i] = global_nums[choice];
nums[choice] = temp; global_nums[choice] = temp;
} }
} }
} }
static void static void
init_globals (void) { init_globals (void) {
MALLOC_N(1, values); XMALLOC_N(1, global_values);
assert(values); XMALLOC_N(1, global_nums);
MALLOC_N(1, nums); global_length = 1;
assert(nums);
length = 1;
} }
static void static void
test_close (enum close_when_done do_close) { test_close (enum close_when_done do_close) {
if (do_close == KEEP_WHEN_DONE) return; if (do_close == KEEP_WHEN_DONE) {
return;
}
assert(do_close == CLOSE_WHEN_DONE); assert(do_close == CLOSE_WHEN_DONE);
toku_omt_destroy(&global_omt); global_omt->destroy();
assert(global_omt==NULL); toku_free(global_omt);
} }
static void static void
test_create (enum close_when_done do_close) { test_create (enum close_when_done do_close) {
int r; XMALLOC(global_omt);
global_omt = NULL; global_omt->create();
r = toku_omt_create(&global_omt);
CKERR(r);
assert(global_omt!=NULL);
test_close(do_close); test_close(do_close);
} }
static void static void
test_create_size (enum close_when_done do_close) { test_create_size (enum close_when_done do_close) {
test_create(KEEP_WHEN_DONE); test_create(KEEP_WHEN_DONE);
assert(toku_omt_size(global_omt) == 0); assert(global_omt->size() == 0);
test_close(do_close); test_close(do_close);
} }
...@@ -258,24 +303,24 @@ test_create_insert_at_almost_random (enum close_when_done do_close) { ...@@ -258,24 +303,24 @@ test_create_insert_at_almost_random (enum close_when_done do_close) {
uint32_t size = 0; uint32_t size = 0;
test_create(KEEP_WHEN_DONE); test_create(KEEP_WHEN_DONE);
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+1); r = global_omt->insert_at(global_values[0], global_omt->size()+1);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+2); r = global_omt->insert_at(global_values[0], global_omt->size()+2);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
for (i = 0; i < length/2; i++) { for (i = 0; i < global_length/2; i++) {
assert(size==toku_omt_size(global_omt)); assert(size==global_omt->size());
r = toku_omt_insert_at(global_omt, values[i], i); r = global_omt->insert_at(global_values[i], i);
CKERR(r); CKERR(r);
assert(++size==toku_omt_size(global_omt)); assert(++size==global_omt->size());
r = toku_omt_insert_at(global_omt, values[length-1-i], i+1); r = global_omt->insert_at(global_values[global_length-1-i], i+1);
CKERR(r); CKERR(r);
assert(++size==toku_omt_size(global_omt)); assert(++size==global_omt->size());
} }
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+1); r = global_omt->insert_at(global_values[0], global_omt->size()+1);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+2); r = global_omt->insert_at(global_values[0], global_omt->size()+2);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
assert(size==toku_omt_size(global_omt)); assert(size==global_omt->size());
test_close(do_close); test_close(do_close);
} }
...@@ -286,38 +331,37 @@ test_create_insert_at_sequential (enum close_when_done do_close) { ...@@ -286,38 +331,37 @@ test_create_insert_at_sequential (enum close_when_done do_close) {
uint32_t size = 0; uint32_t size = 0;
test_create(KEEP_WHEN_DONE); test_create(KEEP_WHEN_DONE);
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+1); r = global_omt->insert_at(global_values[0], global_omt->size()+1);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+2); r = global_omt->insert_at(global_values[0], global_omt->size()+2);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
for (i = 0; i < length; i++) { for (i = 0; i < global_length; i++) {
assert(size==toku_omt_size(global_omt)); assert(size==global_omt->size());
r = toku_omt_insert_at(global_omt, values[i], i); r = global_omt->insert_at(global_values[i], i);
CKERR(r); CKERR(r);
assert(++size==toku_omt_size(global_omt)); assert(++size==global_omt->size());
} }
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+1); r = global_omt->insert_at(global_values[0], global_omt->size()+1);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
r = toku_omt_insert_at(global_omt, values[0], toku_omt_size(global_omt)+2); r = global_omt->insert_at(global_values[0], global_omt->size()+2);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
assert(size==toku_omt_size(global_omt)); assert(size==global_omt->size());
test_close(do_close); test_close(do_close);
} }
static void static void
test_create_from_sorted_array (enum create_type create_choice, enum close_when_done do_close) { test_create_from_sorted_array (enum create_type create_choice, enum close_when_done do_close) {
int r;
global_omt = NULL; global_omt = NULL;
if (create_choice == BATCH_INSERT) { if (create_choice == BATCH_INSERT) {
r = toku_omt_create_from_sorted_array(&global_omt, values, length); XMALLOC(global_omt);
CKERR(r); global_omt->create_from_sorted_array(global_values, global_length);
} }
else if (create_choice == STEAL_ARRAY) { else if (create_choice == STEAL_ARRAY) {
TESTVALUE* MALLOC_N(length, values_copy); XMALLOC(global_omt);
memcpy(values_copy, values, length*sizeof(*values)); OMTVALUE* XMALLOC_N(global_length, values_copy);
r = toku_omt_create_steal_sorted_array(&global_omt, &values_copy, length, length); memcpy(values_copy, global_values, global_length*sizeof(*global_values));
CKERR(r); global_omt->create_steal_sorted_array(&values_copy, global_length, global_length);
assert(values_copy==NULL); assert(values_copy==NULL);
} }
else if (create_choice == INSERT_AT) { else if (create_choice == INSERT_AT) {
...@@ -326,7 +370,9 @@ test_create_from_sorted_array (enum create_type create_choice, enum close_when_d ...@@ -326,7 +370,9 @@ test_create_from_sorted_array (enum create_type create_choice, enum close_when_d
else if (create_choice == INSERT_AT_ALMOST_RANDOM) { else if (create_choice == INSERT_AT_ALMOST_RANDOM) {
test_create_insert_at_almost_random(KEEP_WHEN_DONE); test_create_insert_at_almost_random(KEEP_WHEN_DONE);
} }
else assert(false); else {
assert(false);
}
assert(global_omt!=NULL); assert(global_omt!=NULL);
test_close(do_close); test_close(do_close);
...@@ -335,22 +381,22 @@ test_create_from_sorted_array (enum create_type create_choice, enum close_when_d ...@@ -335,22 +381,22 @@ test_create_from_sorted_array (enum create_type create_choice, enum close_when_d
static void static void
test_create_from_sorted_array_size (enum create_type create_choice, enum close_when_done do_close) { test_create_from_sorted_array_size (enum create_type create_choice, enum close_when_done do_close) {
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
assert(toku_omt_size(global_omt)==length); assert(global_omt->size()==global_length);
test_close(do_close); test_close(do_close);
} }
static void static void
test_fetch_verify (OMT omtree, TESTVALUE* val, uint32_t len ) { test_fetch_verify (toku::omt<void *> *omtree, OMTVALUE* val, uint32_t len ) {
uint32_t i; uint32_t i;
int r; int r;
TESTVALUE v = (TESTVALUE)&i; OMTVALUE v = (OMTVALUE)&i;
TESTVALUE oldv = v; OMTVALUE oldv = v;
assert(len == toku_omt_size(omtree)); assert(len == omtree->size());
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
assert(oldv!=val[i]); assert(oldv!=val[i]);
v = NULL; v = NULL;
r = toku_omt_fetch(omtree, i, &v); r = omtree->fetch(i, &v);
CKERR(r); CKERR(r);
assert(v != NULL); assert(v != NULL);
assert(v != oldv); assert(v != oldv);
...@@ -361,7 +407,7 @@ test_fetch_verify (OMT omtree, TESTVALUE* val, uint32_t len ) { ...@@ -361,7 +407,7 @@ test_fetch_verify (OMT omtree, TESTVALUE* val, uint32_t len ) {
for (i = len; i < len*2; i++) { for (i = len; i < len*2; i++) {
v = oldv; v = oldv;
r = toku_omt_fetch(omtree, i, &v); r = omtree->fetch(i, &v);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
assert(v == oldv); assert(v == oldv);
} }
...@@ -371,16 +417,16 @@ test_fetch_verify (OMT omtree, TESTVALUE* val, uint32_t len ) { ...@@ -371,16 +417,16 @@ test_fetch_verify (OMT omtree, TESTVALUE* val, uint32_t len ) {
static void static void
test_create_fetch_verify (enum create_type create_choice, enum close_when_done do_close) { test_create_fetch_verify (enum create_type create_choice, enum close_when_done do_close) {
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
test_fetch_verify(global_omt, values, length); test_fetch_verify(global_omt, global_values, global_length);
test_close(do_close); test_close(do_close);
} }
static int iterate_helper_error_return = 1; static int iterate_helper_error_return = 1;
static int static int
iterate_helper (TESTVALUE v, uint32_t idx, void* extra) { iterate_helper (OMTVALUE v, uint32_t idx, void* extra) {
if (extra == NULL) return iterate_helper_error_return; if (extra == NULL) return iterate_helper_error_return;
TESTVALUE* vals = (TESTVALUE *)extra; OMTVALUE* vals = (OMTVALUE *)extra;
assert(v != NULL); assert(v != NULL);
assert(v == vals[idx]); assert(v == vals[idx]);
assert(V(v)->number == V(vals[idx])->number); assert(V(v)->number == V(vals[idx])->number);
...@@ -388,13 +434,13 @@ iterate_helper (TESTVALUE v, uint32_t idx, void* extra) { ...@@ -388,13 +434,13 @@ iterate_helper (TESTVALUE v, uint32_t idx, void* extra) {
} }
static void static void
test_iterate_verify (OMT omtree, TESTVALUE* vals, uint32_t len) { test_iterate_verify (toku::omt<void *> *omtree, OMTVALUE* vals, uint32_t len) {
int r; int r;
iterate_helper_error_return = 0; iterate_helper_error_return = 0;
r = toku_omt_iterate(omtree, iterate_helper, (void*)vals); r = omt_iterate(omtree, iterate_helper, (void*)vals);
CKERR(r); CKERR(r);
iterate_helper_error_return = 0xFEEDABBA; iterate_helper_error_return = 0xFEEDABBA;
r = toku_omt_iterate(omtree, iterate_helper, NULL); r = omt_iterate(omtree, iterate_helper, NULL);
if (!len) { if (!len) {
CKERR2(r, 0); CKERR2(r, 0);
} }
...@@ -406,7 +452,7 @@ test_iterate_verify (OMT omtree, TESTVALUE* vals, uint32_t len) { ...@@ -406,7 +452,7 @@ test_iterate_verify (OMT omtree, TESTVALUE* vals, uint32_t len) {
static void static void
test_create_iterate_verify (enum create_type create_choice, enum close_when_done do_close) { test_create_iterate_verify (enum create_type create_choice, enum close_when_done do_close) {
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
test_iterate_verify(global_omt, values, length); test_iterate_verify(global_omt, global_values, global_length);
test_close(do_close); test_close(do_close);
} }
...@@ -436,45 +482,42 @@ test_create_set_at (enum create_type create_choice, enum close_when_done do_clos ...@@ -436,45 +482,42 @@ test_create_set_at (enum create_type create_choice, enum close_when_done do_clos
uint32_t i = 0; uint32_t i = 0;
struct value* old_nums = NULL; struct value* old_nums = NULL;
MALLOC_N(length, old_nums); XMALLOC_N(global_length, old_nums);
assert(nums);
uint32_t* perm = NULL; uint32_t* perm = NULL;
MALLOC_N(length, perm); XMALLOC_N(global_length, perm);
assert(perm);
TESTVALUE* old_values = NULL; OMTVALUE* old_values = NULL;
MALLOC_N(length, old_values); XMALLOC_N(global_length, old_values);
assert(old_values);
permute_array(perm, length); permute_array(perm, global_length);
// //
// These are going to be the new values // These are going to be the new global_values
// //
for (i = 0; i < length; i++) { for (i = 0; i < global_length; i++) {
old_nums[i] = nums[i]; old_nums[i] = global_nums[i];
old_values[i] = &old_nums[i]; old_values[i] = &old_nums[i];
values[i] = &old_nums[i]; global_values[i] = &old_nums[i];
} }
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
int r; int r;
r = toku_omt_set_at (global_omt, values[0], length); r = global_omt->set_at(global_values[0], global_length);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
r = toku_omt_set_at (global_omt, values[0], length+1); r = global_omt->set_at(global_values[0], global_length+1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
for (i = 0; i < length; i++) { for (i = 0; i < global_length; i++) {
uint32_t choice = perm[i]; uint32_t choice = perm[i];
values[choice] = &nums[choice]; global_values[choice] = &global_nums[choice];
nums[choice].number = (uint32_t)random(); global_nums[choice].number = (uint32_t)random();
r = toku_omt_set_at (global_omt, values[choice], choice); r = global_omt->set_at(global_values[choice], choice);
CKERR(r); CKERR(r);
test_iterate_verify(global_omt, values, length); test_iterate_verify(global_omt, global_values, global_length);
test_fetch_verify(global_omt, values, length); test_fetch_verify(global_omt, global_values, global_length);
} }
r = toku_omt_set_at (global_omt, values[0], length); r = global_omt->set_at(global_values[0], global_length);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
r = toku_omt_set_at (global_omt, values[0], length+1); r = global_omt->set_at(global_values[0], global_length+1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
toku_free(perm); toku_free(perm);
...@@ -485,8 +528,8 @@ test_create_set_at (enum create_type create_choice, enum close_when_done do_clos ...@@ -485,8 +528,8 @@ test_create_set_at (enum create_type create_choice, enum close_when_done do_clos
} }
static int static int
insert_helper (TESTVALUE value, void* extra_insert) { insert_helper (OMTVALUE value, void* extra_insert) {
TESTVALUE to_insert = (OMTVALUE)extra_insert; OMTVALUE to_insert = (OMTVALUE)extra_insert;
assert(to_insert); assert(to_insert);
if (V(value)->number < V(to_insert)->number) return -1; if (V(value)->number < V(to_insert)->number) return -1;
...@@ -499,49 +542,48 @@ test_create_insert (enum close_when_done do_close) { ...@@ -499,49 +542,48 @@ test_create_insert (enum close_when_done do_close) {
uint32_t i = 0; uint32_t i = 0;
uint32_t* perm = NULL; uint32_t* perm = NULL;
MALLOC_N(length, perm); XMALLOC_N(global_length, perm);
assert(perm);
permute_array(perm, length); permute_array(perm, global_length);
test_create(KEEP_WHEN_DONE); test_create(KEEP_WHEN_DONE);
int r; int r;
uint32_t size = length; uint32_t size = global_length;
length = 0; global_length = 0;
while (length < size) { while (global_length < size) {
uint32_t choice = perm[length]; uint32_t choice = perm[global_length];
TESTVALUE to_insert = &nums[choice]; OMTVALUE to_insert = &global_nums[choice];
uint32_t idx = UINT32_MAX; uint32_t idx = UINT32_MAX;
assert(length==toku_omt_size(global_omt)); assert(global_length==global_omt->size());
r = toku_omt_insert(global_omt, to_insert, insert_helper, to_insert, &idx); r = omt_insert(global_omt, to_insert, insert_helper, to_insert, &idx);
CKERR(r); CKERR(r);
assert(idx <= length); assert(idx <= global_length);
if (idx > 0) { if (idx > 0) {
assert(V(to_insert)->number > V(values[idx-1])->number); assert(V(to_insert)->number > V(global_values[idx-1])->number);
} }
if (idx < length) { if (idx < global_length) {
assert(V(to_insert)->number < V(values[idx])->number); assert(V(to_insert)->number < V(global_values[idx])->number);
} }
length++; global_length++;
assert(length==toku_omt_size(global_omt)); assert(global_length==global_omt->size());
/* Make room */ /* Make room */
for (i = length-1; i > idx; i--) { for (i = global_length-1; i > idx; i--) {
values[i] = values[i-1]; global_values[i] = global_values[i-1];
} }
values[idx] = to_insert; global_values[idx] = to_insert;
test_fetch_verify(global_omt, values, length); test_fetch_verify(global_omt, global_values, global_length);
test_iterate_verify(global_omt, values, length); test_iterate_verify(global_omt, global_values, global_length);
idx = UINT32_MAX; idx = UINT32_MAX;
r = toku_omt_insert(global_omt, to_insert, insert_helper, to_insert, &idx); r = omt_insert(global_omt, to_insert, insert_helper, to_insert, &idx);
CKERR2(r, DB_KEYEXIST); CKERR2(r, DB_KEYEXIST);
assert(idx < length); assert(idx < global_length);
assert(V(values[idx])->number == V(to_insert)->number); assert(V(global_values[idx])->number == V(to_insert)->number);
assert(length==toku_omt_size(global_omt)); assert(global_length==global_omt->size());
test_iterate_verify(global_omt, values, length); test_iterate_verify(global_omt, global_values, global_length);
test_fetch_verify(global_omt, values, length); test_fetch_verify(global_omt, global_values, global_length);
} }
toku_free(perm); toku_free(perm);
...@@ -555,30 +597,30 @@ test_create_delete_at (enum create_type create_choice, enum close_when_done do_c ...@@ -555,30 +597,30 @@ test_create_delete_at (enum create_type create_choice, enum close_when_done do_c
int r = ENOSYS; int r = ENOSYS;
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
assert(length == toku_omt_size(global_omt)); assert(global_length == global_omt->size());
r = toku_omt_delete_at(global_omt, length); r = global_omt->delete_at(global_length);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
assert(length == toku_omt_size(global_omt)); assert(global_length == global_omt->size());
r = toku_omt_delete_at(global_omt, length+1); r = global_omt->delete_at(global_length+1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
while (length > 0) { while (global_length > 0) {
assert(length == toku_omt_size(global_omt)); assert(global_length == global_omt->size());
uint32_t index_to_delete = random()%length; uint32_t index_to_delete = random()%global_length;
r = toku_omt_delete_at(global_omt, index_to_delete); r = global_omt->delete_at(index_to_delete);
CKERR(r); CKERR(r);
for (i = index_to_delete+1; i < length; i++) { for (i = index_to_delete+1; i < global_length; i++) {
values[i-1] = values[i]; global_values[i-1] = global_values[i];
} }
length--; global_length--;
test_fetch_verify(global_omt, values, length); test_fetch_verify(global_omt, global_values, global_length);
test_iterate_verify(global_omt, values, length); test_iterate_verify(global_omt, global_values, global_length);
} }
assert(length == 0); assert(global_length == 0);
assert(length == toku_omt_size(global_omt)); assert(global_length == global_omt->size());
r = toku_omt_delete_at(global_omt, length); r = global_omt->delete_at(global_length);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
assert(length == toku_omt_size(global_omt)); assert(global_length == global_omt->size());
r = toku_omt_delete_at(global_omt, length+1); r = global_omt->delete_at(global_length+1);
CKERR2(r, EINVAL); CKERR2(r, EINVAL);
test_close(do_close); test_close(do_close);
} }
...@@ -587,59 +629,59 @@ static void ...@@ -587,59 +629,59 @@ static void
test_split_merge (enum create_type create_choice, enum close_when_done do_close) { test_split_merge (enum create_type create_choice, enum close_when_done do_close) {
int r = ENOSYS; int r = ENOSYS;
uint32_t i = 0; uint32_t i = 0;
OMT left_split = NULL; toku::omt<void *> *left_split = NULL;
OMT right_split = NULL; toku::omt<void *> *right_split = NULL;
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE); test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
for (i = 0; i <= length; i++) { for (i = 0; i <= global_length; i++) {
r = toku_omt_split_at(global_omt, &right_split, length+1); r = omt_split_at(global_omt, &right_split, global_length+1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
r = toku_omt_split_at(global_omt, &right_split, length+2); r = omt_split_at(global_omt, &right_split, global_length+2);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
// //
// test successful split // test successful split
// //
r = toku_omt_split_at(global_omt, &right_split, i); r = omt_split_at(global_omt, &right_split, i);
CKERR(r); CKERR(r);
left_split = global_omt; left_split = global_omt;
global_omt = NULL; global_omt = NULL;
assert(toku_omt_size(left_split) == i); assert(left_split->size() == i);
assert(toku_omt_size(right_split) == length - i); assert(right_split->size() == global_length - i);
test_fetch_verify(left_split, values, i); test_fetch_verify(left_split, global_values, i);
test_iterate_verify(left_split, values, i); test_iterate_verify(left_split, global_values, i);
test_fetch_verify(right_split, &values[i], length - i); test_fetch_verify(right_split, &global_values[i], global_length - i);
test_iterate_verify(right_split, &values[i], length - i); test_iterate_verify(right_split, &global_values[i], global_length - i);
// //
// verify that new global_omt's cannot do bad splits // verify that new global_omt's cannot do bad splits
// //
r = toku_omt_split_at(left_split, &global_omt, i+1); r = omt_split_at(left_split, &global_omt, i+1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
assert(toku_omt_size(left_split) == i); assert(left_split->size() == i);
assert(toku_omt_size(right_split) == length - i); assert(right_split->size() == global_length - i);
r = toku_omt_split_at(left_split, &global_omt, i+2); r = omt_split_at(left_split, &global_omt, i+2);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
assert(toku_omt_size(left_split) == i); assert(left_split->size() == i);
assert(toku_omt_size(right_split) == length - i); assert(right_split->size() == global_length - i);
r = toku_omt_split_at(right_split, &global_omt, length - i + 1); r = omt_split_at(right_split, &global_omt, global_length - i + 1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
assert(toku_omt_size(left_split) == i); assert(left_split->size() == i);
assert(toku_omt_size(right_split) == length - i); assert(right_split->size() == global_length - i);
r = toku_omt_split_at(right_split, &global_omt, length - i + 1); r = omt_split_at(right_split, &global_omt, global_length - i + 1);
CKERR2(r,EINVAL); CKERR2(r,EINVAL);
assert(toku_omt_size(left_split) == i); assert(left_split->size() == i);
assert(toku_omt_size(right_split) == length - i); assert(right_split->size() == global_length - i);
// //
// test merge // test merge
// //
r = toku_omt_merge(left_split,right_split,&global_omt); r = omt_merge(left_split,right_split,&global_omt);
CKERR(r); CKERR(r);
left_split = NULL; left_split = NULL;
right_split = NULL; right_split = NULL;
assert(toku_omt_size(global_omt) == length); assert(global_omt->size() == global_length);
test_fetch_verify(global_omt, values, length); test_fetch_verify(global_omt, global_values, global_length);
test_iterate_verify(global_omt, values, length); test_iterate_verify(global_omt, global_values, global_length);
} }
test_close(do_close); test_close(do_close);
} }
...@@ -694,7 +736,7 @@ typedef struct { ...@@ -694,7 +736,7 @@ typedef struct {
static int static int
test_heaviside (OMTVALUE v_omt, void* x) { test_heaviside (OMTVALUE v_omt, void* x) {
TESTVALUE v = (OMTVALUE) v_omt; OMTVALUE v = (OMTVALUE) v_omt;
h_extra* extra = (h_extra*)x; h_extra* extra = (h_extra*)x;
assert(v && x); assert(v && x);
assert(extra->first_zero <= extra->first_pos); assert(extra->first_zero <= extra->first_pos);
...@@ -717,7 +759,7 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*), ...@@ -717,7 +759,7 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*),
uint32_t number_expect, bool UU(cursor_valid)) { uint32_t number_expect, bool UU(cursor_valid)) {
uint32_t idx = UINT32_MAX; uint32_t idx = UINT32_MAX;
uint32_t old_idx = idx; uint32_t old_idx = idx;
TESTVALUE omt_val; OMTVALUE omt_val;
int r; int r;
omt_val = NULL; omt_val = NULL;
...@@ -726,10 +768,10 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*), ...@@ -726,10 +768,10 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*),
omt_val = NULL; omt_val = NULL;
idx = old_idx; idx = old_idx;
if (dir == 0) { if (dir == 0) {
r = toku_omt_find_zero(global_omt, h, extra, NULL, &idx); r = omt_find_zero(global_omt, h, extra, NULL, &idx);
} }
else { else {
r = toku_omt_find( global_omt, h, extra, dir, NULL, &idx); r = omt_find( global_omt, h, extra, dir, NULL, &idx);
} }
CKERR2(r, r_expect); CKERR2(r, r_expect);
if (idx_will_change) { if (idx_will_change) {
...@@ -744,10 +786,10 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*), ...@@ -744,10 +786,10 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*),
omt_val = NULL; omt_val = NULL;
idx = old_idx; idx = old_idx;
if (dir == 0) { if (dir == 0) {
r = toku_omt_find_zero(global_omt, h, extra, &omt_val, 0); r = omt_find_zero(global_omt, h, extra, &omt_val, 0);
} }
else { else {
r = toku_omt_find( global_omt, h, extra, dir, &omt_val, 0); r = omt_find( global_omt, h, extra, dir, &omt_val, 0);
} }
CKERR2(r, r_expect); CKERR2(r, r_expect);
assert(idx == old_idx); assert(idx == old_idx);
...@@ -762,10 +804,10 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*), ...@@ -762,10 +804,10 @@ test_find_dir (int dir, void* extra, int (*h)(OMTVALUE, void*),
omt_val = NULL; omt_val = NULL;
idx = old_idx; idx = old_idx;
if (dir == 0) { if (dir == 0) {
r = toku_omt_find_zero(global_omt, h, extra, NULL, 0); r = omt_find_zero(global_omt, h, extra, NULL, 0);
} }
else { else {
r = toku_omt_find( global_omt, h, extra, dir, NULL, 0); r = omt_find( global_omt, h, extra, dir, NULL, 0);
} }
CKERR2(r, r_expect); CKERR2(r, r_expect);
assert(idx == old_idx); assert(idx == old_idx);
...@@ -782,10 +824,10 @@ test_find (enum create_type create_choice, enum close_when_done do_close) { ...@@ -782,10 +824,10 @@ test_find (enum create_type create_choice, enum close_when_done do_close) {
-...- -...-
A A
*/ */
heavy_extra(&extra, length, length); heavy_extra(&extra, global_length, global_length);
test_find_dir(-1, &extra, test_heaviside, 0, true, length-1, length-1, true); test_find_dir(-1, &extra, test_heaviside, 0, true, global_length-1, global_length-1, true);
test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false);
test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, length, length, false); test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, global_length, global_length, false);
/* /*
...@@ -801,7 +843,7 @@ test_find (enum create_type create_choice, enum close_when_done do_close) { ...@@ -801,7 +843,7 @@ test_find (enum create_type create_choice, enum close_when_done do_close) {
0...0 0...0
C C
*/ */
heavy_extra(&extra, 0, length); heavy_extra(&extra, 0, global_length);
test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false);
test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false);
test_find_dir(0, &extra, test_heaviside, 0, true, 0, 0, true); test_find_dir(0, &extra, test_heaviside, 0, true, 0, 0, true);
...@@ -810,37 +852,37 @@ test_find (enum create_type create_choice, enum close_when_done do_close) { ...@@ -810,37 +852,37 @@ test_find (enum create_type create_choice, enum close_when_done do_close) {
-...-0...0 -...-0...0
AC AC
*/ */
heavy_extra(&extra, length/2, length); heavy_extra(&extra, global_length/2, global_length);
test_find_dir(-1, &extra, test_heaviside, 0, true, length/2-1, length/2-1, true); test_find_dir(-1, &extra, test_heaviside, 0, true, global_length/2-1, global_length/2-1, true);
test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); test_find_dir(+1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false);
test_find_dir(0, &extra, test_heaviside, 0, true, length/2, length/2, true); test_find_dir(0, &extra, test_heaviside, 0, true, global_length/2, global_length/2, true);
/* /*
0...0+...+ 0...0+...+
C B C B
*/ */
heavy_extra(&extra, 0, length/2); heavy_extra(&extra, 0, global_length/2);
test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false); test_find_dir(-1, &extra, test_heaviside, DB_NOTFOUND, false, 0, 0, false);
test_find_dir(+1, &extra, test_heaviside, 0, true, length/2, length/2, true); test_find_dir(+1, &extra, test_heaviside, 0, true, global_length/2, global_length/2, true);
test_find_dir(0, &extra, test_heaviside, 0, true, 0, 0, true); test_find_dir(0, &extra, test_heaviside, 0, true, 0, 0, true);
/* /*
-...-+...+ -...-+...+
AB AB
*/ */
heavy_extra(&extra, length/2, length/2); heavy_extra(&extra, global_length/2, global_length/2);
test_find_dir(-1, &extra, test_heaviside, 0, true, length/2-1, length/2-1, true); test_find_dir(-1, &extra, test_heaviside, 0, true, global_length/2-1, global_length/2-1, true);
test_find_dir(+1, &extra, test_heaviside, 0, true, length/2, length/2, true); test_find_dir(+1, &extra, test_heaviside, 0, true, global_length/2, global_length/2, true);
test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, length/2, length/2, false); test_find_dir(0, &extra, test_heaviside, DB_NOTFOUND, true, global_length/2, global_length/2, false);
/* /*
-...-0...0+...+ -...-0...0+...+
AC B AC B
*/ */
heavy_extra(&extra, length/3, 2*length/3); heavy_extra(&extra, global_length/3, 2*global_length/3);
test_find_dir(-1, &extra, test_heaviside, 0, true, length/3-1, length/3-1, true); test_find_dir(-1, &extra, test_heaviside, 0, true, global_length/3-1, global_length/3-1, true);
test_find_dir(+1, &extra, test_heaviside, 0, true, 2*length/3, 2*length/3, true); test_find_dir(+1, &extra, test_heaviside, 0, true, 2*global_length/3, 2*global_length/3, true);
test_find_dir(0, &extra, test_heaviside, 0, true, length/3, length/3, true); test_find_dir(0, &extra, test_heaviside, 0, true, global_length/3, global_length/3, true);
/* Cleanup */ /* Cleanup */
test_close(do_close); test_close(do_close);
...@@ -857,33 +899,35 @@ runtests_create_choice (enum create_type create_choice) { ...@@ -857,33 +899,35 @@ runtests_create_choice (enum create_type create_choice) {
static void static void
test_clone(uint32_t nelts) test_clone(uint32_t nelts)
// Test that each clone operation gives the right data back. If nelts is // Test that each clone operation gives the right data back. If nelts is
// zero, also tests that you still get a valid OMT back and that the way // zero, also tests that you still get a valid omt back and that the way
// to deallocate it still works. // to deallocate it still works.
{ {
OMT src = NULL, dest = NULL; toku::omt<void *> *src = NULL, *dest = NULL;
int r; int r;
r = toku_omt_create(&src); XMALLOC(src);
assert_zero(r); src->create();
for (long i = 0; i < nelts; ++i) { for (long i = 0; i < nelts; ++i) {
r = toku_omt_insert_at(src, (OMTVALUE) i, i); r = src->insert_at((OMTVALUE) i, i);
assert_zero(r); assert_zero(r);
} }
r = toku_omt_clone_noptr(&dest, src); XMALLOC(dest);
assert_zero(r); dest->clone(*src);
assert(dest != NULL); assert(dest != NULL);
assert(toku_omt_size(dest) == nelts); assert(dest->size() == nelts);
for (long i = 0; i < nelts; ++i) { for (long i = 0; i < nelts; ++i) {
OMTVALUE v; OMTVALUE v;
long l; long l;
r = toku_omt_fetch(dest, i, &v); r = dest->fetch(i, &v);
assert_zero(r); assert_zero(r);
l = (long) v; l = (long) v;
assert(l == i); assert(l == i);
} }
toku_omt_destroy(&dest); dest->destroy();
toku_omt_destroy(&src); toku_free(dest);
src->destroy();
toku_free(src);
} }
int int
......
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