Skip to content
Snippets Groups Projects
Commit 7e0f5a11 authored by Konstantin Osipov's avatar Konstantin Osipov
Browse files

box patch

parent b7f07084
No related branches found
No related tags found
No related merge requests found
......@@ -117,6 +117,42 @@ tuple_txn_ref(struct box_txn *txn, struct box_tuple *tuple)
tuple_ref(tuple, +1);
}
void
validate_indexes(struct box_txn *txn)
{
if (space[txn->n].index[1] == nil)
return;
/* There is more than one index. */
foreach_index(txn->n, index) {
/* XXX: skip the first index here! */
for (u32 f = 0; f < index->key.part_count; ++f) {
if (index->key.parts[f].fieldno >= txn->tuple->cardinality)
tnt_raise(IllegalParams, :"tuple must have all indexed fields");
if (index->key.parts[f].type == STRING)
continue;
void *field = tuple_field(txn->tuple, index->key.parts[f].fieldno);
u32 len = load_varint32(&field);
if (index->key.parts[f].type == NUM && len != sizeof(u32))
tnt_raise(IllegalParams, :"field must be NUM");
if (index->key.parts[f].type == NUM64 && len != sizeof(u64))
tnt_raise(IllegalParams, :"field must be NUM64");
}
if (index->type == TREE && index->unique == false)
/* Don't check non unique indexes */
continue;
struct box_tuple *tuple = [index findBy: txn->tuple];
if (tuple != NULL && tuple != txn->old_tuple)
tnt_raise(ClientError, :ER_INDEX_VIOLATION);
}
}
static void __attribute__((noinline))
prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data)
{
......@@ -132,7 +168,7 @@ prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data)
txn->tuple->cardinality = cardinality;
memcpy(txn->tuple->data, data->data, data->size);
txn->old_tuple = txn->index->find_by_tuple(txn->index, txn->tuple);
txn->old_tuple = [txn->index findBy: txn->tuple];
if (txn->old_tuple != NULL)
tuple_txn_ref(txn, txn->old_tuple);
......@@ -175,7 +211,7 @@ prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data)
* txn_commit().
*/
foreach_index(txn->n, index)
index->replace(index, NULL, txn->tuple);
[index replace: NULL :txn->tuple];
}
txn->out->dup_u32(1); /* Affected tuples */
......@@ -189,7 +225,7 @@ commit_replace(struct box_txn *txn)
{
if (txn->old_tuple != NULL) {
foreach_index(txn->n, index)
index->replace(index, txn->old_tuple, txn->tuple);
[index replace: txn->old_tuple :txn->tuple];
tuple_ref(txn->old_tuple, -1);
}
......@@ -207,7 +243,7 @@ rollback_replace(struct box_txn *txn)
if (txn->tuple && txn->tuple->flags & GHOST) {
foreach_index(txn->n, index)
index->remove(index, txn->tuple);
[index remove: txn->tuple];
}
}
......@@ -341,7 +377,7 @@ prepare_update(struct box_txn *txn, struct tbuf *data)
if (key == NULL)
tnt_raise(IllegalParams, :"invalid key");
txn->old_tuple = txn->index->find(txn->index, key);
txn->old_tuple = [txn->index find: key];
if (txn->old_tuple == NULL) {
txn->flags |= BOX_NOT_STORE;
......@@ -468,9 +504,10 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
for (int i = 1; i < key_cardinality; i++)
read_field(data);
index->iterator_init(index, key_cardinality, key);
struct iterator *it = index->position;
[index initIterator: it :key :key_cardinality];
while ((tuple = index->iterator.next_equal(index)) != NULL) {
while ((tuple = it->next_equal(it)) != NULL) {
if (tuple->flags & GHOST)
continue;
......@@ -494,7 +531,7 @@ prepare_delete(struct box_txn *txn, void *key)
{
u32 tuples_affected = 0;
txn->old_tuple = txn->index->find(txn->index, key);
txn->old_tuple = [txn->index find: key];
if (txn->old_tuple == NULL)
/*
......@@ -523,7 +560,7 @@ commit_delete(struct box_txn *txn)
return;
foreach_index(txn->n, index)
index->remove(index, txn->old_tuple);
[index remove: txn->old_tuple];
tuple_ref(txn->old_tuple, -1);
}
......@@ -892,7 +929,7 @@ space_free(void)
int j;
for (j = 0 ; j < BOX_INDEX_MAX ; j++) {
Index *index = space[i].index[j];
if (index == 0)
if (index == nil)
break;
[index free];
}
......@@ -972,14 +1009,11 @@ space_config(void)
/* fill space indexes */
for (int j = 0; cfg_space->index[j] != NULL; ++j) {
typeof(cfg_space->index[j]) cfg_index = cfg_space->index[j];
Index *index = [[Index alloc] init];
struct key key;
key_config(&key, cfg_index);
index->key = key;
index->unique = cfg_index->unique;
index->type = STR2ENUM(index_type, cfg_index->type);
index->n = j;
[index init: &space[i]];
enum index_type type = STR2ENUM(index_type, cfg_index->type);
Index *index = [Index alloc: type :&key];
[index init: &key :&space[i]];
space[i].index[j] = index;
}
......@@ -1497,8 +1531,9 @@ mod_snapshot(struct log_io_iter *i)
Index *pk = space[n].index[0];
pk->iterator_init(pk, 0, NULL);
while ((tuple = pk->iterator.next(pk))) {
struct iterator *it = pk->position;
[pk initIterator: it];
while ((tuple = it->next(it))) {
snapshot_write_tuple(i, n, tuple);
}
}
......
......@@ -272,7 +272,7 @@ static int
lbox_index_len(struct lua_State *L)
{
Index *index = lua_checkindex(L, 1);
lua_pushinteger(L, index->size(index));
lua_pushinteger(L, [index size]);
return 1;
}
......@@ -280,7 +280,7 @@ static int
lbox_index_min(struct lua_State *L)
{
Index *index = lua_checkindex(L, 1);
lbox_pushtuple(L, index->min(index));
lbox_pushtuple(L, [index min]);
return 1;
}
......@@ -288,7 +288,7 @@ static int
lbox_index_max(struct lua_State *L)
{
Index *index = lua_checkindex(L, 1);
lbox_pushtuple(L, index->max(index));
lbox_pushtuple(L, [index max]);
return 1;
}
......@@ -368,7 +368,7 @@ lbox_index_next(struct lua_State *L)
* If there is nothing or nil on top of the stack,
* start iteration from the beginning.
*/
index->iterator_init(index, 0, NULL);
[index initIterator: index->position];
} else if (argc > 1 || !lua_islightuserdata(L, 2)) {
/*
* We've got something different from iterator's
......@@ -403,11 +403,11 @@ lbox_index_next(struct lua_State *L)
luaL_error(L, "index.next(): key part count (%d) "
"does not match index cardinality (%d)",
cardinality, index->key.part_count);
index->iterator_init(index, cardinality, key);
[index initIterator: index->position :key :cardinality];
}
struct box_tuple *tuple = index->iterator.next(index);
struct box_tuple *tuple = index->position->next(index->position);
if (tuple)
lua_pushlightuserdata(L, &index->iterator);
lua_pushlightuserdata(L, index->position);
/* If tuple is NULL, pushes nil as end indicator. */
lbox_pushtuple(L, tuple);
return tuple ? 2 : 1;
......
......@@ -26,29 +26,12 @@
* SUCH DAMAGE.
*/
#import <objc/Object.h>
#include <assoc.h>
#include <stdbool.h>
#include <util.h>
/**
* A field reference used for TREE indexes. Either stores a copy
* of the corresponding field in the tuple or points to that field
* in the tuple (depending on field length).
*/
struct field {
/** Field data length. */
u32 len;
/** Actual field data. For small fields we store the value
* of the field (u32, u64, strings up to 8 bytes), for
* longer fields, we store a pointer to field data in the
* tuple in the primary index.
*/
union {
u32 u32;
u64 u64;
u8 data[sizeof(u64)];
void *data_ptr;
};
};
struct box_tuple;
struct space;
struct index;
/*
* Possible field data types. Can't use STRS/ENUM macros for them,
......@@ -61,29 +44,13 @@ extern const char *field_data_type_strs[];
enum index_type { HASH, TREE, index_type_MAX };
extern const char *index_type_strs[];
struct index_tree_el {
struct box_tuple *tuple;
struct field key[];
};
#define INDEX_TREE_EL_SIZE(index) \
(sizeof(struct index_tree_el) + sizeof(struct field) * (index)->key.part_count)
#include <third_party/sptree.h>
SPTREE_DEF(str_t, realloc);
/* Indexes at preallocated search positions. */
enum { POS_READ = 0, POS_WRITE = 1, POS_MAX = 2 };
/** Descriptor of a single part in a multipart key. */
struct key_part {
u32 fieldno;
enum field_data_type type;
};
/* Descriptor of a multipart key. */
struct key {
/* Description of parts of a multipart index. */
struct key_part *parts;
......@@ -113,32 +80,6 @@ struct key {
bool enabled;
bool unique;
size_t (*size)(Index *index);
struct box_tuple *(*find)(Index *index, void *key); /* only for unique lookups */
struct box_tuple *(*min)(Index *index);
struct box_tuple *(*max)(Index *index);
struct box_tuple *(*find_by_tuple)(Index * index, struct box_tuple * pattern);
void (*remove)(Index *index, struct box_tuple *);
void (*replace)(Index *index, struct box_tuple *, struct box_tuple *);
void (*iterator_init)(Index *, int cardinality, void *key);
union {
struct mh_lstrptr_t *str_hash;
struct mh_i32ptr_t *int_hash;
struct mh_i64ptr_t *int64_hash;
struct mh_i32ptr_t *hash;
sptree_str_t *tree;
} idx;
struct iterator {
union {
struct sptree_str_t_iterator *t_iter;
mh_int_t h_iter;
};
struct box_tuple *(*next)(Index *);
struct box_tuple *(*next_equal)(Index *);
} iterator;
/* Reusable iteration positions, to save on memory allocation. */
struct index_tree_el *position[POS_MAX];
struct space *space;
/* Description of a possibly multipart key. */
......@@ -148,28 +89,56 @@ struct key {
u32 n;
enum index_type type;
/*
* Pre-allocated iterator to speed up the main case of
* box_process(). Should not be used elsewhere.
*/
struct iterator *position;
};
+ (Index *) alloc: (enum index_type) type :(struct key *) key;
/**
* Initialize index instance.
*
* @param space space the index belongs to
* @param key key part description
*/
- (void) init: (struct space *) space_arg;
- (void) init: (struct key *) key :(struct space *) space_arg;
/** Destroy and free index instance. */
- (void) free;
/**
* Destroy and free index instance.
* Finish index construction.
*/
- (void) free;
- (void) enable;
- (size_t) size;
- (struct box_tuple *) min;
- (struct box_tuple *) max;
- (struct box_tuple *) find: (void *) key; /* only for unique lookups */
- (struct box_tuple *) findBy: (struct box_tuple *) pattern;
- (void) remove: (struct box_tuple *) tuple;
- (void) replace: (struct box_tuple *) old :(struct box_tuple *) new;
/**
* Create a structure to represent an iterator. Must be
* initialized separately.
*/
- (struct iterator *) allocIterator;
- (void) initIterator: (struct iterator *) iterator;
- (void) initIterator: (struct iterator *) iterator :(void *) key
:(int) part_count;
@end
struct iterator {
struct box_tuple *(*next)(struct iterator *);
struct box_tuple *(*next_equal)(struct iterator *);
};
#define foreach_index(n, index_var) \
Index *index_var; \
for (Index **index_ptr = space[(n)].index; \
*index_ptr != nil; index_ptr++) \
if ((index_var = *index_ptr)->enabled)
struct box_txn;
void validate_indexes(struct box_txn *txn);
void build_indexes(void);
#endif /* TARANTOOL_BOX_INDEX_H_INCLUDED */
......@@ -23,7 +23,27 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "index.h"
#include "say.h"
#include "tuple.h"
#include "pickle.h"
#include "exception.h"
#include "box.h"
const char *field_data_type_strs[] = {"NUM", "NUM64", "STR", "\0"};
const char *index_type_strs[] = { "HASH", "TREE", "\0" };
#if 0
index->key = key;
index->unique = cfg_index->unique;
index->type = STR2ENUM(index_type, cfg_index->type);
index->n = j;
memc_index->key = key;
memc_index->unique = true;
memc_index->type = HASH;
memc_index->enabled = true;
memc_index->n = 0;
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
......@@ -44,100 +64,9 @@
#include <mod/box/index.h>
#include <mod/box/tuple.h>
const char *field_data_type_strs[] = {"NUM", "NUM64", "STR", "\0"};
const char *index_type_strs[] = { "HASH", "TREE", "\0" };
const struct field ASTERISK = {
.len = UINT32_MAX,
{
.data_ptr = NULL,
}
};
#define IS_ASTERISK(f) ((f)->len == ASTERISK.len && (f)->data_ptr == ASTERISK.data_ptr)
/** Compare two fields of an index key.
*
* @retval 0 two fields are equal
* @retval -1 f2 is less than f1
* @retval 1 f2 is greater than f1
*/
static i8
field_compare(struct field *f1, struct field *f2, enum field_data_type type)
{
if (IS_ASTERISK(f1) || IS_ASTERISK(f2))
return 0;
if (type == NUM) {
assert(f1->len == f2->len);
assert(f1->len == sizeof(f1->u32));
return f1->u32 >f2->u32 ? 1 : f1->u32 == f2->u32 ? 0 : -1;
} else if (type == NUM64) {
assert(f1->len == f2->len);
assert(f1->len == sizeof(f1->u64));
return f1->u64 >f2->u64 ? 1 : f1->u64 == f2->u64 ? 0 : -1;
} else if (type == STRING) {
i32 cmp;
void *f1_data, *f2_data;
f1_data = f1->len <= sizeof(f1->data) ? f1->data : f1->data_ptr;
f2_data = f2->len <= sizeof(f2->data) ? f2->data : f2->data_ptr;
cmp = memcmp(f1_data, f2_data, MIN(f1->len, f2->len));
if (cmp > 0)
return 1;
else if (cmp < 0)
return -1;
else if (f1->len == f2->len)
return 0;
else if (f1->len > f2->len)
return 1;
else
return -1;
}
panic("impossible happened");
}
/*
* Compare index_tree elements only by fields defined in
* index->field_cmp_order.
* Return:
* Common meaning:
* < 0 - a is smaller than b
* == 0 - a is equal to b
* > 0 - a is greater than b
*/
static int
index_tree_el_unique_cmp(struct index_tree_el *elem_a,
struct index_tree_el *elem_b,
Index *index)
{
int r = 0;
for (i32 i = 0, end = index->key.part_count; i < end; ++i) {
r = field_compare(&elem_a->key[i], &elem_b->key[i],
index->key.parts[i].type);
if (r != 0)
break;
}
return r;
}
static int
index_tree_el_cmp(struct index_tree_el *elem_a, struct index_tree_el *elem_b,
Index *index)
{
int r = index_tree_el_unique_cmp(elem_a, elem_b, index);
if (r == 0 && elem_a->tuple && elem_b->tuple)
r = (elem_a->tuple < elem_b->tuple ?
-1 : elem_a->tuple > elem_b->tuple);
return r;
}
static size_t
index_tree_size(Index *index)
......@@ -281,43 +210,6 @@ index_hash_str_find(Index *self, void *key)
return ret;
}
void
index_tree_el_init(struct index_tree_el *elem,
Index *index, struct box_tuple *tuple)
{
void *tuple_data = tuple->data;
for (i32 i = 0; i < index->key.max_fieldno; ++i) {
struct field f;
if (i < tuple->cardinality) {
f.len = load_varint32(&tuple_data);
if (f.len <= sizeof(f.data)) {
memset(f.data, 0, sizeof(f.data));
memcpy(f.data, tuple_data, f.len);
} else
f.data_ptr = tuple_data;
tuple_data += f.len;
} else
f = ASTERISK;
u32 key_field_no = index->key.cmp_order[i];
if (key_field_no == -1)
continue;
if (index->key.parts[key_field_no].type == NUM) {
if (f.len != 4)
tnt_raise(IllegalParams, :"key is not u32");
} else if (index->key.parts[key_field_no].type == NUM64 && f.len != 8) {
tnt_raise(IllegalParams, :"key is not u64");
}
elem->key[key_field_no] = f;
}
elem->tuple = tuple;
}
void
init_search_pattern(Index *index, int key_cardinality, void *key)
{
......@@ -586,108 +478,8 @@ index_tree_iterator_init(Index *index,
index->position[POS_READ]);
}
void
validate_indexes(struct box_txn *txn)
{
if (space[txn->n].index[1] != nil) { /* there is more than one index */
foreach_index(txn->n, index) {
for (u32 f = 0; f < index->key.part_count; ++f) {
if (index->key.parts[f].fieldno >= txn->tuple->cardinality)
tnt_raise(IllegalParams, :"tuple must have all indexed fields");
if (index->key.parts[f].type == STRING)
continue;
void *field = tuple_field(txn->tuple, index->key.parts[f].fieldno);
u32 len = load_varint32(&field);
if (index->key.parts[f].type == NUM && len != sizeof(u32))
tnt_raise(IllegalParams, :"field must be NUM");
if (index->key.parts[f].type == NUM64 && len != sizeof(u64))
tnt_raise(IllegalParams, :"field must be NUM64");
}
if (index->type == TREE && index->unique == false)
/* Don't check non unique indexes */
continue;
struct box_tuple *tuple = index->find_by_tuple(index, txn->tuple);
if (tuple != NULL && tuple != txn->old_tuple)
tnt_raise(ClientError, :ER_INDEX_VIOLATION);
}
}
}
void
build_index(Index *pk, Index *index)
{
u32 n_tuples = pk->size(pk);
u32 estimated_tuples = n_tuples * 1.2;
struct index_tree_el *elem = NULL;
if (n_tuples) {
/*
* Allocate a little extra to avoid
* unnecessary realloc() when more data is
* inserted.
*/
size_t sz = estimated_tuples * INDEX_TREE_EL_SIZE(index);
elem = malloc(sz);
if (elem == NULL)
panic("malloc(): failed to allocate %"PRI_SZ" bytes", sz);
}
struct index_tree_el *m;
u32 i = 0;
pk->iterator_init(pk, 0, NULL);
struct box_tuple *tuple;
while ((tuple = pk->iterator.next(pk))) {
m = (struct index_tree_el *)
((char *)elem + i * INDEX_TREE_EL_SIZE(index));
index_tree_el_init(m, index, tuple);
++i;
}
if (n_tuples)
say_info("Sorting %"PRIu32 " keys in index %" PRIu32 "...", n_tuples, index->n);
/* If n_tuples == 0 then estimated_tuples = 0, elem == NULL, tree is empty */
sptree_str_t_init(index->idx.tree, INDEX_TREE_EL_SIZE(index),
elem, n_tuples, estimated_tuples,
(void*) (index->unique ? index_tree_el_unique_cmp :
index_tree_el_cmp), index);
index->enabled = true;
}
void
build_indexes(void)
{
for (u32 n = 0; n < BOX_SPACE_MAX; ++n) {
if (space[n].enabled == false)
continue;
/* A shortcut to avoid unnecessary log messages. */
if (space[n].index[1] == nil)
continue; /* no secondary keys */
say_info("Building secondary keys in space %" PRIu32 "...", n);
Index *pk = space[n].index[0];
for (u32 idx = 1;; idx++) {
Index *index = space[n].index[idx];
if (index == nil)
break;
if (index->type != TREE)
continue;
assert(index->enabled == false);
build_index(pk, index);
}
say_info("Space %"PRIu32": done", n);
}
}
static void
index_hash_num(Index *index, struct space *space)
......@@ -857,3 +649,287 @@ index_tree_free(Index *index)
@end
#endif
/* {{{ HashIndex -- base class for all hashes. ********************/
@interface HashIndex: Index
@end
@implementation HashIndex
@end
/* }}} */
/* {{{ Hash32Index ************************************************/
@interface Hash32Index: HashIndex
@end
@implementation Hash32Index
@end
/* }}} */
/* {{{ Hash64Index ************************************************/
@interface Hash64Index: HashIndex
@end
@implementation Hash64Index
@end
/* }}} */
/* {{{ HashStrIndex ***********************************************/
@interface HashStrIndex: HashIndex
@end
@implementation HashStrIndex
@end
/* }}} */
/* {{{ TreeIndex and auxiliary structures. ************************/
/**
* A field reference used for TREE indexes. Either stores a copy
* of the corresponding field in the tuple or points to that field
* in the tuple (depending on field length).
*/
struct field {
/** Field data length. */
u32 len;
/** Actual field data. For small fields we store the value
* of the field (u32, u64, strings up to 8 bytes), for
* longer fields, we store a pointer to field data in the
* tuple in the primary index.
*/
union {
u32 u32;
u64 u64;
u8 data[sizeof(u64)];
void *data_ptr;
};
};
const struct field ASTERISK = {
.len = UINT32_MAX,
{
.data_ptr = NULL,
}
};
#define IS_ASTERISK(f) ((f)->len == ASTERISK.len && (f)->data_ptr == ASTERISK.data_ptr)
/** Compare two fields of an index key.
*
* @retval 0 two fields are equal
* @retval -1 f2 is less than f1
* @retval 1 f2 is greater than f1
*/
static i8
field_compare(struct field *f1, struct field *f2, enum field_data_type type)
{
if (IS_ASTERISK(f1) || IS_ASTERISK(f2))
return 0;
if (type == NUM) {
assert(f1->len == f2->len);
assert(f1->len == sizeof(f1->u32));
return f1->u32 >f2->u32 ? 1 : f1->u32 == f2->u32 ? 0 : -1;
} else if (type == NUM64) {
assert(f1->len == f2->len);
assert(f1->len == sizeof(f1->u64));
return f1->u64 >f2->u64 ? 1 : f1->u64 == f2->u64 ? 0 : -1;
} else if (type == STRING) {
i32 cmp;
void *f1_data, *f2_data;
f1_data = f1->len <= sizeof(f1->data) ? f1->data : f1->data_ptr;
f2_data = f2->len <= sizeof(f2->data) ? f2->data : f2->data_ptr;
cmp = memcmp(f1_data, f2_data, MIN(f1->len, f2->len));
if (cmp > 0)
return 1;
else if (cmp < 0)
return -1;
else if (f1->len == f2->len)
return 0;
else if (f1->len > f2->len)
return 1;
else
return -1;
}
panic("impossible happened");
}
struct index_tree_el {
struct box_tuple *tuple;
struct field key[];
};
#define INDEX_TREE_EL_SIZE(key) \
(sizeof(struct index_tree_el) + sizeof(struct field) * (key)->part_count)
void
index_tree_el_init(struct index_tree_el *elem,
struct key *key, struct box_tuple *tuple)
{
void *tuple_data = tuple->data;
for (i32 i = 0; i < key->max_fieldno; ++i) {
struct field f;
if (i < tuple->cardinality) {
f.len = load_varint32(&tuple_data);
if (f.len <= sizeof(f.data)) {
memset(f.data, 0, sizeof(f.data));
memcpy(f.data, tuple_data, f.len);
} else
f.data_ptr = tuple_data;
tuple_data += f.len;
} else
f = ASTERISK;
u32 key_field_no = key->cmp_order[i];
if (key_field_no == -1)
continue;
if (key->parts[key_field_no].type == NUM) {
if (f.len != 4)
tnt_raise(IllegalParams, :"key is not u32");
} else if (key->parts[key_field_no].type == NUM64 && f.len != 8) {
tnt_raise(IllegalParams, :"key is not u64");
}
elem->key[key_field_no] = f;
}
elem->tuple = tuple;
}
/*
* Compare index_tree elements only by fields defined in
* index->field_cmp_order.
* Return:
* Common meaning:
* < 0 - a is smaller than b
* == 0 - a is equal to b
* > 0 - a is greater than b
*/
static int
index_tree_el_unique_cmp(struct index_tree_el *elem_a,
struct index_tree_el *elem_b,
struct key *key)
{
int r = 0;
for (i32 i = 0, end = key->part_count; i < end; ++i) {
r = field_compare(&elem_a->key[i], &elem_b->key[i],
key->parts[i].type);
if (r != 0)
break;
}
return r;
}
static int
index_tree_el_cmp(struct index_tree_el *elem_a, struct index_tree_el *elem_b,
struct key *key)
{
int r = index_tree_el_unique_cmp(elem_a, elem_b, key);
if (r == 0 && elem_a->tuple && elem_b->tuple)
r = (elem_a->tuple < elem_b->tuple ?
-1 : elem_a->tuple > elem_b->tuple);
return r;
}
#include <third_party/sptree.h>
SPTREE_DEF(str_t, realloc);
@interface TreeIndex: Index {
sptree_str_t *tree;
};
- (void) build: (Index *) pk;
@end
@implementation TreeIndex
- (void) build: (Index *) pk
{
u32 n_tuples = [pk size];
u32 estimated_tuples = n_tuples * 1.2;
assert(enabled == false);
struct index_tree_el *elem = NULL;
if (n_tuples) {
/*
* Allocate a little extra to avoid
* unnecessary realloc() when more data is
* inserted.
*/
size_t sz = estimated_tuples * INDEX_TREE_EL_SIZE(&key);
elem = malloc(sz);
if (elem == NULL)
panic("malloc(): failed to allocate %"PRI_SZ" bytes", sz);
}
struct index_tree_el *m;
u32 i = 0;
struct iterator *it = pk->position;
[pk initIterator: it];
struct box_tuple *tuple;
while ((tuple = it->next(it))) {
m = (struct index_tree_el *)
((char *)elem + i * INDEX_TREE_EL_SIZE(&key));
index_tree_el_init(m, &key, tuple);
++i;
}
if (n_tuples)
say_info("Sorting %"PRIu32 " keys in index %" PRIu32 "...", n_tuples, self->n);
/* If n_tuples == 0 then estimated_tuples = 0, elem == NULL, tree is empty */
sptree_str_t_init(tree, INDEX_TREE_EL_SIZE(&key),
elem, n_tuples, estimated_tuples,
(void *) (unique ? index_tree_el_unique_cmp :
index_tree_el_cmp), &key);
enabled = true;
}
@end
/* }}} */
void
build_indexes(void)
{
for (u32 n = 0; n < BOX_SPACE_MAX; ++n) {
if (space[n].enabled == false)
continue;
/* A shortcut to avoid unnecessary log messages. */
if (space[n].index[1] == nil)
continue; /* no secondary keys */
say_info("Building secondary keys in space %" PRIu32 "...", n);
Index *pk = space[n].index[0];
for (u32 idx = 1;; idx++) {
Index *index = space[n].index[idx];
if (index == nil)
break;
if (index->type != TREE)
continue;
[(TreeIndex*) index build: pk];
}
say_info("Space %"PRIu32": done", n);
}
}
/**
* vim: foldmethod=marker
*/
......@@ -32,6 +32,7 @@
#include "say.h"
#include "stat.h"
#include "salloc.h"
#include "pickle.h"
#define STAT(_) \
_(MEMC_GET, 1) \
......@@ -129,7 +130,7 @@ delete(void *key)
static struct box_tuple *
find(void *key)
{
return memcached_index->find(memcached_index, key);
return [memcached_index find: key];
}
static struct meta *
......@@ -282,10 +283,12 @@ flush_all(void *data)
uintptr_t delay = (uintptr_t)data;
fiber_sleep(delay - ev_now());
struct box_tuple *tuple;
memcached_index->iterator_init(memcached_index, 0, NULL);
while ((tuple = memcached_index->iterator.next(memcached_index))) {
struct iterator *it = [memcached_index allocIterator];
[memcached_index initIterator: it];
while ((tuple = it->next(it))) {
meta(tuple)->exptime = 1;
}
sfree(it);
}
#define STORE \
......@@ -427,9 +430,6 @@ memcached_space_init()
memc_s->cardinality = 4;
memc_s->n = cfg.memcached_space;
/* Configure memcached index. */
Index *memc_index = memc_s->index[0] = [[Index alloc] init];
struct key key;
/* Configure memcached index key. */
key.part_count = 1;
......@@ -446,12 +446,9 @@ memcached_space_init()
key.max_fieldno = 1;
key.cmp_order[0] = 0;
memc_index->key = key;
memc_index->unique = true;
memc_index->type = HASH;
memc_index->enabled = true;
memc_index->n = 0;
[memc_index init: memc_s];
/* Configure memcached index. */
Index *memc_index = memc_s->index[0] = [Index alloc: HASH :&key];
[memc_index init: &key :memc_s];
}
/** Delete a bunch of expired keys. */
......@@ -476,7 +473,7 @@ memcached_delete_expired_keys(struct tbuf *keys_to_delete)
double delay = ((double) cfg.memcached_expire_per_loop *
cfg.memcached_expire_full_sweep /
(memcached_index->size(memcached_index) + 1));
([memcached_index size] + 1));
if (delay > 1)
delay = 1;
fiber_setcancelstate(true);
......@@ -490,15 +487,17 @@ memcached_expire_loop(void *data __attribute__((unused)))
struct box_tuple *tuple = NULL;
say_info("memcached expire fiber started");
for (;;) {
struct iterator *it = [memcached_index allocIterator];
@try {
restart:
if (tuple == NULL)
memcached_index->iterator_init(memcached_index, 0, NULL);
[memcached_index initIterator: it];
struct tbuf *keys_to_delete = tbuf_alloc(fiber->gc_pool);
for (int j = 0; j < cfg.memcached_expire_per_loop; j++) {
tuple = memcached_index->iterator.next(memcached_index);
tuple = it->next(it);
if (tuple == NULL)
break;
......@@ -511,6 +510,9 @@ memcached_expire_loop(void *data __attribute__((unused)))
}
memcached_delete_expired_keys(keys_to_delete);
fiber_gc();
goto restart;
} @finally {
sfree(it);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment