Commit 609f6cf3 authored by John Esmet's avatar John Esmet

fixes #191 Move any relavent dmt wrapper functions to the only place

they are used - ft/tests/dmt-test.cc
parent 5dd15e69
......@@ -31,7 +31,6 @@ set(FT_SOURCES
checkpoint
compress
dbufio
dmt-wrapper
fifo
ft
ft-cachetable-wrappers
......
/* -*- 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 <util/mempool.h>
#include "dmt-wrapper.h"
int
toku_dmt_create_steal_sorted_array(DMT *dmtp, DMTVALUE **valuesp, uint32_t numvalues, uint32_t capacity) {
//TODO: implement using create_steal_sorted_array when it exists
(void)capacity;
toku_dmt_create_from_sorted_array(dmtp, *valuesp, numvalues);
toku_free(*valuesp);
*valuesp = nullptr;
// DMT XMALLOC(dmt);
//dmt->create_steal_sorted_array(valuesp, numvalues, capacity);
// *dmtp = dmt;
return 0;
}
//TODO: Put all dmt API functions here.
int toku_dmt_create (DMT *dmtp) {
DMT XMALLOC(dmt);
dmt->create();
*dmtp = dmt;
return 0;
}
void toku_dmt_destroy(DMT *dmtp) {
DMT dmt=*dmtp;
dmt->destroy();
toku_free(dmt);
*dmtp=NULL;
}
uint32_t toku_dmt_size(DMT V) {
return V->size();
}
int toku_dmt_create_from_sorted_array(DMT *dmtp, DMTVALUE *values, uint32_t numvalues) {
//TODO: implement using create_from_sorted_array when it exists
DMT XMALLOC(dmt);
dmt->create();
for (uint32_t i = 0; i < numvalues; i++) {
toku_dmt_insert_at(dmt, values[i], i);
}
//dmt->create_from_sorted_array(values, numvalues);
*dmtp=dmt;
return 0;
}
int toku_dmt_insert_at(DMT dmt, DMTVALUE value, uint32_t index) {
dmt_wrapper_internal::dmtvalue_writer functor(value);
return dmt->insert_at(functor, index);
}
int toku_dmt_set_at (DMT dmt, DMTVALUE value, uint32_t index) {
int r = dmt->delete_at(index);
if (r!=0) return r;
return toku_dmt_insert_at(dmt, value, index);
}
int toku_dmt_delete_at(DMT dmt, uint32_t index) {
return dmt->delete_at(index);
}
int toku_dmt_fetch(DMT dmt, uint32_t i, DMTVALUE *v) {
uint32_t size;
return dmt->fetch(i, &size, v);
}
struct functor {
int (*f)(DMTVALUE, uint32_t, void *);
void *v;
};
static_assert(std::is_pod<functor>::value, "not POD");
int call_functor(const uint32_t size, const DMTVALUE &v, uint32_t idx, functor *const ftor);
int call_functor(const uint32_t size, const DMTVALUE &v, uint32_t idx, functor *const ftor) {
invariant(size == sizeof(DMTVALUE));
return ftor->f(const_cast<DMTVALUE>(v), idx, ftor->v);
}
int toku_dmt_iterate(DMT dmt, int (*f)(DMTVALUE, uint32_t, void*), void*v) {
struct functor ftor = { .f = f, .v = v };
return dmt->iterate<functor, call_functor>(&ftor);
}
int toku_dmt_iterate_on_range(DMT dmt, uint32_t left, uint32_t right, int (*f)(DMTVALUE, uint32_t, void*), void*v) {
struct functor ftor = { .f = f, .v = v };
return dmt->iterate_on_range<functor, call_functor>(left, right, &ftor);
}
struct heftor {
int (*h)(DMTVALUE, void *v);
void *v;
};
static_assert(std::is_pod<heftor>::value, "not POD");
int call_heftor(const uint32_t size, const DMTVALUE &v, const heftor &htor);
int call_heftor(const uint32_t size, const DMTVALUE &v, const heftor &htor) {
invariant(size == sizeof(DMTVALUE));
return htor.h(const_cast<DMTVALUE>(v), htor.v);
}
int toku_dmt_insert(DMT dmt, DMTVALUE value, int(*h)(DMTVALUE, void*v), void *v, uint32_t *index) {
struct heftor htor = { .h = h, .v = v };
dmt_wrapper_internal::dmtvalue_writer functor(value);
return dmt->insert<heftor, call_heftor>(functor, htor, index);
}
int toku_dmt_find_zero(DMT V, int (*h)(DMTVALUE, void*extra), void*extra, DMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
uint32_t ignore;
return V->find_zero<heftor, call_heftor>(htor, &ignore, value, index);
}
int toku_dmt_find(DMT V, int (*h)(DMTVALUE, void*extra), void*extra, int direction, DMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
uint32_t ignore;
return V->find<heftor, call_heftor>(htor, direction, &ignore, value, index);
}
int toku_dmt_split_at(DMT dmt, DMT *newdmtp, uint32_t index) {
//TODO: use real split_at when it exists
if (index > dmt->size()) { return EINVAL; }
DMT XMALLOC(newdmt);
newdmt->create();
int r;
for (uint32_t i = index; i < dmt->size(); i++) {
DMTVALUE v;
r = toku_dmt_fetch(dmt, i, &v);
invariant_zero(r);
r = toku_dmt_insert_at(newdmt, v, i-index);
invariant_zero(r);
}
if (dmt->size() > 0) {
for (uint32_t i = dmt->size(); i > index; i--) {
r = toku_dmt_delete_at(dmt, i-1);
invariant_zero(r);
}
}
r = 0;
#if 0
int r = dmt->split_at(newdmt, index);
#endif
if (r != 0) {
toku_free(newdmt);
} else {
*newdmtp = newdmt;
}
return r;
}
int toku_dmt_merge(DMT leftdmt, DMT rightdmt, DMT *newdmtp) {
//TODO: use real merge when it exists
DMT XMALLOC(newdmt);
newdmt->create();
int r;
for (uint32_t i = 0; i < leftdmt->size(); i++) {
DMTVALUE v;
r = toku_dmt_fetch(leftdmt, i, &v);
invariant_zero(r);
r = toku_dmt_insert_at(newdmt, v, i);
invariant_zero(r);
}
uint32_t offset = leftdmt->size();
for (uint32_t i = 0; i < rightdmt->size(); i++) {
DMTVALUE v;
r = toku_dmt_fetch(rightdmt, i, &v);
invariant_zero(r);
r = toku_dmt_insert_at(newdmt, v, i+offset);
invariant_zero(r);
}
leftdmt->destroy();
rightdmt->destroy();
// newdmt->merge(leftdmt, rightdmt);
toku_free(leftdmt);
toku_free(rightdmt);
*newdmtp = newdmt;
return 0;
}
int toku_dmt_clone_noptr(DMT *dest, DMT src) {
DMT XMALLOC(dmt);
dmt->clone(*src);
*dest = dmt;
return 0;
}
void toku_dmt_clear(DMT dmt) {
dmt->clear();
}
size_t toku_dmt_memory_size (DMT dmt) {
return dmt->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_DMT_WRAPPER_H)
#define TOKU_DMT_WRAPPER_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 (DMT)
//
// Maintains a collection of totally ordered values, where each value has an integer weight.
// The DMT is a mutable datatype.
//
// The Abstraction:
//
// An DMT 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 DMT, 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 DMT into two DMTs, 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 DMTs contain the values to the left of $j$ and the values to the right of $j$ respectively.
// All of the values from the original DMT go into one of the new DMTs.
// If the weights of the values don't split exactly evenly, then the implementation has the freedom to choose whether
// the new left DMT or the new right DMT 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 *DMTVALUE; // A slight improvement over using void*.
#include <util/dmt.h>
typedef void *DMTVALUE;
namespace dmt_wrapper_internal {
class dmtvalue_writer {
public:
size_t get_size(void) const {
return sizeof(DMTVALUE);
}
void write_to(DMTVALUE *const dest) const {
*dest = value;
}
dmtvalue_writer(DMTVALUE _value)
: value(_value) {}
dmtvalue_writer(const uint32_t size UU(), DMTVALUE *const src)
: value(*src) {
paranoid_invariant(size == sizeof(DMTVALUE));
}
private:
const DMTVALUE value;
};
};
typedef toku::dmt<DMTVALUE, DMTVALUE, dmt_wrapper_internal::dmtvalue_writer> *DMT;
int toku_dmt_create (DMT *dmtp);
// Effect: Create an empty DMT. Stores it in *dmtp.
// Requires: dmtp != NULL
// Returns:
// 0 success
// ENOMEM out of memory (and doesn't modify *dmtp)
// Performance: constant time.
int toku_dmt_create_from_sorted_array(DMT *dmtp, DMTVALUE *values, uint32_t numvalues);
// Effect: Create a DMT containing values. The number of values is in numvalues.
// Stores the new DMT in *dmtp.
// Requires: dmtp != NULL
// Requires: values != NULL
// Requires: values is sorted
// Returns:
// 0 success
// ENOMEM out of memory (and doesn't modify *dmtp)
// 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_dmt_create_steal_sorted_array(DMT *dmtp, DMTVALUE **valuesp, uint32_t numvalues, uint32_t steal_capacity);
// Effect: Create an DMT containing values. The number of values is in numvalues.
// On success the DMT takes ownership of *valuesp array, and sets valuesp=NULL.
// Requires: dmtp != 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 *dmtp)
// EINVAL *valuesp == NULL or numvalues > capacity
// Performance: time=O(1)
// Rational: toku_dmt_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_dmt_destroy(DMT *dmtp);
// Effect: Destroy an DMT, freeing all its memory.
// Does not free the DMTVALUEs stored in the DMT.
// Those values may be freed before or after calling toku_dmt_destroy.
// Also sets *dmtp=NULL.
// Requires: dmtp != NULL
// Requires: *dmtp != NULL
// Rationale: The usage is to do something like
// toku_dmt_destroy(&s->dmt);
// and now s->dmt will have a NULL pointer instead of a dangling freed pointer.
// Rationale: Returns no values since free() cannot fail.
// Rationale: Does not free the DMTVALUEs to reduce complexity.
// Performance: time=O(toku_dmt_size(*dmtp))
uint32_t toku_dmt_size(DMT V);
// Effect: return |V|.
// Requires: V != NULL
// Performance: time=O(1)
int toku_dmt_iterate_on_range(DMT dmt, uint32_t left, uint32_t right, int (*f)(DMTVALUE, uint32_t, void*), void*v);
// Effect: Iterate over the values of the dmt, 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_dmt_size(dmt) (exclusive).
// We will iterate only over [left,right)
//
// Requires: dmt != 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_dmt_iterate.
// If f always returns zero, then toku_dmt_iterate returns 0.
// Requires: Don't modify dmt while running. (E.g., f may not insert or delete values form dmt.)
// Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in dmt.
// Rational: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read.
int toku_dmt_iterate(DMT dmt, int (*f)(DMTVALUE, uint32_t, void*), void*v);
// Effect: Iterate over the values of the dmt, 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_dmt_size(dmt) (exclusive).
// Requires: dmt != NULL
// Requires: f != NULL
// Returns:
// If f ever returns nonzero, then the iteration stops, and the value returned by f is returned by toku_dmt_iterate.
// If f always returns zero, then toku_dmt_iterate returns 0.
// Requires: Don't modify dmt while running. (E.g., f may not insert or delete values form dmt.)
// Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in dmt.
// Rational: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read.
int toku_dmt_insert_at(DMT dmt, DMTVALUE 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_dmt_size(dmt)
// ENOMEM
// On error, dmt 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_dmt_set_at (DMT dmt, DMTVALUE value, uint32_t idx);
// Effect: Replaces the item at index with value.
// Returns:
// 0 success
// EINVAL if index>=toku_dmt_size(dmt)
// On error, dmt 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_dmt_insert(DMT dmt, DMTVALUE value, int(*h)(DMTVALUE, void*v), void *v, uint32_t *idx);
// Effect: Insert value into the DMT.
// 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
// dmt_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, dmt 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_dmt_delete_at(DMT dmt, 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_dmt_size(dmt)
// On error, dmt is unchanged.
// Rationale: To delete an item, first find its index using toku_dmt_find, then delete it.
// Performance: time=O(\log N) amortized.
int toku_dmt_fetch (DMT V, uint32_t i, DMTVALUE *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_dmt_size(dmt)
// 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 DMT. If c is changed by this
// function, the function must remove c's association with the old
// DMT, and associate it with the new DMT.
int toku_dmt_find_zero(DMT V, int (*h)(DMTVALUE, void*extra), void*extra, DMTVALUE *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_dmt_size(V) and return DB_NOTFOUND.
// Requires: index!=NULL
int toku_dmt_find(DMT V, int (*h)(DMTVALUE, void*extra), void*extra, int direction, DMTVALUE *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_dmt_split_at(DMT dmt, DMT *newdmt, uint32_t idx);
// Effect: Create a new DMT, storing it in *newdmt.
// The values to the right of index (starting at index) are moved to *newdmt.
// Requires: dmt != NULL
// Requires: newdmt != NULL
// Returns
// 0 success,
// EINVAL if index > toku_dmt_size(dmt)
// ENOMEM
// On nonzero return, dmt and *newdmt 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_dmt_size(), and dividing by two.
int toku_dmt_merge(DMT leftdmt, DMT rightdmt, DMT *newdmt);
// Effect: Appends leftdmt and rightdmt to produce a new dmt.
// Sets *newdmt to the new dmt.
// On success, leftdmt and rightdmt 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_dmt_clone_noptr(DMT *dest, DMT src);
// Effect: Creates a copy of an dmt.
// Sets *dest to the clone
// Each element is assumed to be stored directly in the dmt, that is, the DMTVALUEs 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_dmt_clear(DMT dmt);
// 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_dmt_memory_size (DMT dmt);
// Effect: Return the size (in bytes) of the dmt, as it resides in main memory. Don't include any of the DMTVALUES.
#endif /* #ifndef TOKU_DMT_WRAPPER_H */
......@@ -90,10 +90,103 @@ PATENT RIGHTS GRANT:
#include "test.h"
#include "dmt-wrapper.h"
#include <util/dmt.h>
typedef DMTVALUE TESTVALUE;
typedef void *DMTVALUE;
class dmtvalue_writer {
public:
size_t get_size(void) const {
return sizeof(DMTVALUE);
}
void write_to(DMTVALUE *const dest) const {
*dest = value;
}
dmtvalue_writer(DMTVALUE _value)
: value(_value) {
}
dmtvalue_writer(const uint32_t size UU(), DMTVALUE *const src)
: value(*src) {
paranoid_invariant(size == sizeof(DMTVALUE));
}
private:
const DMTVALUE value;
};
typedef toku::dmt<DMTVALUE, DMTVALUE, dmtvalue_writer> *DMT;
static int dmt_insert_at(DMT dmt, DMTVALUE value, uint32_t index) {
dmtvalue_writer functor(value);
return dmt->insert_at(functor, index);
}
static DMT dmt_create_from_sorted_array(DMTVALUE *values, uint32_t numvalues) {
DMT XMALLOC(dmt);
dmt->create();
for (uint32_t i = 0; i < numvalues; i++) {
dmt_insert_at(dmt, values[i], i);
}
return dmt;
}
struct heftor {
int (*h)(DMTVALUE, void *v);
void *v;
};
int call_heftor(const uint32_t size, const DMTVALUE &v, const heftor &htor);
int call_heftor(const uint32_t size, const DMTVALUE &v, const heftor &htor) {
invariant(size == sizeof(DMTVALUE));
return htor.h(const_cast<DMTVALUE>(v), htor.v);
}
static int dmt_insert(DMT dmt, DMTVALUE value, int(*h)(DMTVALUE, void*v), void *v, uint32_t *index) {
struct heftor htor = { .h = h, .v = v };
dmtvalue_writer functor(value);
return dmt->insert<heftor, call_heftor>(functor, htor, index);
}
static int dmt_find_zero(DMT V, int (*h)(DMTVALUE, void*extra), void*extra, DMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
uint32_t ignore;
return V->find_zero<heftor, call_heftor>(htor, &ignore, value, index);
}
static int dmt_find(DMT V, int (*h)(DMTVALUE, void*extra), void*extra, int direction, DMTVALUE *value, uint32_t *index) {
struct heftor htor = { .h = h, .v = extra };
uint32_t ignore;
return V->find<heftor, call_heftor>(htor, direction, &ignore, value, index);
}
static int dmt_split_at(DMT dmt, DMT *newdmtp, uint32_t index) {
if (index > dmt->size()) { return EINVAL; }
DMT XMALLOC(newdmt);
newdmt->create();
int r;
for (uint32_t i = index; i < dmt->size(); i++) {
DMTVALUE v;
r = dmt->fetch(i, nullptr, &v);
invariant_zero(r);
r = dmt_insert_at(newdmt, v, i-index);
invariant_zero(r);
}
if (dmt->size() > 0) {
for (uint32_t i = dmt->size(); i > index; i--) {
r = dmt->delete_at(i - 1);
invariant_zero(r);
}
}
r = 0;
if (r != 0) {
toku_free(newdmt);
} else {
*newdmtp = newdmt;
}
return r;
}
static void
parse_args (int argc, const char *argv[]) {
......@@ -133,7 +226,6 @@ enum close_when_done {
KEEP_WHEN_DONE
};
enum create_type {
STEAL_ARRAY,
BATCH_INSERT,
INSERT_AT,
INSERT_AT_ALMOST_RANDOM,
......@@ -141,18 +233,18 @@ enum create_type {
/* Globals */
DMT global_dmt;
TESTVALUE* values = NULL;
struct value* nums = NULL;
DMTVALUE* values = nullptr;
struct value* nums = nullptr;
uint32_t length;
static void
cleanup_globals (void) {
assert(values);
toku_free(values);
values = NULL;
values = nullptr;
assert(nums);
toku_free(nums);
nums = NULL;
nums = nullptr;
}
const unsigned int random_seed = 0xFEADACBA;
......@@ -178,7 +270,7 @@ init_identity_values (unsigned int seed, uint32_t num_elements) {
for (i = 0; i < length; i++) {
nums[i].number = i;
values[i] = (TESTVALUE)&nums[i];
values[i] = (DMTVALUE)&nums[i];
}
}
......@@ -193,7 +285,7 @@ init_distinct_sorted_values (unsigned int seed, uint32_t num_elements) {
for (i = 0; i < length; i++) {
number += (uint32_t)(random() % 32) + 1;
nums[i].number = number;
values[i] = (TESTVALUE)&nums[i];
values[i] = (DMTVALUE)&nums[i];
}
}
......@@ -229,25 +321,22 @@ static void
test_close (enum close_when_done do_close) {
if (do_close == KEEP_WHEN_DONE) return;
assert(do_close == CLOSE_WHEN_DONE);
toku_dmt_destroy(&global_dmt);
assert(global_dmt==NULL);
global_dmt->destroy();
toku_free(global_dmt);
global_dmt = nullptr;
}
static void
test_create (enum close_when_done do_close) {
int r;
global_dmt = NULL;
r = toku_dmt_create(&global_dmt);
CKERR(r);
assert(global_dmt!=NULL);
XMALLOC(global_dmt);
global_dmt->create();
test_close(do_close);
}
static void
test_create_size (enum close_when_done do_close) {
test_create(KEEP_WHEN_DONE);
assert(toku_dmt_size(global_dmt) == 0);
assert(global_dmt->size() == 0);
test_close(do_close);
}
......@@ -258,24 +347,24 @@ test_create_insert_at_almost_random (enum close_when_done do_close) {
uint32_t size = 0;
test_create(KEEP_WHEN_DONE);
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+1);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+1);
CKERR2(r, EINVAL);
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+2);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+2);
CKERR2(r, EINVAL);
for (i = 0; i < length/2; i++) {
assert(size==toku_dmt_size(global_dmt));
r = toku_dmt_insert_at(global_dmt, values[i], i);
assert(size==global_dmt->size());
r = dmt_insert_at(global_dmt, values[i], i);
CKERR(r);
assert(++size==toku_dmt_size(global_dmt));
r = toku_dmt_insert_at(global_dmt, values[length-1-i], i+1);
assert(++size==global_dmt->size());
r = dmt_insert_at(global_dmt, values[length-1-i], i+1);
CKERR(r);
assert(++size==toku_dmt_size(global_dmt));
assert(++size==global_dmt->size());
}
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+1);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+1);
CKERR2(r, EINVAL);
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+2);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+2);
CKERR2(r, EINVAL);
assert(size==toku_dmt_size(global_dmt));
assert(size==global_dmt->size());
test_close(do_close);
}
......@@ -286,39 +375,30 @@ test_create_insert_at_sequential (enum close_when_done do_close) {
uint32_t size = 0;
test_create(KEEP_WHEN_DONE);
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+1);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+1);
CKERR2(r, EINVAL);
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+2);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+2);
CKERR2(r, EINVAL);
for (i = 0; i < length; i++) {
assert(size==toku_dmt_size(global_dmt));
r = toku_dmt_insert_at(global_dmt, values[i], i);
assert(size==global_dmt->size());
r = dmt_insert_at(global_dmt, values[i], i);
CKERR(r);
assert(++size==toku_dmt_size(global_dmt));
assert(++size==global_dmt->size());
}
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+1);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+1);
CKERR2(r, EINVAL);
r = toku_dmt_insert_at(global_dmt, values[0], toku_dmt_size(global_dmt)+2);
r = dmt_insert_at(global_dmt, values[0], global_dmt->size()+2);
CKERR2(r, EINVAL);
assert(size==toku_dmt_size(global_dmt));
assert(size==global_dmt->size());
test_close(do_close);
}
static void
test_create_from_sorted_array (enum create_type create_choice, enum close_when_done do_close) {
int r;
global_dmt = NULL;
global_dmt = nullptr;
if (create_choice == BATCH_INSERT) {
r = toku_dmt_create_from_sorted_array(&global_dmt, values, length);
CKERR(r);
}
else if (create_choice == STEAL_ARRAY) {
TESTVALUE* MALLOC_N(length, values_copy);
memcpy(values_copy, values, length*sizeof(*values));
r = toku_dmt_create_steal_sorted_array(&global_dmt, &values_copy, length, length);
CKERR(r);
assert(values_copy==NULL);
global_dmt = dmt_create_from_sorted_array(values, length);
}
else if (create_choice == INSERT_AT) {
test_create_insert_at_sequential(KEEP_WHEN_DONE);
......@@ -326,33 +406,35 @@ test_create_from_sorted_array (enum create_type create_choice, enum close_when_d
else if (create_choice == INSERT_AT_ALMOST_RANDOM) {
test_create_insert_at_almost_random(KEEP_WHEN_DONE);
}
else assert(false);
else {
assert(false);
}
assert(global_dmt!=NULL);
assert(global_dmt!=nullptr);
test_close(do_close);
}
static void
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);
assert(toku_dmt_size(global_dmt)==length);
assert(global_dmt->size()==length);
test_close(do_close);
}
static void
test_fetch_verify (DMT dmtree, TESTVALUE* val, uint32_t len ) {
test_fetch_verify (DMT dmtree, DMTVALUE* val, uint32_t len ) {
uint32_t i;
int r;
TESTVALUE v = (TESTVALUE)&i;
TESTVALUE oldv = v;
DMTVALUE v = (DMTVALUE)&i;
DMTVALUE oldv = v;
assert(len == toku_dmt_size(dmtree));
assert(len == dmtree->size());
for (i = 0; i < len; i++) {
assert(oldv!=val[i]);
v = NULL;
r = toku_dmt_fetch(dmtree, i, &v);
v = nullptr;
r = dmtree->fetch(i, nullptr, &v);
CKERR(r);
assert(v != NULL);
assert(v != nullptr);
assert(v != oldv);
assert(v == val[i]);
assert(V(v)->number == V(val[i])->number);
......@@ -361,7 +443,7 @@ test_fetch_verify (DMT dmtree, TESTVALUE* val, uint32_t len ) {
for (i = len; i < len*2; i++) {
v = oldv;
r = toku_dmt_fetch(dmtree, i, &v);
r = dmtree->fetch(i, nullptr, &v);
CKERR2(r, EINVAL);
assert(v == oldv);
}
......@@ -378,23 +460,38 @@ test_create_fetch_verify (enum create_type create_choice, enum close_when_done d
static int iterate_helper_error_return = 1;
static int
iterate_helper (TESTVALUE v, uint32_t idx, void* extra) {
if (extra == NULL) return iterate_helper_error_return;
TESTVALUE* vals = (TESTVALUE *)extra;
assert(v != NULL);
iterate_helper (DMTVALUE v, uint32_t idx, void* extra) {
if (extra == nullptr) return iterate_helper_error_return;
DMTVALUE* vals = (DMTVALUE *)extra;
assert(v != nullptr);
assert(v == vals[idx]);
assert(V(v)->number == V(vals[idx])->number);
return 0;
}
struct functor {
int (*f)(DMTVALUE, uint32_t, void *);
void *v;
};
int call_functor(const uint32_t size, const DMTVALUE &v, uint32_t idx, functor *const ftor);
int call_functor(const uint32_t size, const DMTVALUE &v, uint32_t idx, functor *const ftor) {
invariant(size == sizeof(DMTVALUE));
return ftor->f(const_cast<DMTVALUE>(v), idx, ftor->v);
}
static int dmt_iterate(DMT dmt, int (*f)(DMTVALUE, uint32_t, void*), void*v) {
struct functor ftor = { .f = f, .v = v };
return dmt->iterate<functor, call_functor>(&ftor);
}
static void
test_iterate_verify (DMT dmtree, TESTVALUE* vals, uint32_t len) {
test_iterate_verify (DMT dmtree, DMTVALUE* vals, uint32_t len) {
int r;
iterate_helper_error_return = 0;
r = toku_dmt_iterate(dmtree, iterate_helper, (void*)vals);
r = dmt_iterate(dmtree, iterate_helper, (void*)vals);
CKERR(r);
iterate_helper_error_return = 0xFEEDABBA;
r = toku_dmt_iterate(dmtree, iterate_helper, NULL);
r = dmt_iterate(dmtree, iterate_helper, nullptr);
if (!len) {
CKERR2(r, 0);
}
......@@ -431,19 +528,26 @@ permute_array (uint32_t* arr, uint32_t len) {
}
}
static int
dmt_set_at (DMT dmt, DMTVALUE value, uint32_t index) {
int r = dmt->delete_at(index);
if (r!=0) return r;
return dmt_insert_at(dmt, value, index);
}
static void
test_create_set_at (enum create_type create_choice, enum close_when_done do_close) {
uint32_t i = 0;
struct value* old_nums = NULL;
struct value* old_nums = nullptr;
MALLOC_N(length, old_nums);
assert(nums);
uint32_t* perm = NULL;
uint32_t* perm = nullptr;
MALLOC_N(length, perm);
assert(perm);
TESTVALUE* old_values = NULL;
DMTVALUE* old_values = nullptr;
MALLOC_N(length, old_values);
assert(old_values);
......@@ -459,22 +563,22 @@ test_create_set_at (enum create_type create_choice, enum close_when_done do_clos
}
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
int r;
r = toku_dmt_set_at (global_dmt, values[0], length);
r = dmt_set_at (global_dmt, values[0], length);
CKERR2(r,EINVAL);
r = toku_dmt_set_at (global_dmt, values[0], length+1);
r = dmt_set_at (global_dmt, values[0], length+1);
CKERR2(r,EINVAL);
for (i = 0; i < length; i++) {
uint32_t choice = perm[i];
values[choice] = &nums[choice];
nums[choice].number = (uint32_t)random();
r = toku_dmt_set_at (global_dmt, values[choice], choice);
r = dmt_set_at (global_dmt, values[choice], choice);
CKERR(r);
test_iterate_verify(global_dmt, values, length);
test_fetch_verify(global_dmt, values, length);
}
r = toku_dmt_set_at (global_dmt, values[0], length);
r = dmt_set_at (global_dmt, values[0], length);
CKERR2(r,EINVAL);
r = toku_dmt_set_at (global_dmt, values[0], length+1);
r = dmt_set_at (global_dmt, values[0], length+1);
CKERR2(r,EINVAL);
toku_free(perm);
......@@ -485,8 +589,8 @@ test_create_set_at (enum create_type create_choice, enum close_when_done do_clos
}
static int
insert_helper (TESTVALUE value, void* extra_insert) {
TESTVALUE to_insert = (DMTVALUE)extra_insert;
insert_helper (DMTVALUE value, void* extra_insert) {
DMTVALUE to_insert = (DMTVALUE)extra_insert;
assert(to_insert);
if (V(value)->number < V(to_insert)->number) return -1;
......@@ -498,7 +602,7 @@ static void
test_create_insert (enum close_when_done do_close) {
uint32_t i = 0;
uint32_t* perm = NULL;
uint32_t* perm = nullptr;
MALLOC_N(length, perm);
assert(perm);
......@@ -510,11 +614,11 @@ test_create_insert (enum close_when_done do_close) {
length = 0;
while (length < size) {
uint32_t choice = perm[length];
TESTVALUE to_insert = &nums[choice];
DMTVALUE to_insert = &nums[choice];
uint32_t idx = UINT32_MAX;
assert(length==toku_dmt_size(global_dmt));
r = toku_dmt_insert(global_dmt, to_insert, insert_helper, to_insert, &idx);
assert(length==global_dmt->size());
r = dmt_insert(global_dmt, to_insert, insert_helper, to_insert, &idx);
CKERR(r);
assert(idx <= length);
if (idx > 0) {
......@@ -524,7 +628,7 @@ test_create_insert (enum close_when_done do_close) {
assert(V(to_insert)->number < V(values[idx])->number);
}
length++;
assert(length==toku_dmt_size(global_dmt));
assert(length==global_dmt->size());
/* Make room */
for (i = length-1; i > idx; i--) {
values[i] = values[i-1];
......@@ -534,11 +638,11 @@ test_create_insert (enum close_when_done do_close) {
test_iterate_verify(global_dmt, values, length);
idx = UINT32_MAX;
r = toku_dmt_insert(global_dmt, to_insert, insert_helper, to_insert, &idx);
r = dmt_insert(global_dmt, to_insert, insert_helper, to_insert, &idx);
CKERR2(r, DB_KEYEXIST);
assert(idx < length);
assert(V(values[idx])->number == V(to_insert)->number);
assert(length==toku_dmt_size(global_dmt));
assert(length==global_dmt->size());
test_iterate_verify(global_dmt, values, length);
test_fetch_verify(global_dmt, values, length);
......@@ -555,16 +659,16 @@ test_create_delete_at (enum create_type create_choice, enum close_when_done do_c
int r = ENOSYS;
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
assert(length == toku_dmt_size(global_dmt));
r = toku_dmt_delete_at(global_dmt, length);
assert(length == global_dmt->size());
r = global_dmt->delete_at(length);
CKERR2(r,EINVAL);
assert(length == toku_dmt_size(global_dmt));
r = toku_dmt_delete_at(global_dmt, length+1);
assert(length == global_dmt->size());
r = global_dmt->delete_at(length+1);
CKERR2(r,EINVAL);
while (length > 0) {
assert(length == toku_dmt_size(global_dmt));
assert(length == global_dmt->size());
uint32_t index_to_delete = random()%length;
r = toku_dmt_delete_at(global_dmt, index_to_delete);
r = global_dmt->delete_at(index_to_delete);
CKERR(r);
for (i = index_to_delete+1; i < length; i++) {
values[i-1] = values[i];
......@@ -574,38 +678,65 @@ test_create_delete_at (enum create_type create_choice, enum close_when_done do_c
test_iterate_verify(global_dmt, values, length);
}
assert(length == 0);
assert(length == toku_dmt_size(global_dmt));
r = toku_dmt_delete_at(global_dmt, length);
assert(length == global_dmt->size());
r = global_dmt->delete_at(length);
CKERR2(r, EINVAL);
assert(length == toku_dmt_size(global_dmt));
r = toku_dmt_delete_at(global_dmt, length+1);
assert(length == global_dmt->size());
r = global_dmt->delete_at(length+1);
CKERR2(r, EINVAL);
test_close(do_close);
}
static int dmt_merge(DMT leftdmt, DMT rightdmt, DMT *newdmtp) {
DMT XMALLOC(newdmt);
newdmt->create();
int r;
for (uint32_t i = 0; i < leftdmt->size(); i++) {
DMTVALUE v;
r = leftdmt->fetch(i, nullptr, &v);
invariant_zero(r);
r = newdmt->insert_at(v, i);
invariant_zero(r);
}
uint32_t offset = leftdmt->size();
for (uint32_t i = 0; i < rightdmt->size(); i++) {
DMTVALUE v;
r = rightdmt->fetch(i, nullptr, &v);
invariant_zero(r);
r = newdmt->insert_at(v, i+offset);
invariant_zero(r);
}
leftdmt->destroy();
rightdmt->destroy();
toku_free(leftdmt);
toku_free(rightdmt);
*newdmtp = newdmt;
return 0;
}
static void
test_split_merge (enum create_type create_choice, enum close_when_done do_close) {
int r = ENOSYS;
uint32_t i = 0;
DMT left_split = NULL;
DMT right_split = NULL;
DMT left_split = nullptr;
DMT right_split = nullptr;
test_create_from_sorted_array(create_choice, KEEP_WHEN_DONE);
for (i = 0; i <= length; i++) {
r = toku_dmt_split_at(global_dmt, &right_split, length+1);
r = dmt_split_at(global_dmt, &right_split, length+1);
CKERR2(r,EINVAL);
r = toku_dmt_split_at(global_dmt, &right_split, length+2);
r = dmt_split_at(global_dmt, &right_split, length+2);
CKERR2(r,EINVAL);
//
// test successful split
//
r = toku_dmt_split_at(global_dmt, &right_split, i);
r = dmt_split_at(global_dmt, &right_split, i);
CKERR(r);
left_split = global_dmt;
global_dmt = NULL;
assert(toku_dmt_size(left_split) == i);
assert(toku_dmt_size(right_split) == length - i);
global_dmt = nullptr;
assert(left_split->size() == i);
assert(right_split->size() == length - i);
test_fetch_verify(left_split, values, i);
test_iterate_verify(left_split, values, i);
test_fetch_verify(right_split, &values[i], length - i);
......@@ -613,31 +744,31 @@ test_split_merge (enum create_type create_choice, enum close_when_done do_close)
//
// verify that new global_dmt's cannot do bad splits
//
r = toku_dmt_split_at(left_split, &global_dmt, i+1);
r = dmt_split_at(left_split, &global_dmt, i+1);
CKERR2(r,EINVAL);
assert(toku_dmt_size(left_split) == i);
assert(toku_dmt_size(right_split) == length - i);
r = toku_dmt_split_at(left_split, &global_dmt, i+2);
assert(left_split->size() == i);
assert(right_split->size() == length - i);
r = dmt_split_at(left_split, &global_dmt, i+2);
CKERR2(r,EINVAL);
assert(toku_dmt_size(left_split) == i);
assert(toku_dmt_size(right_split) == length - i);
r = toku_dmt_split_at(right_split, &global_dmt, length - i + 1);
assert(left_split->size() == i);
assert(right_split->size() == length - i);
r = dmt_split_at(right_split, &global_dmt, length - i + 1);
CKERR2(r,EINVAL);
assert(toku_dmt_size(left_split) == i);
assert(toku_dmt_size(right_split) == length - i);
r = toku_dmt_split_at(right_split, &global_dmt, length - i + 1);
assert(left_split->size() == i);
assert(right_split->size() == length - i);
r = dmt_split_at(right_split, &global_dmt, length - i + 1);
CKERR2(r,EINVAL);
assert(toku_dmt_size(left_split) == i);
assert(toku_dmt_size(right_split) == length - i);
assert(left_split->size() == i);
assert(right_split->size() == length - i);
//
// test merge
//
r = toku_dmt_merge(left_split,right_split,&global_dmt);
r = dmt_merge(left_split,right_split,&global_dmt);
CKERR(r);
left_split = NULL;
right_split = NULL;
assert(toku_dmt_size(global_dmt) == length);
left_split = nullptr;
right_split = nullptr;
assert(global_dmt->size() == length);
test_fetch_verify(global_dmt, values, length);
test_iterate_verify(global_dmt, values, length);
}
......@@ -694,7 +825,7 @@ typedef struct {
static int
test_heaviside (DMTVALUE v_dmt, void* x) {
TESTVALUE v = (DMTVALUE) v_dmt;
DMTVALUE v = (DMTVALUE) v_dmt;
h_extra* extra = (h_extra*)x;
assert(v && x);
assert(extra->first_zero <= extra->first_pos);
......@@ -717,19 +848,19 @@ test_find_dir (int dir, void* extra, int (*h)(DMTVALUE, void*),
uint32_t number_expect, bool UU(cursor_valid)) {
uint32_t idx = UINT32_MAX;
uint32_t old_idx = idx;
TESTVALUE dmt_val;
DMTVALUE dmt_val;
int r;
dmt_val = NULL;
dmt_val = nullptr;
/* Verify we can pass NULL value. */
dmt_val = NULL;
/* Verify we can pass nullptr value. */
dmt_val = nullptr;
idx = old_idx;
if (dir == 0) {
r = toku_dmt_find_zero(global_dmt, h, extra, NULL, &idx);
r = dmt_find_zero(global_dmt, h, extra, nullptr, &idx);
}
else {
r = toku_dmt_find( global_dmt, h, extra, dir, NULL, &idx);
r = dmt_find( global_dmt, h, extra, dir, nullptr, &idx);
}
CKERR2(r, r_expect);
if (idx_will_change) {
......@@ -738,38 +869,38 @@ test_find_dir (int dir, void* extra, int (*h)(DMTVALUE, void*),
else {
assert(idx == old_idx);
}
assert(dmt_val == NULL);
assert(dmt_val == nullptr);
/* Verify we can pass NULL idx. */
dmt_val = NULL;
/* Verify we can pass nullptr idx. */
dmt_val = nullptr;
idx = old_idx;
if (dir == 0) {
r = toku_dmt_find_zero(global_dmt, h, extra, &dmt_val, 0);
r = dmt_find_zero(global_dmt, h, extra, &dmt_val, 0);
}
else {
r = toku_dmt_find( global_dmt, h, extra, dir, &dmt_val, 0);
r = dmt_find( global_dmt, h, extra, dir, &dmt_val, 0);
}
CKERR2(r, r_expect);
assert(idx == old_idx);
if (r == DB_NOTFOUND) {
assert(dmt_val == NULL);
assert(dmt_val == nullptr);
}
else {
assert(V(dmt_val)->number == number_expect);
}
/* Verify we can pass NULL both. */
dmt_val = NULL;
/* Verify we can pass nullptr both. */
dmt_val = nullptr;
idx = old_idx;
if (dir == 0) {
r = toku_dmt_find_zero(global_dmt, h, extra, NULL, 0);
r = dmt_find_zero(global_dmt, h, extra, nullptr, 0);
}
else {
r = toku_dmt_find( global_dmt, h, extra, dir, NULL, 0);
r = dmt_find( global_dmt, h, extra, dir, nullptr, 0);
}
CKERR2(r, r_expect);
assert(idx == old_idx);
assert(dmt_val == NULL);
assert(dmt_val == nullptr);
}
static void
......@@ -860,30 +991,29 @@ test_clone(uint32_t nelts)
// zero, also tests that you still get a valid DMT back and that the way
// to deallocate it still works.
{
DMT src = NULL, dest = NULL;
int r;
DMT src = nullptr, dest = nullptr;
int r = 0;
r = toku_dmt_create(&src);
assert_zero(r);
XMALLOC(src);
src->create();
for (long i = 0; i < nelts; ++i) {
r = toku_dmt_insert_at(src, (DMTVALUE) i, i);
r = dmt_insert_at(src, (DMTVALUE) i, i);
assert_zero(r);
}
r = toku_dmt_clone_noptr(&dest, src);
assert_zero(r);
assert(dest != NULL);
assert(toku_dmt_size(dest) == nelts);
XMALLOC(dest);
dest->clone(*src);
assert(dest->size() == nelts);
for (long i = 0; i < nelts; ++i) {
DMTVALUE v;
long l;
r = toku_dmt_fetch(dest, i, &v);
r = dest->fetch(i, nullptr, &v);
assert_zero(r);
l = (long) v;
assert(l == i);
}
toku_dmt_destroy(&dest);
toku_dmt_destroy(&src);
dest->destroy();
src->destroy();
}
int
......@@ -893,7 +1023,6 @@ test_main(int argc, const char *argv[]) {
test_create( CLOSE_WHEN_DONE);
test_create_size( CLOSE_WHEN_DONE);
runtests_create_choice(BATCH_INSERT);
runtests_create_choice(STEAL_ARRAY);
runtests_create_choice(INSERT_AT);
runtests_create_choice(INSERT_AT_ALMOST_RANDOM);
test_clone(0);
......
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