From 2dcd0ea0c9635cb4197254ae163beda3b80f3f6d Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tsisyk.com> Date: Mon, 17 Dec 2012 12:19:09 +0400 Subject: [PATCH] Extract HashIndex from index.h(.m), rename tree.h(.m) to tree_index.h(.m) --- src/box/CMakeLists.txt | 4 +- src/box/box_lua_space.m | 13 +- src/box/hash_index.h | 44 ++ src/box/hash_index.m | 741 +++++++++++++++++++++++++++++++ src/box/index.h | 19 +- src/box/index.m | 730 +----------------------------- src/box/space.m | 13 +- src/box/{tree.h => tree_index.h} | 9 +- src/box/{tree.m => tree_index.m} | 30 +- 9 files changed, 844 insertions(+), 759 deletions(-) create mode 100644 src/box/hash_index.h create mode 100644 src/box/hash_index.m rename src/box/{tree.h => tree_index.h} (92%) rename src/box/{tree.m => tree_index.m} (98%) diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index cd7d531ac5..a4246b11d2 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -25,5 +25,5 @@ add_custom_target(generate_lua_sources} DEPENDS ${lua_sources}) set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${lua_sources}) -tarantool_module("box" tuple.m index.m tree.m space.m port.m request.m - txn.m box.m ${lua_sources} box_lua.m box_lua_space.m) +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) diff --git a/src/box/box_lua_space.m b/src/box/box_lua_space.m index 72bbfbee3b..78e7236e28 100644 --- a/src/box/box_lua_space.m +++ b/src/box/box_lua_space.m @@ -81,17 +81,8 @@ lbox_pushspace(struct lua_State *L, struct space *space) lua_settable(L, -3); lua_pushstring(L, "type"); - switch (space->key_defs[i].type) { - case HASH: - lua_pushstring(L, "HASH"); - break; - case TREE: - lua_pushstring(L, "TREE"); - break; - default: - panic("unknown index type %d", - space->key_defs[i].parts[0].type); - } + + lua_pushstring(L, index_type_strs[space->key_defs[i].type]); lua_settable(L, -3); lua_pushstring(L, "key_field"); diff --git a/src/box/hash_index.h b/src/box/hash_index.h new file mode 100644 index 0000000000..5e1fd9c438 --- /dev/null +++ b/src/box/hash_index.h @@ -0,0 +1,44 @@ +#ifndef TARANTOOL_BOX_HASH_INDEX_H_INCLUDED +#define TARANTOOL_BOX_HASH_INDEX_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. + */ + +#include "index.h" + +@class Index; + +@interface HashIndex: Index + ++ (struct index_traits *) traits; ++ (HashIndex *) alloc: (struct key_def *) key_def :(struct space *) space; + +- (void) reserve: (u32) n_tuples; +@end + +#endif /* TARANTOOL_BOX_HASH_INDEX_H_INCLUDED */ diff --git a/src/box/hash_index.m b/src/box/hash_index.m new file mode 100644 index 0000000000..49773839ee --- /dev/null +++ b/src/box/hash_index.m @@ -0,0 +1,741 @@ +/* + * 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 "hash_index.h" +#include "say.h" +#include "tuple.h" +#include "pickle.h" +#include "exception.h" +#include "space.h" +#include "assoc.h" +#include "errinj.h" + +static struct index_traits hash_index_traits = { + .allows_partial_key = false, +}; + +/* {{{ HashIndex Iterators ****************************************/ + +struct hash_i32_iterator { + struct iterator base; /* Must be the first member. */ + struct mh_i32ptr_t *hash; + mh_int_t h_pos; +}; + +struct hash_i64_iterator { + struct iterator base; + struct mh_i64ptr_t *hash; + mh_int_t h_pos; +}; + +struct hash_lstr_iterator { + struct iterator base; + struct mh_lstrptr_t *hash; + mh_int_t h_pos; +}; + +void +hash_iterator_free(struct iterator *iterator) +{ + assert(iterator->free == hash_iterator_free); + free(iterator); +} + +struct tuple * +hash_iterator_i32_ge(struct iterator *ptr) +{ + assert(ptr->free == hash_iterator_free); + struct hash_i32_iterator *it = (struct hash_i32_iterator *) ptr; + + while (it->h_pos < mh_end(it->hash)) { + if (mh_exist(it->hash, it->h_pos)) + return mh_i32ptr_node(it->hash, it->h_pos++)->val; + it->h_pos++; + } + return NULL; +} + +struct tuple * +hash_iterator_i64_ge(struct iterator *ptr) +{ + assert(ptr->free == hash_iterator_free); + struct hash_i64_iterator *it = (struct hash_i64_iterator *) ptr; + + while (it->h_pos < mh_end(it->hash)) { + if (mh_exist(it->hash, it->h_pos)) + return mh_i64ptr_node(it->hash, it->h_pos++)->val; + it->h_pos++; + } + return NULL; +} + +struct tuple * +hash_iterator_lstr_ge(struct iterator *ptr) +{ + assert(ptr->free == hash_iterator_free); + struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) ptr; + + while (it->h_pos < mh_end(it->hash)) { + if (mh_exist(it->hash, it->h_pos)) + return mh_lstrptr_node(it->hash, it->h_pos++)->val; + it->h_pos++; + } + return NULL; +} + +static struct tuple * +hash_iterator_eq_next(struct iterator *it __attribute__((unused))) +{ + return NULL; +} + +static struct tuple * +hash_iterator_i32_eq(struct iterator *it) +{ + it->next = hash_iterator_eq_next; + return hash_iterator_i32_ge(it); +} + +static struct tuple * +hash_iterator_i64_eq(struct iterator *it) +{ + it->next = hash_iterator_eq_next; + return hash_iterator_i64_ge(it); +} + +static struct tuple * +hash_iterator_lstr_eq(struct iterator *it) +{ + it->next = hash_iterator_eq_next; + return hash_iterator_lstr_ge(it); +} + +/* }}} */ + +/* {{{ HashIndex -- base class for all hashes. ********************/ + +@interface Hash32Index: HashIndex { + struct mh_i32ptr_t *int_hash; +}; + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg; +@end + +@interface Hash64Index: HashIndex { + struct mh_i64ptr_t *int64_hash; +}; + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg; +@end + +@interface HashStrIndex: HashIndex { + struct mh_lstrptr_t *str_hash; +}; + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg; +@end + +@implementation HashIndex + ++ (struct index_traits *) traits +{ + return &hash_index_traits; +} + ++ (HashIndex *) alloc: (struct key_def *) key_def :(struct space *) space +{ + (void) space; + + /* + * Hash index always has a single-field key. + */ + switch (key_def->parts[0].type) { + case NUM: + return [Hash32Index alloc]; /* 32-bit integer hash */ + case NUM64: + return [Hash64Index alloc]; /* 64-bit integer hash */ + case STRING: + return [HashStrIndex alloc]; /* string hash */ + default: + assert(false); + } +} + +- (void) reserve: (u32) n_tuples +{ + (void) n_tuples; + [self subclassResponsibility: _cmd]; +} + +- (void) beginBuild +{ +} + +- (void) buildNext: (struct tuple *)tuple +{ + [self replace: NULL :tuple :DUP_INSERT]; +} + +- (void) endBuild +{ +} + +- (void) build: (Index *) pk +{ + u32 n_tuples = [pk size]; + + if (n_tuples == 0) + return; + + [self reserve: n_tuples]; + + say_info("Adding %"PRIu32 " keys to HASH index %" + PRIu32 "...", n_tuples, index_n(self)); + + 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]; +} + +- (void) free +{ + [super free]; +} + +- (struct tuple *) min +{ + tnt_raise(ClientError, :ER_UNSUPPORTED, "Hash index", "min()"); + return NULL; +} + +- (struct tuple *) max +{ + tnt_raise(ClientError, :ER_UNSUPPORTED, "Hash index", "max()"); + return NULL; +} + +@end + +/* }}} */ + +/* {{{ Hash32Index ************************************************/ + +static inline struct mh_i32ptr_node_t +int32_key_to_node(void *key) +{ + u32 key_size = load_varint32(&key); + if (key_size != 4) + tnt_raise(ClientError, :ER_KEY_FIELD_TYPE, "u32"); + struct mh_i32ptr_node_t node = { .key = *(u32 *) key }; + return node; +} + +static inline struct mh_i32ptr_node_t +int32_tuple_to_node(struct tuple *tuple, struct key_def *key_def) +{ + void *field = tuple_field(tuple, key_def->parts[0].fieldno); + struct mh_i32ptr_node_t node = int32_key_to_node(field); + node.val = tuple; + return node; +} + +@implementation Hash32Index + +- (void) reserve: (u32) n_tuples +{ + mh_i32ptr_reserve(int_hash, n_tuples, NULL, NULL); +} + +- (void) free +{ + mh_i32ptr_destroy(int_hash); + [super free]; +} + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg +{ + self = [super init: key_def_arg :space_arg]; + + if (self == NULL) + return NULL; + + int_hash = mh_i32ptr_init(); + return self; +} + +- (size_t) size +{ + return mh_size(int_hash); +} + +- (struct tuple *) findByKey: (void *) key :(int) part_count +{ + assert(key_def->is_unique); + check_key_parts(key_def, part_count, false); + + (void) part_count; + + struct tuple *ret = NULL; + struct mh_i32ptr_node_t node = int32_key_to_node(key); + mh_int_t k = mh_i32ptr_get(int_hash, &node, NULL, NULL); + if (k != mh_end(int_hash)) + ret = mh_i32ptr_node(int_hash, k)->val; +#ifdef DEBUG + say_debug("Hash32Index find(self:%p, key:%i) = %p", self, node.key, ret); +#endif + return ret; +} + +- (struct tuple *) replace: (struct tuple *) old_tuple + :(struct tuple *) new_tuple + :(enum dup_replace_mode) mode +{ + struct mh_i32ptr_node_t new_node, old_node; + uint32_t errcode; + + if (new_tuple) { + struct mh_i32ptr_node_t *dup_node = &old_node; + new_node = int32_tuple_to_node(new_tuple, key_def); + mh_int_t pos = mh_i32ptr_replace(int_hash, &new_node, + &dup_node, NULL, NULL); + + ERROR_INJECT(ERRINJ_INDEX_ALLOC, + { + mh_i32ptr_del(int_hash, pos, NULL, NULL); + pos = mh_end(int_hash); + }); + + if (pos == mh_end(int_hash)) { + tnt_raise(LoggedError, :ER_MEMORY_ISSUE, (ssize_t) pos, + "int hash", "key"); + } + struct tuple *dup_tuple = dup_node ? dup_node->val : NULL; + errcode = replace_check_dup(old_tuple, dup_tuple, mode); + + if (errcode) { + mh_i32ptr_remove(int_hash, &new_node, NULL, NULL); + if (dup_node) { + pos = mh_i32ptr_replace(int_hash, dup_node, + NULL, NULL, NULL); + if (pos == mh_end(int_hash)) { + panic("Failed to allocate memory in " + "recover of int hash"); + } + } + tnt_raise(ClientError, :errcode, index_n(self)); + } + if (dup_tuple) + return dup_tuple; + } + if (old_tuple) { + old_node = int32_tuple_to_node(old_tuple, key_def); + mh_i32ptr_remove(int_hash, &old_node, NULL, NULL); + } + return old_tuple; +} + + +- (struct iterator *) allocIterator +{ + struct hash_i32_iterator *it = malloc(sizeof(struct hash_i32_iterator)); + if (it) { + memset(it, 0, sizeof(*it)); + it->base.next = hash_iterator_i32_ge; + it->base.free = hash_iterator_free; + } + return (struct iterator *) it; +} + +- (void) initIterator: (struct iterator *) ptr: (enum iterator_type) type + :(void *) key :(int) part_count +{ + assert(ptr->free == hash_iterator_free); + struct hash_i32_iterator *it = (struct hash_i32_iterator *) ptr; + struct mh_i32ptr_node_t node; + + switch (type) { + case ITER_GE: + if (key != NULL) { + check_key_parts(key_def, part_count, + traits->allows_partial_key); + node = int32_key_to_node(key); + it->h_pos = mh_i32ptr_get(int_hash, &node, NULL, NULL); + it->base.next = hash_iterator_i32_ge; + break; + } + /* Fall through. */ + case ITER_ALL: + it->h_pos = mh_begin(int_hash); + it->base.next = hash_iterator_i32_ge; + break; + case ITER_EQ: + check_key_parts(key_def, part_count, + traits->allows_partial_key); + node = int32_key_to_node(key); + it->h_pos = mh_i32ptr_get(int_hash, &node, NULL, NULL); + it->base.next = hash_iterator_i32_eq; + break; + default: + tnt_raise(ClientError, :ER_UNSUPPORTED, + "Hash index", "requested iterator type"); + } + it->hash = int_hash; +} +@end + +/* }}} */ + +/* {{{ Hash64Index ************************************************/ + +static inline struct mh_i64ptr_node_t +int64_key_to_node(void *key) +{ + u32 key_size = load_varint32(&key); + if (key_size != 8) + tnt_raise(ClientError, :ER_KEY_FIELD_TYPE, "u64"); + struct mh_i64ptr_node_t node = { .key = *(u64 *) key }; + return node; +} + +static inline struct mh_i64ptr_node_t +int64_tuple_to_node(struct tuple *tuple, struct key_def *key_def) +{ + void *field = tuple_field(tuple, key_def->parts[0].fieldno); + struct mh_i64ptr_node_t node = int64_key_to_node(field); + node.val = tuple; + return node; +} + +@implementation Hash64Index +- (void) reserve: (u32) n_tuples +{ + mh_i64ptr_reserve(int64_hash, n_tuples, NULL, NULL); +} + +- (void) free +{ + mh_i64ptr_destroy(int64_hash); + [super free]; +} + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg +{ + self = [super init: key_def_arg :space_arg]; + if (self == NULL) + return NULL; + + int64_hash = mh_i64ptr_init(); + return self; +} + +- (size_t) size +{ + return mh_size(int64_hash); +} + +- (struct tuple *) findByKey: (void *) key :(int) part_count +{ + assert(key_def->is_unique); + check_key_parts(key_def, part_count, false); + + struct tuple *ret = NULL; + struct mh_i64ptr_node_t node = int64_key_to_node(key); + mh_int_t k = mh_i64ptr_get(int64_hash, &node, NULL, NULL); + if (k != mh_end(int64_hash)) + ret = mh_i64ptr_node(int64_hash, k)->val; +#ifdef DEBUG + say_debug("Hash64Index find(self:%p, key:%"PRIu64") = %p", self, node.key, ret); +#endif + return ret; +} + +- (struct tuple *) replace: (struct tuple *) old_tuple + :(struct tuple *) new_tuple + :(enum dup_replace_mode) mode +{ + struct mh_i64ptr_node_t new_node, old_node; + uint32_t errcode; + + if (new_tuple) { + struct mh_i64ptr_node_t *dup_node = &old_node; + new_node = int64_tuple_to_node(new_tuple, key_def); + mh_int_t pos = mh_i64ptr_replace(int64_hash, &new_node, + &dup_node, NULL, NULL); + + ERROR_INJECT(ERRINJ_INDEX_ALLOC, + { + mh_i64ptr_del(int64_hash, pos, NULL, NULL); + pos = mh_end(int64_hash); + }); + if (pos == mh_end(int64_hash)) { + tnt_raise(LoggedError, :ER_MEMORY_ISSUE, (ssize_t) pos, + "int64 hash", "key"); + } + struct tuple *dup_tuple = dup_node ? dup_node->val : NULL; + errcode = replace_check_dup(old_tuple, dup_tuple, mode); + + if (errcode) { + mh_i64ptr_remove(int64_hash, &new_node, NULL, NULL); + if (dup_node) { + pos = mh_i64ptr_replace(int64_hash, dup_node, + NULL, NULL, NULL); + if (pos == mh_end(int64_hash)) { + panic("Failed to allocate memory in " + "recover of int64 hash"); + } + } + tnt_raise(ClientError, :errcode, index_n(self)); + } + if (dup_tuple) + return dup_tuple; + } + if (old_tuple) { + old_node = int64_tuple_to_node(old_tuple, key_def); + mh_i64ptr_remove(int64_hash, &old_node, NULL, NULL); + } + return old_tuple; +} + + +- (struct iterator *) allocIterator +{ + struct hash_i64_iterator *it = malloc(sizeof(struct hash_i64_iterator)); + if (it) { + memset(it, 0, sizeof(*it)); + it->base.next = hash_iterator_i64_ge; + it->base.free = hash_iterator_free; + } + return (struct iterator *) it; +} + + +- (void) initIterator: (struct iterator *) ptr: (enum iterator_type) type + :(void *) key :(int) part_count +{ + (void) part_count; + assert(ptr->free == hash_iterator_free); + struct hash_i64_iterator *it = (struct hash_i64_iterator *) ptr; + struct mh_i64ptr_node_t node; + + switch (type) { + case ITER_GE: + if (key != NULL) { + check_key_parts(key_def, part_count, + traits->allows_partial_key); + node = int64_key_to_node(key); + it->h_pos = mh_i64ptr_get(int64_hash, &node, NULL, NULL); + it->base.next = hash_iterator_i64_ge; + break; + } + /* Fallthrough. */ + case ITER_ALL: + it->base.next = hash_iterator_i64_ge; + it->h_pos = mh_begin(int64_hash); + break; + case ITER_EQ: + check_key_parts(key_def, part_count, + traits->allows_partial_key); + node = int64_key_to_node(key); + it->h_pos = mh_i64ptr_get(int64_hash, &node, NULL, NULL); + it->base.next = hash_iterator_i64_eq; + break; + default: + tnt_raise(ClientError, :ER_UNSUPPORTED, + "Hash index", "requested iterator type"); + } + it->hash = int64_hash; +} +@end + +/* }}} */ + +/* {{{ HashStrIndex ***********************************************/ + +static inline struct mh_lstrptr_node_t +lstrptr_tuple_to_node(struct tuple *tuple, struct key_def *key_def) +{ + void *field = tuple_field(tuple, key_def->parts[0].fieldno); + if (field == NULL) + tnt_raise(ClientError, :ER_NO_SUCH_FIELD, + key_def->parts[0].fieldno); + + struct mh_lstrptr_node_t node = { .key = field, .val = tuple }; + return node; +} + + +@implementation HashStrIndex +- (void) reserve: (u32) n_tuples +{ + mh_lstrptr_reserve(str_hash, n_tuples, NULL, NULL); +} + +- (void) free +{ + mh_lstrptr_destroy(str_hash); + [super free]; +} + +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg +{ + self = [super init: key_def_arg :space_arg]; + if (self == NULL) + return NULL; + + str_hash = mh_lstrptr_init(); + return self; +} + +- (size_t) size +{ + return mh_size(str_hash); +} + +- (struct tuple *) findByKey: (void *) key :(int) part_count +{ + assert(key_def->is_unique); + check_key_parts(key_def, part_count, false); + + struct tuple *ret = NULL; + const struct mh_lstrptr_node_t node = { .key = key }; + mh_int_t k = mh_lstrptr_get(str_hash, &node, NULL, NULL); + if (k != mh_end(str_hash)) + ret = mh_lstrptr_node(str_hash, k)->val; +#ifdef DEBUG + u32 key_size = load_varint32(&key); + say_debug("HashStrIndex find(self:%p, key:(%i)'%.*s') = %p", + self, key_size, key_size, (u8 *)key, ret); +#endif + return ret; +} + +- (struct tuple *) replace: (struct tuple *) old_tuple + :(struct tuple *) new_tuple + :(enum dup_replace_mode) mode +{ + struct mh_lstrptr_node_t new_node, old_node; + uint32_t errcode; + + if (new_tuple) { + struct mh_lstrptr_node_t *dup_node = &old_node; + new_node = lstrptr_tuple_to_node(new_tuple, key_def); + mh_int_t pos = mh_lstrptr_replace(str_hash, &new_node, + &dup_node, NULL, NULL); + + ERROR_INJECT(ERRINJ_INDEX_ALLOC, + { + mh_lstrptr_del(str_hash, pos, NULL, NULL); + pos = mh_end(str_hash); + }); + + if (pos == mh_end(str_hash)) { + tnt_raise(LoggedError, :ER_MEMORY_ISSUE, (ssize_t) pos, + "str hash", "key"); + } + struct tuple *dup_tuple = dup_node ? dup_node->val : NULL; + errcode = replace_check_dup(old_tuple, dup_tuple, mode); + + if (errcode) { + mh_lstrptr_remove(str_hash, &new_node, NULL, NULL); + if (dup_node) { + pos = mh_lstrptr_replace(str_hash, dup_node, + NULL, NULL, NULL); + if (pos == mh_end(str_hash)) { + panic("Failed to allocate memory in " + "recover of str hash"); + } + } + tnt_raise(ClientError, :errcode, index_n(self)); + } + if (dup_tuple) + return dup_tuple; + } + if (old_tuple) { + old_node = lstrptr_tuple_to_node(old_tuple, key_def); + mh_lstrptr_remove(str_hash, &old_node, NULL, NULL); + } + return old_tuple; +} + +- (struct iterator *) allocIterator +{ + struct hash_lstr_iterator *it = malloc(sizeof(struct hash_lstr_iterator)); + if (it) { + memset(it, 0, sizeof(*it)); + it->base.next = hash_iterator_lstr_ge; + it->base.free = hash_iterator_free; + } + return (struct iterator *) it; +} + + +- (void) initIterator: (struct iterator *) ptr + :(enum iterator_type) type + :(void *) key :(int) part_count +{ + (void) part_count; + + assert(ptr->free == hash_iterator_free); + struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) ptr; + struct mh_lstrptr_node_t node; + + switch (type) { + case ITER_GE: + if (key != NULL) { + check_key_parts(key_def, part_count, + traits->allows_partial_key); + node.key = key; + it->h_pos = mh_lstrptr_get(str_hash, &node, NULL, NULL); + it->base.next = hash_iterator_lstr_ge; + break; + } + /* Fall through. */ + case ITER_ALL: + it->base.next = hash_iterator_lstr_ge; + it->h_pos = mh_begin(str_hash); + break; + case ITER_EQ: + check_key_parts(key_def, part_count, + traits->allows_partial_key); + node.key = key; + it->h_pos = mh_lstrptr_get(str_hash, &node, NULL, NULL); + it->base.next = hash_iterator_lstr_eq; + break; + default: + tnt_raise(ClientError, :ER_UNSUPPORTED, + "Hash index", "requested iterator type"); + } + it->hash = str_hash; +} +@end + +/* }}} */ + diff --git a/src/box/index.h b/src/box/index.h index fb81e2e79f..dba734b9d4 100644 --- a/src/box/index.h +++ b/src/box/index.h @@ -29,12 +29,12 @@ * SUCH DAMAGE. */ #import "object.h" + #include <stdbool.h> #include <util.h> struct tuple; struct space; -struct index; /* * Possible field data types. Can't use STRS/ENUM macros for them, @@ -44,7 +44,11 @@ struct index; enum field_data_type { UNKNOWN = -1, NUM = 0, NUM64, STRING, field_data_type_MAX }; extern const char *field_data_type_strs[]; -enum index_type { HASH, TREE, index_type_MAX }; +#define INDEX_TYPE(_) \ + _(HASH, 0) /* HASH Index */ \ + _(TREE, 1) /* TREE Index */ \ + +ENUM(index_type, INDEX_TYPE); extern const char *index_type_strs[]; /** @@ -86,6 +90,11 @@ iterator_type_is_reverse(enum iterator_type type) return type == ITER_REQ || type == ITER_LT || type == ITER_LE; } +struct iterator { + struct tuple *(*next)(struct iterator *); + void (*free)(struct iterator *); +}; + /** Descriptor of a single part in a multipart key. */ struct key_part { int fieldno; @@ -206,14 +215,8 @@ enum dup_replace_mode { - (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type :(void *) key :(int) part_count; - @end -struct iterator { - struct tuple *(*next)(struct iterator *); - void (*free)(struct iterator *); -}; - void check_key_parts(struct key_def *key_def, int part_count, bool partial_key_allowed); diff --git a/src/box/index.m b/src/box/index.m index 8d02ed5238..5ec5480ccd 100644 --- a/src/box/index.m +++ b/src/box/index.m @@ -27,28 +27,23 @@ * SUCH DAMAGE. */ #include "index.h" -#include "tree.h" -#include "say.h" +#include "hash_index.h" +#include "tree_index.h" #include "tuple.h" -#include "pickle.h" +#include "say.h" #include "exception.h" #include "space.h" -#include "assoc.h" -#include "errinj.h" static struct index_traits index_traits = { .allows_partial_key = false, }; -static struct index_traits hash_index_traits = { - .allows_partial_key = false, -}; - const char *field_data_type_strs[] = {"NUM", "NUM64", "STR", "\0"}; -const char *index_type_strs[] = { "HASH", "TREE", "\0" }; - +STRS(index_type, INDEX_TYPE); STRS(iterator_type, ITERATOR_TYPE); +/* {{{ Utilities. **********************************************/ + void check_key_parts(struct key_def *key_def, int part_count, bool partial_key_allowed) @@ -93,36 +88,12 @@ replace_check_dup(struct tuple *old_tuple, return 0; } +/* }}} */ /* {{{ Index -- base class for all indexes. ********************/ -@interface HashIndex: Index -- (void) reserve: (u32) n_tuples; -@end - -@interface HashStrIndex: HashIndex { - struct mh_lstrptr_t *str_hash; -}; -@end - -@interface Hash64Index: HashIndex { - struct mh_i64ptr_t *int64_hash; -}; -@end - -@interface Hash32Index: HashIndex { - struct mh_i32ptr_t *int_hash; -}; -@end - - @implementation Index -@class Hash32Index; -@class Hash64Index; -@class HashStrIndex; -@class TreeIndex; - + (struct index_traits *) traits { return &index_traits; @@ -134,37 +105,25 @@ replace_check_dup(struct tuple *old_tuple, { switch (type) { case HASH: - /* Hash index, check key type. - * Hash index always has a single-field key. - */ - switch (key_def->parts[0].type) { - case NUM: - return [Hash32Index alloc]; /* 32-bit integer hash */ - case NUM64: - return [Hash64Index alloc]; /* 64-bit integer hash */ - case STRING: - return [HashStrIndex alloc]; /* string hash */ - default: - break; - } - break; + return [HashIndex alloc: key_def :space]; case TREE: return [TreeIndex alloc: key_def :space]; default: - break; + assert(false); } - panic("unsupported index type"); } -- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg +- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg; { self = [super init]; - if (self) { - traits = [object_getClass(self) traits]; - key_def = key_def_arg; - space = space_arg; - position = [self allocIterator]; - } + if (self == NULL) + return NULL; + + traits = [object_getClass(self) traits]; + key_def = key_def_arg; + space = space_arg; + position = [self allocIterator]; + return self; } @@ -255,656 +214,3 @@ replace_check_dup(struct tuple *old_tuple, @end /* }}} */ - -/* {{{ HashIndex -- base class for all hashes. ********************/ - -struct hash_i32_iterator { - struct iterator base; /* Must be the first member. */ - struct mh_i32ptr_t *hash; - mh_int_t h_pos; -}; - -struct hash_i64_iterator { - struct iterator base; - struct mh_i64ptr_t *hash; - mh_int_t h_pos; -}; - -struct hash_lstr_iterator { - struct iterator base; - struct mh_lstrptr_t *hash; - mh_int_t h_pos; -}; - -void -hash_iterator_free(struct iterator *iterator) -{ - assert(iterator->free == hash_iterator_free); - free(iterator); -} - -struct tuple * -hash_iterator_i32_ge(struct iterator *ptr) -{ - assert(ptr->free == hash_iterator_free); - struct hash_i32_iterator *it = (struct hash_i32_iterator *) ptr; - - while (it->h_pos < mh_end(it->hash)) { - if (mh_exist(it->hash, it->h_pos)) - return mh_i32ptr_node(it->hash, it->h_pos++)->val; - it->h_pos++; - } - return NULL; -} - -struct tuple * -hash_iterator_i64_ge(struct iterator *ptr) -{ - assert(ptr->free == hash_iterator_free); - struct hash_i64_iterator *it = (struct hash_i64_iterator *) ptr; - - while (it->h_pos < mh_end(it->hash)) { - if (mh_exist(it->hash, it->h_pos)) - return mh_i64ptr_node(it->hash, it->h_pos++)->val; - it->h_pos++; - } - return NULL; -} - -struct tuple * -hash_iterator_lstr_ge(struct iterator *ptr) -{ - assert(ptr->free == hash_iterator_free); - struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) ptr; - - while (it->h_pos < mh_end(it->hash)) { - if (mh_exist(it->hash, it->h_pos)) - return mh_lstrptr_node(it->hash, it->h_pos++)->val; - it->h_pos++; - } - return NULL; -} - -static struct tuple * -hash_iterator_eq_next(struct iterator *it __attribute__((unused))) -{ - return NULL; -} - -static struct tuple * -hash_iterator_i32_eq(struct iterator *it) -{ - it->next = hash_iterator_eq_next; - return hash_iterator_i32_ge(it); -} - -static struct tuple * -hash_iterator_i64_eq(struct iterator *it) -{ - it->next = hash_iterator_eq_next; - return hash_iterator_i64_ge(it); -} - -static struct tuple * -hash_iterator_lstr_eq(struct iterator *it) -{ - it->next = hash_iterator_eq_next; - return hash_iterator_lstr_ge(it); -} - -@implementation HashIndex - -+ (struct index_traits *) traits -{ - return &hash_index_traits; -} - -- (void) reserve: (u32) n_tuples -{ - (void) n_tuples; - [self subclassResponsibility: _cmd]; -} - -- (void) beginBuild -{ -} - -- (void) buildNext: (struct tuple *)tuple -{ - [self replace: NULL :tuple :DUP_INSERT]; -} - -- (void) endBuild -{ -} - -- (void) build: (Index *) pk -{ - u32 n_tuples = [pk size]; - - if (n_tuples == 0) - return; - - [self reserve: n_tuples]; - - say_info("Adding %"PRIu32 " keys to HASH index %" - PRIu32 "...", n_tuples, index_n(self)); - - 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]; -} - -- (void) free -{ - [super free]; -} - -- (struct tuple *) min -{ - tnt_raise(ClientError, :ER_UNSUPPORTED, "Hash index", "min()"); - return NULL; -} - -- (struct tuple *) max -{ - tnt_raise(ClientError, :ER_UNSUPPORTED, "Hash index", "max()"); - return NULL; -} - -@end - -/* }}} */ - -/* {{{ Hash32Index ************************************************/ - -static inline struct mh_i32ptr_node_t -int32_key_to_node(void *key) -{ - u32 key_size = load_varint32(&key); - if (key_size != 4) - tnt_raise(ClientError, :ER_KEY_FIELD_TYPE, "u32"); - struct mh_i32ptr_node_t node = { .key = *(u32 *) key }; - return node; -} - -static inline struct mh_i32ptr_node_t -int32_tuple_to_node(struct tuple *tuple, struct key_def *key_def) -{ - void *field = tuple_field(tuple, key_def->parts[0].fieldno); - struct mh_i32ptr_node_t node = int32_key_to_node(field); - node.val = tuple; - return node; -} - -@implementation Hash32Index - -- (void) reserve: (u32) n_tuples -{ - mh_i32ptr_reserve(int_hash, n_tuples, NULL, NULL); -} - -- (void) free -{ - mh_i32ptr_destroy(int_hash); - [super free]; -} - -- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg -{ - self = [super init: key_def_arg :space_arg]; - if (self) { - int_hash = mh_i32ptr_init(); - } - return self; -} - -- (size_t) size -{ - return mh_size(int_hash); -} - -- (struct tuple *) findByKey: (void *) key :(int) part_count -{ - assert(key_def->is_unique); - check_key_parts(key_def, part_count, false); - - (void) part_count; - - struct tuple *ret = NULL; - struct mh_i32ptr_node_t node = int32_key_to_node(key); - mh_int_t k = mh_i32ptr_get(int_hash, &node, NULL, NULL); - if (k != mh_end(int_hash)) - ret = mh_i32ptr_node(int_hash, k)->val; -#ifdef DEBUG - say_debug("Hash32Index find(self:%p, key:%i) = %p", self, node.key, ret); -#endif - return ret; -} - -- (struct tuple *) replace: (struct tuple *) old_tuple - :(struct tuple *) new_tuple - :(enum dup_replace_mode) mode -{ - struct mh_i32ptr_node_t new_node, old_node; - uint32_t errcode; - - if (new_tuple) { - struct mh_i32ptr_node_t *dup_node = &old_node; - new_node = int32_tuple_to_node(new_tuple, key_def); - mh_int_t pos = mh_i32ptr_replace(int_hash, &new_node, - &dup_node, NULL, NULL); - - ERROR_INJECT(ERRINJ_INDEX_ALLOC, - { - mh_i32ptr_del(int_hash, pos, NULL, NULL); - pos = mh_end(int_hash); - }); - - if (pos == mh_end(int_hash)) { - tnt_raise(LoggedError, :ER_MEMORY_ISSUE, (ssize_t) pos, - "int hash", "key"); - } - struct tuple *dup_tuple = dup_node ? dup_node->val : NULL; - errcode = replace_check_dup(old_tuple, dup_tuple, mode); - - if (errcode) { - mh_i32ptr_remove(int_hash, &new_node, NULL, NULL); - if (dup_node) { - pos = mh_i32ptr_replace(int_hash, dup_node, - NULL, NULL, NULL); - if (pos == mh_end(int_hash)) { - panic("Failed to allocate memory in " - "recover of int hash"); - } - } - tnt_raise(ClientError, :errcode, index_n(self)); - } - if (dup_tuple) - return dup_tuple; - } - if (old_tuple) { - old_node = int32_tuple_to_node(old_tuple, key_def); - mh_i32ptr_remove(int_hash, &old_node, NULL, NULL); - } - return old_tuple; -} - - -- (struct iterator *) allocIterator -{ - struct hash_i32_iterator *it = malloc(sizeof(struct hash_i32_iterator)); - if (it) { - memset(it, 0, sizeof(*it)); - it->base.next = hash_iterator_i32_ge; - it->base.free = hash_iterator_free; - } - return (struct iterator *) it; -} - -- (void) initIterator: (struct iterator *) ptr: (enum iterator_type) type - :(void *) key :(int) part_count -{ - assert(ptr->free == hash_iterator_free); - struct hash_i32_iterator *it = (struct hash_i32_iterator *) ptr; - struct mh_i32ptr_node_t node; - - switch (type) { - case ITER_GE: - if (key != NULL) { - check_key_parts(key_def, part_count, - traits->allows_partial_key); - node = int32_key_to_node(key); - it->h_pos = mh_i32ptr_get(int_hash, &node, NULL, NULL); - it->base.next = hash_iterator_i32_ge; - break; - } - /* Fall through. */ - case ITER_ALL: - it->h_pos = mh_begin(int_hash); - it->base.next = hash_iterator_i32_ge; - break; - case ITER_EQ: - check_key_parts(key_def, part_count, - traits->allows_partial_key); - node = int32_key_to_node(key); - it->h_pos = mh_i32ptr_get(int_hash, &node, NULL, NULL); - it->base.next = hash_iterator_i32_eq; - break; - default: - tnt_raise(ClientError, :ER_UNSUPPORTED, - "Hash index", "requested iterator type"); - } - it->hash = int_hash; -} -@end - -/* }}} */ - -/* {{{ Hash64Index ************************************************/ - -static inline struct mh_i64ptr_node_t -int64_key_to_node(void *key) -{ - u32 key_size = load_varint32(&key); - if (key_size != 8) - tnt_raise(ClientError, :ER_KEY_FIELD_TYPE, "u64"); - struct mh_i64ptr_node_t node = { .key = *(u64 *) key }; - return node; -} - -static inline struct mh_i64ptr_node_t -int64_tuple_to_node(struct tuple *tuple, struct key_def *key_def) -{ - void *field = tuple_field(tuple, key_def->parts[0].fieldno); - struct mh_i64ptr_node_t node = int64_key_to_node(field); - node.val = tuple; - return node; -} - -@implementation Hash64Index -- (void) reserve: (u32) n_tuples -{ - mh_i64ptr_reserve(int64_hash, n_tuples, NULL, NULL); -} - -- (void) free -{ - mh_i64ptr_destroy(int64_hash); - [super free]; -} - -- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg -{ - self = [super init: key_def_arg :space_arg]; - if (self) { - int64_hash = mh_i64ptr_init(); - } - return self; -} - -- (size_t) size -{ - return mh_size(int64_hash); -} - -- (struct tuple *) findByKey: (void *) key :(int) part_count -{ - assert(key_def->is_unique); - check_key_parts(key_def, part_count, false); - - struct tuple *ret = NULL; - struct mh_i64ptr_node_t node = int64_key_to_node(key); - mh_int_t k = mh_i64ptr_get(int64_hash, &node, NULL, NULL); - if (k != mh_end(int64_hash)) - ret = mh_i64ptr_node(int64_hash, k)->val; -#ifdef DEBUG - say_debug("Hash64Index find(self:%p, key:%"PRIu64") = %p", self, node.key, ret); -#endif - return ret; -} - -- (struct tuple *) replace: (struct tuple *) old_tuple - :(struct tuple *) new_tuple - :(enum dup_replace_mode) mode -{ - struct mh_i64ptr_node_t new_node, old_node; - uint32_t errcode; - - if (new_tuple) { - struct mh_i64ptr_node_t *dup_node = &old_node; - new_node = int64_tuple_to_node(new_tuple, key_def); - mh_int_t pos = mh_i64ptr_replace(int64_hash, &new_node, - &dup_node, NULL, NULL); - - ERROR_INJECT(ERRINJ_INDEX_ALLOC, - { - mh_i64ptr_del(int64_hash, pos, NULL, NULL); - pos = mh_end(int64_hash); - }); - if (pos == mh_end(int64_hash)) { - tnt_raise(LoggedError, :ER_MEMORY_ISSUE, (ssize_t) pos, - "int64 hash", "key"); - } - struct tuple *dup_tuple = dup_node ? dup_node->val : NULL; - errcode = replace_check_dup(old_tuple, dup_tuple, mode); - - if (errcode) { - mh_i64ptr_remove(int64_hash, &new_node, NULL, NULL); - if (dup_node) { - pos = mh_i64ptr_replace(int64_hash, dup_node, - NULL, NULL, NULL); - if (pos == mh_end(int64_hash)) { - panic("Failed to allocate memory in " - "recover of int64 hash"); - } - } - tnt_raise(ClientError, :errcode, index_n(self)); - } - if (dup_tuple) - return dup_tuple; - } - if (old_tuple) { - old_node = int64_tuple_to_node(old_tuple, key_def); - mh_i64ptr_remove(int64_hash, &old_node, NULL, NULL); - } - return old_tuple; -} - - -- (struct iterator *) allocIterator -{ - struct hash_i64_iterator *it = malloc(sizeof(struct hash_i64_iterator)); - if (it) { - memset(it, 0, sizeof(*it)); - it->base.next = hash_iterator_i64_ge; - it->base.free = hash_iterator_free; - } - return (struct iterator *) it; -} - - -- (void) initIterator: (struct iterator *) ptr: (enum iterator_type) type - :(void *) key :(int) part_count -{ - (void) part_count; - assert(ptr->free == hash_iterator_free); - struct hash_i64_iterator *it = (struct hash_i64_iterator *) ptr; - struct mh_i64ptr_node_t node; - - switch (type) { - case ITER_GE: - if (key != NULL) { - check_key_parts(key_def, part_count, - traits->allows_partial_key); - node = int64_key_to_node(key); - it->h_pos = mh_i64ptr_get(int64_hash, &node, NULL, NULL); - it->base.next = hash_iterator_i64_ge; - break; - } - /* Fallthrough. */ - case ITER_ALL: - it->base.next = hash_iterator_i64_ge; - it->h_pos = mh_begin(int64_hash); - break; - case ITER_EQ: - check_key_parts(key_def, part_count, - traits->allows_partial_key); - node = int64_key_to_node(key); - it->h_pos = mh_i64ptr_get(int64_hash, &node, NULL, NULL); - it->base.next = hash_iterator_i64_eq; - break; - default: - tnt_raise(ClientError, :ER_UNSUPPORTED, - "Hash index", "requested iterator type"); - } - it->hash = int64_hash; -} -@end - -/* }}} */ - -/* {{{ HashStrIndex ***********************************************/ - -static inline struct mh_lstrptr_node_t -lstrptr_tuple_to_node(struct tuple *tuple, struct key_def *key_def) -{ - void *field = tuple_field(tuple, key_def->parts[0].fieldno); - if (field == NULL) - tnt_raise(ClientError, :ER_NO_SUCH_FIELD, - key_def->parts[0].fieldno); - - struct mh_lstrptr_node_t node = { .key = field, .val = tuple }; - return node; -} - - -@implementation HashStrIndex -- (void) reserve: (u32) n_tuples -{ - mh_lstrptr_reserve(str_hash, n_tuples, NULL, NULL); -} - -- (void) free -{ - mh_lstrptr_destroy(str_hash); - [super free]; -} - -- (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg -{ - self = [super init: key_def_arg :space_arg]; - if (self) { - str_hash = mh_lstrptr_init(); - } - return self; -} - -- (size_t) size -{ - return mh_size(str_hash); -} - -- (struct tuple *) findByKey: (void *) key :(int) part_count -{ - assert(key_def->is_unique); - check_key_parts(key_def, part_count, false); - - struct tuple *ret = NULL; - const struct mh_lstrptr_node_t node = { .key = key }; - mh_int_t k = mh_lstrptr_get(str_hash, &node, NULL, NULL); - if (k != mh_end(str_hash)) - ret = mh_lstrptr_node(str_hash, k)->val; -#ifdef DEBUG - u32 key_size = load_varint32(&key); - say_debug("HashStrIndex find(self:%p, key:(%i)'%.*s') = %p", - self, key_size, key_size, (u8 *)key, ret); -#endif - return ret; -} - -- (struct tuple *) replace: (struct tuple *) old_tuple - :(struct tuple *) new_tuple - :(enum dup_replace_mode) mode -{ - struct mh_lstrptr_node_t new_node, old_node; - uint32_t errcode; - - if (new_tuple) { - struct mh_lstrptr_node_t *dup_node = &old_node; - new_node = lstrptr_tuple_to_node(new_tuple, key_def); - mh_int_t pos = mh_lstrptr_replace(str_hash, &new_node, - &dup_node, NULL, NULL); - - ERROR_INJECT(ERRINJ_INDEX_ALLOC, - { - mh_lstrptr_del(str_hash, pos, NULL, NULL); - pos = mh_end(str_hash); - }); - - if (pos == mh_end(str_hash)) { - tnt_raise(LoggedError, :ER_MEMORY_ISSUE, (ssize_t) pos, - "str hash", "key"); - } - struct tuple *dup_tuple = dup_node ? dup_node->val : NULL; - errcode = replace_check_dup(old_tuple, dup_tuple, mode); - - if (errcode) { - mh_lstrptr_remove(str_hash, &new_node, NULL, NULL); - if (dup_node) { - pos = mh_lstrptr_replace(str_hash, dup_node, - NULL, NULL, NULL); - if (pos == mh_end(str_hash)) { - panic("Failed to allocate memory in " - "recover of str hash"); - } - } - tnt_raise(ClientError, :errcode, index_n(self)); - } - if (dup_tuple) - return dup_tuple; - } - if (old_tuple) { - old_node = lstrptr_tuple_to_node(old_tuple, key_def); - mh_lstrptr_remove(str_hash, &old_node, NULL, NULL); - } - return old_tuple; -} - -- (struct iterator *) allocIterator -{ - struct hash_lstr_iterator *it = malloc(sizeof(struct hash_lstr_iterator)); - if (it) { - memset(it, 0, sizeof(*it)); - it->base.next = hash_iterator_lstr_ge; - it->base.free = hash_iterator_free; - } - return (struct iterator *) it; -} - - -- (void) initIterator: (struct iterator *) ptr - :(enum iterator_type) type - :(void *) key :(int) part_count -{ - (void) part_count; - - assert(ptr->free == hash_iterator_free); - struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) ptr; - struct mh_lstrptr_node_t node; - - switch (type) { - case ITER_GE: - if (key != NULL) { - check_key_parts(key_def, part_count, - traits->allows_partial_key); - node.key = key; - it->h_pos = mh_lstrptr_get(str_hash, &node, NULL, NULL); - it->base.next = hash_iterator_lstr_ge; - break; - } - /* Fall through. */ - case ITER_ALL: - it->base.next = hash_iterator_lstr_ge; - it->h_pos = mh_begin(str_hash); - break; - case ITER_EQ: - check_key_parts(key_def, part_count, - traits->allows_partial_key); - node.key = key; - it->h_pos = mh_lstrptr_get(str_hash, &node, NULL, NULL); - it->base.next = hash_iterator_lstr_eq; - break; - default: - tnt_raise(ClientError, :ER_UNSUPPORTED, - "Hash index", "requested iterator type"); - } - it->hash = str_hash; -} -@end - -/* }}} */ - diff --git a/src/box/space.m b/src/box/space.m index 523f7ae05e..a202fd2127 100644 --- a/src/box/space.m +++ b/src/box/space.m @@ -216,11 +216,9 @@ key_init(struct key_def *def, struct tarantool_cfg_space_index *cfg_index) { def->max_fieldno = 0; def->part_count = 0; - if (strcmp(cfg_index->type, "HASH") == 0) - def->type = HASH; - else if (strcmp(cfg_index->type, "TREE") == 0) - def->type = TREE; - else + + def->type = STR2ENUM(index_type, cfg_index->type); + if (def->type == index_type_MAX) panic("Wrong index type: %s", cfg_index->type); /* Calculate key part count and maximal field number. */ @@ -370,8 +368,9 @@ space_config() typeof(cfg_space->index[j]) cfg_index = cfg_space->index[j]; enum index_type type = STR2ENUM(index_type, cfg_index->type); struct key_def *key_def = &space->key_defs[j]; - Index *index = [Index alloc: type :key_def :space]; - [index init: key_def :space]; + Index *index = [[Index alloc :type :key_def :space] + init :key_def :space]; + assert (index != NULL); space->index[j] = index; } diff --git a/src/box/tree.h b/src/box/tree_index.h similarity index 92% rename from src/box/tree.h rename to src/box/tree_index.h index 6cacb96a19..d1ff337d80 100644 --- a/src/box/tree.h +++ b/src/box/tree_index.h @@ -1,5 +1,5 @@ -#ifndef TARANTOOL_BOX_TREE_H_INCLUDED -#define TARANTOOL_BOX_TREE_H_INCLUDED +#ifndef TARANTOOL_BOX_TREE_INDEX_H_INCLUDED +#define TARANTOOL_BOX_TREE_INDEX_H_INCLUDED /* * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -46,11 +46,8 @@ typedef int (*tree_cmp_t)(const void *, const void *, void *); }; + (struct index_traits *) traits; - + (Index *) alloc: (struct key_def *) key_def :(struct space *) space; -- (void) buildNext: (struct tuple *) tuple; - /** To be defined in subclasses. */ - (size_t) node_size; - (tree_cmp_t) node_cmp; @@ -61,4 +58,4 @@ typedef int (*tree_cmp_t)(const void *, const void *, void *); @end -#endif /* TARANTOOL_BOX_TREE_H_INCLUDED */ +#endif /* TARANTOOL_BOX_TREE_INDEX_H_INCLUDED */ diff --git a/src/box/tree.m b/src/box/tree_index.m similarity index 98% rename from src/box/tree.m rename to src/box/tree_index.m index b437e987f1..c105723c49 100644 --- a/src/box/tree.m +++ b/src/box/tree_index.m @@ -26,7 +26,7 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include "tree.h" +#include "tree_index.h" #include "tuple.h" #include "space.h" #include "exception.h" @@ -738,7 +738,7 @@ linear_key_node_compare(struct key_def *key_def, /* }}} */ -/* {{{ Tree iterator **********************************************/ +/* {{{ TreeIndex Iterators ****************************************/ struct tree_iterator { struct iterator base; @@ -889,8 +889,9 @@ tree_iterator_gt(struct iterator *iterator) return [Num32TreeIndex alloc]; case TREE_FIXED: return [FixedTreeIndex alloc]; + default: + assert(false); } - panic("tree index type not implemented"); } - (void) free @@ -902,9 +903,10 @@ tree_iterator_gt(struct iterator *iterator) - (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg { self = [super init: key_def_arg :space_arg]; - if (self) { - memset(&tree, 0, sizeof tree); - } + if (self == NULL) + return NULL; + + memset(&tree, 0, sizeof tree); return self; } @@ -1328,9 +1330,10 @@ linear_dense_key_node_cmp(const void *key, const void * node, void *arg) - (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg { self = [super init: key_def_arg :space_arg]; - if (self) { - first_field = find_first_field(key_def); - } + if (self == NULL) + return NULL; + + first_field = find_first_field(key_def); return self; } @@ -1525,10 +1528,11 @@ linear_fixed_key_node_cmp(const void *key, const void * node, void *arg) - (id) init: (struct key_def *) key_def_arg :(struct space *) space_arg { self = [super init: key_def_arg :space_arg]; - if (self) { - first_field = find_first_field(key_def); - first_offset = find_fixed_offset(space, first_field, 0); - } + if (self == NULL) + return NULL; + + first_field = find_first_field(key_def); + first_offset = find_fixed_offset(space, first_field, 0); return self; } -- GitLab