diff --git a/include/mhash.h b/include/mhash.h index c277095b8c7d5988d5c822eab36001e5cbfa8b6b..172d94f3cbd58b3faeeeaaea70b0c90975801d00 100644 --- a/include/mhash.h +++ b/include/mhash.h @@ -118,12 +118,14 @@ struct _mh(t) { #define mh_begin(h) ({ 0; }) #define mh_end(h) ({ (h)->n_buckets; }) +#define MH_DENSITY 0.7 struct _mh(t) * _mh(init)(); void _mh(clear)(struct _mh(t) *h); void _mh(destroy)(struct _mh(t) *h); void _mh(resize)(struct _mh(t) *h); mh_int_t _mh(start_resize)(struct _mh(t) *h, mh_int_t buckets, mh_int_t batch); +void _mh(reserve)(struct _mh(t) *h, mh_int_t size); void __attribute__((noinline)) _mh(put_resize)(struct _mh(t) *h, mh_key_t key, mh_val_t val); void __attribute__((noinline)) _mh(del_resize)(struct _mh(t) *h, mh_int_t x); void _mh(dump)(struct _mh(t) *h); @@ -280,7 +282,7 @@ _mh(init)() h->n_buckets = __ac_prime_list[h->prime]; h->p = calloc(h->n_buckets, sizeof(struct _mh(pair))); h->b = calloc(h->n_buckets / 16 + 1, sizeof(unsigned)); - h->upper_bound = h->n_buckets * 0.7; + h->upper_bound = h->n_buckets * MH_DENSITY; return h; } @@ -291,7 +293,7 @@ _mh(clear)(struct _mh(t) *h) h->prime = 0; h->n_buckets = __ac_prime_list[h->prime]; h->p = calloc(h->n_buckets, sizeof(struct _mh(pair))); - h->upper_bound = h->n_buckets * 0.7; + h->upper_bound = h->n_buckets * MH_DENSITY; } void @@ -352,7 +354,8 @@ _mh(start_resize)(struct _mh(t) *h, mh_int_t buckets, mh_int_t batch) if (h->batch < 256) { /* * Minimal batch must be greater or equal to - * 1 / (1 - f), where f is upper bound percent = 0.7 + * 1 / (1 - f), where f is upper bound percent + * = MH_DENSITY */ h->batch = 256; } @@ -361,7 +364,7 @@ _mh(start_resize)(struct _mh(t) *h, mh_int_t buckets, mh_int_t batch) memcpy(s, h, sizeof(*h)); s->resize_position = 0; s->n_buckets = __ac_prime_list[h->prime]; - s->upper_bound = s->n_buckets * 0.7; + s->upper_bound = s->n_buckets * MH_DENSITY; s->n_dirty = 0; s->p = malloc(s->n_buckets * sizeof(struct _mh(pair))); s->b = calloc(s->n_buckets / 16 + 1, sizeof(unsigned)); @@ -370,6 +373,12 @@ _mh(start_resize)(struct _mh(t) *h, mh_int_t buckets, mh_int_t batch) return h->n_buckets; } +void +_mh(reserve)(struct _mh(t) *h, mh_int_t size) +{ + _mh(start_resize)(h, size/MH_DENSITY, h->size); +} + #ifndef mh_stat #define mh_stat(buf, h) ({ \ tbuf_printf(buf, " n_buckets: %"PRIu32 CRLF \ @@ -425,6 +434,7 @@ _mh(dump)(struct _mh(t) *h) #undef mh_unlikely #undef slot #undef slot_and_dirty +#undef MH_DENSITY #endif #undef mh_cat diff --git a/mod/box/box.m b/mod/box/box.m index 9150e9f26ec0fa29859ed0b0b962b027a37f63b6..3673757696828525e08a594b8fba1f6c8a50b42e 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -47,7 +47,6 @@ #include <mod/box/tuple.h> #include "memcached.h" #include "box_lua.h" -#include "tree.h" static void box_process_ro(u32 op, struct tbuf *request_data); static void box_process_rw(u32 op, struct tbuf *request_data); @@ -1534,9 +1533,7 @@ build_indexes(void) Index *pk = space[n].index[0]; for (int i = 1; i < space[n].key_count; i++) { Index *index = space[n].index[i]; - if ([index isKindOf: [TreeIndex class]]) { - [(TreeIndex *) index build: pk]; - } + [index build: pk]; } say_info("Space %"PRIu32": done", n); diff --git a/mod/box/index.h b/mod/box/index.h index caf0eb95caf1e0af42ae7f06670501fcd992951b..e3cb401c391dc15f4ece1ac8191093825c5537c3 100644 --- a/mod/box/index.h +++ b/mod/box/index.h @@ -111,6 +111,7 @@ struct key_def { * Finish index construction. */ - (void) enable; +- (void) build: (Index *) pk; - (size_t) size; - (struct box_tuple *) min; - (struct box_tuple *) max; diff --git a/mod/box/index.m b/mod/box/index.m index 5b3883c6dc180af6efdc3bf002be92005718cd8f..c1bab7ea15ebdc99a6f6c698deff5b37fb792cb3 100644 --- a/mod/box/index.m +++ b/mod/box/index.m @@ -107,6 +107,13 @@ iterator_first_equal(struct iterator *it) [self subclassResponsibility: _cmd]; } +- (void) build: (Index *) pk +{ + (void) pk; + [self subclassResponsibility: _cmd]; +} + + - (size_t) size { [self subclassResponsibility: _cmd]; @@ -180,6 +187,7 @@ iterator_first_equal(struct iterator *it) /* {{{ HashIndex -- base class for all hashes. ********************/ @interface HashIndex: Index + - (void) reserve: (u32) n_tuples; @end struct hash_iterator { @@ -218,6 +226,33 @@ hash_iterator_free(struct iterator *iterator) @implementation HashIndex + +- (void) reserve: (u32) n_tuples +{ + (void) n_tuples; + [self subclassResponsibility: _cmd]; +} + +- (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 box_tuple *tuple; + [pk initIterator: it]; + + while ((tuple = it->next(it))) + [self replace: NULL :tuple]; +} + - (void) free { [super free]; @@ -267,6 +302,12 @@ hash_iterator_free(struct iterator *iterator) @end @implementation Hash32Index + +- (void) reserve: (u32) n_tuples +{ + mh_i32ptr_reserve(int_hash, n_tuples); +} + - (void) free { mh_i32ptr_destroy(int_hash); @@ -388,6 +429,11 @@ hash_iterator_free(struct iterator *iterator) @end @implementation Hash64Index +- (void) reserve: (u32) n_tuples +{ + mh_i64ptr_reserve(int64_hash, n_tuples); +} + - (void) free { mh_i64ptr_destroy(int64_hash); @@ -509,6 +555,11 @@ hash_iterator_free(struct iterator *iterator) @end @implementation HashStrIndex +- (void) reserve: (u32) n_tuples +{ + mh_lstrptr_reserve(str_hash, n_tuples); +} + - (void) free { mh_lstrptr_destroy(str_hash); diff --git a/mod/box/tree.h b/mod/box/tree.h index e51f167861a65f60c6d7211344abc94860874b01..19b58b28b751ce5a1fdf76cac8322a4adda16536 100644 --- a/mod/box/tree.h +++ b/mod/box/tree.h @@ -42,7 +42,6 @@ typedef int (*tree_cmp_t)(const void *, const void *, void *); }; + (Index *) alloc: (struct key_def *) key_def :(struct space *) space; -- (void) build: (Index *) pk; /** To be defined in subclasses. */ - (size_t) node_size; diff --git a/test/box_big/sql.result b/test/box_big/sql.result index ec1fe56abd7336439544614b3e1323eae47d9d43..e9e87ba6fa021b5774a2ca24ac741c564083f5b8 100644 --- a/test/box_big/sql.result +++ b/test/box_big/sql.result @@ -169,6 +169,32 @@ call box.select('5', '1', 'part1', 'part2') Found 2 tuples: ['01234567', 'part1', 'part2'] ['11234567', 'part1', 'part2'] +insert into t7 values (1, 'hello') +Insert OK, 1 row affected +insert into t7 values (2, 'brave') +Insert OK, 1 row affected +insert into t7 values (3, 'new') +Insert OK, 1 row affected +insert into t7 values (4, 'world') +Insert OK, 1 row affected +# +# Bug#929654 - secondary hash index is not built with build_indexes() +# +select * from t7 where k1='hello' +Found 1 tuple: +[1, 'hello'] +select * from t7 where k1='brave' +Found 1 tuple: +[2, 'brave'] +select * from t7 where k1='new' +Found 1 tuple: +[3, 'new'] +select * from t7 where k1='world' +Found 1 tuple: +[4, 'world'] +lua box.space[7]:truncate() +--- +... select * from t1 where k0='key1' Found 1 tuple: [830039403, 'part1', 'part2'] diff --git a/test/box_big/sql.test b/test/box_big/sql.test index 602ca6b3f92e6ed815527f8f4f426d02df00b78b..65c21b649e46853b496fbf3dfbb55f8f974c15cf 100644 --- a/test/box_big/sql.test +++ b/test/box_big/sql.test @@ -86,9 +86,21 @@ exec sql "select * from t5 where k1='part1_a'" exec sql "select * from t5 where k1='part_none'" exec sql "call box.select('5', '1', 'part1', 'part2')" sql.sort = False +exec sql "insert into t7 values (1, 'hello')" +exec sql "insert into t7 values (2, 'brave')" +exec sql "insert into t7 values (3, 'new')" +exec sql "insert into t7 values (4, 'world')" # Check how build_idnexes() works server.stop() server.start() +print """# +# Bug#929654 - secondary hash index is not built with build_indexes() +#""" +exec sql "select * from t7 where k1='hello'" +exec sql "select * from t7 where k1='brave'" +exec sql "select * from t7 where k1='new'" +exec sql "select * from t7 where k1='world'" +exec admin "lua box.space[7]:truncate()" exec sql "select * from t1 where k0='key1'" exec sql "select * from t1 where k0='key2'" exec sql "select * from t1 where k0='key3'" diff --git a/test/box_big/tarantool.cfg b/test/box_big/tarantool.cfg index f298f2bdd0d0ffd5f7f010bab50d0673d5709171..6a3d5fea29b623db875bf3dcaeca265310cbec5b 100644 --- a/test/box_big/tarantool.cfg +++ b/test/box_big/tarantool.cfg @@ -124,3 +124,15 @@ space[6].index[6].key_field[3].type = "STR" space[6].index[6].key_field[4].fieldno = 8 space[6].index[6].key_field[4].type = "NUM" +# Space #7, https://bugs.launchpad.net/tarantool/+bug/929654 +space[7].enabled = true + +space[7].index[0].type = "HASH" +space[7].index[0].unique = true +space[7].index[0].key_field[0].fieldno = 0 +space[7].index[0].key_field[0].type = "NUM" + +space[7].index[1].type = "HASH" +space[7].index[1].unique = true +space[7].index[1].key_field[0].fieldno = 1 +space[7].index[1].key_field[0].type = "STR"