From a28c57bf70aa4dffb45601cbacc6eb7e5f4f4369 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Wed, 21 Aug 2013 21:29:05 +0400 Subject: [PATCH] Modify format of server snapshot to version 12. The new server snapshot format is identical to format of XLOG, i.e. it contains REPLACE statements with BOX_INSERT flags for every tuple in a space. This allows to streamline recovery, since rows from a snapshot can be treated the same as rows from the write ahead log (XLOG). This is an incompatible change: - tarantool 1.5 won't be able to read data of tarantool 1.6 - tarantool 1.6, without extra effort, won't be able to read data of tarantool 1.5 (a conversion procedure is needed). This change as such doesn't break replication, but further changes are in the pipeline which will inevitably finish this matter up as well. Why this patch is necessary --------------------------- To create system spaces dict-v5 branch employs on_replace triggers mechanism, fired off by txn_replace(). Thus it's vital that all changes go into spaces using txn_replace(). What else this patch does ------------------------- - since now XLOG and SNAP have the same format, log_io.cc code has become a bit simpler - struct key_def is re-factored to simplify dynamic creation/deletion of keys - reference counting for tuple formats is added - a number of error messages is improved to provide part no in a multipart key. - space cache is split away from space.cc into a separate module, schema.[h,cc] --- connector/c/include/tarantool/tnt_log.h | 2 +- connector/c/tntrpl/tnt_rpl.c | 2 +- include/errcode.h | 10 +- include/log_io.h | 24 +- include/recovery.h | 2 +- src/bootstrap.snap | Bin 15 -> 16 bytes src/box/CMakeLists.txt | 1 + src/box/bitset_index.cc | 6 +- src/box/box.cc | 87 +- src/box/box_lua.cc | 13 +- src/box/box_lua_space.cc | 6 +- src/box/box_lua_space.h | 4 +- src/box/hash_index.cc | 24 +- src/box/index.cc | 39 +- src/box/index.h | 4 +- src/box/key_def.cc | 19 +- src/box/key_def.h | 40 +- src/box/lua/box.lua | 2 - src/box/request.cc | 15 +- src/box/schema.cc | 435 +++++++ src/box/schema.h | 94 ++ src/box/space.cc | 571 +++------ src/box/space.h | 116 +- src/box/tree_index.cc | 12 +- src/box/tuple.cc | 196 ++- src/box/tuple.h | 23 +- src/box/tuple_update.cc | 6 +- src/box/txn.cc | 4 +- src/log_io.cc | 58 +- src/lua/uuid.lua | 1 + src/memcached.cc | 14 +- src/recovery.cc | 29 +- src/replica.cc | 12 +- test/big/bitset.result | 6 +- test/big/hash.result | 30 +- test/big/hash_multipart.result | 4 +- test/big/tree_pk.result | 6 +- test/big/tree_variants.result | 8 +- test/box/bad_record.xlog | Bin 22 -> 22 bytes test/box/dup_key1.xlog | Bin 137 -> 138 bytes test/box/dup_key2.xlog | Bin 137 -> 138 bytes test/box/just_header.xlog | Bin 11 -> 11 bytes test/box/lua.result | 2 +- test/box/lua_misc.result | 20 +- test/box/snapshot.result | 1507 ----------------------- test/box/snapshot.test.py | 20 +- test/box/snapshot_1_3.result | 1507 +++++++++++++++++++++++ test/box/snapshot_1_3.test.py | 21 + test/box/sql.result | 2 +- test/box/suite.ini | 5 +- test/box/unfinished.xlog | Bin 86 -> 86 bytes test/connector_c/connector.snap | Bin 259 -> 260 bytes test/connector_c/connector.xlog | Bin 178495 -> 178496 bytes test/lib/sql_ast.py | 4 +- 54 files changed, 2706 insertions(+), 2307 deletions(-) create mode 100644 src/box/schema.cc create mode 100644 src/box/schema.h create mode 100644 test/box/snapshot_1_3.result create mode 100644 test/box/snapshot_1_3.test.py diff --git a/connector/c/include/tarantool/tnt_log.h b/connector/c/include/tarantool/tnt_log.h index 352a1164f5..194a03215f 100644 --- a/connector/c/include/tarantool/tnt_log.h +++ b/connector/c/include/tarantool/tnt_log.h @@ -32,7 +32,7 @@ #define TNT_LOG_MAGIC_XLOG "XLOG\n" #define TNT_LOG_MAGIC_SNAP "SNAP\n" -#define TNT_LOG_VERSION "0.11\n" +#define TNT_LOG_VERSION "0.12\n" enum tnt_log_error { TNT_LOG_EOK, diff --git a/connector/c/tntrpl/tnt_rpl.c b/connector/c/tntrpl/tnt_rpl.c index cabb6de39c..94358a46f4 100644 --- a/connector/c/tntrpl/tnt_rpl.c +++ b/connector/c/tntrpl/tnt_rpl.c @@ -43,7 +43,7 @@ #include <connector/c/include/tarantool/tnt_log.h> #include <connector/c/include/tarantool/tnt_rpl.h> -static const uint32_t tnt_rpl_version = 11; +static const uint32_t tnt_rpl_version = 12; static void tnt_rpl_free(struct tnt_stream *s) { struct tnt_stream_rpl *sr = TNT_RPL_CAST(s); diff --git a/include/errcode.h b/include/errcode.h index 3f834717c6..c18e414a91 100644 --- a/include/errcode.h +++ b/include/errcode.h @@ -80,7 +80,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 25 */_(ER_UNUSED25, 2, "Unused25") \ /* 26 */_(ER_FIBER_STACK, 2, "Can not create a new fiber: recursion limit reached") \ /* 27 */_(ER_UNUSED27, 2, "Unused27") \ - /* 28 */_(ER_UNUSED28, 2, "Unused28") \ + /* 28 */_(ER_TUPLE_FORMAT_LIMIT, 2, "Tuple format limit reached: %u") \ /* 29 */_(ER_UNUSED29, 2, "Unused29") \ /* 30 */_(ER_UNUSED30, 2, "Unused30") \ /* 31 */_(ER_UNUSED31, 2, "Unused31") \ @@ -90,15 +90,15 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 35 */_(ER_UNUSED35, 2, "Unused35") \ /* 36 */_(ER_UNUSED36, 2, "Unused36") \ /* 37 */_(ER_UNUSED37, 2, "Unused37") \ - /* 38 */_(ER_KEY_FIELD_TYPE, 2, "Supplied key field type does not match index type: expected %s") \ + /* 38 */_(ER_KEY_FIELD_TYPE, 2, "Supplied key type of part %u does not match index part type: expected %s") \ /* 39 */_(ER_WAL_IO, 2, "Failed to write to disk") \ - /* 40 */_(ER_FIELD_TYPE, 2, "Field type does not match one required by operation: expected a %s") \ - /* 41 */_(ER_ARG_TYPE, 2, "Argument type in operation does not match field type: expected a %s") \ + /* 40 */_(ER_FIELD_TYPE, 2, "Tuple field %u type does not match one required by operation: expected %s") \ + /* 41 */_(ER_ARG_TYPE, 2, "Argument type in operation on field %u does not match field type: expected a %s") \ /* 42 */_(ER_SPLICE, 2, "Field SPLICE error: %s") \ /* 43 */_(ER_TUPLE_IS_TOO_LONG, 2, "Tuple is too long %u") \ /* 44 */_(ER_UNKNOWN_UPDATE_OP, 2, "Unknown UPDATE operation") \ /* 45 */_(ER_EXACT_MATCH, 2, "Invalid key part count in an exact match (expected %u, got %u)") \ - /* 46 */_(ER_UNUSED46, 2, "Unused46") \ + /* 46 */_(ER_FIELD_TYPE_MISMATCH, 2, "Ambiguous field type in index %u, key part %u. Requested type is %s but the field has previously been defined as %s") \ /* 47 */_(ER_KEY_PART_COUNT, 2, "Invalid key part count (expected [0..%u], got %u)") \ /* 48 */_(ER_PROC_RET, 2, "Return type '%s' is not supported in the binary protocol") \ /* 49 */_(ER_TUPLE_NOT_FOUND, 2, "Tuple doesn't exist in index %u") \ diff --git a/include/log_io.h b/include/log_io.h index 21b25eeee5..ecb4631373 100644 --- a/include/log_io.h +++ b/include/log_io.h @@ -36,7 +36,7 @@ extern const uint32_t default_version; -enum log_format { XLOG = 65534, SNAP = 65535 }; +enum log_format { WAL = 65534 }; enum log_mode { LOG_READ, @@ -116,7 +116,7 @@ log_io_cursor_next(struct log_io_cursor *i, uint32_t *rowlen); typedef uint32_t log_magic_t; -struct header_v11 { +struct row_header { uint32_t header_crc32c; int64_t lsn; double tm; @@ -124,13 +124,13 @@ struct header_v11 { uint32_t data_crc32c; } __attribute__((packed)); -static inline struct header_v11 *header_v11(const char *t) +static inline struct row_header *row_header(const char *t) { - return (struct header_v11 *)t; + return (struct row_header *)t; } static inline void -header_v11_fill(struct header_v11 *header, int64_t lsn, size_t data_len) +row_header_fill(struct row_header *header, int64_t lsn, size_t data_len) { header->lsn = lsn; header->tm = ev_now(); @@ -138,25 +138,25 @@ header_v11_fill(struct header_v11 *header, int64_t lsn, size_t data_len) } void -header_v11_sign(struct header_v11 *header); +row_header_sign(struct row_header *header); -struct row_v11 { +struct wal_row { log_magic_t marker; - struct header_v11 header; + struct row_header header; uint16_t tag; uint64_t cookie; uint8_t data[]; } __attribute__((packed)); void -row_v11_fill(struct row_v11 *row, int64_t lsn, uint16_t tag, - uint64_t cookie, const char *metadata, size_t metadata_len, +wal_row_fill(struct wal_row *row, int64_t lsn, + const char *metadata, size_t metadata_len, const char *data, size_t data_len); static inline size_t -row_v11_size(struct row_v11 *row) +wal_row_size(struct wal_row *row) { - return sizeof(row->marker) + sizeof(struct header_v11) + row->header.len; + return sizeof(row->marker) + sizeof(struct row_header) + row->header.len; } int diff --git a/include/recovery.h b/include/recovery.h index 816f4f2d56..e8208010dc 100644 --- a/include/recovery.h +++ b/include/recovery.h @@ -119,7 +119,7 @@ void recover_snap(struct recovery_state *); void recover_existing_wals(struct recovery_state *); void recovery_follow_local(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay); void recovery_finalize(struct recovery_state *r); -int wal_write(struct recovery_state *r, int64_t lsn, uint64_t cookie, +int wal_write(struct recovery_state *r, int64_t lsn, uint16_t op, const char *data, uint32_t len); void recovery_setup_panic(struct recovery_state *r, bool on_snap_error, bool on_wal_error); diff --git a/src/bootstrap.snap b/src/bootstrap.snap index 8f8d8ac5b4c8634e2099b9d6671560db48518960..f5162cd01ca676bfbe85a8dcb2d85c6bb39e2726 100644 GIT binary patch literal 16 XcmWIca}3}z&@(jR;*wjvR)7lt9|8lS literal 15 WcmWIca}3}z&@(jT;*wjvRsaASSp$~< diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index 3df5f31448..14603d831b 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -25,6 +25,7 @@ tarantool_module("box" tree_index.cc bitset_index.cc space.cc + schema.cc port.cc request.cc txn.cc diff --git a/src/box/bitset_index.cc b/src/box/bitset_index.cc index 6273b51920..c2b09d86fb 100644 --- a/src/box/bitset_index.cc +++ b/src/box/bitset_index.cc @@ -88,7 +88,7 @@ bitset_index_iterator_next(struct iterator *iterator) BitsetIndex::BitsetIndex(struct key_def *key_def) : Index(key_def) { - assert(!this->key_def.is_unique); + assert(!this->key_def->is_unique); if (bitset_index_create(&index, realloc) != 0) panic_syserror("bitset_index_create"); @@ -135,7 +135,7 @@ struct tuple * BitsetIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode) { - assert(!key_def.is_unique); + assert(!key_def->is_unique); assert(old_tuple != NULL || new_tuple != NULL); (void) mode; @@ -154,7 +154,7 @@ BitsetIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple, if (new_tuple != NULL) { uint32_t len = 0; const char *field; - field = tuple_field(new_tuple, key_def.parts[0].fieldno, + field = tuple_field(new_tuple, key_def->parts[0].fieldno, &len); size_t value = tuple_to_value(new_tuple); diff --git a/src/box/box.cc b/src/box/box.cc index 901fa3cafe..107e5730f4 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -45,11 +45,11 @@ extern "C" { #include "tuple.h" #include "memcached.h" #include "box_lua.h" +#include "schema.h" #include "space.h" #include "port.h" #include "request.h" #include "txn.h" -#include <third_party/base64.h> static void process_replica(struct port *port, struct request *request); static void process_ro(struct port *port, struct request *request); @@ -61,10 +61,12 @@ static char status[64] = "unknown"; static int stat_base; +/** The snapshot row metadata repeats the structure of REPLACE request. */ struct box_snap_row { + uint16_t op; uint32_t space; - uint32_t tuple_size; - uint32_t data_size; + uint32_t flags; + uint32_t field_count; char data[]; } __attribute__((packed)); @@ -112,68 +114,25 @@ process_ro(struct port *port, struct request *request) return process_rw(port, request); } -static void -recover_snap_row(const void *data) -{ - const struct box_snap_row *row = (const struct box_snap_row *) data; - - struct space *space = space_find(row->space); - Index *index = space_index(space, 0); - - struct tuple *tuple; - try { - const char *tuple_data = row->data; - tuple = tuple_new(space->format, - row->tuple_size, &tuple_data, - tuple_data + row->data_size); - } catch (const ClientError &e) { - say_error("\n" - "********************************************\n" - "* Found a corrupted tuple in the snapshot! *\n" - "* This can be either due to a memory *\n" - "* corruption or a bug in the server. *\n" - "* The tuple can not be loaded. *\n" - "********************************************\n" - "Tuple data, BAS64 encoded: \n"); - - int base64_buflen = base64_bufsize(row->data_size); - char *base64_buf = (char *) malloc(base64_buflen); - int len = base64_encode(row->data, row->data_size, - base64_buf, base64_buflen); - write(STDERR_FILENO, base64_buf, len); - free(base64_buf); - throw; - } - index->buildNext(tuple); - tuple_ref(tuple, 1); -} - static int recover_row(void *param __attribute__((unused)), const char *row, uint32_t rowlen) { /* drop wal header */ - if (rowlen < sizeof(struct header_v11)) { + if (rowlen < sizeof(struct row_header)) { say_error("incorrect row header: expected %zd, got %zd bytes", - sizeof(struct header_v11), (size_t) rowlen); + sizeof(struct row_header), (size_t) rowlen); return -1; } try { const char *end = row + rowlen; - row += sizeof(struct header_v11); - uint16_t tag = pick_u16(&row, end); + row += sizeof(struct row_header); + (void) pick_u16(&row, end); /* drop tag - unused. */ (void) pick_u64(&row, end); /* drop cookie */ - if (tag == SNAP) { - recover_snap_row(row); - } else if (tag == XLOG) { - uint16_t op = pick_u16(&row, end); - struct request request; - request_create(&request, op, row, end - row); - process_rw(&null_port, &request); - } else { - say_error("unknown row tag: %i", (int)tag); - return -1; - } + uint16_t op = pick_u16(&row, end); + struct request request; + request_create(&request, op, row, end - row); + process_rw(&null_port, &request); } catch (const Exception& e) { e.log(); return -1; @@ -312,7 +271,8 @@ box_reload_config(struct tarantool_cfg *old_conf, struct tarantool_cfg *new_conf void box_free(void) { - space_free(); + schema_free(); + tuple_free(); } void @@ -321,8 +281,8 @@ box_init() title("loading"); atexit(box_free); - /* initialization spaces */ - space_init(); + tuple_init(); + schema_init(); /* configure memcached space */ memcached_space_init(); @@ -334,16 +294,14 @@ box_init() stat_base = stat_register(requests_strs, requests_MAX); - begin_build_primary_indexes(); recover_snap(recovery_state); - end_build_primary_indexes(); + space_end_recover_snapshot(); recover_existing_wals(recovery_state); + space_end_recover(); stat_cleanup(stat_base, requests_MAX); - - say_info("building secondary indexes"); - build_secondary_indexes(); title("orphan"); + if (cfg.local_hot_standby) { say_info("starting local hot standby"); recovery_follow_local(recovery_state, cfg.wal_dir_rescan_delay); @@ -358,9 +316,10 @@ snapshot_write_tuple(struct log_io *l, struct fio_batch *batch, uint32_t n, struct tuple *tuple) { struct box_snap_row header; + header.op = REPLACE; header.space = n; - header.tuple_size = tuple->field_count; - header.data_size = tuple->bsize; + header.flags = BOX_ADD; + header.field_count = tuple->field_count; snapshot_write_row(l, batch, (const char *) &header, sizeof(header), tuple->data, tuple->bsize); diff --git a/src/box/box_lua.cc b/src/box/box_lua.cc index fbbeca8f8f..ea79e7b8b7 100644 --- a/src/box/box_lua.cc +++ b/src/box/box_lua.cc @@ -48,6 +48,7 @@ extern "C" { #include "pickle.h" #include "tuple.h" +#include "schema.h" #include "space.h" #include "port.h" #include "tbuf.h" @@ -649,7 +650,7 @@ lbox_pushiterator(struct lua_State *L, Index *index, memcpy(udata->key, key, size); key = udata->key; } - key_validate(&index->key_def, type, key, part_count); + key_validate(index->key_def, type, key, part_count); index->initIterator(it, type, key, part_count); } @@ -708,7 +709,7 @@ static int lbox_index_part_count(struct lua_State *L) { Index *index = lua_checkindex(L, 1); - lua_pushinteger(L, index->key_def.part_count); + lua_pushinteger(L, index->key_def->part_count); return 1; } @@ -813,10 +814,10 @@ lbox_create_iterator(struct lua_State *L) * indexes. HASH indexes can only use single-part * keys. */ - if (key_part_count > index->key_def.part_count) + if (key_part_count > index->key_def->part_count) luaL_error(L, "Key part count %d" " is greater than index part count %d", - key_part_count, index->key_def.part_count); + key_part_count, index->key_def->part_count); luaL_pushresult(&b); key = lua_tolstring(L, -1, &key_size); if (key_size == 0) @@ -926,7 +927,7 @@ lbox_index_count(struct lua_State *L) const char *key = lua_tostring(L, -1); uint32_t count = 0; - key_validate(&index->key_def, ITER_EQ, key, key_part_count); + key_validate(index->key_def, ITER_EQ, key, key_part_count); /* Prepare index iterator */ struct iterator *it = index->position(); index->initIterator(it, ITER_EQ, key, key_part_count); @@ -1095,7 +1096,7 @@ port_add_lua_ret(struct port *port, struct lua_State *L, int index) struct tuple *tuple = lua_totuple(L, index); auto scoped_guard = make_scoped_guard([=] { if (tuple->refs == 0) - tuple_free(tuple); + tuple_delete(tuple); }); port_add_tuple(port, tuple, BOX_RETURN_TUPLE); } diff --git a/src/box/box_lua_space.cc b/src/box/box_lua_space.cc index 607b5be25a..443fe1d5ef 100644 --- a/src/box/box_lua_space.cc +++ b/src/box/box_lua_space.cc @@ -75,7 +75,7 @@ lbox_pushspace(struct lua_State *L, struct space *space) Index *index = space_index(space, i); if (index == NULL) continue; - struct key_def *key_def = &index->key_def; + struct key_def *key_def = index->key_def; lua_pushnumber(L, key_def->id); lua_newtable(L); /* space.index[i] */ @@ -148,13 +148,13 @@ box_lua_space_new(struct lua_State *L, struct space *space) /** Delete a given space in Lua */ void -box_lua_space_delete(struct lua_State *L, struct space *space) +box_lua_space_delete(struct lua_State *L, uint32_t id) { lua_getfield(L, LUA_GLOBALSINDEX, "box"); lua_getfield(L, -1, "space"); lua_pushnil(L); - lua_rawseti(L, -2, space_id(space)); + lua_rawseti(L, -2, id); lua_pop(L, 2); /* box, space */ assert(lua_gettop(L) == 0); diff --git a/src/box/box_lua_space.h b/src/box/box_lua_space.h index 68ba8a563e..bc8852dc29 100644 --- a/src/box/box_lua_space.h +++ b/src/box/box_lua_space.h @@ -28,6 +28,8 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include <stdint.h> + struct lua_State; struct space; @@ -35,6 +37,6 @@ void box_lua_space_new(struct lua_State *L, struct space *space); void -box_lua_space_delete(struct lua_State *L, struct space *space); +box_lua_space_delete(struct lua_State *L, uint32_t id); #endif /* INCLUDES_TARANTOOL_LUA_SPACE_H */ diff --git a/src/box/hash_index.cc b/src/box/hash_index.cc index 7e7e27c320..5eb756741e 100644 --- a/src/box/hash_index.cc +++ b/src/box/hash_index.cc @@ -58,7 +58,7 @@ mh_index_eq_key(const char *key, struct tuple *const *tuple, static inline uint32_t mh_index_hash(struct tuple *const *tuple, const struct key_def *key_def) { - struct key_part *part = key_def->parts; + const struct key_part *part = key_def->parts; uint32_t size = 0; /* * Speed up the simplest case when we have a @@ -84,7 +84,7 @@ mh_index_hash(struct tuple *const *tuple, const struct key_def *key_def) static inline uint32_t mh_index_hash_key(const char *key, const struct key_def *key_def) { - struct key_part *part = key_def->parts; + const struct key_part *part = key_def->parts; if (key_def->part_count == 1 && part->type == NUM) { (void) load_varint32(&key); @@ -190,7 +190,7 @@ HashIndex::~HashIndex() void HashIndex::reserve(uint32_t size_hint) { - mh_index_reserve(hash, size_hint, &key_def); + mh_index_reserve(hash, size_hint, key_def); } size_t @@ -211,11 +211,11 @@ HashIndex::random(uint32_t rnd) const struct tuple * HashIndex::findByKey(const char *key, uint32_t part_count) const { - assert(key_def.is_unique && part_count == key_def.part_count); + assert(key_def->is_unique && part_count == key_def->part_count); (void) part_count; struct tuple *ret = NULL; - uint32_t k = mh_index_find(hash, key, &key_def); + uint32_t k = mh_index_find(hash, key, key_def); if (k != mh_end(hash)) ret = *mh_index_node(hash, k); return ret; @@ -231,11 +231,11 @@ HashIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple, struct tuple *dup_tuple = NULL; struct tuple **dup_node = &dup_tuple; uint32_t pos = mh_index_put(hash, &new_tuple, - &dup_node, &key_def); + &dup_node, key_def); ERROR_INJECT(ERRINJ_INDEX_ALLOC, { - mh_index_del(hash, pos, &key_def); + mh_index_del(hash, pos, key_def); pos = mh_end(hash); }); @@ -246,10 +246,10 @@ HashIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple, errcode = replace_check_dup(old_tuple, dup_tuple, mode); if (errcode) { - mh_index_remove(hash, &new_tuple, &key_def); + mh_index_remove(hash, &new_tuple, key_def); if (dup_tuple) { pos = mh_index_put(hash, &dup_tuple, NULL, - &key_def); + key_def); if (pos == mh_end(hash)) { panic("Failed to allocate memory in " "recover of int hash"); @@ -263,7 +263,7 @@ HashIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple, } if (old_tuple) { - mh_index_remove(hash, &old_tuple, &key_def); + mh_index_remove(hash, &old_tuple, key_def); } return old_tuple; } @@ -297,7 +297,7 @@ HashIndex::initIterator(struct iterator *ptr, enum iterator_type type, switch (type) { case ITER_GE: if (key != NULL) { - it->h_pos = mh_index_find(hash, key, &key_def); + it->h_pos = mh_index_find(hash, key, key_def); it->base.next = hash_iterator_ge; break; } @@ -307,7 +307,7 @@ HashIndex::initIterator(struct iterator *ptr, enum iterator_type type, it->base.next = hash_iterator_ge; break; case ITER_EQ: - it->h_pos = mh_index_find(hash, key, &key_def); + it->h_pos = mh_index_find(hash, key, key_def); it->base.next = hash_iterator_eq; break; default: diff --git a/src/box/index.cc b/src/box/index.cc index 424623a584..d6b81721a8 100644 --- a/src/box/index.cc +++ b/src/box/index.cc @@ -33,12 +33,15 @@ #include "tuple.h" #include "say.h" #include "exception.h" +#include <new> STRS(iterator_type, ITERATOR_TYPE); /* {{{ Utilities. **********************************************/ -static inline void + + +void key_validate_parts(struct key_def *key_def, const char *key, uint32_t part_count) { @@ -48,11 +51,13 @@ key_validate_parts(struct key_def *key_def, enum field_type part_type = key_def->parts[part].type; if (part_type == NUM && part_size != sizeof(uint32_t)) - tnt_raise(ClientError, ER_KEY_FIELD_TYPE, "u32"); + tnt_raise(ClientError, ER_KEY_FIELD_TYPE, + part, field_type_strs[part_type]); if (part_type == NUM64 && part_size != sizeof(uint64_t) && part_size != sizeof(uint32_t)) - tnt_raise(ClientError, ER_KEY_FIELD_TYPE, "u64"); + tnt_raise(ClientError, ER_KEY_FIELD_TYPE, + part, field_type_strs[part_type]); key += part_size; } @@ -108,23 +113,21 @@ Index::factory(struct key_def *key_def) { switch (key_def->type) { case HASH: - return new HashIndex(key_def); + return new (std::nothrow) HashIndex(key_def); case TREE: - return new TreeIndex(key_def); + return new (std::nothrow) TreeIndex(key_def); case BITSET: - return new BitsetIndex(key_def); + return new (std::nothrow) BitsetIndex(key_def); default: assert(false); } - return NULL; } -Index::Index(struct key_def *key_def) -{ - this->key_def = *key_def; - m_position = NULL; -} +Index::Index(struct key_def *key_def_arg) + :key_def(key_def_arg), + m_position(NULL) +{} void Index::beginBuild() @@ -148,14 +151,14 @@ Index::~Index() { if (m_position != NULL) m_position->free(m_position); - key_def_destroy(&key_def); + key_def_delete(key_def); } struct tuple * Index::min() const { tnt_raise(ClientError, ER_UNSUPPORTED, - index_type_strs[key_def.type], + index_type_strs[key_def->type], "min()"); return NULL; } @@ -164,7 +167,7 @@ struct tuple * Index::max() const { tnt_raise(ClientError, ER_UNSUPPORTED, - index_type_strs[key_def.type], + index_type_strs[key_def->type], "max()"); return NULL; } @@ -174,7 +177,7 @@ Index::random(uint32_t rnd) const { (void) rnd; tnt_raise(ClientError, ER_UNSUPPORTED, - index_type_strs[key_def.type], + index_type_strs[key_def->type], "random()"); return NULL; } @@ -184,7 +187,7 @@ Index::findByTuple(struct tuple *tuple) const { (void) tuple; tnt_raise(ClientError, ER_UNSUPPORTED, - index_type_strs[key_def.type], + index_type_strs[key_def->type], "findByTuple()"); return NULL; } @@ -201,7 +204,7 @@ index_build(Index *index, Index *pk) if (n_tuples > 0) { say_info("Adding %" PRIu32 " keys to %s index %" PRIu32 "...", n_tuples, - index_type_strs[index->key_def.type], index_id(index)); + index_type_strs[index->key_def->type], index_id(index)); } struct iterator *it = pk->position(); diff --git a/src/box/index.h b/src/box/index.h index 9c223fc683..a90b5c71c5 100644 --- a/src/box/index.h +++ b/src/box/index.h @@ -132,7 +132,7 @@ enum dup_replace_mode { class Index: public Object { public: /* Description of a possibly multipart key. */ - struct key_def key_def; + struct key_def *key_def; /** * Allocate index instance. @@ -232,7 +232,7 @@ replace_check_dup(struct tuple *old_tuple, struct tuple *dup_tuple, static inline uint32_t index_id(const Index *index) { - return index->key_def.id; + return index->key_def->id; } /** True if this index is a primary key. */ diff --git a/src/box/key_def.cc b/src/box/key_def.cc index bd0a33c382..28d09b84b4 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -30,26 +30,27 @@ #include <stdlib.h> const char *field_type_strs[] = {"UNKNOWN", "NUM", "NUM64", "STR", "\0"}; -STRS(index_type, INDEX_TYPE); +STRS(index_type, ENUM_INDEX_TYPE); -void -key_def_create(struct key_def *def, uint32_t id, - enum index_type type, bool is_unique, uint32_t part_count) +struct key_def * +key_def_new(uint32_t id, enum index_type type, bool is_unique, + uint32_t part_count) { + uint32_t parts_size = sizeof(struct key_part) * part_count; + struct key_def *def = (struct key_def *) + malloc(parts_size + sizeof(*def)); def->type = type; def->id = id; def->is_unique = is_unique; def->part_count = part_count; - uint32_t parts_size = sizeof(struct key_part) * def->part_count; - def->parts = (struct key_part *) malloc(parts_size); memset(def->parts, 0, parts_size); + return def; } /** Free a key definition. */ void -key_def_destroy(struct key_def *key_def) +key_def_delete(struct key_def *key_def) { - free(key_def->parts); + free(key_def); } - diff --git a/src/box/key_def.h b/src/box/key_def.h index 03939f7e8e..8dd6216807 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -53,12 +53,12 @@ field_type_maxlen(enum field_type type) return maxlen[type]; } -#define INDEX_TYPE(_) \ +#define ENUM_INDEX_TYPE(_) \ _(HASH, 0) /* HASH Index */ \ _(TREE, 1) /* TREE Index */ \ _(BITSET, 2) /* BITSET Index */ \ -ENUM(index_type, INDEX_TYPE); +ENUM(index_type, ENUM_INDEX_TYPE); extern const char *index_type_strs[]; /** Descriptor of a single part in a multipart key. */ @@ -69,23 +69,36 @@ struct key_part { /* Descriptor of a multipart key. */ struct key_def { + /* A link in key list. */ + struct rlist link; /** Ordinal index number in the index array. */ uint32_t id; /** The size of the 'parts' array. */ uint32_t part_count; - /** Description of parts of a multipart index. */ - struct key_part *parts; /** Index type. */ enum index_type type; /** Is this key unique. */ bool is_unique; + /** Description of parts of a multipart index. */ + struct key_part parts[]; }; /** Initialize a pre-allocated key_def. */ -void -key_def_create(struct key_def *def, uint32_t id, - enum index_type type, bool is_unique, - uint32_t part_count); +struct key_def * +key_def_new(uint32_t id, enum index_type type, + bool is_unique, uint32_t part_count); + +static inline struct key_def * +key_def_dup(struct key_def *def) +{ + struct key_def *dup = key_def_new(def->id, def->type, def->is_unique, + def->part_count); + if (dup) { + memcpy(dup->parts, def->parts, + def->part_count * sizeof(*def->parts)); + } + return dup; +} /** * Set a single key part in a key def. @@ -100,8 +113,17 @@ key_def_set_part(struct key_def *def, uint32_t part_no, def->parts[part_no].type = type; } +/* Destroy and free a key_def. */ void -key_def_destroy(struct key_def *def); +key_def_delete(struct key_def *def); + +/** Add a key to the list of keys. */ +static inline void +key_list_add_key(struct rlist *key_list, struct key_def *key) +{ + rlist_add_entry(key_list, key, link); +} + /** Space metadata. */ struct space_def { diff --git a/src/box/lua/box.lua b/src/box/lua/box.lua index 30265e439e..bf67a9ca56 100644 --- a/src/box/lua/box.lua +++ b/src/box/lua/box.lua @@ -2,8 +2,6 @@ box.flags = { BOX_RETURN_TUPLE = 0x01, BOX_ADD = 0x02, BOX_REPLACE = 0x04 } - - -- -- -- diff --git a/src/box/request.cc b/src/box/request.cc index 87ff5e8cae..9e72464d7e 100644 --- a/src/box/request.cc +++ b/src/box/request.cc @@ -31,6 +31,7 @@ #include "tuple.h" #include "index.h" #include "space.h" +#include "schema.h" #include "port.h" #include "box_lua.h" #include <errinj.h> @@ -78,7 +79,7 @@ execute_replace(const struct request *request, struct txn *txn, txn_replace(txn, space, NULL, new_tuple, mode); } catch (const Exception &e) { - tuple_free(new_tuple); + tuple_delete(new_tuple); throw; } } @@ -93,9 +94,9 @@ execute_update(const struct request *request, struct txn *txn, /** Search key and key part count. */ struct space *space = space_find(request->u.space_no); - Index *pk = space_index(space, 0); + Index *pk = index_find(space, 0); /* Try to find the tuple by primary key. */ - primary_key_validate(&pk->key_def, request->u.key, + primary_key_validate(pk->key_def, request->u.key, request->u.key_part_count); struct tuple *old_tuple = pk->findByKey(request->u.key, request->u.key_part_count); @@ -113,7 +114,7 @@ execute_update(const struct request *request, struct txn *txn, space_validate_tuple(space, new_tuple); txn_replace(txn, space, old_tuple, new_tuple, DUP_INSERT); } catch (const Exception &e) { - tuple_free(new_tuple); + tuple_delete(new_tuple); throw; } } @@ -149,7 +150,7 @@ execute_select(const struct request *request, struct txn *txn, &key_part_count); struct iterator *it = index->position(); - key_validate(&index->key_def, ITER_EQ, key, key_part_count); + key_validate(index->key_def, ITER_EQ, key, key_part_count); index->initIterator(it, ITER_EQ, key, key_part_count); struct tuple *tuple; @@ -179,8 +180,8 @@ execute_delete(const struct request *request, struct txn *txn, struct space *space = space_find(request->d.space_no); /* Try to find tuple by primary key */ - Index *pk = space_index(space, 0); - primary_key_validate(&pk->key_def, request->d.key, + Index *pk = index_find(space, 0); + primary_key_validate(pk->key_def, request->d.key, request->d.key_part_count); struct tuple *old_tuple = pk->findByKey(request->d.key, request->d.key_part_count); diff --git a/src/box/schema.cc b/src/box/schema.cc new file mode 100644 index 0000000000..2ef8f3cc1b --- /dev/null +++ b/src/box/schema.cc @@ -0,0 +1,435 @@ +/* + * 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 "schema.h" +#include "space.h" +#include "assoc.h" +#include "lua/init.h" +#include "box_lua_space.h" +#include "key_def.h" +extern "C" { +#include <cfg/warning.h> +#include <cfg/tarantool_box_cfg.h> +} /* extern "C" */ +/** + * @module Data Dictionary + * + * The data dictionary is responsible for storage and caching + * of system metadata, such as information about existing + * spaces, indexes, tuple formats. + * + * struct space is an in-memory instance representing a single + * space with its metadata, space data, and methods to manage + * it. + */ + +/** All existing spaces. */ +static struct mh_i32ptr_t *spaces; + +static void +space_config(); + +/** Return space by its number */ +struct space * +space_by_id(uint32_t id) +{ + mh_int_t space = mh_i32ptr_find(spaces, id, NULL); + if (space == mh_end(spaces)) + return NULL; + return (struct space *) mh_i32ptr_node(spaces, space)->val; +} + +/** + * Visit all spaces and apply 'func'. + */ +void +space_foreach(void (*func)(struct space *sp, void *udata), void *udata) +{ + mh_int_t i; + mh_foreach(spaces, i) { + struct space *space = (struct space *) + mh_i32ptr_node(spaces, i)->val; + func(space, udata); + } +} + +/** Delete a space from the space cache and Lua. */ +struct space * +space_cache_delete(uint32_t id) +{ + if (tarantool_L) + box_lua_space_delete(tarantool_L, id); + mh_int_t k = mh_i32ptr_find(spaces, id, NULL); + assert(k != mh_end(spaces)); + struct space *space = (struct space *)mh_i32ptr_node(spaces, k)->val; + mh_i32ptr_del(spaces, k, NULL); + return space; +} + +/** + * Update the space in the space cache and in Lua. Returns + * the old space instance, if any, or NULL if it's a new space. + */ +struct space * +space_cache_replace(struct space *space) +{ + const struct mh_i32ptr_node_t node = { space_id(space), space }; + struct mh_i32ptr_node_t old, *p_old = &old; + mh_int_t k = mh_i32ptr_put(spaces, &node, &p_old, NULL); + if (k == mh_end(spaces)) { + panic_syserror("Out of memory for the data " + "dictionary cache."); + } + /* + * Must be after the space is put into the hash, since + * box.schema.space.bless() uses hash look up to find the + * space and create userdata objects for space objects. + */ + box_lua_space_new(tarantool_L, space); + return p_old ? (struct space *) p_old->val : NULL; +} + +static void +do_one_recover_step(struct space *space, void * /* param */) +{ + if (space_index(space, 0)) + space->engine.recover(space); + else + space->engine = engine_no_keys; +} + +/** + * Initialize a prototype for the two mandatory data + * dictionary spaces and create a cache entry for them. + * When restoring data from the snapshot these spaces + * will get altered automatically to their actual format. + */ +void +schema_init() +{ + /* Initialize the space cache. */ + spaces = mh_i32ptr_new(); + space_config(); + space_foreach(do_one_recover_step, NULL); +} + +void +space_end_recover_snapshot() +{ + /* + * For all new spaces created from now on, when the + * PRIMARY key is added, enable it right away. + */ + engine_no_keys.recover = space_build_primary_key; + space_foreach(do_one_recover_step, NULL); +} + +void +space_end_recover() +{ + /* + * For all new spaces created after recovery is complete, + * when the primary key is added, enable all keys. + */ + engine_no_keys.recover = space_build_all_keys; + space_foreach(do_one_recover_step, NULL); +} + +void +schema_free(void) +{ + while (mh_size(spaces) > 0) { + mh_int_t i = mh_first(spaces); + + struct space *space = (struct space *) + mh_i32ptr_node(spaces, i)->val; + space_cache_delete(space_id(space)); + space_delete(space); + } + mh_i32ptr_delete(spaces); +} + +struct key_def * +key_def_new_from_cfg(uint32_t id, + struct tarantool_cfg_space_index *cfg_index) +{ + uint32_t part_count = 0; + enum index_type type = STR2ENUM(index_type, cfg_index->type); + + if (type == index_type_MAX) + tnt_raise(LoggedError, ER_INDEX_TYPE, cfg_index->type); + + /* Find out key part count. */ + for (uint32_t k = 0; cfg_index->key_field[k] != NULL; ++k) { + auto cfg_key = cfg_index->key_field[k]; + + if (cfg_key->fieldno == -1) { + /* last filled key reached */ + break; + } + part_count++; + } + + struct key_def *key= key_def_new(id, type, cfg_index->unique, + part_count); + + for (uint32_t k = 0; k < part_count; k++) { + auto cfg_key = cfg_index->key_field[k]; + + key_def_set_part(key, k, cfg_key->fieldno, + STR2ENUM(field_type, cfg_key->type)); + } + return key; +} + +static void +space_config() +{ + extern tarantool_cfg cfg; + /* exit if no spaces are configured */ + if (cfg.space == NULL) { + return; + } + + /* fill box spaces */ + for (uint32_t i = 0; cfg.space[i] != NULL; ++i) { + struct space_def space_def; + space_def.id = i; + tarantool_cfg_space *cfg_space = cfg.space[i]; + + if (!CNF_STRUCT_DEFINED(cfg_space) || !cfg_space->enabled) + continue; + + assert(cfg.memcached_port == 0 || i != cfg.memcached_space); + + space_def.arity = (cfg_space->arity != -1 ? + cfg_space->arity : 0); + + struct rlist key_defs; + rlist_create(&key_defs); + struct key_def *key; + + for (uint32_t j = 0; cfg_space->index[j] != NULL; ++j) { + auto cfg_index = cfg_space->index[j]; + key = key_def_new_from_cfg(j, cfg_index); + key_list_add_key(&key_defs, key); + } + space_cache_replace(space_new(&space_def, &key_defs)); + + say_info("space %i successfully configured", i); + } +} + +int +check_spaces(struct tarantool_cfg *conf) +{ + /* exit if no spaces are configured */ + if (conf->space == NULL) { + return 0; + } + + for (size_t i = 0; conf->space[i] != NULL; ++i) { + auto space = conf->space[i]; + + if (i >= BOX_SPACE_MAX) { + out_warning(CNF_OK, "(space = %zu) invalid id, (maximum=%u)", + i, BOX_SPACE_MAX); + return -1; + } + + if (!CNF_STRUCT_DEFINED(space)) { + /* space undefined, skip it */ + continue; + } + + if (!space->enabled) { + /* space disabled, skip it */ + continue; + } + + if (conf->memcached_port && i == conf->memcached_space) { + out_warning(CNF_OK, "Space %zu is already used as " + "memcached_space.", i); + return -1; + } + + /* at least one index in space must be defined + * */ + if (space->index == NULL) { + out_warning(CNF_OK, "(space = %zu) " + "at least one index must be defined", i); + return -1; + } + + uint32_t max_key_fieldno = 0; + + /* check spaces indexes */ + for (size_t j = 0; space->index[j] != NULL; ++j) { + auto index = space->index[j]; + uint32_t key_part_count = 0; + enum index_type index_type; + + /* check index bound */ + if (j >= BOX_INDEX_MAX) { + /* maximum index in space reached */ + out_warning(CNF_OK, "(space = %zu index = %zu) " + "too many indexed (%u maximum)", i, j, BOX_INDEX_MAX); + return -1; + } + + /* at least one key in index must be defined */ + if (index->key_field == NULL) { + out_warning(CNF_OK, "(space = %zu index = %zu) " + "at least one field must be defined", i, j); + return -1; + } + + /* check unique property */ + if (index->unique == -1) { + /* unique property undefined */ + out_warning(CNF_OK, "(space = %zu index = %zu) " + "unique property is undefined", i, j); + } + + for (size_t k = 0; index->key_field[k] != NULL; ++k) { + auto key = index->key_field[k]; + + if (key->fieldno == -1) { + /* last key reached */ + break; + } + + if (key->fieldno >= BOX_FIELD_MAX) { + /* maximum index in space reached */ + out_warning(CNF_OK, "(space = %zu index = %zu) " + "invalid field number (%u maximum)", + i, j, BOX_FIELD_MAX); + return -1; + } + + /* key must has valid type */ + if (STR2ENUM(field_type, key->type) == field_type_MAX) { + out_warning(CNF_OK, "(space = %zu index = %zu) " + "unknown field data type: `%s'", i, j, key->type); + return -1; + } + + if (max_key_fieldno < key->fieldno + 1) { + max_key_fieldno = key->fieldno + 1; + } + + ++key_part_count; + } + + /* Check key part count. */ + if (key_part_count == 0) { + out_warning(CNF_OK, "(space = %zu index = %zu) " + "at least one field must be defined", i, j); + return -1; + } + + index_type = STR2ENUM(index_type, index->type); + + /* check index type */ + if (index_type == index_type_MAX) { + out_warning(CNF_OK, "(space = %zu index = %zu) " + "unknown index type '%s'", i, j, index->type); + return -1; + } + + /* First index must be unique. */ + if (j == 0 && index->unique == false) { + out_warning(CNF_OK, "(space = %zu) space first index must be unique", i); + return -1; + } + + switch (index_type) { + case HASH: + /* check hash index */ + /* hash index must be unique */ + if (!index->unique) { + out_warning(CNF_OK, "(space = %zu index = %zu) " + "hash index must be unique", i, j); + return -1; + } + break; + 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(CNF_OK, "(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(CNF_OK, "(space = %zu index = %zu) " + "bitset index must be non-unique", i, j); + return -1; + } + break; + default: + assert(false); + } + } + + /* Check for index field type conflicts */ + if (max_key_fieldno > 0) { + char *types = (char *) alloca(max_key_fieldno); + memset(types, 0, max_key_fieldno); + for (size_t j = 0; space->index[j] != NULL; ++j) { + auto index = space->index[j]; + for (size_t k = 0; index->key_field[k] != NULL; ++k) { + auto key = index->key_field[k]; + if (key->fieldno == -1) + break; + + uint32_t f = key->fieldno; + enum field_type t = STR2ENUM(field_type, key->type); + assert(t != field_type_MAX); + if (types[f] != t) { + if (types[f] == UNKNOWN) { + types[f] = t; + } else { + out_warning(CNF_OK, "(space = %zu fieldno = %zu) " + "index field type mismatch", i, f); + return -1; + } + } + } + + } + } + } + + return 0; +} + diff --git a/src/box/schema.h b/src/box/schema.h new file mode 100644 index 0000000000..85ecf97b89 --- /dev/null +++ b/src/box/schema.h @@ -0,0 +1,94 @@ +#ifndef INCLUDES_TARANTOOL_BOX_DATADICT_H +#define INCLUDES_TARANTOOL_BOX_DATADICT_H +/* + * 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 "exception.h" + +struct space; + +/** Call a visitor function on every space in the space cache. */ +void +space_foreach(void (*func)(struct space *sp, void *udata), void *udata); + +/** + * Try to look up a space by space number in the space cache. + * + * @return NULL if space not found, otherwise space object. + */ +struct space * +space_by_id(uint32_t id); + +static inline struct space * +space_find(uint32_t id) +{ + struct space *space = space_by_id(id); + if (space) + return space; + + tnt_raise(ClientError, ER_NO_SUCH_SPACE, id); +} + +/** + * Update contents of the space cache. Typically the new space is + * an altered version of the original space. + * Returns the old space, if any. + */ +struct space * +space_cache_replace(struct space *space); + +/** Delete a space from the space cache. */ +struct space * +space_cache_delete(uint32_t id); + +void +schema_init(); + +void +schema_free(); + +/** + * Called at the end of recovery from snapshot. + * Build primary keys in all spaces. + * */ +void +space_end_recover_snapshot(); + +/** + * Called at the end of recovery. + * Build secondary keys in all spaces. + */ +void +space_end_recover(); + +struct tarantool_cfg; + +int +check_spaces(struct tarantool_cfg *conf); + +#endif /* INCLUDES_TARANTOOL_BOX_DATADICT_H */ diff --git a/src/box/space.cc b/src/box/space.cc index 4a565b8f3a..186a701358 100644 --- a/src/box/space.cc +++ b/src/box/space.cc @@ -29,144 +29,136 @@ #include "space.h" #include <stdlib.h> #include <string.h> -extern "C" { -#include <cfg/warning.h> -#include <cfg/tarantool_box_cfg.h> -} /* extern "C" */ -#include <tarantool.h> #include <exception.h> #include "tuple.h" -#include <pickle.h> -#include <palloc.h> -#include <assoc.h> -#include <box/box.h> -#include "lua/init.h" -#include "box_lua_space.h" - -static struct mh_i32ptr_t *spaces; +void +space_fill_index_map(struct space *space) +{ + space->index_count = 0; + for (uint32_t j = 0; j <= space->index_id_max; j++) { + Index *index = space->index_map[j]; + if (index) + space->index[space->index_count++] = index; + } +} struct space * -space_new(struct space_def *space_def, struct key_def *key_defs, - uint32_t key_count) +space_new(struct space_def *space_def, struct rlist *key_list) { - struct space *space = space_by_id(space_def->id); - if (space) - tnt_raise(LoggedError, ER_SPACE_EXISTS, space_def->id); - uint32_t index_id_max = 0; - for (uint32_t j = 0; j < key_count; ++j) - index_id_max = MAX(index_id_max, key_defs[j].id); - + uint32_t index_count = 0; + struct key_def *key_def; + rlist_foreach_entry(key_def, key_list, link) { + index_count++; + index_id_max = MAX(index_id_max, key_def->id); + } size_t sz = sizeof(struct space) + - (key_count + index_id_max + 1) * sizeof(Index *); - space = (struct space *) calloc(1, sz); + (index_count + index_id_max + 1) * sizeof(Index *); + struct space *space = (struct space *) calloc(1, sz); + + if (space == NULL) + return NULL; space->index_map = (Index **)((char *) space + sizeof(*space) + - key_count * sizeof(Index *)); + index_count * sizeof(Index *)); space->def = *space_def; - space->format = tuple_format_new(key_defs, key_count); + space->format = tuple_format_new(key_list); + tuple_format_ref(space->format, 1); space->index_id_max = index_id_max; /* fill space indexes */ - for (uint32_t j = 0; j < key_count; ++j) { - struct key_def *key_def = &key_defs[j]; - Index *index = Index::factory(key_def); + rlist_foreach_entry(key_def, key_list, link) { + struct key_def *dup = key_def_dup(key_def); + if (dup == NULL) + goto error; + Index *index = Index::factory(dup); if (index == NULL) { - tnt_raise(LoggedError, ER_MEMORY_ISSUE, - "class Index", "malloc"); + key_def_delete(dup); + goto error; } space->index_map[key_def->id] = index; } - /* - * Initialize the primary key, but do not the secondary - * keys - they are built by space_build_secondary_keys(). - */ - space->index[space->index_count++] = space->index_map[0]; - - const struct mh_i32ptr_node_t node = { space_id(space), space }; - mh_i32ptr_put(spaces, &node, NULL, NULL); - /* - * Must be after the space is put into the hash, since - * box.bless_space() uses hash look up to find the space - * and create userdata objects for space objects. - */ - box_lua_space_new(tarantool_L, space); + space_fill_index_map(space); + space->engine = engine_no_keys; return space; +error: + space_delete(space); + return NULL; } void -space_build_secondary_keys(struct space *space) -{ - if (space->index_id_max == 0) - return; /* no secondary keys */ - - Index *pk = space->index_map[0]; - uint32_t n_tuples = pk->size(); - - if (n_tuples > 0) { - say_info("Building secondary indexes in space %d...", - space_id(space)); - } - - for (uint32_t j = 1; j <= space->index_id_max; j++) { - Index *index = space->index_map[j]; - if (index) { - index_build(index, pk); - space->index[space->index_count++] = index; - } - } - - if (n_tuples > 0) { - say_info("Space %d: done", space_id(space)); - } -} - -static void space_delete(struct space *space) { - if (tarantool_L) - box_lua_space_delete(tarantool_L, space); - mh_int_t k = mh_i32ptr_find(spaces, space_id(space), NULL); - assert(k != mh_end(spaces)); - mh_i32ptr_del(spaces, k, NULL); - for (uint32_t j = 0 ; j <= space->index_id_max; j++) - delete space->index_map[j]; + for (uint32_t j = 0; j < space->index_count; j++) + delete space->index[j]; + tuple_format_ref(space->format, -1); free(space); } -/* return space by its number */ -struct space * -space_by_id(uint32_t id) +/** + * A version of space_replace for a space which has + * no indexes (is not yet fully built). + */ +struct tuple * +space_replace_no_keys(struct space *space, struct tuple * /* old_tuple */, + struct tuple * /* new_tuple */, + enum dup_replace_mode /* mode */) { - mh_int_t space = mh_i32ptr_find(spaces, id, NULL); - if (space == mh_end(spaces)) - return NULL; - return (struct space *) mh_i32ptr_node(spaces, space)->val; + Index *index = index_find(space, 0); + assert(index == NULL); /* not reached. */ + (void) index; + return NULL; /* replace found no old tuple */ } -/** - * Visit all enabled spaces and apply 'func'. - */ +/** Do nothing if the space is already recovered. */ void -space_foreach(void (*func)(struct space *sp, void *udata), void *udata) { +space_noop(struct space * /* space */) +{} - mh_int_t i; - mh_foreach(spaces, i) { - struct space *space = (struct space *) - mh_i32ptr_node(spaces, i)->val; - func(space, udata); +/** + * A short-cut version of space_replace() used during bulk load + * from snapshot. + */ +struct tuple * +space_replace_build_next(struct space *space, struct tuple *old_tuple, + struct tuple *new_tuple, enum dup_replace_mode mode) +{ + assert(old_tuple == NULL && mode == DUP_INSERT); + (void) mode; + if (old_tuple) { + /* + * Called from txn_rollback() In practice + * is impossible: all possible checks for tuple + * validity are done before the space is changed, + * and WAL is off, so this part can't fail. + */ + panic("Failed to commit transaction when loading " + "from snapshot"); } + space->index[0]->buildNext(new_tuple); + return NULL; /* replace found no old tuple */ } +/** + * A short-cut version of space_replace() used when loading + * data from XLOG files. + */ struct tuple * -space_replace(struct space *space, struct tuple *old_tuple, - struct tuple *new_tuple, enum dup_replace_mode mode) +space_replace_primary_key(struct space *space, struct tuple *old_tuple, + struct tuple *new_tuple, enum dup_replace_mode mode) +{ + return space->index[0]->replace(old_tuple, new_tuple, mode); +} + +static struct tuple * +space_replace_all_keys(struct space *space, struct tuple *old_tuple, + struct tuple *new_tuple, enum dup_replace_mode mode) { uint32_t i = 0; try { /* Update the primary key */ Index *pk = space->index[0]; - assert(pk->key_def.is_unique); + assert(pk->key_def->is_unique); /* * If old_tuple is not NULL, the index * has to find and delete it, or raise an @@ -175,11 +167,7 @@ space_replace(struct space *space, struct tuple *old_tuple, old_tuple = pk->replace(old_tuple, new_tuple, mode); assert(old_tuple || new_tuple); - /* - * Update secondary keys. When loading data from - * the WAL secondary keys are not enabled - * (index_count is 1). - */ + /* Update secondary keys. */ for (i++; i < space->index_count; i++) { Index *index = space->index[i]; index->replace(old_tuple, new_tuple, DUP_INSERT); @@ -198,336 +186,107 @@ space_replace(struct space *space, struct tuple *old_tuple, return NULL; } +/** + * Secondary indexes are built in bulk after all data is + * recovered. This function enables secondary keys on a space. + * Data dictionary spaces are an exception, they are fully + * built right from the start. + */ void -space_validate_tuple(struct space *sp, struct tuple *new_tuple) -{ - if (sp->def.arity > 0 && sp->def.arity != new_tuple->field_count) - tnt_raise(IllegalParams, - "tuple field count must match space arity"); - -} - -void -space_free(void) -{ - while (mh_size(spaces) > 0) { - mh_int_t i = mh_first(spaces); - - struct space *space = (struct space *) - mh_i32ptr_node(spaces, i)->val; - space_delete(space); - } - tuple_free(); -} - -void -key_def_create_from_cfg(struct key_def *def, uint32_t id, - struct tarantool_cfg_space_index *cfg_index) +space_build_secondary_keys(struct space *space) { - uint32_t part_count = 0; - enum index_type type = STR2ENUM(index_type, cfg_index->type); - - if (type == index_type_MAX) - tnt_raise(LoggedError, ER_INDEX_TYPE, cfg_index->type); - - /* Find out key part count. */ - for (uint32_t k = 0; cfg_index->key_field[k] != NULL; ++k) { - auto cfg_key = cfg_index->key_field[k]; + if (space->index_id_max > 0) { + Index *pk = space->index[0]; + uint32_t n_tuples = pk->size(); - if (cfg_key->fieldno == -1) { - /* last filled key reached */ - break; + if (n_tuples > 0) { + say_info("Building secondary indexes in space %d...", + space_id(space)); } - part_count++; - } - key_def_create(def, id, type, cfg_index->unique, part_count); + for (uint32_t j = 1; j < space->index_count; j++) + index_build(space->index[j], pk); - for (uint32_t k = 0; k < part_count; k++) { - auto cfg_key = cfg_index->key_field[k]; - - key_def_set_part(def, k, cfg_key->fieldno, - STR2ENUM(field_type, cfg_key->type)); - } -} - - -static void -space_config() -{ - /* exit if no spaces are configured */ - if (cfg.space == NULL) { - return; - } - - /* fill box spaces */ - for (uint32_t i = 0; cfg.space[i] != NULL; ++i) { - struct space_def space_def; - space_def.id = i; - tarantool_cfg_space *cfg_space = cfg.space[i]; - - if (!CNF_STRUCT_DEFINED(cfg_space) || !cfg_space->enabled) - continue; - - assert(cfg.memcached_port == 0 || i != cfg.memcached_space); - - space_def.arity = (cfg_space->arity != -1 ? - cfg_space->arity : 0); - /* - * Collect key/field info. We need aggregate - * information on all keys before we can create - * indexes. - */ - uint32_t key_count = 0; - while (cfg_space->index[key_count] != NULL) - key_count++; - - struct key_def *key_defs = (struct key_def *) - malloc(key_count * sizeof(struct key_def)); - - for (uint32_t j = 0; cfg_space->index[j] != NULL; ++j) { - auto cfg_index = cfg_space->index[j]; - key_def_create_from_cfg(&key_defs[j], j, cfg_index); + if (n_tuples > 0) { + say_info("Space %d: done", space_id(space)); } - (void) space_new(&space_def, key_defs, key_count); - free(key_defs); - - say_info("space %i successfully configured", i); } + space->engine.state = READY_ALL_KEYS; + space->engine.recover = space_noop; /* mark the end of recover */ + space->engine.replace = space_replace_all_keys; } +/** Build the primary key after loading data from a snapshot. */ void -space_init(void) +space_end_build_primary_key(struct space *space) { - spaces = mh_i32ptr_new(); - tuple_init(); - - /* configure regular spaces */ - space_config(); + space->index[0]->endBuild(); + space->engine.state = READY_PRIMARY_KEY; + space->engine.replace = space_replace_primary_key; + space->engine.recover = space_build_secondary_keys; } +/** Prepare the primary key for bulk load (loading from + * a snapshot). + */ void -begin_build_primary_indexes(void) +space_begin_build_primary_key(struct space *space) { - mh_int_t i; - - mh_foreach(spaces, i) { - struct space *space = (struct space *) - mh_i32ptr_node(spaces, i)->val; - Index *index = space->index[0]; - index->beginBuild(); - } + space->index[0]->beginBuild(); + space->engine.replace = space_replace_build_next; + space->engine.recover = space_end_build_primary_key; } +/** + * Bring a space up to speed if its primary key is added during + * XLOG recovery. This is a recovery function called on + * spaces which had no primary key at the end of snapshot + * recovery, and got one only when reading an XLOG. + */ void -end_build_primary_indexes(void) +space_build_primary_key(struct space *space) { - mh_int_t i; - mh_foreach(spaces, i) { - struct space *space = (struct space *) - mh_i32ptr_node(spaces, i)->val; - Index *index = space->index[0]; - index->endBuild(); - } + space_begin_build_primary_key(space); + space_end_build_primary_key(space); } +/** Bring a space up to speed once it's got a primary key. + * + * This is a recovery function used for all spaces added after the + * end of SNAP/XLOG recovery. + */ void -build_secondary_indexes(void) +space_build_all_keys(struct space *space) { - mh_int_t i; - mh_foreach(spaces, i) { - struct space *space = (struct space *) - mh_i32ptr_node(spaces, i)->val; - - space_build_secondary_keys(space); - } + space_build_primary_key(space); + space_build_secondary_keys(space); } -int -check_spaces(struct tarantool_cfg *conf) -{ - /* exit if no spaces are configured */ - if (conf->space == NULL) { - return 0; - } - - for (size_t i = 0; conf->space[i] != NULL; ++i) { - auto space = conf->space[i]; - - if (i >= BOX_SPACE_MAX) { - out_warning(CNF_OK, "(space = %zu) invalid id, (maximum=%u)", - i, BOX_SPACE_MAX); - return -1; - } - - if (!CNF_STRUCT_DEFINED(space)) { - /* space undefined, skip it */ - continue; - } - - if (!space->enabled) { - /* space disabled, skip it */ - continue; - } - - if (conf->memcached_port && i == conf->memcached_space) { - out_warning(CNF_OK, "Space %zu is already used as " - "memcached_space.", i); - return -1; - } - - /* at least one index in space must be defined - * */ - if (space->index == NULL) { - out_warning(CNF_OK, "(space = %zu) " - "at least one index must be defined", i); - return -1; - } - - uint32_t max_key_fieldno = 0; - - /* check spaces indexes */ - for (size_t j = 0; space->index[j] != NULL; ++j) { - auto index = space->index[j]; - uint32_t key_part_count = 0; - enum index_type index_type; - - /* check index bound */ - if (j >= BOX_INDEX_MAX) { - /* maximum index in space reached */ - out_warning(CNF_OK, "(space = %zu index = %zu) " - "too many indexed (%u maximum)", i, j, BOX_INDEX_MAX); - return -1; - } - - /* at least one key in index must be defined */ - if (index->key_field == NULL) { - out_warning(CNF_OK, "(space = %zu index = %zu) " - "at least one field must be defined", i, j); - return -1; - } - - /* check unique property */ - if (index->unique == -1) { - /* unique property undefined */ - out_warning(CNF_OK, "(space = %zu index = %zu) " - "unique property is undefined", i, j); - } - - for (size_t k = 0; index->key_field[k] != NULL; ++k) { - auto key = index->key_field[k]; - - if (key->fieldno == -1) { - /* last key reached */ - break; - } - - if (key->fieldno >= BOX_FIELD_MAX) { - /* maximum index in space reached */ - out_warning(CNF_OK, "(space = %zu index = %zu) " - "invalid field number (%u maximum)", - i, j, BOX_FIELD_MAX); - return -1; - } - - /* key must has valid type */ - if (STR2ENUM(field_type, key->type) == field_type_MAX) { - out_warning(CNF_OK, "(space = %zu index = %zu) " - "unknown field data type: `%s'", i, j, key->type); - return -1; - } - - if (max_key_fieldno < key->fieldno + 1) { - max_key_fieldno = key->fieldno + 1; - } - - ++key_part_count; - } - - /* Check key part count. */ - if (key_part_count == 0) { - out_warning(CNF_OK, "(space = %zu index = %zu) " - "at least one field must be defined", i, j); - return -1; - } - - index_type = STR2ENUM(index_type, index->type); - - /* check index type */ - if (index_type == index_type_MAX) { - out_warning(CNF_OK, "(space = %zu index = %zu) " - "unknown index type '%s'", i, j, index->type); - return -1; - } - - /* First index must be unique. */ - if (j == 0 && index->unique == false) { - out_warning(CNF_OK, "(space = %zu) space first index must be unique", i); - return -1; - } - - switch (index_type) { - case HASH: - /* check hash index */ - /* hash index must be unique */ - if (!index->unique) { - out_warning(CNF_OK, "(space = %zu index = %zu) " - "hash index must be unique", i, j); - return -1; - } - break; - 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(CNF_OK, "(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(CNF_OK, "(space = %zu index = %zu) " - "bitset index must be non-unique", i, j); - return -1; - } - break; - default: - assert(false); - } - } - - /* Check for index field type conflicts */ - if (max_key_fieldno > 0) { - char *types = (char *) alloca(max_key_fieldno); - memset(types, 0, max_key_fieldno); - for (size_t j = 0; space->index[j] != NULL; ++j) { - auto index = space->index[j]; - for (size_t k = 0; index->key_field[k] != NULL; ++k) { - auto key = index->key_field[k]; - if (key->fieldno == -1) - break; - - uint32_t f = key->fieldno; - enum field_type t = STR2ENUM(field_type, key->type); - assert(t != field_type_MAX); - if (types[f] != t) { - if (types[f] == UNKNOWN) { - types[f] = t; - } else { - out_warning(CNF_OK, "(space = %zu fieldno = %zu) " - "index field type mismatch", i, f); - return -1; - } - } - } +/** + * This is a vtab with which a newly created space which has no + * keys is primed. + * At first it is set to correctly work for spaces created during + * recovery from snapshot. In process of recovery it is updated as + * below: + * + * 1) after SNAP is loaded: + * recover = space_build_primary_key + * 2) when all XLOGs are loaded: + * recover = space_build_all_keys + */ +struct engine engine_no_keys = { + /* .state = */ READY_NO_KEYS, + /* .recover = */ space_begin_build_primary_key, + /* .replace = */ space_replace_no_keys +}; - } - } - } +void +space_validate_tuple(struct space *sp, struct tuple *new_tuple) +{ + if (sp->def.arity > 0 && sp->def.arity != new_tuple->field_count) + tnt_raise(IllegalParams, + "tuple field count must match space arity"); - return 0; } +/* vim: set fm=marker */ diff --git a/src/box/space.h b/src/box/space.h index d3b6c99b74..91aa007054 100644 --- a/src/box/space.h +++ b/src/box/space.h @@ -32,11 +32,57 @@ #include "key_def.h" #include <exception.h> -#include <box/box.h> +typedef void (*space_f)(struct space *space); +typedef struct tuple *(*space_replace_f) + (struct space *space, struct tuple *old_tuple, + struct tuple *new_tuple, enum dup_replace_mode mode); -struct tarantool_cfg; +/** Reflects what space_replace() is supposed to do. */ +enum space_state { + /** + * The space is created, but has no data + * and no primary key, or, if there is a primary + * key, it's not ready for use (being built with + * buildNext()). + * Replace is always an error, since there are no + * indexes to add data to. + */ + READY_NO_KEYS, + /** + * The space has a functional primary key. + * Replace adds the tuple to this key. + */ + READY_PRIMARY_KEY, + /** + * The space is fully functional, all keys + * are fully built, replace adds its tuple + * to all keys. + */ + READY_ALL_KEYS +}; + +struct engine { + enum space_state state; + /* Recover is called after each recover step to enable + * keys. When recovery is complete, it enables all keys + * at once and resets itself to a no-op. + */ + space_f recover; + space_replace_f replace; +}; + +extern struct engine engine_no_keys; +void space_build_primary_key(struct space *space); +void space_build_all_keys(struct space *space); struct space { + /** + * Reflects the current space state and is also a vtab + * with methods. Unlike a C++ vtab, changes during space + * life cycle, throughout phases of recovery or with + * deletion and addition of indexes. + */ + struct engine engine; /** * The number of *enabled* indexes in the space. * @@ -159,9 +205,13 @@ space_id(struct space *space) { return space->def.id; } * Otherwise, it's taken into account only for the * primary key. */ -struct tuple * +static inline struct tuple * space_replace(struct space *space, struct tuple *old_tuple, - struct tuple *new_tuple, enum dup_replace_mode mode); + struct tuple *new_tuple, enum dup_replace_mode mode) +{ + return space->engine.replace(space, old_tuple, new_tuple, + mode); +} /** * Check that the tuple has correct arity and correct field @@ -170,9 +220,21 @@ space_replace(struct space *space, struct tuple *old_tuple, void space_validate_tuple(struct space *sp, struct tuple *new_tuple); +/** + * Allocate and initialize a space. The space + * needs to be loaded before it can be used + * (see space->engine.recover()). + */ +struct space * +space_new(struct space_def *space_def, struct rlist *key_list); + +/** Destroy and free a space. */ +void +space_delete(struct space *space); + /** * Get index by index id. - * @return NULL if index not found. + * @return NULL if the index is not found. */ static inline Index * space_index(struct space *space, uint32_t id) @@ -183,49 +245,9 @@ space_index(struct space *space, uint32_t id) } /** - * Call a visitor function on every enabled space. - */ -void -space_foreach(void (*func)(struct space *sp, void *udata), void *udata); - -/** - * Try to look up a space by space number. - * - * @return NULL if space not found, otherwise space object. + * Look up index by id. + * Raise an error if the index is not found. */ -struct space *space_by_id(uint32_t id); - -static inline struct space * -space_find(uint32_t id) -{ - struct space *space = space_by_id(id); - if (space) - return space; - - tnt_raise(ClientError, ER_NO_SUCH_SPACE, id); -} - -struct space * -space_new(struct space_def *space_def, - struct key_def *key_defs, uint32_t key_count); - -/** - * Secondary indexes are built in bulk after all data is - * recovered. This flag indicates that the indexes are - * already built and ready for use. - */ -void -space_build_secondary_keys(struct space *space); - -void space_init(void); -void space_free(void); -int -check_spaces(struct tarantool_cfg *conf); -/* Build secondary keys. */ -void begin_build_primary_indexes(void); -void end_build_primary_indexes(void); -void build_secondary_indexes(void); - static inline Index * index_find(struct space *space, uint32_t index_id) { diff --git a/src/box/tree_index.cc b/src/box/tree_index.cc index 911765b266..1576001c1c 100644 --- a/src/box/tree_index.cc +++ b/src/box/tree_index.cc @@ -226,7 +226,7 @@ TreeIndex::random(uint32_t rnd) const struct tuple * TreeIndex::findByKey(const char *key, uint32_t part_count) const { - assert(key_def.is_unique && part_count == key_def.part_count); + assert(key_def->is_unique && part_count == key_def->part_count); struct sptree_index_key_data key_data; key_data.key = key; @@ -276,7 +276,7 @@ TreeIndex::allocIterator() const "TreeIndex", "iterator"); } - it->key_def = (struct key_def *) &key_def; + it->key_def = key_def; it->compare = tree.compare; it->base.free = tree_iterator_free; return (struct iterator *) it; @@ -374,7 +374,7 @@ TreeIndex::endBuild() if (n_tuples) { say_info("Sorting %" PRIu32 " keys in %s index %" PRIu32 "...", - n_tuples, index_type_strs[key_def.type], index_id(this)); + n_tuples, index_type_strs[key_def->type], index_id(this)); } uint32_t estimated_tuples = tree.max_size; void *nodes = tree.members; @@ -383,8 +383,8 @@ TreeIndex::endBuild() sptree_index_init(&tree, sizeof(struct tuple *), nodes, n_tuples, estimated_tuples, sptree_index_node_compare_with_key, - key_def.is_unique ? sptree_index_node_compare - : sptree_index_node_compare_dup, - &key_def); + key_def->is_unique ? sptree_index_node_compare + : sptree_index_node_compare_dup, + key_def); } diff --git a/src/box/tuple.cc b/src/box/tuple.cc index 32c8bb9d7e..ed370b1aee 100644 --- a/src/box/tuple.cc +++ b/src/box/tuple.cc @@ -34,102 +34,147 @@ #include "key_def.h" #include "tuple_update.h" #include <exception.h> -#include <palloc.h> -#include <fiber.h> -#include "scoped_guard.h" #include <stdio.h> +#include <third_party/base64.h> + +enum { FORMAT_ID_MAX = UINT16_MAX - 1, FORMAT_ID_NIL = UINT16_MAX }; /** Global table of tuple formats */ struct tuple_format **tuple_formats; struct tuple_format *tuple_format_ber; +static intptr_t recycled_format_ids = FORMAT_ID_NIL; static uint32_t formats_size, formats_capacity; /** Extract all available type info from keys. */ void field_type_create(enum field_type *types, uint32_t field_count, - struct key_def *key_def, uint32_t key_count) + struct rlist *key_list) { /* There may be fields between indexed fields (gaps). */ memset(types, 0, sizeof(*types) * field_count); - struct key_def *end = key_def + key_count; + struct key_def *key_def; /* extract field type info */ - for (; key_def < end; key_def++) { + rlist_foreach_entry(key_def, key_list, link) { struct key_part *part = key_def->parts; struct key_part *pend = part + key_def->part_count; for (; part < pend; part++) { - assert(part->fieldno < field_count); - types[part->fieldno] = part->type; + enum field_type *ptype = &types[part->fieldno]; + if (*ptype != UNKNOWN && *ptype != part->type) { + tnt_raise(ClientError, + ER_FIELD_TYPE_MISMATCH, + key_def->id, part - key_def->parts, + field_type_strs[part->type], + field_type_strs[*ptype]); + } + *ptype = part->type; } } } -static struct tuple_format * -tuple_format_alloc_and_register(struct key_def *key_def, - uint32_t key_count) +void +tuple_format_register(struct tuple_format *format) { - uint32_t total; - struct tuple_format *format; - struct key_def *end = key_def + key_count; - uint32_t max_fieldno = 0; - uint32_t field_count; - - /* find max max field no */ - for (; key_def < end; key_def++) { - struct key_part *part = key_def->parts; - struct key_part *pend = part + key_def->part_count; - for (; part < pend; part++) - max_fieldno= MAX(max_fieldno, part->fieldno); - } + if (recycled_format_ids != FORMAT_ID_NIL) { - if (formats_size == formats_capacity) { + format->id = (uint16_t) recycled_format_ids; + recycled_format_ids = (intptr_t) tuple_formats[recycled_format_ids]; + } else if (formats_size == formats_capacity) { uint32_t new_capacity = formats_capacity ? formats_capacity * 2 : 16; struct tuple_format **formats; - if (new_capacity >= UINT16_MAX) - goto error; - formats = (struct tuple_format **) realloc(tuple_formats, - new_capacity * sizeof(tuple_formats[0])); + if (new_capacity >= FORMAT_ID_MAX) { + tnt_raise(LoggedError, ER_TUPLE_FORMAT_LIMIT, + (unsigned) new_capacity); + } + formats = (struct tuple_format **) + realloc(tuple_formats, new_capacity * + sizeof(tuple_formats[0])); if (formats == NULL) - goto error; + tnt_raise(LoggedError, ER_MEMORY_ISSUE, + sizeof(struct tuple_format), + "tuple_formats", "malloc"); formats_capacity = new_capacity; tuple_formats = formats; + + format->id = formats_size++; + } else { + format->id = formats_size++; } - field_count = key_count > 0 ? max_fieldno + 1 : 0; + tuple_formats[format->id] = format; +} - total = sizeof(struct tuple_format) + +void +tuple_format_deregister(struct tuple_format *format) +{ + if (format->id == FORMAT_ID_NIL) + return; + tuple_formats[format->id] = (struct tuple_format *) recycled_format_ids; + recycled_format_ids = format->id; + format->id = FORMAT_ID_NIL; +} + +static struct tuple_format * +tuple_format_alloc(struct rlist *key_list) +{ + struct key_def *key_def; + uint32_t max_fieldno = 0; + uint32_t key_count = 0; + + /* find max max field no */ + rlist_foreach_entry(key_def, key_list, link) { + struct key_part *part = key_def->parts; + struct key_part *pend = part + key_def->part_count; + key_count++; + for (; part < pend; part++) + max_fieldno = MAX(max_fieldno, part->fieldno); + } + uint32_t field_count = key_count > 0 ? max_fieldno + 1 : 0; + + uint32_t total = sizeof(struct tuple_format) + field_count * sizeof(int32_t) + field_count * sizeof(enum field_type); - format = (struct tuple_format *) malloc(total); + struct tuple_format *format = (struct tuple_format *) malloc(total); - if (format == NULL) - goto error; + if (format == NULL) { + tnt_raise(LoggedError, ER_MEMORY_ISSUE, + sizeof(struct tuple_format), + "tuple format", "malloc"); + } - format->id = formats_size++; + format->refs = 0; + format->id = FORMAT_ID_NIL; format->max_fieldno = max_fieldno; format->field_count = field_count; format->types = (enum field_type *) ((char *) format + sizeof(*format) + field_count * sizeof(int32_t)); - tuple_formats[format->id] = format; return format; -error: - tnt_raise(LoggedError, ER_MEMORY_ISSUE, - sizeof(struct tuple_format), "tuple format", "malloc"); - return NULL; +} + +void +tuple_format_delete(struct tuple_format *format) +{ + tuple_format_deregister(format); + free(format); } struct tuple_format * -tuple_format_new(struct key_def *key_def, uint32_t key_count) +tuple_format_new(struct rlist *key_list) { - struct tuple_format *format = - tuple_format_alloc_and_register(key_def, key_count); + struct tuple_format *format = tuple_format_alloc(key_list); - field_type_create(format->types, format->field_count, - key_def, key_count); + try { + tuple_format_register(format); + field_type_create(format->types, format->field_count, + key_list); + } catch (...) { + tuple_format_delete(format); + throw; + } int32_t i = 0; uint32_t prev_offset = 0; @@ -186,8 +231,9 @@ tuple_init_field_map(struct tuple *tuple, struct tuple_format *format) enum field_type *end = format->types + format->field_count; const char *pos = tuple->data; uint32_t *field_map = (uint32_t *) tuple; + uint32_t i = 0; - for (; type < end; offset++, type++) { + for (; type < end; offset++, type++, i++) { if (pos >= tuple->data + tuple->bsize) tnt_raise(IllegalParams, "incorrect tuple format"); @@ -198,7 +244,7 @@ tuple_init_field_map(struct tuple *tuple, struct tuple_format *format) * correct lengths. */ if (type_maxlen != UINT32_MAX && len != type_maxlen) { - tnt_raise(ClientError, ER_KEY_FIELD_TYPE, + tnt_raise(ClientError, ER_FIELD_TYPE, i, field_type_strs[*type]); } pos += len; @@ -218,6 +264,7 @@ tuple_alloc(struct tuple_format *format, size_t size) tuple->refs = 0; tuple->bsize = size; tuple->format_id = tuple_format_id(format); + tuple_format_ref(format, 1); say_debug("tuple_alloc(%zu) = %p", size, tuple); return tuple; @@ -228,11 +275,13 @@ tuple_alloc(struct tuple_format *format, size_t size) * @pre tuple->refs == 0 */ void -tuple_free(struct tuple *tuple) +tuple_delete(struct tuple *tuple) { - say_debug("tuple_free(%p)", tuple); + say_debug("tuple_delete(%p)", tuple); assert(tuple->refs == 0); - char *ptr = (char *) tuple - tuple_format(tuple)->field_map_size; + struct tuple_format *format = tuple_format(tuple); + char *ptr = (char *) tuple - format->field_map_size; + tuple_format_ref(format, -1); sfree(ptr); } @@ -249,7 +298,7 @@ tuple_ref(struct tuple *tuple, int count) tuple->refs += count; if (tuple->refs == 0) - tuple_free(tuple); + tuple_delete(tuple); } /** @@ -393,7 +442,7 @@ tuple_update(struct tuple_format *format, tuple_update_execute(update, new_tuple->data); tuple_init_field_map(new_tuple, format); } catch (const Exception&) { - tuple_free(new_tuple); + tuple_delete(new_tuple); throw; } return new_tuple; @@ -405,8 +454,24 @@ tuple_new(struct tuple_format *format, uint32_t field_count, { size_t tuple_len = end - *data; - if (tuple_len != tuple_range_size(data, end, field_count)) + if (tuple_len != tuple_range_size(data, end, field_count)) { + say_error("\n" + "********************************************\n" + "* Found a corrupted tuple in the snapshot! *\n" + "* This can be either due to a memory *\n" + "* corruption or a bug in the server. *\n" + "* The tuple can not be loaded. *\n" + "********************************************\n" + "Tuple data, BASE64 encoded: \n"); + + int base64_buflen = base64_bufsize(tuple_len); + char *base64_buf = (char *) malloc(base64_buflen); + int len = base64_encode(end - tuple_len, tuple_len, + base64_buf, base64_buflen); + write(STDERR_FILENO, base64_buf, len); + free(base64_buf); tnt_raise(IllegalParams, "tuple_new(): incorrect tuple format"); + } struct tuple *new_tuple = tuple_alloc(format, tuple_len); new_tuple->field_count = field_count; @@ -414,7 +479,7 @@ tuple_new(struct tuple_format *format, uint32_t field_count, try { tuple_init_field_map(new_tuple, format); } catch (...) { - tuple_free(new_tuple); + tuple_delete(new_tuple); throw; } return new_tuple; @@ -470,8 +535,8 @@ tuple_compare(const struct tuple *tuple_a, const struct tuple *tuple_b, return tuple_compare_field(tuple_a->data, tuple_b->data, key_def->parts[0].type); - struct key_part *part = key_def->parts; - struct key_part *end = part + key_def->part_count; + const struct key_part *part = key_def->parts; + const struct key_part *end = part + key_def->part_count; struct tuple_format *format_a = tuple_format(tuple_a); struct tuple_format *format_b = tuple_format(tuple_b); const char *field_a; @@ -502,8 +567,8 @@ int tuple_compare_with_key(const struct tuple *tuple, const char *key, uint32_t part_count, const struct key_def *key_def) { - struct key_part *part = key_def->parts; - struct key_part *end = part + MIN(part_count, key_def->part_count); + const struct key_part *part = key_def->parts; + const struct key_part *end = part + MIN(part_count, key_def->part_count); struct tuple_format *format = tuple_format(tuple); const char *field; uint32_t field_size; @@ -552,15 +617,24 @@ tuple_compare_with_key(const struct tuple *tuple, const char *key, void tuple_init() { - tuple_format_ber = tuple_format_new(NULL, 0); + tuple_format_ber = tuple_format_new(&rlist_nil); + /* Make sure this one stays around. */ + tuple_format_ref(tuple_format_ber, 1); } void tuple_free() { + /* Clear recycled ids. */ + while (recycled_format_ids != FORMAT_ID_NIL) { + + uint16_t id = (uint16_t) recycled_format_ids; + recycled_format_ids = (intptr_t) tuple_formats[id]; + tuple_formats[id] = NULL; + } for (struct tuple_format **format = tuple_formats; format < tuple_formats + formats_size; format++) - free(*format); + free(*format); /* ignore the reference count. */ free(tuple_formats); } diff --git a/src/box/tuple.h b/src/box/tuple.h index 8ba49b1946..2ea4442ab4 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -29,7 +29,7 @@ * SUCH DAMAGE. */ #include "tarantool/util.h" -#include "key_def.h" +#include "key_def.h" /* for enum field_type */ #include <pickle.h> struct tbuf; @@ -39,6 +39,8 @@ struct tbuf; */ struct tuple_format { uint16_t id; + /* Format objects are reference counted. */ + int refs; /** * Max field no which participates in any of the space * indexes. Each tuple of this format must have, @@ -107,7 +109,21 @@ tuple_format_id(struct tuple_format *format) * @return tuple format */ struct tuple_format * -tuple_format_new(struct key_def *key_def, uint32_t key_count); +tuple_format_new(struct rlist *key_list); + +/** Delete a format with zero ref count. */ +void +tuple_format_delete(struct tuple_format *format); + +static inline void +tuple_format_ref(struct tuple_format *format, int count) +{ + assert(format->refs + count >= 0); + format->refs += count; + if (format->refs == 0) + tuple_format_delete(format); + +}; /** * An atom of Tarantool/Box storage. Consists of a list of fields. @@ -197,6 +213,7 @@ tuple_field(const struct tuple *tuple, uint32_t i, uint32_t *len) *len = load_varint32(&field); return field; } + *len = 0; return NULL; } @@ -287,7 +304,7 @@ tuple_range_size(const char **begin, const char *end, uint32_t count) return *begin - start; } -void tuple_free(struct tuple *tuple); +void tuple_delete(struct tuple *tuple); /** * @brief Compare two tuples using field by field using key definition diff --git a/src/box/tuple_update.cc b/src/box/tuple_update.cc index 451b579ce5..ae6bc51d3d 100644 --- a/src/box/tuple_update.cc +++ b/src/box/tuple_update.cc @@ -342,7 +342,7 @@ init_update_op_arith(struct tuple_update *update, struct update_op *op) /* Check the operand type. */ if (op->arg.set.length != sizeof(int32_t)) tnt_raise(ClientError, ER_ARG_TYPE, - "32-bit int"); + op->field_no, "NUM"); arg->i32_val = *(int32_t *)op->arg.set.value; break; @@ -360,12 +360,12 @@ init_update_op_arith(struct tuple_update *update, struct update_op *op) break; default: tnt_raise(ClientError, ER_ARG_TYPE, - "32-bit or 64-bit int"); + op->field_no, "NUM or NUM64"); } break; default: tnt_raise(ClientError, ER_FIELD_TYPE, - "32-bit or 64-bit int"); + op->field_no, "NUM or NUM64"); } STAILQ_INSERT_TAIL(&field->ops, op, next); arg->val_size = op->new_field_len = field_len; diff --git a/src/box/txn.cc b/src/box/txn.cc index f4885074a0..0214a4e515 100644 --- a/src/box/txn.cc +++ b/src/box/txn.cc @@ -78,8 +78,8 @@ txn_commit(struct txn *txn) int64_t lsn = next_lsn(recovery_state); ev_tstamp start = ev_now(), stop; - int res = wal_write(recovery_state, lsn, 0, - txn->op, txn->data, txn->len); + int res = wal_write(recovery_state, lsn, txn->op, + txn->data, txn->len); stop = ev_now(); if (stop - start > cfg.too_long_threshold) { diff --git a/src/log_io.cc b/src/log_io.cc index 16f0e78343..e4730b4455 100644 --- a/src/log_io.cc +++ b/src/log_io.cc @@ -36,33 +36,33 @@ #include "fio.h" #include "tarantool_eio.h" -const uint32_t default_version = 11; -const log_magic_t row_marker_v11 = 0xba0babed; -const log_magic_t eof_marker_v11 = 0x10adab1e; +const uint32_t default_version = 12; +const log_magic_t row_marker = 0xba0babed; +const log_magic_t eof_marker = 0x10adab1e; const char inprogress_suffix[] = ".inprogress"; -const char v11[] = "0.11\n"; +const char v12[] = "0.12\n"; void -header_v11_sign(struct header_v11 *header) +row_header_sign(struct row_header *header) { header->data_crc32c = crc32_calc(0, (const unsigned char *) header + sizeof(struct - header_v11), header->len); + row_header), header->len); header->header_crc32c = crc32_calc(0, (const unsigned char *) &header->lsn, - sizeof(struct header_v11) - + sizeof(struct row_header) - sizeof(header->header_crc32c)); } void -row_v11_fill(struct row_v11 *row, int64_t lsn, uint16_t tag, uint64_t cookie, +wal_row_fill(struct wal_row *row, int64_t lsn, const char *metadata, size_t metadata_len, const char *data, size_t data_len) { - row->marker = row_marker_v11; - row->tag = tag; - row->cookie = cookie; + row->marker = row_marker; + row->tag = WAL; /* unused. */ + row->cookie = 0; /* unused. */ memcpy(row->data, metadata, metadata_len); memcpy(row->data + metadata_len, data, data_len); - header_v11_fill(&row->header, lsn, metadata_len + data_len + + row_header_fill(&row->header, lsn, metadata_len + data_len + sizeof(row->tag) + sizeof(row->cookie)); } @@ -224,9 +224,9 @@ format_filename(struct log_dir *dir, int64_t lsn, enum log_suffix suffix) static const char ROW_EOF[] = ""; const char * -row_reader_v11(FILE *f, uint32_t *rowlen) +row_reader(FILE *f, uint32_t *rowlen) { - struct header_v11 m; + struct row_header m; uint32_t header_crc, data_crc; @@ -234,8 +234,8 @@ row_reader_v11(FILE *f, uint32_t *rowlen) return ROW_EOF; /* header crc32c calculated on <lsn, tm, len, data_crc32c> */ - header_crc = crc32_calc(0, (unsigned char *) &m + offsetof(struct header_v11, lsn), - sizeof(m) - offsetof(struct header_v11, lsn)); + header_crc = crc32_calc(0, (unsigned char *) &m + offsetof(struct row_header, lsn), + sizeof(m) - offsetof(struct row_header, lsn)); if (m.header_crc32c != header_crc) { say_error("header crc32c mismatch"); @@ -300,7 +300,7 @@ log_io_cursor_next(struct log_io_cursor *i, uint32_t *rowlen) assert(i->eof_read == false); say_debug("log_io_cursor_next: marker:0x%016X/%zu", - row_marker_v11, sizeof(row_marker_v11)); + row_marker, sizeof(row_marker)); /* * Don't let gc pool grow too much. Yet to @@ -316,7 +316,7 @@ log_io_cursor_next(struct log_io_cursor *i, uint32_t *rowlen) if (fread(&magic, sizeof(magic), 1, l->f) != 1) goto eof; - while (magic != row_marker_v11) { + while (magic != row_marker) { int c = fgetc(l->f); if (c == EOF) { say_debug("eof while looking for magic"); @@ -325,14 +325,14 @@ log_io_cursor_next(struct log_io_cursor *i, uint32_t *rowlen) magic = magic >> 8 | ((log_magic_t) c & 0xff) << (sizeof(magic)*8 - 8); } - marker_offset = ftello(l->f) - sizeof(row_marker_v11); + marker_offset = ftello(l->f) - sizeof(row_marker); if (i->good_offset != marker_offset) say_warn("skipped %jd bytes after 0x%08jx offset", (intmax_t)(marker_offset - i->good_offset), (uintmax_t)i->good_offset); say_debug("magic found at 0x%08jx", (uintmax_t)marker_offset); - row = row_reader_v11(l->f, rowlen); + row = row_reader(l->f, rowlen); if (row == ROW_EOF) goto eof; @@ -356,15 +356,15 @@ log_io_cursor_next(struct log_io_cursor *i, uint32_t *rowlen) * 1. sizeof(eof_marker) > 0 and it is the last record in file * 2. sizeof(eof_marker) == 0 and there is no unread data in file */ - if (ftello(l->f) == i->good_offset + sizeof(eof_marker_v11)) { + if (ftello(l->f) == i->good_offset + sizeof(eof_marker)) { fseeko(l->f, i->good_offset, SEEK_SET); if (fread(&magic, sizeof(magic), 1, l->f) != 1) { say_error("can't read eof marker"); - } else if (magic == eof_marker_v11) { + } else if (magic == eof_marker) { i->good_offset = ftello(l->f); i->eof_read = true; - } else if (magic != row_marker_v11) { + } else if (magic != row_marker) { say_error("eof marker is corrupt: %lu", (unsigned long) magic); } else { @@ -441,7 +441,7 @@ log_io_close(struct log_io **lptr) int r; if (l->mode == LOG_WRITE) { - fio_write(fileno(l->f), &eof_marker_v11, sizeof(log_magic_t)); + fio_write(fileno(l->f), &eof_marker, sizeof(log_magic_t)); /* * Sync the file before closing, since * otherwise we can end up with a partially @@ -514,7 +514,7 @@ log_io_sync(struct log_io *l) static int log_io_write_header(struct log_io *l) { - int ret = fprintf(l->f, "%s%s\n", l->dir->filetype, v11); + int ret = fprintf(l->f, "%s%s\n", l->dir->filetype, v12); return ret < 0 ? -1 : 0; } @@ -544,8 +544,8 @@ log_io_verify_meta(struct log_io *l, const char **errmsg) goto error; } - if (strcmp(v11, version) != 0) { - *errmsg = "unknown version"; + if (strcmp(v12, version) != 0) { + *errmsg = "unsupported file format version"; goto error; } for (;;) { @@ -587,10 +587,8 @@ log_io_open(struct log_dir *dir, enum log_mode mode, l->dir = dir; l->is_inprogress = suffix == INPROGRESS; if (mode == LOG_READ) { - if (log_io_verify_meta(l, &errmsg) != 0) { - errmsg = strerror(errno); + if (log_io_verify_meta(l, &errmsg) != 0) goto error; - } } else { /* LOG_WRITE */ setvbuf(l->f, NULL, _IONBF, 0); if (log_io_write_header(l) != 0) { diff --git a/src/lua/uuid.lua b/src/lua/uuid.lua index f08afa56f6..0fe76633ba 100644 --- a/src/lua/uuid.lua +++ b/src/lua/uuid.lua @@ -1,3 +1,4 @@ +-- uuid.lua (internal file) (function(box) local ffi = require("ffi") ffi.cdef[[ diff --git a/src/memcached.cc b/src/memcached.cc index ecb306ebfb..3aa6836ef8 100644 --- a/src/memcached.cc +++ b/src/memcached.cc @@ -36,6 +36,7 @@ #include "box/space.h" #include "box/port.h" #include "box/tuple.h" +#include "box/schema.h" #include "fiber.h" extern "C" { #include <cfg/warning.h> @@ -505,15 +506,20 @@ memcached_space_init() return; /* Configure memcached index key. */ - struct key_def key_def; - key_def_create(&key_def, 0, HASH, true, 1); - key_def_set_part(&key_def, 0, 0, STRING); + struct key_def *key_def = key_def_new(0, HASH, true, 1); + key_def_set_part(key_def, 0, 0, STRING); + struct rlist keys; + rlist_create(&keys); + key_list_add_key(&keys, key_def); struct space_def space_def; space_def.id = cfg.memcached_space; space_def.arity = 4; - (void) space_new(&space_def, &key_def, 1); + struct space *space = space_new(&space_def, &keys); + space->engine.recover(space); + space_cache_replace(space); + key_def_delete(key_def); } /** Delete a bunch of expired keys. */ diff --git a/src/recovery.cc b/src/recovery.cc index f1d5eaf271..465faad3c6 100644 --- a/src/recovery.cc +++ b/src/recovery.cc @@ -352,7 +352,7 @@ recover_wal(struct recovery_state *r, struct log_io *l) const char *row; uint32_t rowlen; while ((row = log_io_cursor_next(&i, &rowlen))) { - int64_t lsn = header_v11(row)->lsn; + int64_t lsn = row_header(row)->lsn; if (lsn <= r->confirmed_lsn) { say_debug("skipping too young row"); continue; @@ -689,7 +689,7 @@ struct wal_write_request { /* Auxiliary. */ int res; struct fiber *fiber; - struct row_v11 row; + struct wal_row row; }; /* Context of the WAL writer thread. */ @@ -1013,9 +1013,9 @@ wal_fill_batch(struct log_io *wal, struct fio_batch *batch, int rows_per_wal, assert(max_rows > 0); fio_batch_start(batch, max_rows); while (req != NULL && ! fio_batch_is_full(batch)) { - struct row_v11 *row = &req->row; - header_v11_sign(&row->header); - fio_batch_add(batch, row, row_v11_size(row)); + struct wal_row *row = &req->row; + row_header_sign(&row->header); + fio_batch_add(batch, row, wal_row_size(row)); req = STAILQ_NEXT(req, wal_fifo_entry); } return req; @@ -1104,7 +1104,7 @@ wal_writer_thread(void *worker_args) * to be written to disk and wait until this task is completed. */ int -wal_write(struct recovery_state *r, int64_t lsn, uint64_t cookie, +wal_write(struct recovery_state *r, int64_t lsn, uint16_t op, const char *row, uint32_t row_len) { say_debug("wal_write lsn=%" PRIi64, lsn); @@ -1121,7 +1121,7 @@ wal_write(struct recovery_state *r, int64_t lsn, uint64_t cookie, req->fiber = fiber; req->res = -1; - row_v11_fill(&req->row, lsn, XLOG, cookie, (const char *) &op, + wal_row_fill(&req->row, lsn, (const char *) &op, sizeof(op), row, row_len); (void) tt_pthread_mutex_lock(&writer->mutex); @@ -1164,17 +1164,16 @@ snapshot_write_row(struct log_io *l, struct fio_batch *batch, ev_tstamp elapsed; static ev_tstamp last = 0; - struct row_v11 *row = (struct row_v11 *) palloc(fiber->gc_pool, - sizeof(struct row_v11) + + struct wal_row *row = (struct wal_row *) palloc(fiber->gc_pool, + sizeof(struct wal_row) + data_len + metadata_len); - row_v11_fill(row, 0, SNAP, snapshot_cookie, - metadata, metadata_len, data, data_len); - header_v11_sign(&row->header); + wal_row_fill(row, ++rows, metadata, metadata_len, data, data_len); + row_header_sign(&row->header); - fio_batch_add(batch, row, row_v11_size(row)); + fio_batch_add(batch, row, wal_row_size(row)); - if (++rows % 100000 == 0) + if (rows % 100000 == 0) say_crit("%.1fM rows written", rows / 1000000.); if (fio_batch_is_full(batch)) { @@ -1188,7 +1187,7 @@ snapshot_write_row(struct log_io *l, struct fio_batch *batch, ev_now_update(); last = ev_now(); } - bytes += row_v11_size(row); + bytes += wal_row_size(row); while (bytes >= recovery_state->snap_io_rate_limit) { ev_now_update(); diff --git a/src/replica.cc b/src/replica.cc index b4acbb7744..2d2983b9bd 100644 --- a/src/replica.cc +++ b/src/replica.cc @@ -44,15 +44,15 @@ const char * remote_read_row(struct ev_io *coio, struct iobuf *iobuf, uint32_t *rowlen) { struct ibuf *in = &iobuf->in; - ssize_t to_read = sizeof(struct header_v11) - ibuf_size(in); + ssize_t to_read = sizeof(struct row_header) - ibuf_size(in); if (to_read > 0) { ibuf_reserve(in, cfg_readahead); coio_breadn(coio, in, to_read); } - ssize_t request_len = header_v11(in->pos)->len - + sizeof(struct header_v11); + ssize_t request_len = row_header(in->pos)->len + + sizeof(struct row_header); to_read = request_len - ibuf_size(in); if (to_read > 0) @@ -115,7 +115,7 @@ pull_from_remote(va_list ap) fiber_setcancellable(false); err = NULL; - r->remote->recovery_lag = ev_now() - header_v11(row)->tm; + r->remote->recovery_lag = ev_now() - row_header(row)->tm; r->remote->recovery_last_update_tstamp = ev_now(); remote_apply_row(r, row, rowlen); @@ -143,9 +143,9 @@ pull_from_remote(va_list ap) static void remote_apply_row(struct recovery_state *r, const char *row, uint32_t rowlen) { - int64_t lsn = header_v11(row)->lsn; + int64_t lsn = row_header(row)->lsn; - assert(*(uint16_t*)(row + sizeof(struct header_v11)) == XLOG); + assert(*(uint16_t*)(row + sizeof(struct row_header)) == WAL); if (r->row_handler(r->row_handler_param, row, rowlen) < 0) panic("replication failure: can't apply row"); diff --git a/test/big/bitset.result b/test/big/bitset.result index 8f1f7a101c..74a9ec5bbd 100644 --- a/test/big/bitset.result +++ b/test/big/bitset.result @@ -374,7 +374,7 @@ sorted output ... dump(box.index.BITS_ALL_SET, 4294967296) --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 0 does not match index part type: expected NUM' ... ------------------------------------------------------------------------------ -- BitsetIndex: BITS_ALL_SET (multiple bit) @@ -812,7 +812,7 @@ $ 128$ ... dump(box.index.BITS_ALL_NOT_SET, 4294967296) --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 0 does not match index part type: expected NUM' ... ------------------------------------------------------------------------------ -- BitsetIndex: BITS_ALL_NOT_SET (multiple bit) @@ -1019,7 +1019,7 @@ $ 128$ ... dump(box.index.BITS_ANY_SET, 4294967296) --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 0 does not match index part type: expected NUM' ... ------------------------------------------------------------------------------ -- BitsetIndex: BITS_ANY_SET (multiple bit) diff --git a/test/big/hash.result b/test/big/hash.result index 4b9ad1c1f4..04fcbab549 100644 --- a/test/big/hash.result +++ b/test/big/hash.result @@ -27,7 +27,7 @@ box.space[10]:insert(3, 'value1 v1.0', 'value2 v1.0') -- Insert invalid fields box.space[10]:insert('invalid key', 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... ------------------------------------------------------------------------------- -- 32-bit hash replace fields tests @@ -48,7 +48,7 @@ box.space[10]:replace(2, 'value1 v1.43', 'value2 1.92') -- Replace invalid fields box.space[10]:replace('invalid key', 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... ------------------------------------------------------------------------------- -- 32-bit hash select fields test @@ -79,7 +79,7 @@ box.space[10]:select(0, 5) -- select by invalid keys box.space[10]:select(0, 'invalid key') --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 0 does not match index part type: expected NUM' ... box.space[10]:select(0, 1, 2) --- @@ -114,7 +114,7 @@ box.space[10]:delete(5) -- delete by invalid keys box.space[10]:delete('invalid key') --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 0 does not match index part type: expected NUM' ... box.space[10]:delete(1, 2) --- @@ -146,23 +146,23 @@ box.space[11]:insert(3ULL, 'value1 v1.0', 'value2 v1.0') -- Insert invalid fields box.space[11]:insert(100, 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:insert(101, 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:insert(102, 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:insert(103, 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:insert('invalid key', 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... ------------------------------------------------------------------------------- -- 64-bit hash replace fields tests @@ -183,19 +183,19 @@ box.space[11]:replace(2ULL, 'value1 v1.43', 'value2 1.92') -- Replace invalid fields box.space[11]:replace(3, 'value1 v1.31', 'value2 1.12') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:replace(1, 'value1 v1.32', 'value2 1.72') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:replace(2, 'value1 v1.43', 'value2 1.92') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... box.space[11]:replace('invalid key', 'value1 v1.0', 'value2 v1.0') --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 0 type does not match one required by operation: expected NUM64' ... ------------------------------------------------------------------------------- -- 64-bit hash select fields test @@ -249,7 +249,7 @@ box.space[11]:select(0, 5) -- select by invalid keys box.space[11]:select(0, 'invalid key') --- -error: 'Supplied key field type does not match index type: expected u64' +error: 'Supplied key type of part 0 does not match index part type: expected NUM64' ... box.space[11]:select(0, '00000001', '00000002') --- @@ -323,7 +323,7 @@ box.space[11]:delete(5) -- delete by invalid keys box.space[11]:delete('invalid key') --- -error: 'Supplied key field type does not match index type: expected u64' +error: 'Supplied key type of part 0 does not match index part type: expected NUM64' ... box.space[11]:delete('00000001', '00000002') --- diff --git a/test/big/hash_multipart.result b/test/big/hash_multipart.result index 58c3a8db9e..cfea570e17 100644 --- a/test/big/hash_multipart.result +++ b/test/big/hash_multipart.result @@ -84,7 +84,7 @@ error: 'Invalid key part count (expected [0..3], got 4)' -- primary index select with wrong type box.space[27]:select(0, 1, 'foo', 'baz') --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 2 does not match index part type: expected NUM' ... -- secondary index select box.space[27]:select(1, 1, 4) @@ -103,7 +103,7 @@ error: 'Invalid key part count in an exact match (expected 2, got 1)' -- secondary index select with wrong type box.space[27]:select(1, 1, 'baz') --- -error: 'Supplied key field type does not match index type: expected u32' +error: 'Supplied key type of part 1 does not match index part type: expected NUM' ... -- cleanup box.space[27]:truncate() diff --git a/test/big/tree_pk.result b/test/big/tree_pk.result index 56b5ee32ec..9f6401ad8a 100644 --- a/test/big/tree_pk.result +++ b/test/big/tree_pk.result @@ -51,15 +51,15 @@ box.space[2]:delete(3) -- https://bugs.launchpad.net/tarantool/+bug/1072624 box.space[2]:insert('xxxxxxx') --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... box.space[2]:insert('') --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... box.space[2]:insert('12') --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... -- string keys box.space[3]:insert('identifier', 'tuple') diff --git a/test/big/tree_variants.result b/test/big/tree_variants.result index 5233818e3d..941d12e74e 100644 --- a/test/big/tree_variants.result +++ b/test/big/tree_variants.result @@ -155,18 +155,18 @@ for k,v in box.space[6]:pairs() do print(' - ', v) end -- https://bugs.launchpad.net/tarantool/+bug/1072624 box.space[6]:insert('', '00000001', '00000002', '', '', '', '', '', 0) --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... box.space[6]:insert('xxxxxxxx', '00000001', '00000002', '', '', '', '', '', 0) --- -error: 'Supplied key field type does not match index type: expected NUM' +error: 'Tuple field 0 type does not match one required by operation: expected NUM' ... box.space[6]:insert(1, '', '00000002', '', '', '', '', '', 0) --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 1 type does not match one required by operation: expected NUM64' ... box.space[6]:insert(1, 'xxxxxxxxxxx', '00000002', '', '', '', '', '', 0) --- -error: 'Supplied key field type does not match index type: expected NUM64' +error: 'Tuple field 1 type does not match one required by operation: expected NUM64' ... -- vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 syntax=lua diff --git a/test/box/bad_record.xlog b/test/box/bad_record.xlog index 28e8cd35f26399e406ef600e314af78bdafa04d9..113b4df5648f8ca5dc22524ef8dc62deab3b378b 100644 GIT binary patch literal 22 dcma#>@ptDk&@(jR;z~+PQ7B4H&M!*g0suaL1?m6* literal 22 dcma#>@ptDk&@(jT;z~+PQ7B4H&M!*g0sua71?d0) diff --git a/test/box/dup_key1.xlog b/test/box/dup_key1.xlog index 096b48ccc5c9e81dc613a37ac0bef8cd3ea58d7b..994ac020f1d31f8ad57367665169b96106b52653 100644 GIT binary patch delta 19 acmeBV>|*4M@bP!&GSD+Ln#kF}$OQl{3Is_2 delta 17 YcmeBT>}2GO@bP!&GSD+LoXFV#040C~Jpcdz diff --git a/test/box/dup_key2.xlog b/test/box/dup_key2.xlog index 2651dd6f0f692394c6f03bd61c955e5d693cf307..61c93bdfae3101dba0b89287aa4ce7cdf43bf24c 100644 GIT binary patch delta 19 acmeBV>|*4M@bP!&GSD+Ln#kF}$OQl{3Is_2 delta 17 YcmeBT>}2GO@bP!&GSD+LoXFV#040C~Jpcdz diff --git a/test/box/just_header.xlog b/test/box/just_header.xlog index 3472cc4eb0dbaff89e0ff37b3637d2ff6580af1a..82963618db683d5a6c344e50862eac8b8b21fe83 100644 GIT binary patch literal 11 Scma#>@ptDk&@(jR;sO8<jshA0 literal 11 Scma#>@ptDk&@(jT;sO8<ivk${ diff --git a/test/box/lua.result b/test/box/lua.result index d6043125f2..1c5b2b114f 100644 --- a/test/box/lua.result +++ b/test/box/lua.result @@ -292,7 +292,7 @@ error: 'No index #1 is defined in space 0' ... box.select(0) --- -error: '[string "-- box.lua (internal file)..."]:13: box.pack: expected 32-bit int' +error: '[string "-- box.lua (internal file)..."]:11: box.pack: expected 32-bit int' ... call box.replace('0', 'abcd', 'hello', 'world') Found 1 tuple: diff --git a/test/box/lua_misc.result b/test/box/lua_misc.result index 73ae3cc994..302d58dcce 100644 --- a/test/box/lua_misc.result +++ b/test/box/lua_misc.result @@ -107,29 +107,31 @@ box.error.ER_KEY_FIELD_TYPE : 9730 box.error.ER_NONMASTER : 258 box.error.ER_PROC_RET : 12290 box.error.ER_TUPLE_IS_TOO_LONG : 11010 +box.error.ER_UNKNOWN_UPDATE_OP : 11266 box.error.ER_EXACT_MATCH : 11522 +box.error.ER_TUPLE_FORMAT_LIMIT : 7170 box.error.ER_FIELD_TYPE : 10242 -box.error.ER_PROC_LUA : 13058 box.error.ER_TUPLE_FOUND : 14082 -box.error.ER_OK : 0 box.error.ER_NO_SUCH_FIELD : 13826 +box.error.ER_OK : 0 +box.error.ER_NO_SUCH_INDEX : 13570 box.error.ER_TUPLE_NOT_FOUND : 12546 box.error.ER_FIBER_STACK : 6658 -box.error.ER_SPLICE : 10754 -box.error.ER_NO_SUCH_INDEX : 13570 +box.error.ER_WAL_IO : 9986 +box.error.ER_SPACE_DISABLED : 13314 box.error.ER_UNSUPPORTED : 2562 box.error.ER_INJECTION : 2306 -box.error.ER_SPACE_DISABLED : 13314 +box.error.ER_PROC_LUA : 13058 box.error.ER_INDEX_TYPE : 1282 box.error.ER_ARG_TYPE : 10498 box.error.ER_NO_SUCH_SPACE : 14594 -box.error.ER_UNKNOWN_UPDATE_OP : 11266 -box.error.ER_SPACE_EXISTS : 1538 +box.error.ER_SECONDARY : 770 +box.error.ER_FIELD_TYPE_MISMATCH : 11778 box.error.ER_NO_SUCH_PROC : 12802 -box.error.ER_WAL_IO : 9986 +box.error.ER_SPLICE : 10754 box.error.ER_KEY_PART_COUNT : 12034 +box.error.ER_SPACE_EXISTS : 1538 box.error.ER_TUPLE_IS_RO : 1025 -box.error.ER_SECONDARY : 770 box.error.ER_MEMORY_ISSUE : 1793 ... -- vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 syntax=lua diff --git a/test/box/snapshot.result b/test/box/snapshot.result index a9ad91db75..08cb03f6ef 100644 --- a/test/box/snapshot.result +++ b/test/box/snapshot.result @@ -1,1510 +1,3 @@ - -# Verify that the server starts from a pre-recorded snapshot. -# This way we check that the server can read old snapshots (v11) -# going forward. - -select * from t0 where k0=0 -No match -select * from t0 where k0=1 -Found 1 tuple: -[1, 'I am a tuple 1'] -select * from t0 where k0=2 -Found 1 tuple: -[2, 'I am a tuple 2'] -select * from t0 where k0=3 -Found 1 tuple: -[3, 'I am a tuple 3'] -select * from t0 where k0=4 -Found 1 tuple: -[4, 'I am a tuple 4'] -select * from t0 where k0=5 -Found 1 tuple: -[5, 'I am a tuple 5'] -select * from t0 where k0=6 -Found 1 tuple: -[6, 'I am a tuple 6'] -select * from t0 where k0=7 -Found 1 tuple: -[7, 'I am a tuple 7'] -select * from t0 where k0=8 -Found 1 tuple: -[8, 'I am a tuple 8'] -select * from t0 where k0=9 -Found 1 tuple: -[9, 'I am a tuple 9'] -select * from t0 where k0=10 -Found 1 tuple: -[10, 'I am a tuple 10'] -select * from t0 where k0=11 -Found 1 tuple: -[11, 'I am a tuple 11'] -select * from t0 where k0=12 -Found 1 tuple: -[12, 'I am a tuple 12'] -select * from t0 where k0=13 -Found 1 tuple: -[13, 'I am a tuple 13'] -select * from t0 where k0=14 -Found 1 tuple: -[14, 'I am a tuple 14'] -select * from t0 where k0=15 -Found 1 tuple: -[15, 'I am a tuple 15'] -select * from t0 where k0=16 -Found 1 tuple: -[16, 'I am a tuple 16'] -select * from t0 where k0=17 -Found 1 tuple: -[17, 'I am a tuple 17'] -select * from t0 where k0=18 -Found 1 tuple: -[18, 'I am a tuple 18'] -select * from t0 where k0=19 -Found 1 tuple: -[19, 'I am a tuple 19'] -select * from t0 where k0=20 -Found 1 tuple: -[20, 'I am a tuple 20'] -select * from t0 where k0=21 -Found 1 tuple: -[21, 'I am a tuple 21'] -select * from t0 where k0=22 -Found 1 tuple: -[22, 'I am a tuple 22'] -select * from t0 where k0=23 -Found 1 tuple: -[23, 'I am a tuple 23'] -select * from t0 where k0=24 -Found 1 tuple: -[24, 'I am a tuple 24'] -select * from t0 where k0=25 -Found 1 tuple: -[25, 'I am a tuple 25'] -select * from t0 where k0=26 -Found 1 tuple: -[26, 'I am a tuple 26'] -select * from t0 where k0=27 -Found 1 tuple: -[27, 'I am a tuple 27'] -select * from t0 where k0=28 -Found 1 tuple: -[28, 'I am a tuple 28'] -select * from t0 where k0=29 -Found 1 tuple: -[29, 'I am a tuple 29'] -select * from t0 where k0=30 -Found 1 tuple: -[30, 'I am a tuple 30'] -select * from t0 where k0=31 -Found 1 tuple: -[31, 'I am a tuple 31'] -select * from t0 where k0=32 -Found 1 tuple: -[32, 'I am a tuple 32'] -select * from t0 where k0=33 -Found 1 tuple: -[33, 'I am a tuple 33'] -select * from t0 where k0=34 -Found 1 tuple: -[34, 'I am a tuple 34'] -select * from t0 where k0=35 -Found 1 tuple: -[35, 'I am a tuple 35'] -select * from t0 where k0=36 -Found 1 tuple: -[36, 'I am a tuple 36'] -select * from t0 where k0=37 -Found 1 tuple: -[37, 'I am a tuple 37'] -select * from t0 where k0=38 -Found 1 tuple: -[38, 'I am a tuple 38'] -select * from t0 where k0=39 -Found 1 tuple: -[39, 'I am a tuple 39'] -select * from t0 where k0=40 -Found 1 tuple: -[40, 'I am a tuple 40'] -select * from t0 where k0=41 -Found 1 tuple: -[41, 'I am a tuple 41'] -select * from t0 where k0=42 -Found 1 tuple: -[42, 'I am a tuple 42'] -select * from t0 where k0=43 -Found 1 tuple: -[43, 'I am a tuple 43'] -select * from t0 where k0=44 -Found 1 tuple: -[44, 'I am a tuple 44'] -select * from t0 where k0=45 -Found 1 tuple: -[45, 'I am a tuple 45'] -select * from t0 where k0=46 -Found 1 tuple: -[46, 'I am a tuple 46'] -select * from t0 where k0=47 -Found 1 tuple: -[47, 'I am a tuple 47'] -select * from t0 where k0=48 -Found 1 tuple: -[48, 'I am a tuple 48'] -select * from t0 where k0=49 -Found 1 tuple: -[49, 'I am a tuple 49'] -select * from t0 where k0=50 -Found 1 tuple: -[50, 'I am a tuple 50'] -select * from t0 where k0=51 -Found 1 tuple: -[51, 'I am a tuple 51'] -select * from t0 where k0=52 -Found 1 tuple: -[52, 'I am a tuple 52'] -select * from t0 where k0=53 -Found 1 tuple: -[53, 'I am a tuple 53'] -select * from t0 where k0=54 -Found 1 tuple: -[54, 'I am a tuple 54'] -select * from t0 where k0=55 -Found 1 tuple: -[55, 'I am a tuple 55'] -select * from t0 where k0=56 -Found 1 tuple: -[56, 'I am a tuple 56'] -select * from t0 where k0=57 -Found 1 tuple: -[57, 'I am a tuple 57'] -select * from t0 where k0=58 -Found 1 tuple: -[58, 'I am a tuple 58'] -select * from t0 where k0=59 -Found 1 tuple: -[59, 'I am a tuple 59'] -select * from t0 where k0=60 -Found 1 tuple: -[60, 'I am a tuple 60'] -select * from t0 where k0=61 -Found 1 tuple: -[61, 'I am a tuple 61'] -select * from t0 where k0=62 -Found 1 tuple: -[62, 'I am a tuple 62'] -select * from t0 where k0=63 -Found 1 tuple: -[63, 'I am a tuple 63'] -select * from t0 where k0=64 -Found 1 tuple: -[64, 'I am a tuple 64'] -select * from t0 where k0=65 -Found 1 tuple: -[65, 'I am a tuple 65'] -select * from t0 where k0=66 -Found 1 tuple: -[66, 'I am a tuple 66'] -select * from t0 where k0=67 -Found 1 tuple: -[67, 'I am a tuple 67'] -select * from t0 where k0=68 -Found 1 tuple: -[68, 'I am a tuple 68'] -select * from t0 where k0=69 -Found 1 tuple: -[69, 'I am a tuple 69'] -select * from t0 where k0=70 -Found 1 tuple: -[70, 'I am a tuple 70'] -select * from t0 where k0=71 -Found 1 tuple: -[71, 'I am a tuple 71'] -select * from t0 where k0=72 -Found 1 tuple: -[72, 'I am a tuple 72'] -select * from t0 where k0=73 -Found 1 tuple: -[73, 'I am a tuple 73'] -select * from t0 where k0=74 -Found 1 tuple: -[74, 'I am a tuple 74'] -select * from t0 where k0=75 -Found 1 tuple: -[75, 'I am a tuple 75'] -select * from t0 where k0=76 -Found 1 tuple: -[76, 'I am a tuple 76'] -select * from t0 where k0=77 -Found 1 tuple: -[77, 'I am a tuple 77'] -select * from t0 where k0=78 -Found 1 tuple: -[78, 'I am a tuple 78'] -select * from t0 where k0=79 -Found 1 tuple: -[79, 'I am a tuple 79'] -select * from t0 where k0=80 -Found 1 tuple: -[80, 'I am a tuple 80'] -select * from t0 where k0=81 -Found 1 tuple: -[81, 'I am a tuple 81'] -select * from t0 where k0=82 -Found 1 tuple: -[82, 'I am a tuple 82'] -select * from t0 where k0=83 -Found 1 tuple: -[83, 'I am a tuple 83'] -select * from t0 where k0=84 -Found 1 tuple: -[84, 'I am a tuple 84'] -select * from t0 where k0=85 -Found 1 tuple: -[85, 'I am a tuple 85'] -select * from t0 where k0=86 -Found 1 tuple: -[86, 'I am a tuple 86'] -select * from t0 where k0=87 -Found 1 tuple: -[87, 'I am a tuple 87'] -select * from t0 where k0=88 -Found 1 tuple: -[88, 'I am a tuple 88'] -select * from t0 where k0=89 -Found 1 tuple: -[89, 'I am a tuple 89'] -select * from t0 where k0=90 -Found 1 tuple: -[90, 'I am a tuple 90'] -select * from t0 where k0=91 -Found 1 tuple: -[91, 'I am a tuple 91'] -select * from t0 where k0=92 -Found 1 tuple: -[92, 'I am a tuple 92'] -select * from t0 where k0=93 -Found 1 tuple: -[93, 'I am a tuple 93'] -select * from t0 where k0=94 -Found 1 tuple: -[94, 'I am a tuple 94'] -select * from t0 where k0=95 -Found 1 tuple: -[95, 'I am a tuple 95'] -select * from t0 where k0=96 -Found 1 tuple: -[96, 'I am a tuple 96'] -select * from t0 where k0=97 -Found 1 tuple: -[97, 'I am a tuple 97'] -select * from t0 where k0=98 -Found 1 tuple: -[98, 'I am a tuple 98'] -select * from t0 where k0=99 -Found 1 tuple: -[99, 'I am a tuple 99'] -select * from t0 where k0=100 -Found 1 tuple: -[100, 'I am a tuple 100'] -select * from t0 where k0=101 -Found 1 tuple: -[101, 'I am a tuple 101'] -select * from t0 where k0=102 -Found 1 tuple: -[102, 'I am a tuple 102'] -select * from t0 where k0=103 -Found 1 tuple: -[103, 'I am a tuple 103'] -select * from t0 where k0=104 -Found 1 tuple: -[104, 'I am a tuple 104'] -select * from t0 where k0=105 -Found 1 tuple: -[105, 'I am a tuple 105'] -select * from t0 where k0=106 -Found 1 tuple: -[106, 'I am a tuple 106'] -select * from t0 where k0=107 -Found 1 tuple: -[107, 'I am a tuple 107'] -select * from t0 where k0=108 -Found 1 tuple: -[108, 'I am a tuple 108'] -select * from t0 where k0=109 -Found 1 tuple: -[109, 'I am a tuple 109'] -select * from t0 where k0=110 -Found 1 tuple: -[110, 'I am a tuple 110'] -select * from t0 where k0=111 -Found 1 tuple: -[111, 'I am a tuple 111'] -select * from t0 where k0=112 -Found 1 tuple: -[112, 'I am a tuple 112'] -select * from t0 where k0=113 -Found 1 tuple: -[113, 'I am a tuple 113'] -select * from t0 where k0=114 -Found 1 tuple: -[114, 'I am a tuple 114'] -select * from t0 where k0=115 -Found 1 tuple: -[115, 'I am a tuple 115'] -select * from t0 where k0=116 -Found 1 tuple: -[116, 'I am a tuple 116'] -select * from t0 where k0=117 -Found 1 tuple: -[117, 'I am a tuple 117'] -select * from t0 where k0=118 -Found 1 tuple: -[118, 'I am a tuple 118'] -select * from t0 where k0=119 -Found 1 tuple: -[119, 'I am a tuple 119'] -select * from t0 where k0=120 -Found 1 tuple: -[120, 'I am a tuple 120'] -select * from t0 where k0=121 -Found 1 tuple: -[121, 'I am a tuple 121'] -select * from t0 where k0=122 -Found 1 tuple: -[122, 'I am a tuple 122'] -select * from t0 where k0=123 -Found 1 tuple: -[123, 'I am a tuple 123'] -select * from t0 where k0=124 -Found 1 tuple: -[124, 'I am a tuple 124'] -select * from t0 where k0=125 -Found 1 tuple: -[125, 'I am a tuple 125'] -select * from t0 where k0=126 -Found 1 tuple: -[126, 'I am a tuple 126'] -select * from t0 where k0=127 -Found 1 tuple: -[127, 'I am a tuple 127'] -select * from t0 where k0=128 -Found 1 tuple: -[128, 'I am a tuple 128'] -select * from t0 where k0=129 -Found 1 tuple: -[129, 'I am a tuple 129'] -select * from t0 where k0=130 -Found 1 tuple: -[130, 'I am a tuple 130'] -select * from t0 where k0=131 -Found 1 tuple: -[131, 'I am a tuple 131'] -select * from t0 where k0=132 -Found 1 tuple: -[132, 'I am a tuple 132'] -select * from t0 where k0=133 -Found 1 tuple: -[133, 'I am a tuple 133'] -select * from t0 where k0=134 -Found 1 tuple: -[134, 'I am a tuple 134'] -select * from t0 where k0=135 -Found 1 tuple: -[135, 'I am a tuple 135'] -select * from t0 where k0=136 -Found 1 tuple: -[136, 'I am a tuple 136'] -select * from t0 where k0=137 -Found 1 tuple: -[137, 'I am a tuple 137'] -select * from t0 where k0=138 -Found 1 tuple: -[138, 'I am a tuple 138'] -select * from t0 where k0=139 -Found 1 tuple: -[139, 'I am a tuple 139'] -select * from t0 where k0=140 -Found 1 tuple: -[140, 'I am a tuple 140'] -select * from t0 where k0=141 -Found 1 tuple: -[141, 'I am a tuple 141'] -select * from t0 where k0=142 -Found 1 tuple: -[142, 'I am a tuple 142'] -select * from t0 where k0=143 -Found 1 tuple: -[143, 'I am a tuple 143'] -select * from t0 where k0=144 -Found 1 tuple: -[144, 'I am a tuple 144'] -select * from t0 where k0=145 -Found 1 tuple: -[145, 'I am a tuple 145'] -select * from t0 where k0=146 -Found 1 tuple: -[146, 'I am a tuple 146'] -select * from t0 where k0=147 -Found 1 tuple: -[147, 'I am a tuple 147'] -select * from t0 where k0=148 -Found 1 tuple: -[148, 'I am a tuple 148'] -select * from t0 where k0=149 -Found 1 tuple: -[149, 'I am a tuple 149'] -select * from t0 where k0=150 -Found 1 tuple: -[150, 'I am a tuple 150'] -select * from t0 where k0=151 -Found 1 tuple: -[151, 'I am a tuple 151'] -select * from t0 where k0=152 -Found 1 tuple: -[152, 'I am a tuple 152'] -select * from t0 where k0=153 -Found 1 tuple: -[153, 'I am a tuple 153'] -select * from t0 where k0=154 -Found 1 tuple: -[154, 'I am a tuple 154'] -select * from t0 where k0=155 -Found 1 tuple: -[155, 'I am a tuple 155'] -select * from t0 where k0=156 -Found 1 tuple: -[156, 'I am a tuple 156'] -select * from t0 where k0=157 -Found 1 tuple: -[157, 'I am a tuple 157'] -select * from t0 where k0=158 -Found 1 tuple: -[158, 'I am a tuple 158'] -select * from t0 where k0=159 -Found 1 tuple: -[159, 'I am a tuple 159'] -select * from t0 where k0=160 -Found 1 tuple: -[160, 'I am a tuple 160'] -select * from t0 where k0=161 -Found 1 tuple: -[161, 'I am a tuple 161'] -select * from t0 where k0=162 -Found 1 tuple: -[162, 'I am a tuple 162'] -select * from t0 where k0=163 -Found 1 tuple: -[163, 'I am a tuple 163'] -select * from t0 where k0=164 -Found 1 tuple: -[164, 'I am a tuple 164'] -select * from t0 where k0=165 -Found 1 tuple: -[165, 'I am a tuple 165'] -select * from t0 where k0=166 -Found 1 tuple: -[166, 'I am a tuple 166'] -select * from t0 where k0=167 -Found 1 tuple: -[167, 'I am a tuple 167'] -select * from t0 where k0=168 -Found 1 tuple: -[168, 'I am a tuple 168'] -select * from t0 where k0=169 -Found 1 tuple: -[169, 'I am a tuple 169'] -select * from t0 where k0=170 -Found 1 tuple: -[170, 'I am a tuple 170'] -select * from t0 where k0=171 -Found 1 tuple: -[171, 'I am a tuple 171'] -select * from t0 where k0=172 -Found 1 tuple: -[172, 'I am a tuple 172'] -select * from t0 where k0=173 -Found 1 tuple: -[173, 'I am a tuple 173'] -select * from t0 where k0=174 -Found 1 tuple: -[174, 'I am a tuple 174'] -select * from t0 where k0=175 -Found 1 tuple: -[175, 'I am a tuple 175'] -select * from t0 where k0=176 -Found 1 tuple: -[176, 'I am a tuple 176'] -select * from t0 where k0=177 -Found 1 tuple: -[177, 'I am a tuple 177'] -select * from t0 where k0=178 -Found 1 tuple: -[178, 'I am a tuple 178'] -select * from t0 where k0=179 -Found 1 tuple: -[179, 'I am a tuple 179'] -select * from t0 where k0=180 -Found 1 tuple: -[180, 'I am a tuple 180'] -select * from t0 where k0=181 -Found 1 tuple: -[181, 'I am a tuple 181'] -select * from t0 where k0=182 -Found 1 tuple: -[182, 'I am a tuple 182'] -select * from t0 where k0=183 -Found 1 tuple: -[183, 'I am a tuple 183'] -select * from t0 where k0=184 -Found 1 tuple: -[184, 'I am a tuple 184'] -select * from t0 where k0=185 -Found 1 tuple: -[185, 'I am a tuple 185'] -select * from t0 where k0=186 -Found 1 tuple: -[186, 'I am a tuple 186'] -select * from t0 where k0=187 -Found 1 tuple: -[187, 'I am a tuple 187'] -select * from t0 where k0=188 -Found 1 tuple: -[188, 'I am a tuple 188'] -select * from t0 where k0=189 -Found 1 tuple: -[189, 'I am a tuple 189'] -select * from t0 where k0=190 -Found 1 tuple: -[190, 'I am a tuple 190'] -select * from t0 where k0=191 -Found 1 tuple: -[191, 'I am a tuple 191'] -select * from t0 where k0=192 -Found 1 tuple: -[192, 'I am a tuple 192'] -select * from t0 where k0=193 -Found 1 tuple: -[193, 'I am a tuple 193'] -select * from t0 where k0=194 -Found 1 tuple: -[194, 'I am a tuple 194'] -select * from t0 where k0=195 -Found 1 tuple: -[195, 'I am a tuple 195'] -select * from t0 where k0=196 -Found 1 tuple: -[196, 'I am a tuple 196'] -select * from t0 where k0=197 -Found 1 tuple: -[197, 'I am a tuple 197'] -select * from t0 where k0=198 -Found 1 tuple: -[198, 'I am a tuple 198'] -select * from t0 where k0=199 -Found 1 tuple: -[199, 'I am a tuple 199'] -select * from t0 where k0=200 -Found 1 tuple: -[200, 'I am a tuple 200'] -select * from t0 where k0=201 -Found 1 tuple: -[201, 'I am a tuple 201'] -select * from t0 where k0=202 -Found 1 tuple: -[202, 'I am a tuple 202'] -select * from t0 where k0=203 -Found 1 tuple: -[203, 'I am a tuple 203'] -select * from t0 where k0=204 -Found 1 tuple: -[204, 'I am a tuple 204'] -select * from t0 where k0=205 -Found 1 tuple: -[205, 'I am a tuple 205'] -select * from t0 where k0=206 -Found 1 tuple: -[206, 'I am a tuple 206'] -select * from t0 where k0=207 -Found 1 tuple: -[207, 'I am a tuple 207'] -select * from t0 where k0=208 -Found 1 tuple: -[208, 'I am a tuple 208'] -select * from t0 where k0=209 -Found 1 tuple: -[209, 'I am a tuple 209'] -select * from t0 where k0=210 -Found 1 tuple: -[210, 'I am a tuple 210'] -select * from t0 where k0=211 -Found 1 tuple: -[211, 'I am a tuple 211'] -select * from t0 where k0=212 -Found 1 tuple: -[212, 'I am a tuple 212'] -select * from t0 where k0=213 -Found 1 tuple: -[213, 'I am a tuple 213'] -select * from t0 where k0=214 -Found 1 tuple: -[214, 'I am a tuple 214'] -select * from t0 where k0=215 -Found 1 tuple: -[215, 'I am a tuple 215'] -select * from t0 where k0=216 -Found 1 tuple: -[216, 'I am a tuple 216'] -select * from t0 where k0=217 -Found 1 tuple: -[217, 'I am a tuple 217'] -select * from t0 where k0=218 -Found 1 tuple: -[218, 'I am a tuple 218'] -select * from t0 where k0=219 -Found 1 tuple: -[219, 'I am a tuple 219'] -select * from t0 where k0=220 -Found 1 tuple: -[220, 'I am a tuple 220'] -select * from t0 where k0=221 -Found 1 tuple: -[221, 'I am a tuple 221'] -select * from t0 where k0=222 -Found 1 tuple: -[222, 'I am a tuple 222'] -select * from t0 where k0=223 -Found 1 tuple: -[223, 'I am a tuple 223'] -select * from t0 where k0=224 -Found 1 tuple: -[224, 'I am a tuple 224'] -select * from t0 where k0=225 -Found 1 tuple: -[225, 'I am a tuple 225'] -select * from t0 where k0=226 -Found 1 tuple: -[226, 'I am a tuple 226'] -select * from t0 where k0=227 -Found 1 tuple: -[227, 'I am a tuple 227'] -select * from t0 where k0=228 -Found 1 tuple: -[228, 'I am a tuple 228'] -select * from t0 where k0=229 -Found 1 tuple: -[229, 'I am a tuple 229'] -select * from t0 where k0=230 -Found 1 tuple: -[230, 'I am a tuple 230'] -select * from t0 where k0=231 -Found 1 tuple: -[231, 'I am a tuple 231'] -select * from t0 where k0=232 -Found 1 tuple: -[232, 'I am a tuple 232'] -select * from t0 where k0=233 -Found 1 tuple: -[233, 'I am a tuple 233'] -select * from t0 where k0=234 -Found 1 tuple: -[234, 'I am a tuple 234'] -select * from t0 where k0=235 -Found 1 tuple: -[235, 'I am a tuple 235'] -select * from t0 where k0=236 -Found 1 tuple: -[236, 'I am a tuple 236'] -select * from t0 where k0=237 -Found 1 tuple: -[237, 'I am a tuple 237'] -select * from t0 where k0=238 -Found 1 tuple: -[238, 'I am a tuple 238'] -select * from t0 where k0=239 -Found 1 tuple: -[239, 'I am a tuple 239'] -select * from t0 where k0=240 -Found 1 tuple: -[240, 'I am a tuple 240'] -select * from t0 where k0=241 -Found 1 tuple: -[241, 'I am a tuple 241'] -select * from t0 where k0=242 -Found 1 tuple: -[242, 'I am a tuple 242'] -select * from t0 where k0=243 -Found 1 tuple: -[243, 'I am a tuple 243'] -select * from t0 where k0=244 -Found 1 tuple: -[244, 'I am a tuple 244'] -select * from t0 where k0=245 -Found 1 tuple: -[245, 'I am a tuple 245'] -select * from t0 where k0=246 -Found 1 tuple: -[246, 'I am a tuple 246'] -select * from t0 where k0=247 -Found 1 tuple: -[247, 'I am a tuple 247'] -select * from t0 where k0=248 -Found 1 tuple: -[248, 'I am a tuple 248'] -select * from t0 where k0=249 -Found 1 tuple: -[249, 'I am a tuple 249'] -select * from t0 where k0=250 -Found 1 tuple: -[250, 'I am a tuple 250'] -select * from t0 where k0=251 -Found 1 tuple: -[251, 'I am a tuple 251'] -select * from t0 where k0=252 -Found 1 tuple: -[252, 'I am a tuple 252'] -select * from t0 where k0=253 -Found 1 tuple: -[253, 'I am a tuple 253'] -select * from t0 where k0=254 -Found 1 tuple: -[254, 'I am a tuple 254'] -select * from t0 where k0=255 -Found 1 tuple: -[255, 'I am a tuple 255'] -select * from t0 where k0=256 -Found 1 tuple: -[256, 'I am a tuple 256'] -select * from t0 where k0=257 -Found 1 tuple: -[257, 'I am a tuple 257'] -select * from t0 where k0=258 -Found 1 tuple: -[258, 'I am a tuple 258'] -select * from t0 where k0=259 -Found 1 tuple: -[259, 'I am a tuple 259'] -select * from t0 where k0=260 -Found 1 tuple: -[260, 'I am a tuple 260'] -select * from t0 where k0=261 -Found 1 tuple: -[261, 'I am a tuple 261'] -select * from t0 where k0=262 -Found 1 tuple: -[262, 'I am a tuple 262'] -select * from t0 where k0=263 -Found 1 tuple: -[263, 'I am a tuple 263'] -select * from t0 where k0=264 -Found 1 tuple: -[264, 'I am a tuple 264'] -select * from t0 where k0=265 -Found 1 tuple: -[265, 'I am a tuple 265'] -select * from t0 where k0=266 -Found 1 tuple: -[266, 'I am a tuple 266'] -select * from t0 where k0=267 -Found 1 tuple: -[267, 'I am a tuple 267'] -select * from t0 where k0=268 -Found 1 tuple: -[268, 'I am a tuple 268'] -select * from t0 where k0=269 -Found 1 tuple: -[269, 'I am a tuple 269'] -select * from t0 where k0=270 -Found 1 tuple: -[270, 'I am a tuple 270'] -select * from t0 where k0=271 -Found 1 tuple: -[271, 'I am a tuple 271'] -select * from t0 where k0=272 -Found 1 tuple: -[272, 'I am a tuple 272'] -select * from t0 where k0=273 -Found 1 tuple: -[273, 'I am a tuple 273'] -select * from t0 where k0=274 -Found 1 tuple: -[274, 'I am a tuple 274'] -select * from t0 where k0=275 -Found 1 tuple: -[275, 'I am a tuple 275'] -select * from t0 where k0=276 -Found 1 tuple: -[276, 'I am a tuple 276'] -select * from t0 where k0=277 -Found 1 tuple: -[277, 'I am a tuple 277'] -select * from t0 where k0=278 -Found 1 tuple: -[278, 'I am a tuple 278'] -select * from t0 where k0=279 -Found 1 tuple: -[279, 'I am a tuple 279'] -select * from t0 where k0=280 -Found 1 tuple: -[280, 'I am a tuple 280'] -select * from t0 where k0=281 -Found 1 tuple: -[281, 'I am a tuple 281'] -select * from t0 where k0=282 -Found 1 tuple: -[282, 'I am a tuple 282'] -select * from t0 where k0=283 -Found 1 tuple: -[283, 'I am a tuple 283'] -select * from t0 where k0=284 -Found 1 tuple: -[284, 'I am a tuple 284'] -select * from t0 where k0=285 -Found 1 tuple: -[285, 'I am a tuple 285'] -select * from t0 where k0=286 -Found 1 tuple: -[286, 'I am a tuple 286'] -select * from t0 where k0=287 -Found 1 tuple: -[287, 'I am a tuple 287'] -select * from t0 where k0=288 -Found 1 tuple: -[288, 'I am a tuple 288'] -select * from t0 where k0=289 -Found 1 tuple: -[289, 'I am a tuple 289'] -select * from t0 where k0=290 -Found 1 tuple: -[290, 'I am a tuple 290'] -select * from t0 where k0=291 -Found 1 tuple: -[291, 'I am a tuple 291'] -select * from t0 where k0=292 -Found 1 tuple: -[292, 'I am a tuple 292'] -select * from t0 where k0=293 -Found 1 tuple: -[293, 'I am a tuple 293'] -select * from t0 where k0=294 -Found 1 tuple: -[294, 'I am a tuple 294'] -select * from t0 where k0=295 -Found 1 tuple: -[295, 'I am a tuple 295'] -select * from t0 where k0=296 -Found 1 tuple: -[296, 'I am a tuple 296'] -select * from t0 where k0=297 -Found 1 tuple: -[297, 'I am a tuple 297'] -select * from t0 where k0=298 -Found 1 tuple: -[298, 'I am a tuple 298'] -select * from t0 where k0=299 -Found 1 tuple: -[299, 'I am a tuple 299'] -select * from t0 where k0=300 -Found 1 tuple: -[300, 'I am a tuple 300'] -select * from t0 where k0=301 -Found 1 tuple: -[301, 'I am a tuple 301'] -select * from t0 where k0=302 -Found 1 tuple: -[302, 'I am a tuple 302'] -select * from t0 where k0=303 -Found 1 tuple: -[303, 'I am a tuple 303'] -select * from t0 where k0=304 -Found 1 tuple: -[304, 'I am a tuple 304'] -select * from t0 where k0=305 -Found 1 tuple: -[305, 'I am a tuple 305'] -select * from t0 where k0=306 -Found 1 tuple: -[306, 'I am a tuple 306'] -select * from t0 where k0=307 -Found 1 tuple: -[307, 'I am a tuple 307'] -select * from t0 where k0=308 -Found 1 tuple: -[308, 'I am a tuple 308'] -select * from t0 where k0=309 -Found 1 tuple: -[309, 'I am a tuple 309'] -select * from t0 where k0=310 -Found 1 tuple: -[310, 'I am a tuple 310'] -select * from t0 where k0=311 -Found 1 tuple: -[311, 'I am a tuple 311'] -select * from t0 where k0=312 -Found 1 tuple: -[312, 'I am a tuple 312'] -select * from t0 where k0=313 -Found 1 tuple: -[313, 'I am a tuple 313'] -select * from t0 where k0=314 -Found 1 tuple: -[314, 'I am a tuple 314'] -select * from t0 where k0=315 -Found 1 tuple: -[315, 'I am a tuple 315'] -select * from t0 where k0=316 -Found 1 tuple: -[316, 'I am a tuple 316'] -select * from t0 where k0=317 -Found 1 tuple: -[317, 'I am a tuple 317'] -select * from t0 where k0=318 -Found 1 tuple: -[318, 'I am a tuple 318'] -select * from t0 where k0=319 -Found 1 tuple: -[319, 'I am a tuple 319'] -select * from t0 where k0=320 -Found 1 tuple: -[320, 'I am a tuple 320'] -select * from t0 where k0=321 -Found 1 tuple: -[321, 'I am a tuple 321'] -select * from t0 where k0=322 -Found 1 tuple: -[322, 'I am a tuple 322'] -select * from t0 where k0=323 -Found 1 tuple: -[323, 'I am a tuple 323'] -select * from t0 where k0=324 -Found 1 tuple: -[324, 'I am a tuple 324'] -select * from t0 where k0=325 -Found 1 tuple: -[325, 'I am a tuple 325'] -select * from t0 where k0=326 -Found 1 tuple: -[326, 'I am a tuple 326'] -select * from t0 where k0=327 -Found 1 tuple: -[327, 'I am a tuple 327'] -select * from t0 where k0=328 -Found 1 tuple: -[328, 'I am a tuple 328'] -select * from t0 where k0=329 -Found 1 tuple: -[329, 'I am a tuple 329'] -select * from t0 where k0=330 -Found 1 tuple: -[330, 'I am a tuple 330'] -select * from t0 where k0=331 -Found 1 tuple: -[331, 'I am a tuple 331'] -select * from t0 where k0=332 -Found 1 tuple: -[332, 'I am a tuple 332'] -select * from t0 where k0=333 -Found 1 tuple: -[333, 'I am a tuple 333'] -select * from t0 where k0=334 -Found 1 tuple: -[334, 'I am a tuple 334'] -select * from t0 where k0=335 -Found 1 tuple: -[335, 'I am a tuple 335'] -select * from t0 where k0=336 -Found 1 tuple: -[336, 'I am a tuple 336'] -select * from t0 where k0=337 -Found 1 tuple: -[337, 'I am a tuple 337'] -select * from t0 where k0=338 -Found 1 tuple: -[338, 'I am a tuple 338'] -select * from t0 where k0=339 -Found 1 tuple: -[339, 'I am a tuple 339'] -select * from t0 where k0=340 -Found 1 tuple: -[340, 'I am a tuple 340'] -select * from t0 where k0=341 -Found 1 tuple: -[341, 'I am a tuple 341'] -select * from t0 where k0=342 -Found 1 tuple: -[342, 'I am a tuple 342'] -select * from t0 where k0=343 -Found 1 tuple: -[343, 'I am a tuple 343'] -select * from t0 where k0=344 -Found 1 tuple: -[344, 'I am a tuple 344'] -select * from t0 where k0=345 -Found 1 tuple: -[345, 'I am a tuple 345'] -select * from t0 where k0=346 -Found 1 tuple: -[346, 'I am a tuple 346'] -select * from t0 where k0=347 -Found 1 tuple: -[347, 'I am a tuple 347'] -select * from t0 where k0=348 -Found 1 tuple: -[348, 'I am a tuple 348'] -select * from t0 where k0=349 -Found 1 tuple: -[349, 'I am a tuple 349'] -select * from t0 where k0=350 -Found 1 tuple: -[350, 'I am a tuple 350'] -select * from t0 where k0=351 -Found 1 tuple: -[351, 'I am a tuple 351'] -select * from t0 where k0=352 -Found 1 tuple: -[352, 'I am a tuple 352'] -select * from t0 where k0=353 -Found 1 tuple: -[353, 'I am a tuple 353'] -select * from t0 where k0=354 -Found 1 tuple: -[354, 'I am a tuple 354'] -select * from t0 where k0=355 -Found 1 tuple: -[355, 'I am a tuple 355'] -select * from t0 where k0=356 -Found 1 tuple: -[356, 'I am a tuple 356'] -select * from t0 where k0=357 -Found 1 tuple: -[357, 'I am a tuple 357'] -select * from t0 where k0=358 -Found 1 tuple: -[358, 'I am a tuple 358'] -select * from t0 where k0=359 -Found 1 tuple: -[359, 'I am a tuple 359'] -select * from t0 where k0=360 -Found 1 tuple: -[360, 'I am a tuple 360'] -select * from t0 where k0=361 -Found 1 tuple: -[361, 'I am a tuple 361'] -select * from t0 where k0=362 -Found 1 tuple: -[362, 'I am a tuple 362'] -select * from t0 where k0=363 -Found 1 tuple: -[363, 'I am a tuple 363'] -select * from t0 where k0=364 -Found 1 tuple: -[364, 'I am a tuple 364'] -select * from t0 where k0=365 -Found 1 tuple: -[365, 'I am a tuple 365'] -select * from t0 where k0=366 -Found 1 tuple: -[366, 'I am a tuple 366'] -select * from t0 where k0=367 -Found 1 tuple: -[367, 'I am a tuple 367'] -select * from t0 where k0=368 -Found 1 tuple: -[368, 'I am a tuple 368'] -select * from t0 where k0=369 -Found 1 tuple: -[369, 'I am a tuple 369'] -select * from t0 where k0=370 -Found 1 tuple: -[370, 'I am a tuple 370'] -select * from t0 where k0=371 -Found 1 tuple: -[371, 'I am a tuple 371'] -select * from t0 where k0=372 -Found 1 tuple: -[372, 'I am a tuple 372'] -select * from t0 where k0=373 -Found 1 tuple: -[373, 'I am a tuple 373'] -select * from t0 where k0=374 -Found 1 tuple: -[374, 'I am a tuple 374'] -select * from t0 where k0=375 -Found 1 tuple: -[375, 'I am a tuple 375'] -select * from t0 where k0=376 -Found 1 tuple: -[376, 'I am a tuple 376'] -select * from t0 where k0=377 -Found 1 tuple: -[377, 'I am a tuple 377'] -select * from t0 where k0=378 -Found 1 tuple: -[378, 'I am a tuple 378'] -select * from t0 where k0=379 -Found 1 tuple: -[379, 'I am a tuple 379'] -select * from t0 where k0=380 -Found 1 tuple: -[380, 'I am a tuple 380'] -select * from t0 where k0=381 -Found 1 tuple: -[381, 'I am a tuple 381'] -select * from t0 where k0=382 -Found 1 tuple: -[382, 'I am a tuple 382'] -select * from t0 where k0=383 -Found 1 tuple: -[383, 'I am a tuple 383'] -select * from t0 where k0=384 -Found 1 tuple: -[384, 'I am a tuple 384'] -select * from t0 where k0=385 -Found 1 tuple: -[385, 'I am a tuple 385'] -select * from t0 where k0=386 -Found 1 tuple: -[386, 'I am a tuple 386'] -select * from t0 where k0=387 -Found 1 tuple: -[387, 'I am a tuple 387'] -select * from t0 where k0=388 -Found 1 tuple: -[388, 'I am a tuple 388'] -select * from t0 where k0=389 -Found 1 tuple: -[389, 'I am a tuple 389'] -select * from t0 where k0=390 -Found 1 tuple: -[390, 'I am a tuple 390'] -select * from t0 where k0=391 -Found 1 tuple: -[391, 'I am a tuple 391'] -select * from t0 where k0=392 -Found 1 tuple: -[392, 'I am a tuple 392'] -select * from t0 where k0=393 -Found 1 tuple: -[393, 'I am a tuple 393'] -select * from t0 where k0=394 -Found 1 tuple: -[394, 'I am a tuple 394'] -select * from t0 where k0=395 -Found 1 tuple: -[395, 'I am a tuple 395'] -select * from t0 where k0=396 -Found 1 tuple: -[396, 'I am a tuple 396'] -select * from t0 where k0=397 -Found 1 tuple: -[397, 'I am a tuple 397'] -select * from t0 where k0=398 -Found 1 tuple: -[398, 'I am a tuple 398'] -select * from t0 where k0=399 -Found 1 tuple: -[399, 'I am a tuple 399'] -select * from t0 where k0=400 -Found 1 tuple: -[400, 'I am a tuple 400'] -select * from t0 where k0=401 -Found 1 tuple: -[401, 'I am a tuple 401'] -select * from t0 where k0=402 -Found 1 tuple: -[402, 'I am a tuple 402'] -select * from t0 where k0=403 -Found 1 tuple: -[403, 'I am a tuple 403'] -select * from t0 where k0=404 -Found 1 tuple: -[404, 'I am a tuple 404'] -select * from t0 where k0=405 -Found 1 tuple: -[405, 'I am a tuple 405'] -select * from t0 where k0=406 -Found 1 tuple: -[406, 'I am a tuple 406'] -select * from t0 where k0=407 -Found 1 tuple: -[407, 'I am a tuple 407'] -select * from t0 where k0=408 -Found 1 tuple: -[408, 'I am a tuple 408'] -select * from t0 where k0=409 -Found 1 tuple: -[409, 'I am a tuple 409'] -select * from t0 where k0=410 -Found 1 tuple: -[410, 'I am a tuple 410'] -select * from t0 where k0=411 -Found 1 tuple: -[411, 'I am a tuple 411'] -select * from t0 where k0=412 -Found 1 tuple: -[412, 'I am a tuple 412'] -select * from t0 where k0=413 -Found 1 tuple: -[413, 'I am a tuple 413'] -select * from t0 where k0=414 -Found 1 tuple: -[414, 'I am a tuple 414'] -select * from t0 where k0=415 -Found 1 tuple: -[415, 'I am a tuple 415'] -select * from t0 where k0=416 -Found 1 tuple: -[416, 'I am a tuple 416'] -select * from t0 where k0=417 -Found 1 tuple: -[417, 'I am a tuple 417'] -select * from t0 where k0=418 -Found 1 tuple: -[418, 'I am a tuple 418'] -select * from t0 where k0=419 -Found 1 tuple: -[419, 'I am a tuple 419'] -select * from t0 where k0=420 -Found 1 tuple: -[420, 'I am a tuple 420'] -select * from t0 where k0=421 -Found 1 tuple: -[421, 'I am a tuple 421'] -select * from t0 where k0=422 -Found 1 tuple: -[422, 'I am a tuple 422'] -select * from t0 where k0=423 -Found 1 tuple: -[423, 'I am a tuple 423'] -select * from t0 where k0=424 -Found 1 tuple: -[424, 'I am a tuple 424'] -select * from t0 where k0=425 -Found 1 tuple: -[425, 'I am a tuple 425'] -select * from t0 where k0=426 -Found 1 tuple: -[426, 'I am a tuple 426'] -select * from t0 where k0=427 -Found 1 tuple: -[427, 'I am a tuple 427'] -select * from t0 where k0=428 -Found 1 tuple: -[428, 'I am a tuple 428'] -select * from t0 where k0=429 -Found 1 tuple: -[429, 'I am a tuple 429'] -select * from t0 where k0=430 -Found 1 tuple: -[430, 'I am a tuple 430'] -select * from t0 where k0=431 -Found 1 tuple: -[431, 'I am a tuple 431'] -select * from t0 where k0=432 -Found 1 tuple: -[432, 'I am a tuple 432'] -select * from t0 where k0=433 -Found 1 tuple: -[433, 'I am a tuple 433'] -select * from t0 where k0=434 -Found 1 tuple: -[434, 'I am a tuple 434'] -select * from t0 where k0=435 -Found 1 tuple: -[435, 'I am a tuple 435'] -select * from t0 where k0=436 -Found 1 tuple: -[436, 'I am a tuple 436'] -select * from t0 where k0=437 -Found 1 tuple: -[437, 'I am a tuple 437'] -select * from t0 where k0=438 -Found 1 tuple: -[438, 'I am a tuple 438'] -select * from t0 where k0=439 -Found 1 tuple: -[439, 'I am a tuple 439'] -select * from t0 where k0=440 -Found 1 tuple: -[440, 'I am a tuple 440'] -select * from t0 where k0=441 -Found 1 tuple: -[441, 'I am a tuple 441'] -select * from t0 where k0=442 -Found 1 tuple: -[442, 'I am a tuple 442'] -select * from t0 where k0=443 -Found 1 tuple: -[443, 'I am a tuple 443'] -select * from t0 where k0=444 -Found 1 tuple: -[444, 'I am a tuple 444'] -select * from t0 where k0=445 -Found 1 tuple: -[445, 'I am a tuple 445'] -select * from t0 where k0=446 -Found 1 tuple: -[446, 'I am a tuple 446'] -select * from t0 where k0=447 -Found 1 tuple: -[447, 'I am a tuple 447'] -select * from t0 where k0=448 -Found 1 tuple: -[448, 'I am a tuple 448'] -select * from t0 where k0=449 -Found 1 tuple: -[449, 'I am a tuple 449'] -select * from t0 where k0=450 -Found 1 tuple: -[450, 'I am a tuple 450'] -select * from t0 where k0=451 -Found 1 tuple: -[451, 'I am a tuple 451'] -select * from t0 where k0=452 -Found 1 tuple: -[452, 'I am a tuple 452'] -select * from t0 where k0=453 -Found 1 tuple: -[453, 'I am a tuple 453'] -select * from t0 where k0=454 -Found 1 tuple: -[454, 'I am a tuple 454'] -select * from t0 where k0=455 -Found 1 tuple: -[455, 'I am a tuple 455'] -select * from t0 where k0=456 -Found 1 tuple: -[456, 'I am a tuple 456'] -select * from t0 where k0=457 -Found 1 tuple: -[457, 'I am a tuple 457'] -select * from t0 where k0=458 -Found 1 tuple: -[458, 'I am a tuple 458'] -select * from t0 where k0=459 -Found 1 tuple: -[459, 'I am a tuple 459'] -select * from t0 where k0=460 -Found 1 tuple: -[460, 'I am a tuple 460'] -select * from t0 where k0=461 -Found 1 tuple: -[461, 'I am a tuple 461'] -select * from t0 where k0=462 -Found 1 tuple: -[462, 'I am a tuple 462'] -select * from t0 where k0=463 -Found 1 tuple: -[463, 'I am a tuple 463'] -select * from t0 where k0=464 -Found 1 tuple: -[464, 'I am a tuple 464'] -select * from t0 where k0=465 -Found 1 tuple: -[465, 'I am a tuple 465'] -select * from t0 where k0=466 -Found 1 tuple: -[466, 'I am a tuple 466'] -select * from t0 where k0=467 -Found 1 tuple: -[467, 'I am a tuple 467'] -select * from t0 where k0=468 -Found 1 tuple: -[468, 'I am a tuple 468'] -select * from t0 where k0=469 -Found 1 tuple: -[469, 'I am a tuple 469'] -select * from t0 where k0=470 -Found 1 tuple: -[470, 'I am a tuple 470'] -select * from t0 where k0=471 -Found 1 tuple: -[471, 'I am a tuple 471'] -select * from t0 where k0=472 -Found 1 tuple: -[472, 'I am a tuple 472'] -select * from t0 where k0=473 -Found 1 tuple: -[473, 'I am a tuple 473'] -select * from t0 where k0=474 -Found 1 tuple: -[474, 'I am a tuple 474'] -select * from t0 where k0=475 -Found 1 tuple: -[475, 'I am a tuple 475'] -select * from t0 where k0=476 -Found 1 tuple: -[476, 'I am a tuple 476'] -select * from t0 where k0=477 -Found 1 tuple: -[477, 'I am a tuple 477'] -select * from t0 where k0=478 -Found 1 tuple: -[478, 'I am a tuple 478'] -select * from t0 where k0=479 -Found 1 tuple: -[479, 'I am a tuple 479'] -select * from t0 where k0=480 -Found 1 tuple: -[480, 'I am a tuple 480'] -select * from t0 where k0=481 -Found 1 tuple: -[481, 'I am a tuple 481'] -select * from t0 where k0=482 -Found 1 tuple: -[482, 'I am a tuple 482'] -select * from t0 where k0=483 -Found 1 tuple: -[483, 'I am a tuple 483'] -select * from t0 where k0=484 -Found 1 tuple: -[484, 'I am a tuple 484'] -select * from t0 where k0=485 -Found 1 tuple: -[485, 'I am a tuple 485'] -select * from t0 where k0=486 -Found 1 tuple: -[486, 'I am a tuple 486'] -select * from t0 where k0=487 -Found 1 tuple: -[487, 'I am a tuple 487'] -select * from t0 where k0=488 -Found 1 tuple: -[488, 'I am a tuple 488'] -select * from t0 where k0=489 -Found 1 tuple: -[489, 'I am a tuple 489'] -select * from t0 where k0=490 -Found 1 tuple: -[490, 'I am a tuple 490'] -select * from t0 where k0=491 -Found 1 tuple: -[491, 'I am a tuple 491'] -select * from t0 where k0=492 -Found 1 tuple: -[492, 'I am a tuple 492'] -select * from t0 where k0=493 -Found 1 tuple: -[493, 'I am a tuple 493'] -select * from t0 where k0=494 -Found 1 tuple: -[494, 'I am a tuple 494'] -select * from t0 where k0=495 -Found 1 tuple: -[495, 'I am a tuple 495'] -select * from t0 where k0=496 -Found 1 tuple: -[496, 'I am a tuple 496'] -select * from t0 where k0=497 -Found 1 tuple: -[497, 'I am a tuple 497'] -select * from t0 where k0=498 -Found 1 tuple: -[498, 'I am a tuple 498'] -select * from t0 where k0=499 -Found 1 tuple: -[499, 'I am a tuple 499'] -select * from t0 where k0=500 -No match -# Restore the default server... # # A test case for: http://bugs.launchpad.net/bugs/686411 # Check that 'save snapshot' does not overwrite a snapshot diff --git a/test/box/snapshot.test.py b/test/box/snapshot.test.py index 90ab8ba895..0be0b92a06 100644 --- a/test/box/snapshot.test.py +++ b/test/box/snapshot.test.py @@ -1,26 +1,8 @@ -# encoding: utf-8 -# import os -import time import yaml +import time from signal import SIGUSR1 -print """ -# Verify that the server starts from a pre-recorded snapshot. -# This way we check that the server can read old snapshots (v11) -# going forward. -""" -server.stop() -snapshot = os.path.join(vardir, "00000000000000000500.snap") -os.symlink(os.path.abspath("box/00000000000000000500.snap"), snapshot) -server.start() -for i in range(0, 501): - sql("select * from t0 where k0={0}".format(i)) -print "# Restore the default server..." -server.stop() -os.unlink(snapshot) -server.start() - print """# # A test case for: http://bugs.launchpad.net/bugs/686411 # Check that 'save snapshot' does not overwrite a snapshot diff --git a/test/box/snapshot_1_3.result b/test/box/snapshot_1_3.result new file mode 100644 index 0000000000..2167ee5024 --- /dev/null +++ b/test/box/snapshot_1_3.result @@ -0,0 +1,1507 @@ + +# Verify that the server starts from a pre-recorded snapshot. +# This way we check that the server can read old snapshots (v11) +# going forward. + +select * from t0 where k0=0 +No match +select * from t0 where k0=1 +Found 1 tuple: +[1, 'I am a tuple 1'] +select * from t0 where k0=2 +Found 1 tuple: +[2, 'I am a tuple 2'] +select * from t0 where k0=3 +Found 1 tuple: +[3, 'I am a tuple 3'] +select * from t0 where k0=4 +Found 1 tuple: +[4, 'I am a tuple 4'] +select * from t0 where k0=5 +Found 1 tuple: +[5, 'I am a tuple 5'] +select * from t0 where k0=6 +Found 1 tuple: +[6, 'I am a tuple 6'] +select * from t0 where k0=7 +Found 1 tuple: +[7, 'I am a tuple 7'] +select * from t0 where k0=8 +Found 1 tuple: +[8, 'I am a tuple 8'] +select * from t0 where k0=9 +Found 1 tuple: +[9, 'I am a tuple 9'] +select * from t0 where k0=10 +Found 1 tuple: +[10, 'I am a tuple 10'] +select * from t0 where k0=11 +Found 1 tuple: +[11, 'I am a tuple 11'] +select * from t0 where k0=12 +Found 1 tuple: +[12, 'I am a tuple 12'] +select * from t0 where k0=13 +Found 1 tuple: +[13, 'I am a tuple 13'] +select * from t0 where k0=14 +Found 1 tuple: +[14, 'I am a tuple 14'] +select * from t0 where k0=15 +Found 1 tuple: +[15, 'I am a tuple 15'] +select * from t0 where k0=16 +Found 1 tuple: +[16, 'I am a tuple 16'] +select * from t0 where k0=17 +Found 1 tuple: +[17, 'I am a tuple 17'] +select * from t0 where k0=18 +Found 1 tuple: +[18, 'I am a tuple 18'] +select * from t0 where k0=19 +Found 1 tuple: +[19, 'I am a tuple 19'] +select * from t0 where k0=20 +Found 1 tuple: +[20, 'I am a tuple 20'] +select * from t0 where k0=21 +Found 1 tuple: +[21, 'I am a tuple 21'] +select * from t0 where k0=22 +Found 1 tuple: +[22, 'I am a tuple 22'] +select * from t0 where k0=23 +Found 1 tuple: +[23, 'I am a tuple 23'] +select * from t0 where k0=24 +Found 1 tuple: +[24, 'I am a tuple 24'] +select * from t0 where k0=25 +Found 1 tuple: +[25, 'I am a tuple 25'] +select * from t0 where k0=26 +Found 1 tuple: +[26, 'I am a tuple 26'] +select * from t0 where k0=27 +Found 1 tuple: +[27, 'I am a tuple 27'] +select * from t0 where k0=28 +Found 1 tuple: +[28, 'I am a tuple 28'] +select * from t0 where k0=29 +Found 1 tuple: +[29, 'I am a tuple 29'] +select * from t0 where k0=30 +Found 1 tuple: +[30, 'I am a tuple 30'] +select * from t0 where k0=31 +Found 1 tuple: +[31, 'I am a tuple 31'] +select * from t0 where k0=32 +Found 1 tuple: +[32, 'I am a tuple 32'] +select * from t0 where k0=33 +Found 1 tuple: +[33, 'I am a tuple 33'] +select * from t0 where k0=34 +Found 1 tuple: +[34, 'I am a tuple 34'] +select * from t0 where k0=35 +Found 1 tuple: +[35, 'I am a tuple 35'] +select * from t0 where k0=36 +Found 1 tuple: +[36, 'I am a tuple 36'] +select * from t0 where k0=37 +Found 1 tuple: +[37, 'I am a tuple 37'] +select * from t0 where k0=38 +Found 1 tuple: +[38, 'I am a tuple 38'] +select * from t0 where k0=39 +Found 1 tuple: +[39, 'I am a tuple 39'] +select * from t0 where k0=40 +Found 1 tuple: +[40, 'I am a tuple 40'] +select * from t0 where k0=41 +Found 1 tuple: +[41, 'I am a tuple 41'] +select * from t0 where k0=42 +Found 1 tuple: +[42, 'I am a tuple 42'] +select * from t0 where k0=43 +Found 1 tuple: +[43, 'I am a tuple 43'] +select * from t0 where k0=44 +Found 1 tuple: +[44, 'I am a tuple 44'] +select * from t0 where k0=45 +Found 1 tuple: +[45, 'I am a tuple 45'] +select * from t0 where k0=46 +Found 1 tuple: +[46, 'I am a tuple 46'] +select * from t0 where k0=47 +Found 1 tuple: +[47, 'I am a tuple 47'] +select * from t0 where k0=48 +Found 1 tuple: +[48, 'I am a tuple 48'] +select * from t0 where k0=49 +Found 1 tuple: +[49, 'I am a tuple 49'] +select * from t0 where k0=50 +Found 1 tuple: +[50, 'I am a tuple 50'] +select * from t0 where k0=51 +Found 1 tuple: +[51, 'I am a tuple 51'] +select * from t0 where k0=52 +Found 1 tuple: +[52, 'I am a tuple 52'] +select * from t0 where k0=53 +Found 1 tuple: +[53, 'I am a tuple 53'] +select * from t0 where k0=54 +Found 1 tuple: +[54, 'I am a tuple 54'] +select * from t0 where k0=55 +Found 1 tuple: +[55, 'I am a tuple 55'] +select * from t0 where k0=56 +Found 1 tuple: +[56, 'I am a tuple 56'] +select * from t0 where k0=57 +Found 1 tuple: +[57, 'I am a tuple 57'] +select * from t0 where k0=58 +Found 1 tuple: +[58, 'I am a tuple 58'] +select * from t0 where k0=59 +Found 1 tuple: +[59, 'I am a tuple 59'] +select * from t0 where k0=60 +Found 1 tuple: +[60, 'I am a tuple 60'] +select * from t0 where k0=61 +Found 1 tuple: +[61, 'I am a tuple 61'] +select * from t0 where k0=62 +Found 1 tuple: +[62, 'I am a tuple 62'] +select * from t0 where k0=63 +Found 1 tuple: +[63, 'I am a tuple 63'] +select * from t0 where k0=64 +Found 1 tuple: +[64, 'I am a tuple 64'] +select * from t0 where k0=65 +Found 1 tuple: +[65, 'I am a tuple 65'] +select * from t0 where k0=66 +Found 1 tuple: +[66, 'I am a tuple 66'] +select * from t0 where k0=67 +Found 1 tuple: +[67, 'I am a tuple 67'] +select * from t0 where k0=68 +Found 1 tuple: +[68, 'I am a tuple 68'] +select * from t0 where k0=69 +Found 1 tuple: +[69, 'I am a tuple 69'] +select * from t0 where k0=70 +Found 1 tuple: +[70, 'I am a tuple 70'] +select * from t0 where k0=71 +Found 1 tuple: +[71, 'I am a tuple 71'] +select * from t0 where k0=72 +Found 1 tuple: +[72, 'I am a tuple 72'] +select * from t0 where k0=73 +Found 1 tuple: +[73, 'I am a tuple 73'] +select * from t0 where k0=74 +Found 1 tuple: +[74, 'I am a tuple 74'] +select * from t0 where k0=75 +Found 1 tuple: +[75, 'I am a tuple 75'] +select * from t0 where k0=76 +Found 1 tuple: +[76, 'I am a tuple 76'] +select * from t0 where k0=77 +Found 1 tuple: +[77, 'I am a tuple 77'] +select * from t0 where k0=78 +Found 1 tuple: +[78, 'I am a tuple 78'] +select * from t0 where k0=79 +Found 1 tuple: +[79, 'I am a tuple 79'] +select * from t0 where k0=80 +Found 1 tuple: +[80, 'I am a tuple 80'] +select * from t0 where k0=81 +Found 1 tuple: +[81, 'I am a tuple 81'] +select * from t0 where k0=82 +Found 1 tuple: +[82, 'I am a tuple 82'] +select * from t0 where k0=83 +Found 1 tuple: +[83, 'I am a tuple 83'] +select * from t0 where k0=84 +Found 1 tuple: +[84, 'I am a tuple 84'] +select * from t0 where k0=85 +Found 1 tuple: +[85, 'I am a tuple 85'] +select * from t0 where k0=86 +Found 1 tuple: +[86, 'I am a tuple 86'] +select * from t0 where k0=87 +Found 1 tuple: +[87, 'I am a tuple 87'] +select * from t0 where k0=88 +Found 1 tuple: +[88, 'I am a tuple 88'] +select * from t0 where k0=89 +Found 1 tuple: +[89, 'I am a tuple 89'] +select * from t0 where k0=90 +Found 1 tuple: +[90, 'I am a tuple 90'] +select * from t0 where k0=91 +Found 1 tuple: +[91, 'I am a tuple 91'] +select * from t0 where k0=92 +Found 1 tuple: +[92, 'I am a tuple 92'] +select * from t0 where k0=93 +Found 1 tuple: +[93, 'I am a tuple 93'] +select * from t0 where k0=94 +Found 1 tuple: +[94, 'I am a tuple 94'] +select * from t0 where k0=95 +Found 1 tuple: +[95, 'I am a tuple 95'] +select * from t0 where k0=96 +Found 1 tuple: +[96, 'I am a tuple 96'] +select * from t0 where k0=97 +Found 1 tuple: +[97, 'I am a tuple 97'] +select * from t0 where k0=98 +Found 1 tuple: +[98, 'I am a tuple 98'] +select * from t0 where k0=99 +Found 1 tuple: +[99, 'I am a tuple 99'] +select * from t0 where k0=100 +Found 1 tuple: +[100, 'I am a tuple 100'] +select * from t0 where k0=101 +Found 1 tuple: +[101, 'I am a tuple 101'] +select * from t0 where k0=102 +Found 1 tuple: +[102, 'I am a tuple 102'] +select * from t0 where k0=103 +Found 1 tuple: +[103, 'I am a tuple 103'] +select * from t0 where k0=104 +Found 1 tuple: +[104, 'I am a tuple 104'] +select * from t0 where k0=105 +Found 1 tuple: +[105, 'I am a tuple 105'] +select * from t0 where k0=106 +Found 1 tuple: +[106, 'I am a tuple 106'] +select * from t0 where k0=107 +Found 1 tuple: +[107, 'I am a tuple 107'] +select * from t0 where k0=108 +Found 1 tuple: +[108, 'I am a tuple 108'] +select * from t0 where k0=109 +Found 1 tuple: +[109, 'I am a tuple 109'] +select * from t0 where k0=110 +Found 1 tuple: +[110, 'I am a tuple 110'] +select * from t0 where k0=111 +Found 1 tuple: +[111, 'I am a tuple 111'] +select * from t0 where k0=112 +Found 1 tuple: +[112, 'I am a tuple 112'] +select * from t0 where k0=113 +Found 1 tuple: +[113, 'I am a tuple 113'] +select * from t0 where k0=114 +Found 1 tuple: +[114, 'I am a tuple 114'] +select * from t0 where k0=115 +Found 1 tuple: +[115, 'I am a tuple 115'] +select * from t0 where k0=116 +Found 1 tuple: +[116, 'I am a tuple 116'] +select * from t0 where k0=117 +Found 1 tuple: +[117, 'I am a tuple 117'] +select * from t0 where k0=118 +Found 1 tuple: +[118, 'I am a tuple 118'] +select * from t0 where k0=119 +Found 1 tuple: +[119, 'I am a tuple 119'] +select * from t0 where k0=120 +Found 1 tuple: +[120, 'I am a tuple 120'] +select * from t0 where k0=121 +Found 1 tuple: +[121, 'I am a tuple 121'] +select * from t0 where k0=122 +Found 1 tuple: +[122, 'I am a tuple 122'] +select * from t0 where k0=123 +Found 1 tuple: +[123, 'I am a tuple 123'] +select * from t0 where k0=124 +Found 1 tuple: +[124, 'I am a tuple 124'] +select * from t0 where k0=125 +Found 1 tuple: +[125, 'I am a tuple 125'] +select * from t0 where k0=126 +Found 1 tuple: +[126, 'I am a tuple 126'] +select * from t0 where k0=127 +Found 1 tuple: +[127, 'I am a tuple 127'] +select * from t0 where k0=128 +Found 1 tuple: +[128, 'I am a tuple 128'] +select * from t0 where k0=129 +Found 1 tuple: +[129, 'I am a tuple 129'] +select * from t0 where k0=130 +Found 1 tuple: +[130, 'I am a tuple 130'] +select * from t0 where k0=131 +Found 1 tuple: +[131, 'I am a tuple 131'] +select * from t0 where k0=132 +Found 1 tuple: +[132, 'I am a tuple 132'] +select * from t0 where k0=133 +Found 1 tuple: +[133, 'I am a tuple 133'] +select * from t0 where k0=134 +Found 1 tuple: +[134, 'I am a tuple 134'] +select * from t0 where k0=135 +Found 1 tuple: +[135, 'I am a tuple 135'] +select * from t0 where k0=136 +Found 1 tuple: +[136, 'I am a tuple 136'] +select * from t0 where k0=137 +Found 1 tuple: +[137, 'I am a tuple 137'] +select * from t0 where k0=138 +Found 1 tuple: +[138, 'I am a tuple 138'] +select * from t0 where k0=139 +Found 1 tuple: +[139, 'I am a tuple 139'] +select * from t0 where k0=140 +Found 1 tuple: +[140, 'I am a tuple 140'] +select * from t0 where k0=141 +Found 1 tuple: +[141, 'I am a tuple 141'] +select * from t0 where k0=142 +Found 1 tuple: +[142, 'I am a tuple 142'] +select * from t0 where k0=143 +Found 1 tuple: +[143, 'I am a tuple 143'] +select * from t0 where k0=144 +Found 1 tuple: +[144, 'I am a tuple 144'] +select * from t0 where k0=145 +Found 1 tuple: +[145, 'I am a tuple 145'] +select * from t0 where k0=146 +Found 1 tuple: +[146, 'I am a tuple 146'] +select * from t0 where k0=147 +Found 1 tuple: +[147, 'I am a tuple 147'] +select * from t0 where k0=148 +Found 1 tuple: +[148, 'I am a tuple 148'] +select * from t0 where k0=149 +Found 1 tuple: +[149, 'I am a tuple 149'] +select * from t0 where k0=150 +Found 1 tuple: +[150, 'I am a tuple 150'] +select * from t0 where k0=151 +Found 1 tuple: +[151, 'I am a tuple 151'] +select * from t0 where k0=152 +Found 1 tuple: +[152, 'I am a tuple 152'] +select * from t0 where k0=153 +Found 1 tuple: +[153, 'I am a tuple 153'] +select * from t0 where k0=154 +Found 1 tuple: +[154, 'I am a tuple 154'] +select * from t0 where k0=155 +Found 1 tuple: +[155, 'I am a tuple 155'] +select * from t0 where k0=156 +Found 1 tuple: +[156, 'I am a tuple 156'] +select * from t0 where k0=157 +Found 1 tuple: +[157, 'I am a tuple 157'] +select * from t0 where k0=158 +Found 1 tuple: +[158, 'I am a tuple 158'] +select * from t0 where k0=159 +Found 1 tuple: +[159, 'I am a tuple 159'] +select * from t0 where k0=160 +Found 1 tuple: +[160, 'I am a tuple 160'] +select * from t0 where k0=161 +Found 1 tuple: +[161, 'I am a tuple 161'] +select * from t0 where k0=162 +Found 1 tuple: +[162, 'I am a tuple 162'] +select * from t0 where k0=163 +Found 1 tuple: +[163, 'I am a tuple 163'] +select * from t0 where k0=164 +Found 1 tuple: +[164, 'I am a tuple 164'] +select * from t0 where k0=165 +Found 1 tuple: +[165, 'I am a tuple 165'] +select * from t0 where k0=166 +Found 1 tuple: +[166, 'I am a tuple 166'] +select * from t0 where k0=167 +Found 1 tuple: +[167, 'I am a tuple 167'] +select * from t0 where k0=168 +Found 1 tuple: +[168, 'I am a tuple 168'] +select * from t0 where k0=169 +Found 1 tuple: +[169, 'I am a tuple 169'] +select * from t0 where k0=170 +Found 1 tuple: +[170, 'I am a tuple 170'] +select * from t0 where k0=171 +Found 1 tuple: +[171, 'I am a tuple 171'] +select * from t0 where k0=172 +Found 1 tuple: +[172, 'I am a tuple 172'] +select * from t0 where k0=173 +Found 1 tuple: +[173, 'I am a tuple 173'] +select * from t0 where k0=174 +Found 1 tuple: +[174, 'I am a tuple 174'] +select * from t0 where k0=175 +Found 1 tuple: +[175, 'I am a tuple 175'] +select * from t0 where k0=176 +Found 1 tuple: +[176, 'I am a tuple 176'] +select * from t0 where k0=177 +Found 1 tuple: +[177, 'I am a tuple 177'] +select * from t0 where k0=178 +Found 1 tuple: +[178, 'I am a tuple 178'] +select * from t0 where k0=179 +Found 1 tuple: +[179, 'I am a tuple 179'] +select * from t0 where k0=180 +Found 1 tuple: +[180, 'I am a tuple 180'] +select * from t0 where k0=181 +Found 1 tuple: +[181, 'I am a tuple 181'] +select * from t0 where k0=182 +Found 1 tuple: +[182, 'I am a tuple 182'] +select * from t0 where k0=183 +Found 1 tuple: +[183, 'I am a tuple 183'] +select * from t0 where k0=184 +Found 1 tuple: +[184, 'I am a tuple 184'] +select * from t0 where k0=185 +Found 1 tuple: +[185, 'I am a tuple 185'] +select * from t0 where k0=186 +Found 1 tuple: +[186, 'I am a tuple 186'] +select * from t0 where k0=187 +Found 1 tuple: +[187, 'I am a tuple 187'] +select * from t0 where k0=188 +Found 1 tuple: +[188, 'I am a tuple 188'] +select * from t0 where k0=189 +Found 1 tuple: +[189, 'I am a tuple 189'] +select * from t0 where k0=190 +Found 1 tuple: +[190, 'I am a tuple 190'] +select * from t0 where k0=191 +Found 1 tuple: +[191, 'I am a tuple 191'] +select * from t0 where k0=192 +Found 1 tuple: +[192, 'I am a tuple 192'] +select * from t0 where k0=193 +Found 1 tuple: +[193, 'I am a tuple 193'] +select * from t0 where k0=194 +Found 1 tuple: +[194, 'I am a tuple 194'] +select * from t0 where k0=195 +Found 1 tuple: +[195, 'I am a tuple 195'] +select * from t0 where k0=196 +Found 1 tuple: +[196, 'I am a tuple 196'] +select * from t0 where k0=197 +Found 1 tuple: +[197, 'I am a tuple 197'] +select * from t0 where k0=198 +Found 1 tuple: +[198, 'I am a tuple 198'] +select * from t0 where k0=199 +Found 1 tuple: +[199, 'I am a tuple 199'] +select * from t0 where k0=200 +Found 1 tuple: +[200, 'I am a tuple 200'] +select * from t0 where k0=201 +Found 1 tuple: +[201, 'I am a tuple 201'] +select * from t0 where k0=202 +Found 1 tuple: +[202, 'I am a tuple 202'] +select * from t0 where k0=203 +Found 1 tuple: +[203, 'I am a tuple 203'] +select * from t0 where k0=204 +Found 1 tuple: +[204, 'I am a tuple 204'] +select * from t0 where k0=205 +Found 1 tuple: +[205, 'I am a tuple 205'] +select * from t0 where k0=206 +Found 1 tuple: +[206, 'I am a tuple 206'] +select * from t0 where k0=207 +Found 1 tuple: +[207, 'I am a tuple 207'] +select * from t0 where k0=208 +Found 1 tuple: +[208, 'I am a tuple 208'] +select * from t0 where k0=209 +Found 1 tuple: +[209, 'I am a tuple 209'] +select * from t0 where k0=210 +Found 1 tuple: +[210, 'I am a tuple 210'] +select * from t0 where k0=211 +Found 1 tuple: +[211, 'I am a tuple 211'] +select * from t0 where k0=212 +Found 1 tuple: +[212, 'I am a tuple 212'] +select * from t0 where k0=213 +Found 1 tuple: +[213, 'I am a tuple 213'] +select * from t0 where k0=214 +Found 1 tuple: +[214, 'I am a tuple 214'] +select * from t0 where k0=215 +Found 1 tuple: +[215, 'I am a tuple 215'] +select * from t0 where k0=216 +Found 1 tuple: +[216, 'I am a tuple 216'] +select * from t0 where k0=217 +Found 1 tuple: +[217, 'I am a tuple 217'] +select * from t0 where k0=218 +Found 1 tuple: +[218, 'I am a tuple 218'] +select * from t0 where k0=219 +Found 1 tuple: +[219, 'I am a tuple 219'] +select * from t0 where k0=220 +Found 1 tuple: +[220, 'I am a tuple 220'] +select * from t0 where k0=221 +Found 1 tuple: +[221, 'I am a tuple 221'] +select * from t0 where k0=222 +Found 1 tuple: +[222, 'I am a tuple 222'] +select * from t0 where k0=223 +Found 1 tuple: +[223, 'I am a tuple 223'] +select * from t0 where k0=224 +Found 1 tuple: +[224, 'I am a tuple 224'] +select * from t0 where k0=225 +Found 1 tuple: +[225, 'I am a tuple 225'] +select * from t0 where k0=226 +Found 1 tuple: +[226, 'I am a tuple 226'] +select * from t0 where k0=227 +Found 1 tuple: +[227, 'I am a tuple 227'] +select * from t0 where k0=228 +Found 1 tuple: +[228, 'I am a tuple 228'] +select * from t0 where k0=229 +Found 1 tuple: +[229, 'I am a tuple 229'] +select * from t0 where k0=230 +Found 1 tuple: +[230, 'I am a tuple 230'] +select * from t0 where k0=231 +Found 1 tuple: +[231, 'I am a tuple 231'] +select * from t0 where k0=232 +Found 1 tuple: +[232, 'I am a tuple 232'] +select * from t0 where k0=233 +Found 1 tuple: +[233, 'I am a tuple 233'] +select * from t0 where k0=234 +Found 1 tuple: +[234, 'I am a tuple 234'] +select * from t0 where k0=235 +Found 1 tuple: +[235, 'I am a tuple 235'] +select * from t0 where k0=236 +Found 1 tuple: +[236, 'I am a tuple 236'] +select * from t0 where k0=237 +Found 1 tuple: +[237, 'I am a tuple 237'] +select * from t0 where k0=238 +Found 1 tuple: +[238, 'I am a tuple 238'] +select * from t0 where k0=239 +Found 1 tuple: +[239, 'I am a tuple 239'] +select * from t0 where k0=240 +Found 1 tuple: +[240, 'I am a tuple 240'] +select * from t0 where k0=241 +Found 1 tuple: +[241, 'I am a tuple 241'] +select * from t0 where k0=242 +Found 1 tuple: +[242, 'I am a tuple 242'] +select * from t0 where k0=243 +Found 1 tuple: +[243, 'I am a tuple 243'] +select * from t0 where k0=244 +Found 1 tuple: +[244, 'I am a tuple 244'] +select * from t0 where k0=245 +Found 1 tuple: +[245, 'I am a tuple 245'] +select * from t0 where k0=246 +Found 1 tuple: +[246, 'I am a tuple 246'] +select * from t0 where k0=247 +Found 1 tuple: +[247, 'I am a tuple 247'] +select * from t0 where k0=248 +Found 1 tuple: +[248, 'I am a tuple 248'] +select * from t0 where k0=249 +Found 1 tuple: +[249, 'I am a tuple 249'] +select * from t0 where k0=250 +Found 1 tuple: +[250, 'I am a tuple 250'] +select * from t0 where k0=251 +Found 1 tuple: +[251, 'I am a tuple 251'] +select * from t0 where k0=252 +Found 1 tuple: +[252, 'I am a tuple 252'] +select * from t0 where k0=253 +Found 1 tuple: +[253, 'I am a tuple 253'] +select * from t0 where k0=254 +Found 1 tuple: +[254, 'I am a tuple 254'] +select * from t0 where k0=255 +Found 1 tuple: +[255, 'I am a tuple 255'] +select * from t0 where k0=256 +Found 1 tuple: +[256, 'I am a tuple 256'] +select * from t0 where k0=257 +Found 1 tuple: +[257, 'I am a tuple 257'] +select * from t0 where k0=258 +Found 1 tuple: +[258, 'I am a tuple 258'] +select * from t0 where k0=259 +Found 1 tuple: +[259, 'I am a tuple 259'] +select * from t0 where k0=260 +Found 1 tuple: +[260, 'I am a tuple 260'] +select * from t0 where k0=261 +Found 1 tuple: +[261, 'I am a tuple 261'] +select * from t0 where k0=262 +Found 1 tuple: +[262, 'I am a tuple 262'] +select * from t0 where k0=263 +Found 1 tuple: +[263, 'I am a tuple 263'] +select * from t0 where k0=264 +Found 1 tuple: +[264, 'I am a tuple 264'] +select * from t0 where k0=265 +Found 1 tuple: +[265, 'I am a tuple 265'] +select * from t0 where k0=266 +Found 1 tuple: +[266, 'I am a tuple 266'] +select * from t0 where k0=267 +Found 1 tuple: +[267, 'I am a tuple 267'] +select * from t0 where k0=268 +Found 1 tuple: +[268, 'I am a tuple 268'] +select * from t0 where k0=269 +Found 1 tuple: +[269, 'I am a tuple 269'] +select * from t0 where k0=270 +Found 1 tuple: +[270, 'I am a tuple 270'] +select * from t0 where k0=271 +Found 1 tuple: +[271, 'I am a tuple 271'] +select * from t0 where k0=272 +Found 1 tuple: +[272, 'I am a tuple 272'] +select * from t0 where k0=273 +Found 1 tuple: +[273, 'I am a tuple 273'] +select * from t0 where k0=274 +Found 1 tuple: +[274, 'I am a tuple 274'] +select * from t0 where k0=275 +Found 1 tuple: +[275, 'I am a tuple 275'] +select * from t0 where k0=276 +Found 1 tuple: +[276, 'I am a tuple 276'] +select * from t0 where k0=277 +Found 1 tuple: +[277, 'I am a tuple 277'] +select * from t0 where k0=278 +Found 1 tuple: +[278, 'I am a tuple 278'] +select * from t0 where k0=279 +Found 1 tuple: +[279, 'I am a tuple 279'] +select * from t0 where k0=280 +Found 1 tuple: +[280, 'I am a tuple 280'] +select * from t0 where k0=281 +Found 1 tuple: +[281, 'I am a tuple 281'] +select * from t0 where k0=282 +Found 1 tuple: +[282, 'I am a tuple 282'] +select * from t0 where k0=283 +Found 1 tuple: +[283, 'I am a tuple 283'] +select * from t0 where k0=284 +Found 1 tuple: +[284, 'I am a tuple 284'] +select * from t0 where k0=285 +Found 1 tuple: +[285, 'I am a tuple 285'] +select * from t0 where k0=286 +Found 1 tuple: +[286, 'I am a tuple 286'] +select * from t0 where k0=287 +Found 1 tuple: +[287, 'I am a tuple 287'] +select * from t0 where k0=288 +Found 1 tuple: +[288, 'I am a tuple 288'] +select * from t0 where k0=289 +Found 1 tuple: +[289, 'I am a tuple 289'] +select * from t0 where k0=290 +Found 1 tuple: +[290, 'I am a tuple 290'] +select * from t0 where k0=291 +Found 1 tuple: +[291, 'I am a tuple 291'] +select * from t0 where k0=292 +Found 1 tuple: +[292, 'I am a tuple 292'] +select * from t0 where k0=293 +Found 1 tuple: +[293, 'I am a tuple 293'] +select * from t0 where k0=294 +Found 1 tuple: +[294, 'I am a tuple 294'] +select * from t0 where k0=295 +Found 1 tuple: +[295, 'I am a tuple 295'] +select * from t0 where k0=296 +Found 1 tuple: +[296, 'I am a tuple 296'] +select * from t0 where k0=297 +Found 1 tuple: +[297, 'I am a tuple 297'] +select * from t0 where k0=298 +Found 1 tuple: +[298, 'I am a tuple 298'] +select * from t0 where k0=299 +Found 1 tuple: +[299, 'I am a tuple 299'] +select * from t0 where k0=300 +Found 1 tuple: +[300, 'I am a tuple 300'] +select * from t0 where k0=301 +Found 1 tuple: +[301, 'I am a tuple 301'] +select * from t0 where k0=302 +Found 1 tuple: +[302, 'I am a tuple 302'] +select * from t0 where k0=303 +Found 1 tuple: +[303, 'I am a tuple 303'] +select * from t0 where k0=304 +Found 1 tuple: +[304, 'I am a tuple 304'] +select * from t0 where k0=305 +Found 1 tuple: +[305, 'I am a tuple 305'] +select * from t0 where k0=306 +Found 1 tuple: +[306, 'I am a tuple 306'] +select * from t0 where k0=307 +Found 1 tuple: +[307, 'I am a tuple 307'] +select * from t0 where k0=308 +Found 1 tuple: +[308, 'I am a tuple 308'] +select * from t0 where k0=309 +Found 1 tuple: +[309, 'I am a tuple 309'] +select * from t0 where k0=310 +Found 1 tuple: +[310, 'I am a tuple 310'] +select * from t0 where k0=311 +Found 1 tuple: +[311, 'I am a tuple 311'] +select * from t0 where k0=312 +Found 1 tuple: +[312, 'I am a tuple 312'] +select * from t0 where k0=313 +Found 1 tuple: +[313, 'I am a tuple 313'] +select * from t0 where k0=314 +Found 1 tuple: +[314, 'I am a tuple 314'] +select * from t0 where k0=315 +Found 1 tuple: +[315, 'I am a tuple 315'] +select * from t0 where k0=316 +Found 1 tuple: +[316, 'I am a tuple 316'] +select * from t0 where k0=317 +Found 1 tuple: +[317, 'I am a tuple 317'] +select * from t0 where k0=318 +Found 1 tuple: +[318, 'I am a tuple 318'] +select * from t0 where k0=319 +Found 1 tuple: +[319, 'I am a tuple 319'] +select * from t0 where k0=320 +Found 1 tuple: +[320, 'I am a tuple 320'] +select * from t0 where k0=321 +Found 1 tuple: +[321, 'I am a tuple 321'] +select * from t0 where k0=322 +Found 1 tuple: +[322, 'I am a tuple 322'] +select * from t0 where k0=323 +Found 1 tuple: +[323, 'I am a tuple 323'] +select * from t0 where k0=324 +Found 1 tuple: +[324, 'I am a tuple 324'] +select * from t0 where k0=325 +Found 1 tuple: +[325, 'I am a tuple 325'] +select * from t0 where k0=326 +Found 1 tuple: +[326, 'I am a tuple 326'] +select * from t0 where k0=327 +Found 1 tuple: +[327, 'I am a tuple 327'] +select * from t0 where k0=328 +Found 1 tuple: +[328, 'I am a tuple 328'] +select * from t0 where k0=329 +Found 1 tuple: +[329, 'I am a tuple 329'] +select * from t0 where k0=330 +Found 1 tuple: +[330, 'I am a tuple 330'] +select * from t0 where k0=331 +Found 1 tuple: +[331, 'I am a tuple 331'] +select * from t0 where k0=332 +Found 1 tuple: +[332, 'I am a tuple 332'] +select * from t0 where k0=333 +Found 1 tuple: +[333, 'I am a tuple 333'] +select * from t0 where k0=334 +Found 1 tuple: +[334, 'I am a tuple 334'] +select * from t0 where k0=335 +Found 1 tuple: +[335, 'I am a tuple 335'] +select * from t0 where k0=336 +Found 1 tuple: +[336, 'I am a tuple 336'] +select * from t0 where k0=337 +Found 1 tuple: +[337, 'I am a tuple 337'] +select * from t0 where k0=338 +Found 1 tuple: +[338, 'I am a tuple 338'] +select * from t0 where k0=339 +Found 1 tuple: +[339, 'I am a tuple 339'] +select * from t0 where k0=340 +Found 1 tuple: +[340, 'I am a tuple 340'] +select * from t0 where k0=341 +Found 1 tuple: +[341, 'I am a tuple 341'] +select * from t0 where k0=342 +Found 1 tuple: +[342, 'I am a tuple 342'] +select * from t0 where k0=343 +Found 1 tuple: +[343, 'I am a tuple 343'] +select * from t0 where k0=344 +Found 1 tuple: +[344, 'I am a tuple 344'] +select * from t0 where k0=345 +Found 1 tuple: +[345, 'I am a tuple 345'] +select * from t0 where k0=346 +Found 1 tuple: +[346, 'I am a tuple 346'] +select * from t0 where k0=347 +Found 1 tuple: +[347, 'I am a tuple 347'] +select * from t0 where k0=348 +Found 1 tuple: +[348, 'I am a tuple 348'] +select * from t0 where k0=349 +Found 1 tuple: +[349, 'I am a tuple 349'] +select * from t0 where k0=350 +Found 1 tuple: +[350, 'I am a tuple 350'] +select * from t0 where k0=351 +Found 1 tuple: +[351, 'I am a tuple 351'] +select * from t0 where k0=352 +Found 1 tuple: +[352, 'I am a tuple 352'] +select * from t0 where k0=353 +Found 1 tuple: +[353, 'I am a tuple 353'] +select * from t0 where k0=354 +Found 1 tuple: +[354, 'I am a tuple 354'] +select * from t0 where k0=355 +Found 1 tuple: +[355, 'I am a tuple 355'] +select * from t0 where k0=356 +Found 1 tuple: +[356, 'I am a tuple 356'] +select * from t0 where k0=357 +Found 1 tuple: +[357, 'I am a tuple 357'] +select * from t0 where k0=358 +Found 1 tuple: +[358, 'I am a tuple 358'] +select * from t0 where k0=359 +Found 1 tuple: +[359, 'I am a tuple 359'] +select * from t0 where k0=360 +Found 1 tuple: +[360, 'I am a tuple 360'] +select * from t0 where k0=361 +Found 1 tuple: +[361, 'I am a tuple 361'] +select * from t0 where k0=362 +Found 1 tuple: +[362, 'I am a tuple 362'] +select * from t0 where k0=363 +Found 1 tuple: +[363, 'I am a tuple 363'] +select * from t0 where k0=364 +Found 1 tuple: +[364, 'I am a tuple 364'] +select * from t0 where k0=365 +Found 1 tuple: +[365, 'I am a tuple 365'] +select * from t0 where k0=366 +Found 1 tuple: +[366, 'I am a tuple 366'] +select * from t0 where k0=367 +Found 1 tuple: +[367, 'I am a tuple 367'] +select * from t0 where k0=368 +Found 1 tuple: +[368, 'I am a tuple 368'] +select * from t0 where k0=369 +Found 1 tuple: +[369, 'I am a tuple 369'] +select * from t0 where k0=370 +Found 1 tuple: +[370, 'I am a tuple 370'] +select * from t0 where k0=371 +Found 1 tuple: +[371, 'I am a tuple 371'] +select * from t0 where k0=372 +Found 1 tuple: +[372, 'I am a tuple 372'] +select * from t0 where k0=373 +Found 1 tuple: +[373, 'I am a tuple 373'] +select * from t0 where k0=374 +Found 1 tuple: +[374, 'I am a tuple 374'] +select * from t0 where k0=375 +Found 1 tuple: +[375, 'I am a tuple 375'] +select * from t0 where k0=376 +Found 1 tuple: +[376, 'I am a tuple 376'] +select * from t0 where k0=377 +Found 1 tuple: +[377, 'I am a tuple 377'] +select * from t0 where k0=378 +Found 1 tuple: +[378, 'I am a tuple 378'] +select * from t0 where k0=379 +Found 1 tuple: +[379, 'I am a tuple 379'] +select * from t0 where k0=380 +Found 1 tuple: +[380, 'I am a tuple 380'] +select * from t0 where k0=381 +Found 1 tuple: +[381, 'I am a tuple 381'] +select * from t0 where k0=382 +Found 1 tuple: +[382, 'I am a tuple 382'] +select * from t0 where k0=383 +Found 1 tuple: +[383, 'I am a tuple 383'] +select * from t0 where k0=384 +Found 1 tuple: +[384, 'I am a tuple 384'] +select * from t0 where k0=385 +Found 1 tuple: +[385, 'I am a tuple 385'] +select * from t0 where k0=386 +Found 1 tuple: +[386, 'I am a tuple 386'] +select * from t0 where k0=387 +Found 1 tuple: +[387, 'I am a tuple 387'] +select * from t0 where k0=388 +Found 1 tuple: +[388, 'I am a tuple 388'] +select * from t0 where k0=389 +Found 1 tuple: +[389, 'I am a tuple 389'] +select * from t0 where k0=390 +Found 1 tuple: +[390, 'I am a tuple 390'] +select * from t0 where k0=391 +Found 1 tuple: +[391, 'I am a tuple 391'] +select * from t0 where k0=392 +Found 1 tuple: +[392, 'I am a tuple 392'] +select * from t0 where k0=393 +Found 1 tuple: +[393, 'I am a tuple 393'] +select * from t0 where k0=394 +Found 1 tuple: +[394, 'I am a tuple 394'] +select * from t0 where k0=395 +Found 1 tuple: +[395, 'I am a tuple 395'] +select * from t0 where k0=396 +Found 1 tuple: +[396, 'I am a tuple 396'] +select * from t0 where k0=397 +Found 1 tuple: +[397, 'I am a tuple 397'] +select * from t0 where k0=398 +Found 1 tuple: +[398, 'I am a tuple 398'] +select * from t0 where k0=399 +Found 1 tuple: +[399, 'I am a tuple 399'] +select * from t0 where k0=400 +Found 1 tuple: +[400, 'I am a tuple 400'] +select * from t0 where k0=401 +Found 1 tuple: +[401, 'I am a tuple 401'] +select * from t0 where k0=402 +Found 1 tuple: +[402, 'I am a tuple 402'] +select * from t0 where k0=403 +Found 1 tuple: +[403, 'I am a tuple 403'] +select * from t0 where k0=404 +Found 1 tuple: +[404, 'I am a tuple 404'] +select * from t0 where k0=405 +Found 1 tuple: +[405, 'I am a tuple 405'] +select * from t0 where k0=406 +Found 1 tuple: +[406, 'I am a tuple 406'] +select * from t0 where k0=407 +Found 1 tuple: +[407, 'I am a tuple 407'] +select * from t0 where k0=408 +Found 1 tuple: +[408, 'I am a tuple 408'] +select * from t0 where k0=409 +Found 1 tuple: +[409, 'I am a tuple 409'] +select * from t0 where k0=410 +Found 1 tuple: +[410, 'I am a tuple 410'] +select * from t0 where k0=411 +Found 1 tuple: +[411, 'I am a tuple 411'] +select * from t0 where k0=412 +Found 1 tuple: +[412, 'I am a tuple 412'] +select * from t0 where k0=413 +Found 1 tuple: +[413, 'I am a tuple 413'] +select * from t0 where k0=414 +Found 1 tuple: +[414, 'I am a tuple 414'] +select * from t0 where k0=415 +Found 1 tuple: +[415, 'I am a tuple 415'] +select * from t0 where k0=416 +Found 1 tuple: +[416, 'I am a tuple 416'] +select * from t0 where k0=417 +Found 1 tuple: +[417, 'I am a tuple 417'] +select * from t0 where k0=418 +Found 1 tuple: +[418, 'I am a tuple 418'] +select * from t0 where k0=419 +Found 1 tuple: +[419, 'I am a tuple 419'] +select * from t0 where k0=420 +Found 1 tuple: +[420, 'I am a tuple 420'] +select * from t0 where k0=421 +Found 1 tuple: +[421, 'I am a tuple 421'] +select * from t0 where k0=422 +Found 1 tuple: +[422, 'I am a tuple 422'] +select * from t0 where k0=423 +Found 1 tuple: +[423, 'I am a tuple 423'] +select * from t0 where k0=424 +Found 1 tuple: +[424, 'I am a tuple 424'] +select * from t0 where k0=425 +Found 1 tuple: +[425, 'I am a tuple 425'] +select * from t0 where k0=426 +Found 1 tuple: +[426, 'I am a tuple 426'] +select * from t0 where k0=427 +Found 1 tuple: +[427, 'I am a tuple 427'] +select * from t0 where k0=428 +Found 1 tuple: +[428, 'I am a tuple 428'] +select * from t0 where k0=429 +Found 1 tuple: +[429, 'I am a tuple 429'] +select * from t0 where k0=430 +Found 1 tuple: +[430, 'I am a tuple 430'] +select * from t0 where k0=431 +Found 1 tuple: +[431, 'I am a tuple 431'] +select * from t0 where k0=432 +Found 1 tuple: +[432, 'I am a tuple 432'] +select * from t0 where k0=433 +Found 1 tuple: +[433, 'I am a tuple 433'] +select * from t0 where k0=434 +Found 1 tuple: +[434, 'I am a tuple 434'] +select * from t0 where k0=435 +Found 1 tuple: +[435, 'I am a tuple 435'] +select * from t0 where k0=436 +Found 1 tuple: +[436, 'I am a tuple 436'] +select * from t0 where k0=437 +Found 1 tuple: +[437, 'I am a tuple 437'] +select * from t0 where k0=438 +Found 1 tuple: +[438, 'I am a tuple 438'] +select * from t0 where k0=439 +Found 1 tuple: +[439, 'I am a tuple 439'] +select * from t0 where k0=440 +Found 1 tuple: +[440, 'I am a tuple 440'] +select * from t0 where k0=441 +Found 1 tuple: +[441, 'I am a tuple 441'] +select * from t0 where k0=442 +Found 1 tuple: +[442, 'I am a tuple 442'] +select * from t0 where k0=443 +Found 1 tuple: +[443, 'I am a tuple 443'] +select * from t0 where k0=444 +Found 1 tuple: +[444, 'I am a tuple 444'] +select * from t0 where k0=445 +Found 1 tuple: +[445, 'I am a tuple 445'] +select * from t0 where k0=446 +Found 1 tuple: +[446, 'I am a tuple 446'] +select * from t0 where k0=447 +Found 1 tuple: +[447, 'I am a tuple 447'] +select * from t0 where k0=448 +Found 1 tuple: +[448, 'I am a tuple 448'] +select * from t0 where k0=449 +Found 1 tuple: +[449, 'I am a tuple 449'] +select * from t0 where k0=450 +Found 1 tuple: +[450, 'I am a tuple 450'] +select * from t0 where k0=451 +Found 1 tuple: +[451, 'I am a tuple 451'] +select * from t0 where k0=452 +Found 1 tuple: +[452, 'I am a tuple 452'] +select * from t0 where k0=453 +Found 1 tuple: +[453, 'I am a tuple 453'] +select * from t0 where k0=454 +Found 1 tuple: +[454, 'I am a tuple 454'] +select * from t0 where k0=455 +Found 1 tuple: +[455, 'I am a tuple 455'] +select * from t0 where k0=456 +Found 1 tuple: +[456, 'I am a tuple 456'] +select * from t0 where k0=457 +Found 1 tuple: +[457, 'I am a tuple 457'] +select * from t0 where k0=458 +Found 1 tuple: +[458, 'I am a tuple 458'] +select * from t0 where k0=459 +Found 1 tuple: +[459, 'I am a tuple 459'] +select * from t0 where k0=460 +Found 1 tuple: +[460, 'I am a tuple 460'] +select * from t0 where k0=461 +Found 1 tuple: +[461, 'I am a tuple 461'] +select * from t0 where k0=462 +Found 1 tuple: +[462, 'I am a tuple 462'] +select * from t0 where k0=463 +Found 1 tuple: +[463, 'I am a tuple 463'] +select * from t0 where k0=464 +Found 1 tuple: +[464, 'I am a tuple 464'] +select * from t0 where k0=465 +Found 1 tuple: +[465, 'I am a tuple 465'] +select * from t0 where k0=466 +Found 1 tuple: +[466, 'I am a tuple 466'] +select * from t0 where k0=467 +Found 1 tuple: +[467, 'I am a tuple 467'] +select * from t0 where k0=468 +Found 1 tuple: +[468, 'I am a tuple 468'] +select * from t0 where k0=469 +Found 1 tuple: +[469, 'I am a tuple 469'] +select * from t0 where k0=470 +Found 1 tuple: +[470, 'I am a tuple 470'] +select * from t0 where k0=471 +Found 1 tuple: +[471, 'I am a tuple 471'] +select * from t0 where k0=472 +Found 1 tuple: +[472, 'I am a tuple 472'] +select * from t0 where k0=473 +Found 1 tuple: +[473, 'I am a tuple 473'] +select * from t0 where k0=474 +Found 1 tuple: +[474, 'I am a tuple 474'] +select * from t0 where k0=475 +Found 1 tuple: +[475, 'I am a tuple 475'] +select * from t0 where k0=476 +Found 1 tuple: +[476, 'I am a tuple 476'] +select * from t0 where k0=477 +Found 1 tuple: +[477, 'I am a tuple 477'] +select * from t0 where k0=478 +Found 1 tuple: +[478, 'I am a tuple 478'] +select * from t0 where k0=479 +Found 1 tuple: +[479, 'I am a tuple 479'] +select * from t0 where k0=480 +Found 1 tuple: +[480, 'I am a tuple 480'] +select * from t0 where k0=481 +Found 1 tuple: +[481, 'I am a tuple 481'] +select * from t0 where k0=482 +Found 1 tuple: +[482, 'I am a tuple 482'] +select * from t0 where k0=483 +Found 1 tuple: +[483, 'I am a tuple 483'] +select * from t0 where k0=484 +Found 1 tuple: +[484, 'I am a tuple 484'] +select * from t0 where k0=485 +Found 1 tuple: +[485, 'I am a tuple 485'] +select * from t0 where k0=486 +Found 1 tuple: +[486, 'I am a tuple 486'] +select * from t0 where k0=487 +Found 1 tuple: +[487, 'I am a tuple 487'] +select * from t0 where k0=488 +Found 1 tuple: +[488, 'I am a tuple 488'] +select * from t0 where k0=489 +Found 1 tuple: +[489, 'I am a tuple 489'] +select * from t0 where k0=490 +Found 1 tuple: +[490, 'I am a tuple 490'] +select * from t0 where k0=491 +Found 1 tuple: +[491, 'I am a tuple 491'] +select * from t0 where k0=492 +Found 1 tuple: +[492, 'I am a tuple 492'] +select * from t0 where k0=493 +Found 1 tuple: +[493, 'I am a tuple 493'] +select * from t0 where k0=494 +Found 1 tuple: +[494, 'I am a tuple 494'] +select * from t0 where k0=495 +Found 1 tuple: +[495, 'I am a tuple 495'] +select * from t0 where k0=496 +Found 1 tuple: +[496, 'I am a tuple 496'] +select * from t0 where k0=497 +Found 1 tuple: +[497, 'I am a tuple 497'] +select * from t0 where k0=498 +Found 1 tuple: +[498, 'I am a tuple 498'] +select * from t0 where k0=499 +Found 1 tuple: +[499, 'I am a tuple 499'] +select * from t0 where k0=500 +No match +# Restore the default server... diff --git a/test/box/snapshot_1_3.test.py b/test/box/snapshot_1_3.test.py new file mode 100644 index 0000000000..52b95ca7f7 --- /dev/null +++ b/test/box/snapshot_1_3.test.py @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +import os + +print """ +# Verify that the server starts from a pre-recorded snapshot. +# This way we check that the server can read old snapshots (v11) +# going forward. +""" +server.stop() +snapshot = os.path.join(vardir, "00000000000000000500.snap") +os.symlink(os.path.abspath("box/00000000000000000500.snap"), snapshot) +server.start() +for i in range(0, 501): + sql("select * from t0 where k0={0}".format(i)) +print "# Restore the default server..." +server.stop() +os.unlink(snapshot) +server.start() + +# vim: syntax=python spell diff --git a/test/box/sql.result b/test/box/sql.result index a3df489986..128a69408d 100644 --- a/test/box/sql.result +++ b/test/box/sql.result @@ -2,7 +2,7 @@ ping ok --- select * from t0 -An error occurred: ER_KEY_FIELD_TYPE, 'Supplied key field type does not match index type: expected u32' +An error occurred: ER_KEY_FIELD_TYPE, 'Supplied key type of part 0 does not match index part type: expected NUM' insert into t0 values (1, 'I am a tuple') Insert OK, 1 row affected select * from t0 where k0 = 1 diff --git a/test/box/suite.ini b/test/box/suite.ini index 98726d55b7..cbf3d6abdb 100644 --- a/test/box/suite.ini +++ b/test/box/suite.ini @@ -2,5 +2,6 @@ core = tarantool description = tarantool/box, minimal configuration config = tarantool.cfg -valgrind_disabled = admin_coredump.test -release_disabled = errinj.test +disabled = snapshot_1_3.test.py +valgrind_disabled = admin_coredump.test.lua +release_disabled = errinj.test.lua diff --git a/test/box/unfinished.xlog b/test/box/unfinished.xlog index c905fec9229b37c384366bc267c471184e5d7238..7e087fca8b9bb7f4ba3793e672af4016bf4f0698 100644 GIT binary patch delta 15 WcmWFw<Bag}cjq$DGc=mW=?efIz5}8F delta 15 WcmWFw<Bag}cjq$DGc=sY=?efIx&xsA diff --git a/test/connector_c/connector.snap b/test/connector_c/connector.snap index 7396bb8df919ec98f404765a663e4ca0854928f8..ffc209f51d042180e4cfd71166febcfb31959c0f 100644 GIT binary patch delta 19 acmZo>YGL9G_Hzv2GSD+Ln#lQ!kqZDWQ3SC7 delta 17 YcmZo+YG&dL_Hzv2GSD+LoXGhL03`PWr2qf` diff --git a/test/connector_c/connector.xlog b/test/connector_c/connector.xlog index 8230d2b0c9190908a798ef6fdaeb2d2b4c62be5d..af5a837d453d449f57fd1627708fdf60d95196d9 100644 GIT binary patch delta 28 jcmdo0iR-{8F3t!ae|IheJwu~L&Q?ywt(;6|I~lnEl6eSO delta 26 hcmX@`iEIBSF3t!ae|IheJwwAr&Q?ywt(;6|I{|^o2u%P0 diff --git a/test/lib/sql_ast.py b/test/lib/sql_ast.py index abe931200f..34cbe57003 100644 --- a/test/lib/sql_ast.py +++ b/test/lib/sql_ast.py @@ -53,7 +53,7 @@ ER = { 25: "ER_UNUSED25" , 26: "ER_FIBER_STACK" , 27: "ER_UNUSED27" , - 28: "ER_UNUSED28" , + 28: "ER_TUPLE_FORMAT_LIMIT" , 29: "ER_UNUSED29" , 30: "ER_UNUSED30" , 31: "ER_UNUSED31" , @@ -71,7 +71,7 @@ ER = { 43: "ER_TUPLE_IS_TOO_LONG" , 44: "ER_UNKNOWN_UPDATE_OP" , 45: "ER_EXACT_MATCH" , - 46: "ER_UNUSED46" , + 46: "ER_FIELD_TYPE_MISMATCH" , 47: "ER_KEY_PART_COUNT" , 48: "ER_PROC_RET" , 49: "ER_TUPLE_NOT_FOUND" , -- GitLab