From 4974b057919a8c9ba9b1e9efac266079132bba02 Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tsisyk.com> Date: Fri, 8 Feb 2013 13:06:28 +0400 Subject: [PATCH] BitsetIndex implementation (initial import) --- src/box/CMakeLists.txt | 5 +- src/box/bitset_index.h | 50 +++++++ src/box/bitset_index.m | 307 +++++++++++++++++++++++++++++++++++++++++ src/box/index.h | 10 +- src/box/index.m | 3 + src/box/space.m | 15 ++ 6 files changed, 386 insertions(+), 4 deletions(-) create mode 100644 src/box/bitset_index.h create mode 100644 src/box/bitset_index.m diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index a4246b11d2..bb02aaa38b 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -26,4 +26,7 @@ add_custom_target(generate_lua_sources} set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${lua_sources}) tarantool_module("box" tuple.m index.m hash_index.m tree_index.m space.m - port.m request.m txn.m box.m ${lua_sources} box_lua.m box_lua_space.m) + port.m request.m txn.m box.m ${lua_sources} box_lua.m box_lua_space.m + bitset_index.m) + +target_link_libraries(tarantool_box bitset) diff --git a/src/box/bitset_index.h b/src/box/bitset_index.h new file mode 100644 index 0000000000..fbaf074409 --- /dev/null +++ b/src/box/bitset_index.h @@ -0,0 +1,50 @@ +#ifndef TARANTOOL_BOX_INDEX_BITSET_H_INCLUDED +#define TARANTOOL_BOX_INDEX_BITSET_H_INCLUDED + +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @brief Objective C wrapper for bitset_index + * @see bitset/index.h + */ + +#include "index.h" +#include <lib/bitset/index.h> + +struct bitset_index; +struct bitset_expr; + +@interface BitsetIndex: Index { + @private + struct bitset_index index; +} +@end + +#endif /* TARANTOOL_BOX_INDEX_BITSET_H_INCLUDED */ diff --git a/src/box/bitset_index.m b/src/box/bitset_index.m new file mode 100644 index 0000000000..0cd2c7b9cd --- /dev/null +++ b/src/box/bitset_index.m @@ -0,0 +1,307 @@ +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "bitset_index.h" + +#include <string.h> + +#include "salloc.h" +#include "tuple.h" +#include "space.h" +#include "exception.h" +#include "pickle.h" +#include <lib/bitset/index.h> + +static struct index_traits bitset_index_traits = { + .allows_partial_key = false, +}; + +static inline size_t +tuple_to_value(struct tuple *tuple) +{ +#if 0 + size_t value = salloc_ptr_to_index(tuple); + assert(salloc_ptr_from_index(value) == tuple); + return value; +#endif + return (size_t) tuple; +} + +static inline struct tuple * +value_to_tuple(size_t value) +{ +#if 0 + return salloc_ptr_from_index(value); +#endif + return (struct tuple *) value; +} + +struct iterator_wrapper { + struct iterator base; /* Must be the first member. */ + struct bitset_iterator bitset_it; +}; + +static struct iterator_wrapper * +iterator_wrapper(struct iterator *it) +{ + return (struct iterator_wrapper *) it; +} + +void +iterator_wrapper_free(struct iterator *iterator) +{ + assert(iterator->free == iterator_wrapper_free); + struct iterator_wrapper *it = iterator_wrapper(iterator); + + bitset_iterator_destroy(&it->bitset_it); + free(it); +} + +struct tuple * +iterator_wrapper_next(struct iterator *iterator) +{ + assert(iterator->free == iterator_wrapper_free); + struct iterator_wrapper *it = iterator_wrapper(iterator); + + size_t value = bitset_iterator_next(&it->bitset_it); + if (value == SIZE_MAX) + return NULL; + + return value_to_tuple(value); +} + +@implementation BitsetIndex; + ++ (struct index_traits *) traits +{ + return &bitset_index_traits; +} + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg +{ + assert (!key_def_arg->is_unique); + + self = [super init: key_def_arg :space_arg]; + assert (self != NULL); + + if (bitset_index_create(&self->index, realloc) != 0) + panic_syserror("bitset_index_create"); + + return self; +} + +- (void) free +{ + bitset_index_destroy(&self->index); + [super free]; +} + +- (void) beginBuild +{ + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "beginBuild()"); +} + +- (void) buildNext: (struct tuple *)tuple +{ + (void) tuple; + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "buildNext()"); +} + +- (void) endBuild +{ + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "endBuild()"); +} + +- (void) build: (Index *) pk +{ + assert (!key_def->is_unique); + + struct iterator *it = pk->position; + struct tuple *tuple; + [pk initIterator: it :ITER_ALL :NULL :0]; + + while ((tuple = it->next(it))) + [self replace: NULL :tuple :DUP_INSERT]; +} + +- (size_t) size +{ + return bitset_index_size(&self->index); +} + +- (struct tuple *) min +{ + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "min()"); + return NULL; +} + +- (struct tuple *) max +{ + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "max()"); + return NULL; +} + +- (struct iterator *) allocIterator +{ + struct iterator_wrapper *it = malloc(sizeof(struct iterator_wrapper)); + if (!it) + return NULL; + + memset(it, 0, sizeof(struct iterator_wrapper)); + it->base.next = iterator_wrapper_next; + it->base.free = iterator_wrapper_free; + + bitset_iterator_create(&it->bitset_it, realloc); + + return (struct iterator *) it; +} + +- (struct tuple *) findByKey: (void *) key :(int) part_count +{ + (void) key; + (void) part_count; + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "findByKey()"); + return NULL; +} + +- (struct tuple *) findByTuple: (struct tuple *) tuple +{ + (void) tuple; + tnt_raise(ClientError, :ER_UNSUPPORTED, "BitsetIndex", "findByTuple()"); + return NULL; +} + +- (struct tuple *) replace: (struct tuple *) old_tuple + : (struct tuple *) new_tuple + : (u32) flags +{ + assert(!key_def->is_unique); + assert(old_tuple != NULL || new_tuple != NULL); + (void) flags; + + struct tuple *ret = NULL; + + if (old_tuple != NULL) { + size_t value = tuple_to_value(old_tuple); +#if defined(DEBUG) + say_debug("BitsetIndex: remove value = %zu (%p)", + value, old_tuple); +#endif /* defined(DEBUG) */ + if (bitset_index_contains_value(&self->index, value)) { + ret = old_tuple; + + assert (old_tuple != new_tuple); + bitset_index_remove_value(&self->index, value); + } + } + + if (new_tuple != NULL) { + const void *field = tuple_field(new_tuple, + key_def->parts[0].fieldno); + assert (field != NULL); + size_t bitset_key_size = (size_t) load_varint32(&field); + const void *bitset_key = field; + + size_t value = tuple_to_value(new_tuple); +#if defined(DEBUG) + say_debug("BitsetIndex: insert value = %zu (%p)", + value, new_tuple); +#endif /* defined(DEBUG) */ + if (bitset_index_insert(&self->index, bitset_key, + bitset_key_size, value) < 0) { + tnt_raise(ClientError, :ER_MEMORY_ISSUE, 0, + "BitsetIndex", "insert"); + } + } + + return ret; +} + +- (void) initIterator: (struct iterator *) iterator:(enum iterator_type) type + :(const void *) key :(int) part_count +{ + assert(iterator->free == iterator_wrapper_free); + struct iterator_wrapper *it = iterator_wrapper(iterator); + + const void *bitset_key = NULL; + size_t bitset_key_size = 0; + + if (type != ITER_ALL) { + check_key_parts(key_def, part_count, + bitset_index_traits.allows_partial_key); + const void *key2 = key; + bitset_key_size = (size_t) load_varint32(&key2); + bitset_key = key2; + } + + struct bitset_expr expr; + bitset_expr_create(&expr, realloc); + @try { + int rc = 0; + switch (type) { + case ITER_ALL: + rc = bitset_index_expr_all(&expr); + break; + case ITER_EQ: + rc = bitset_index_expr_equals(&expr, bitset_key, + bitset_key_size); + break; + case ITER_BITS_ALL_SET: + rc = bitset_index_expr_all_set(&expr, bitset_key, + bitset_key_size); + break; + case ITER_BITS_ALL_NOT_SET: + rc = bitset_index_expr_all_not_set(&expr, bitset_key, + bitset_key_size); + break; + case ITER_BITS_ANY_SET: + rc = bitset_index_expr_any_set(&expr, bitset_key, + bitset_key_size); + break; + default: + tnt_raise(ClientError, :ER_UNSUPPORTED, + "BitsetIndex", "requested iterator type"); + } + + if (rc != 0) { + tnt_raise(ClientError, :ER_MEMORY_ISSUE, + 0, "BitsetIndex", "iterator expression"); + } + + if (bitset_index_init_iterator(&self->index, &it->bitset_it, + &expr) != 0) { + tnt_raise(ClientError, :ER_MEMORY_ISSUE, + 0, "BitsetIndex", "iterator state"); + } + } @finally { + bitset_expr_destroy(&expr); + } +} + +@end diff --git a/src/box/index.h b/src/box/index.h index 7d394fb1b2..9c989731e5 100644 --- a/src/box/index.h +++ b/src/box/index.h @@ -43,9 +43,10 @@ struct space; enum field_data_type { UNKNOWN = -1, NUM = 0, NUM64, STRING, field_data_type_MAX }; extern const char *field_data_type_strs[]; -#define INDEX_TYPE(_) \ - _(HASH, 0) /* HASH Index */ \ - _(TREE, 1) /* TREE Index */ \ +#define INDEX_TYPE(_) \ + _(HASH, 0) /* HASH Index */ \ + _(TREE, 1) /* TREE Index */ \ + _(BITSET, 2) /* BITSET Index */ \ ENUM(index_type, INDEX_TYPE); extern const char *index_type_strs[]; @@ -79,6 +80,9 @@ extern const char *index_type_strs[]; _(ITER_LE, 4) /* key <= x */ \ _(ITER_GE, 5) /* key >= x */ \ _(ITER_GT, 6) /* key > x */ \ + _(ITER_BITS_ALL_SET, 7) /* all bits from x are set in key */ \ + _(ITER_BITS_ANY_SET, 8) /* at least one x's bit is set */ \ + _(ITER_BITS_ALL_NOT_SET, 9) /* all bits are not set */ \ ENUM(iterator_type, ITERATOR_TYPE); extern const char *iterator_type_strs[]; diff --git a/src/box/index.m b/src/box/index.m index c105cb4a30..b36865a9f2 100644 --- a/src/box/index.m +++ b/src/box/index.m @@ -29,6 +29,7 @@ #include "index.h" #include "hash_index.h" #include "tree_index.h" +#include "bitset_index.h" #include "tuple.h" #include "say.h" #include "exception.h" @@ -108,6 +109,8 @@ replace_check_dup(struct tuple *old_tuple, return [HashIndex alloc: key_def :space]; case TREE: return [TreeIndex alloc: key_def :space]; + case BITSET: + return [BitsetIndex alloc]; default: assert(false); } diff --git a/src/box/space.m b/src/box/space.m index d3d0f60a0c..43767d31d8 100644 --- a/src/box/space.m +++ b/src/box/space.m @@ -572,6 +572,21 @@ check_spaces(struct tarantool_cfg *conf) case TREE: /* extra check for tree index not needed */ break; + case BITSET: + /* check bitset index */ + /* bitset index must has single-field key */ + if (key_part_count != 1) { + out_warning(0, "(space = %zu index = %zu) " + "bitset index must has a single-field key", i, j); + return -1; + } + /* bitset index must not be unique */ + if (index->unique) { + out_warning(0, "(space = %zu index = %zu) " + "bitset index must be non-unique", i, j); + return -1; + } + break; default: assert(false); } -- GitLab