diff --git a/doc/box-protocol.txt b/doc/box-protocol.txt index bb431b4c5e62b3b4199594e0f348a645958b2c78..62a95bf4d1772c4e98e6131d6e3e5fe5a4ed1138 100644 --- a/doc/box-protocol.txt +++ b/doc/box-protocol.txt @@ -226,8 +226,14 @@ Tarantool/Box IPROTO protocol. <insert_request_body> ::= <space_no><flags><tuple> -; The only defined flag BOX_RETURN_TUPLE (0x01) indicates +; Flag BOX_RETURN_TUPLE (0x01) indicates ; that it is required to return the inserted tuple back: +; Flag BOX_ADD (0x02) requests that no tuple with the same primary +; key exists in the space. I.e. it turns INSERT into INSERT, +; without this flag INSERT behaves like REPLACE: replaces +; an existing tuple if it is found. +; Flag BOX_REPLACE (0x04) requests that a tuple with the same +; primary key is present in the space. <flags> ::= <int32> diff --git a/include/tarantool.h b/include/tarantool.h index d46756035ca534530f991b77b6d443ba061dc36b..957e33b3cc1433ca70380b3c1c474e5e47da04c8 100644 --- a/include/tarantool.h +++ b/include/tarantool.h @@ -30,9 +30,6 @@ #include <util.h> #include <log_io.h> -struct lua_State; -struct luaL_Reg; - void mod_init(void); void mod_free(void); struct tarantool_cfg; @@ -43,53 +40,6 @@ i32 mod_reload_config(struct tarantool_cfg *old_conf, struct tarantool_cfg *new_ int mod_cat(const char *filename); void mod_snapshot(struct log_io_iter *); void mod_info(struct tbuf *out); -/** - * This is a callback used by tarantool_lua_init() to open - * module-specific libraries into given Lua state. - * - * @return L on success, 0 if out of memory - */ -struct lua_State *mod_lua_init(struct lua_State *L); - -void -tarantool_lua_register_type(struct lua_State *L, const char *type_name, - const struct luaL_Reg *methods); - -/** - * Create an instance of Lua interpreter and load it with - * Tarantool modules. Creates a Lua state, imports global - * Tarantool modules, then calls mod_lua_init(), which performs - * module-specific imports. The created state can be freed as any - * other, with lua_close(). - * - * @return L on success, 0 if out of memory - */ -struct lua_State *tarantool_lua_init(); -void tarantool_lua_close(struct lua_State *L); - -/* - * Single global lua_State shared by core and modules. - * Created with tarantool_lua_init(). - */ -extern struct lua_State *tarantool_L; -/* Call Lua 'tostring' built-in to print userdata nicely. */ -const char * -tarantool_lua_tostring(struct lua_State *L, int index); - -/* Convert Lua string, number or cdata (u64) to 64bit value */ -uint64_t -tarantool_lua_tointeger64(struct lua_State *L, int idx); - -/* Make a new configuration available in Lua */ -void tarantool_lua_load_cfg(struct lua_State *L, - struct tarantool_cfg *cfg); - -/** - * Load and execute start-up file - * - * @param L is Lua State - */ -void tarantool_lua_load_init_script(struct lua_State *L); extern struct tarantool_cfg cfg; extern const char *cfg_filename; @@ -106,9 +56,4 @@ void tarantool_free(void); char **init_set_proc_title(int argc, char **argv); void free_proc_title(int argc, char **argv); void set_proc_title(const char *format, ...); - -void -tarantool_lua(struct lua_State *L, - struct tbuf *out, const char *str); - #endif /* TARANTOOL_H_INCLUDED */ diff --git a/include/tarantool_lua.h b/include/tarantool_lua.h new file mode 100644 index 0000000000000000000000000000000000000000..af20890bde6bec465a9fdcb3cc86071c2df7bb83 --- /dev/null +++ b/include/tarantool_lua.h @@ -0,0 +1,87 @@ +#ifndef INCLUDES_TARANTOOL_LUA_H +#define INCLUDES_TARANTOOL_LUA_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 <inttypes.h> +struct lua_State; +struct luaL_Reg; +struct tarantool_cfg; +struct tbuf; + +/** + * This is a callback used by tarantool_lua_init() to open + * module-specific libraries into given Lua state. + * + * @return L on success, 0 if out of memory + */ +struct lua_State *mod_lua_init(struct lua_State *L); + +void +tarantool_lua_register_type(struct lua_State *L, const char *type_name, + const struct luaL_Reg *methods); + +/** + * Create an instance of Lua interpreter and load it with + * Tarantool modules. Creates a Lua state, imports global + * Tarantool modules, then calls mod_lua_init(), which performs + * module-specific imports. The created state can be freed as any + * other, with lua_close(). + * + * @return L on success, 0 if out of memory + */ +struct lua_State *tarantool_lua_init(); +void tarantool_lua_close(struct lua_State *L); + +/* + * Single global lua_State shared by core and modules. + * Created with tarantool_lua_init(). + */ +extern struct lua_State *tarantool_L; +/* Call Lua 'tostring' built-in to print userdata nicely. */ +const char * +tarantool_lua_tostring(struct lua_State *L, int index); + +/* Convert Lua string, number or cdata (u64) to 64bit value */ +uint64_t +tarantool_lua_tointeger64(struct lua_State *L, int idx); + +/* Make a new configuration available in Lua */ +void tarantool_lua_load_cfg(struct lua_State *L, + struct tarantool_cfg *cfg); + +/** + * Load and execute start-up file + * + * @param L is Lua State + */ +void tarantool_lua_load_init_script(struct lua_State *L); +void +tarantool_lua(struct lua_State *L, + struct tbuf *out, const char *str); +#endif /* INCLUDES_TARANTOOL_LUA_H */ diff --git a/mod/box/CMakeLists.txt b/mod/box/CMakeLists.txt index 790e960cafb5c5e5851d27cd1f86961f4aa0e916..60397d1c27214b4fdb658f1f8f566cc15a44b400 100644 --- a/mod/box/CMakeLists.txt +++ b/mod/box/CMakeLists.txt @@ -34,5 +34,5 @@ set_source_files_properties(memcached-grammar.m set_source_files_properties(memcached.m PROPERTIES COMPILE_FLAGS "-Wno-uninitialized") -tarantool_module("box" tuple.m index.m tree.m space.m box.m box.lua.c - box_lua.m memcached.m memcached-grammar.m) +tarantool_module("box" tuple.m index.m tree.m space.m port.m box.m + box.lua.c box_lua.m memcached.m memcached-grammar.m) diff --git a/mod/box/box.h b/mod/box/box.h index a02b6024659255fcf5f3ad79d29d73f4c53bd795..ff6ae3eb71aafef97d1495c76fd88da4a78dcc3b 100644 --- a/mod/box/box.h +++ b/mod/box/box.h @@ -37,14 +37,9 @@ enum { /** A limit on how many operations a single UPDATE can have. */ BOX_UPDATE_OP_CNT_MAX = 128, }; +struct port; -struct box_out { - void (*add_u32)(u32 *u32); - void (*dup_u32)(u32 u32); - void (*add_tuple)(struct box_tuple *tuple); -}; -extern struct box_out box_out_quiet; @class Index; struct space; @@ -53,7 +48,7 @@ struct box_txn { u32 flags; struct lua_State *L; - struct box_out *out; + struct port *port; struct space *space; Index *index; diff --git a/mod/box/box.m b/mod/box/box.m index 99a50e3d5a32954549f0e7797ded8e8b43f72c8c..ad70b3757c5c1fc1411e38b9c23c96fd83a37fb7 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -48,6 +48,7 @@ #include "memcached.h" #include "box_lua.h" #include "space.h" +#include "port.h" extern pid_t logger_pid; @@ -63,20 +64,6 @@ static int stat_base; STRS(messages, MESSAGES); STRS(update_op_codes, UPDATE_OP_CODES); -/* - For tuples of size below this threshold, when sending a tuple - to the client, make a deep copy of the tuple for the duration - of sending rather than increment a reference counter. - This is necessary to avoid excessive page splits when taking - a snapshot: many small tuples can be accessed by clients - immediately after the snapshot process has forked off, - thus incrementing tuple ref count, and causing the OS to - create a copy of the memory page for the forked - child. -*/ - -const int BOX_REF_THRESHOLD = 8196; - struct box_snap_row { u32 space; u32 tuple_size; @@ -196,10 +183,10 @@ prepare_replace(struct box_txn *txn, size_t field_count, struct tbuf *data) space_replace(txn->space, NULL, txn->new_tuple); } - txn->out->dup_u32(1); /* Affected tuples */ + txn->port->dup_u32(1); /* Affected tuples */ if (txn->flags & BOX_RETURN_TUPLE) - txn->out->add_tuple(txn->new_tuple); + txn->port->add_tuple(txn->new_tuple); } static void @@ -957,10 +944,10 @@ prepare_update(struct box_txn *txn, struct tbuf *data) space_validate(txn->space, txn->old_tuple, txn->new_tuple); out: - txn->out->dup_u32(tuples_affected); + txn->port->dup_u32(tuples_affected); if (txn->flags & BOX_RETURN_TUPLE && txn->new_tuple) - txn->out->add_tuple(txn->new_tuple); + txn->port->add_tuple(txn->new_tuple); } /** }}} */ @@ -975,7 +962,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) tnt_raise(IllegalParams, :"tuple count must be positive"); found = palloc(fiber->gc_pool, sizeof(*found)); - txn->out->add_u32(found); + txn->port->add_u32(found); *found = 0; for (u32 i = 0; i < count; i++) { @@ -1002,7 +989,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) continue; } - txn->out->add_tuple(tuple); + txn->port->add_tuple(tuple); if (limit == ++(*found)) break; @@ -1039,10 +1026,10 @@ prepare_delete(struct box_txn *txn, struct tbuf *data) tuples_affected = 1; } - txn->out->dup_u32(tuples_affected); + txn->port->dup_u32(tuples_affected); if (txn->old_tuple && (txn->flags & BOX_RETURN_TUPLE)) - txn->out->add_tuple(txn->old_tuple); + txn->port->add_tuple(txn->old_tuple); } static void @@ -1060,47 +1047,6 @@ op_is_select(u32 op) return op == SELECT || op == CALL; } -static void -iov_add_u32(u32 *p_u32) -{ - iov_add(p_u32, sizeof(u32)); -} - -static void -iov_dup_u32(u32 u32) -{ - iov_dup(&u32, sizeof(u32)); -} - -static void -iov_add_tuple(struct box_tuple *tuple) -{ - size_t len = tuple_len(tuple); - - if (len > BOX_REF_THRESHOLD) { - tuple_txn_ref(in_txn(), tuple); - iov_add(&tuple->bsize, len); - } else { - iov_dup(&tuple->bsize, len); - } -} - -static struct box_out box_out_iproto = { - iov_add_u32, - iov_dup_u32, - iov_add_tuple -}; - -static void box_quiet_add_u32(u32 *p_u32 __attribute__((unused))) {} -static void box_quiet_dup_u32(u32 u32 __attribute__((unused))) {} -static void box_quiet_add_tuple(struct box_tuple *tuple __attribute__((unused))) {} - -struct box_out box_out_quiet = { - box_quiet_add_u32, - box_quiet_dup_u32, - box_quiet_add_tuple -}; - struct box_txn * txn_begin() { @@ -1409,7 +1355,7 @@ box_process_rw(u32 op, struct tbuf *request_data) if (txn == NULL) { txn = txn_begin(); txn->flags |= BOX_GC_TXN; - txn->out = &box_out_iproto; + txn->port = &port_iproto; } @try { @@ -1478,7 +1424,7 @@ recover_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t) struct box_txn *txn = txn_begin(); txn->flags |= BOX_NOT_STORE; - txn->out = &box_out_quiet; + txn->port = &port_null; @try { box_process_rw(op, t); @@ -1689,9 +1635,6 @@ mod_init(void) /* build secondary indexes */ build_indexes(); - /* enable secondary indexes now */ - secondary_indexes_enabled = true; - title("orphan"); if (cfg.local_hot_standby) { diff --git a/mod/box/box_lua.h b/mod/box/box_lua.h index f837e3e472b060be1ab30764b2b23385c1c31632..c50c40ba8444b258a80e656c9dc3b698dd925338 100644 --- a/mod/box/box_lua.h +++ b/mod/box/box_lua.h @@ -32,6 +32,8 @@ */ struct tbuf; struct box_txn; +struct box_tuple; +struct lua_State; /** * Invoke a Lua stored procedure from the binary protocol @@ -42,4 +44,6 @@ void box_lua_call(struct box_txn *txn, struct tbuf *req); * Create an instance of Lua interpreter in box. */ void box_lua_init(); + +struct box_tuple *lua_istuple(struct lua_State *L, int narg); #endif /* INCLUDES_TARANTOOL_MOD_BOX_LUA_H */ diff --git a/mod/box/box_lua.m b/mod/box/box_lua.m index caa0a047e26e103bc044267f9ebfb295ff53f52b..f0ea443e88e4226aa738be3e716c2a9d7d802625 100644 --- a/mod/box/box_lua.m +++ b/mod/box/box_lua.m @@ -29,21 +29,17 @@ * SUCH DAMAGE. */ #include "box_lua.h" -#include "tarantool.h" +#include <tarantool_lua.h> #include "box.h" #include "lua.h" #include "lauxlib.h" #include "lualib.h" -#include "lj_obj.h" -#include "lj_ctype.h" -#include "lj_cdata.h" -#include "lj_cconv.h" - #include "pickle.h" #include "tuple.h" #include "space.h" +#include "port.h" /* contents of box.lua */ extern const char box_lua[]; @@ -81,7 +77,7 @@ lua_checktuple(struct lua_State *L, int narg) return *(void **) luaL_checkudata(L, narg, tuplelib_name); } -static inline struct box_tuple * +struct box_tuple * lua_istuple(struct lua_State *L, int narg) { if (lua_getmetatable(L, narg) == 0) @@ -549,161 +545,11 @@ static const struct luaL_reg lbox_iterator_meta[] = { /* }}} */ /** {{{ Lua I/O: facilities to intercept box output - * and push into Lua stack and the opposite: append Lua types - * to fiber IOV. + * and push into Lua stack. */ -/* Add a Lua table to iov as if it was a tuple, with as little - * overhead as possible. */ - static void -iov_add_lua_table(struct lua_State *L, int index) -{ - u32 *field_count = palloc(fiber->gc_pool, sizeof(u32)); - u32 *tuple_len = palloc(fiber->gc_pool, sizeof(u32)); - - *field_count = 0; - *tuple_len = 0; - - iov_add(tuple_len, sizeof(u32)); - iov_add(field_count, sizeof(u32)); - - u8 field_len_buf[5]; - size_t field_len, field_len_len; - const char *field; - - lua_pushnil(L); /* first key */ - while (lua_next(L, index) != 0) { - ++*field_count; - - switch (lua_type(L, -1)) { - case LUA_TNUMBER: - { - u32 field_num = lua_tonumber(L, -1); - field_len = sizeof(u32); - field_len_len = - save_varint32(field_len_buf, - field_len) - field_len_buf; - iov_dup(field_len_buf, field_len_len); - iov_dup(&field_num, field_len); - *tuple_len += field_len_len + field_len; - break; - } - case LUA_TCDATA: - { - u64 field_num = tarantool_lua_tointeger64(L, -1); - field_len = sizeof(u64); - field_len_len = - save_varint32(field_len_buf, - field_len) - field_len_buf; - iov_dup(field_len_buf, field_len_len); - iov_dup(&field_num, field_len); - *tuple_len += field_len_len + field_len; - break; - } - case LUA_TSTRING: - { - field = lua_tolstring(L, -1, &field_len); - field_len_len = - save_varint32(field_len_buf, - field_len) - field_len_buf; - iov_dup(field_len_buf, field_len_len); - iov_dup(field, field_len); - *tuple_len += field_len_len + field_len; - break; - } - default: - tnt_raise(ClientError, :ER_PROC_RET, - lua_typename(L, lua_type(L, -1))); - break; - } - lua_pop(L, 1); - } -} - -void iov_add_ret(struct lua_State *L, int index) -{ - int type = lua_type(L, index); - struct box_tuple *tuple; - switch (type) { - case LUA_TTABLE: - { - iov_add_lua_table(L, index); - return; - } - case LUA_TNUMBER: - { - size_t len = sizeof(u32); - u32 num = lua_tointeger(L, index); - tuple = tuple_alloc(len + varint32_sizeof(len)); - tuple->field_count = 1; - memcpy(save_varint32(tuple->data, len), &num, len); - break; - } - case LUA_TCDATA: - { - u64 num = tarantool_lua_tointeger64(L, index); - size_t len = sizeof(u64); - tuple = tuple_alloc(len + varint32_sizeof(len)); - tuple->field_count = 1; - memcpy(save_varint32(tuple->data, len), &num, len); - break; - } - case LUA_TSTRING: - { - size_t len; - const char *str = lua_tolstring(L, index, &len); - tuple = tuple_alloc(len + varint32_sizeof(len)); - tuple->field_count = 1; - memcpy(save_varint32(tuple->data, len), str, len); - break; - } - case LUA_TNIL: - case LUA_TBOOLEAN: - { - const char *str = tarantool_lua_tostring(L, index); - size_t len = strlen(str); - tuple = tuple_alloc(len + varint32_sizeof(len)); - tuple->field_count = 1; - memcpy(save_varint32(tuple->data, len), str, len); - break; - } - case LUA_TUSERDATA: - { - tuple = lua_istuple(L, index); - if (tuple) - break; - } - default: - /* - * LUA_TNONE, LUA_TTABLE, LUA_THREAD, LUA_TFUNCTION - */ - tnt_raise(ClientError, :ER_PROC_RET, lua_typename(L, type)); - break; - } - tuple_txn_ref(in_txn(), tuple); - iov_add(&tuple->bsize, tuple_len(tuple)); -} - -/** - * Add all elements from Lua stack to fiber iov. - * - * To allow clients to understand a complex return from - * a procedure, we are compatible with SELECT protocol, - * and return the number of return values first, and - * then each return value as a tuple. - */ -void -iov_add_multret(struct lua_State *L) -{ - int nargs = lua_gettop(L); - iov_dup(&nargs, sizeof(u32)); - for (int i = 1; i <= nargs; ++i) - iov_add_ret(L, i); -} - -static void -box_lua_dup_u32(u32 u32 __attribute__((unused))) +port_lua_dup_u32(u32 u32 __attribute__((unused))) { /* * Do nothing -- the only u32 Box can give us is @@ -714,22 +560,35 @@ box_lua_dup_u32(u32 u32 __attribute__((unused))) } static void -box_lua_add_u32(u32 *p_u32 __attribute__((unused))) +port_lua_add_u32(u32 *p_u32 __attribute__((unused))) { - /* See the comment in box_lua_dup_u32. */ + /* See the comment in port_lua_dup_u32. */ } static void -box_lua_add_tuple(struct box_tuple *tuple) +port_lua_add_tuple(struct box_tuple *tuple) { struct lua_State *L = in_txn()->L; lbox_pushtuple(L, tuple); } -static struct box_out box_out_lua = { - box_lua_add_u32, - box_lua_dup_u32, - box_lua_add_tuple +static void +port_lua_add_lua_multret(struct lua_State *L) +{ + /* + * We cannot issue a CALL request from within a CALL + * request. Instead users should call Lua procedures + * directly. + */ + assert(false); + (void) L; +} + +static struct port port_lua = { + port_lua_add_u32, + port_lua_dup_u32, + port_lua_add_tuple, + port_lua_add_lua_multret }; /* }}} */ @@ -740,7 +599,7 @@ txn_enter_lua(lua_State *L) struct box_txn *old_txn = in_txn(); fiber->mod_data.txn = NULL; struct box_txn *txn = fiber->mod_data.txn = txn_begin(); - txn->out = &box_out_lua; + txn->port = &port_lua; txn->L = L; return old_txn; } @@ -836,8 +695,7 @@ box_lua_panic(struct lua_State *L) * Invoke a Lua stored procedure from the binary protocol * (implementation of 'CALL' command code). */ -void box_lua_call(struct box_txn *txn __attribute__((unused)), - struct tbuf *data) +void box_lua_call(struct box_txn *txn, struct tbuf *data) { lua_State *L = lua_newthread(root_L); int coro_ref = luaL_ref(root_L, LUA_REGISTRYINDEX); @@ -856,7 +714,7 @@ void box_lua_call(struct box_txn *txn __attribute__((unused)), } lua_call(L, nargs, LUA_MULTRET); /* Send results of the called procedure to the client. */ - iov_add_multret(L); + txn->port->add_lua_multret(L); } @finally { /* * Allow the used coro to be garbage collected. diff --git a/mod/box/index.h b/mod/box/index.h index 430d31d4acc25651b50b2480574eef7ef982a9da..2c518ffa1f379c36740e77e8fba5cc5a34936daf 100644 --- a/mod/box/index.h +++ b/mod/box/index.h @@ -76,8 +76,6 @@ struct key_def { bool is_unique; }; -@class Index; - @interface Index: Object { @public /* Index owner space */ diff --git a/mod/box/memcached-grammar.m b/mod/box/memcached-grammar.m index 2b07325cb84394b7bee1929e4e61ab847aaaf5cc..d97e8038de51101dcc64bde2538cfbd677b4a091 100644 --- a/mod/box/memcached-grammar.m +++ b/mod/box/memcached-grammar.m @@ -1034,7 +1034,7 @@ tr195: { struct box_txn *txn = txn_begin(); txn->flags |= BOX_GC_TXN; - txn->out = &box_out_quiet; + txn->port = &port_null; @try { memcached_get(txn, keys_count, keys, show_cas); txn_commit(txn); diff --git a/mod/box/memcached-grammar.rl b/mod/box/memcached-grammar.rl index 22ac49629ffc2bc7f9448d0d2697cd6857985a5c..b8c239a2dd389eccd5a0751a0a8e069981d0b1f7 100644 --- a/mod/box/memcached-grammar.rl +++ b/mod/box/memcached-grammar.rl @@ -192,7 +192,7 @@ memcached_dispatch() action get { struct box_txn *txn = txn_begin(); txn->flags |= BOX_GC_TXN; - txn->out = &box_out_quiet; + txn->port = &port_null; @try { memcached_get(txn, keys_count, keys, show_cas); txn_commit(txn); diff --git a/mod/box/memcached.m b/mod/box/memcached.m index 1641d3241227923687b82500c3454558f2288982..c9d87090011f4da8244816fd8f7899db3915bf18 100644 --- a/mod/box/memcached.m +++ b/mod/box/memcached.m @@ -34,6 +34,7 @@ #include "salloc.h" #include "pickle.h" #include "space.h" +#include "port.h" #define STAT(_) \ _(MEMC_GET, 1) \ @@ -103,7 +104,7 @@ store(void *key, u32 exptime, u32 flags, u32 bytes, u8 *data) key_len, key_len, (u8 *)key, exptime, flags, cas); struct box_txn *txn = txn_begin(); - txn->out = &box_out_quiet; + txn->port = &port_null; /* * Use a box dispatch wrapper which handles correctly * read-only/read-write modes. @@ -124,7 +125,7 @@ delete(void *key) tbuf_append_field(req, key); struct box_txn *txn = txn_begin(); - txn->out = &box_out_quiet; + txn->port = &port_null; rw_callback(DELETE, req); } diff --git a/mod/box/port.h b/mod/box/port.h new file mode 100644 index 0000000000000000000000000000000000000000..efe495c56d3de110fb4946884734a2339f563647 --- /dev/null +++ b/mod/box/port.h @@ -0,0 +1,46 @@ +#ifndef INCLUDES_TARANTOOL_BOX_PORT_H +#define INCLUDES_TARANTOOL_BOX_PORT_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 <util.h> + +struct box_tuple; +struct lua_State; + +struct port { + void (*add_u32)(u32 *u32); + void (*dup_u32)(u32 u32); + void (*add_tuple)(struct box_tuple *tuple); + void (*add_lua_multret)(struct lua_State *L); +}; + +extern struct port port_null; +extern struct port port_iproto; + +#endif /* INCLUDES_TARANTOOL_BOX_PORT_H */ diff --git a/mod/box/port.m b/mod/box/port.m new file mode 100644 index 0000000000000000000000000000000000000000..0946a7bb2431c854e93d6bf5d92ea653eb005206 --- /dev/null +++ b/mod/box/port.m @@ -0,0 +1,249 @@ +/* + * 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 "port.h" +#include "box.h" +#include <pickle.h> +#include <tarantool_lua.h> +#include "tuple.h" +#include "box_lua.h" +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#include "lj_obj.h" +#include "lj_ctype.h" +#include "lj_cdata.h" +#include "lj_cconv.h" + +/* + For tuples of size below this threshold, when sending a tuple + to the client, make a deep copy of the tuple for the duration + of sending rather than increment a reference counter. + This is necessary to avoid excessive page splits when taking + a snapshot: many small tuples can be accessed by clients + immediately after the snapshot process has forked off, + thus incrementing tuple ref count, and causing the OS to + create a copy of the memory page for the forked + child. +*/ +const int BOX_REF_THRESHOLD = 8196; + + +static void +iov_add_u32(u32 *p_u32) +{ + iov_add(p_u32, sizeof(u32)); +} + +static void +iov_dup_u32(u32 u32) +{ + iov_dup(&u32, sizeof(u32)); +} + +static void +iov_add_tuple(struct box_tuple *tuple) +{ + size_t len = tuple_len(tuple); + + if (len > BOX_REF_THRESHOLD) { + tuple_txn_ref(in_txn(), tuple); + iov_add(&tuple->bsize, len); + } else { + iov_dup(&tuple->bsize, len); + } +} + +/* Add a Lua table to iov as if it was a tuple, with as little + * overhead as possible. */ + +static void +iov_add_lua_table(struct lua_State *L, int index) +{ + u32 *field_count = palloc(fiber->gc_pool, sizeof(u32)); + u32 *tuple_len = palloc(fiber->gc_pool, sizeof(u32)); + + *field_count = 0; + *tuple_len = 0; + + iov_add(tuple_len, sizeof(u32)); + iov_add(field_count, sizeof(u32)); + + u8 field_len_buf[5]; + size_t field_len, field_len_len; + const char *field; + + lua_pushnil(L); /* first key */ + while (lua_next(L, index) != 0) { + ++*field_count; + + switch (lua_type(L, -1)) { + case LUA_TNUMBER: + { + u32 field_num = lua_tonumber(L, -1); + field_len = sizeof(u32); + field_len_len = + save_varint32(field_len_buf, + field_len) - field_len_buf; + iov_dup(field_len_buf, field_len_len); + iov_dup(&field_num, field_len); + *tuple_len += field_len_len + field_len; + break; + } + case LUA_TCDATA: + { + u64 field_num = tarantool_lua_tointeger64(L, -1); + field_len = sizeof(u64); + field_len_len = + save_varint32(field_len_buf, + field_len) - field_len_buf; + iov_dup(field_len_buf, field_len_len); + iov_dup(&field_num, field_len); + *tuple_len += field_len_len + field_len; + break; + } + case LUA_TSTRING: + { + field = lua_tolstring(L, -1, &field_len); + field_len_len = + save_varint32(field_len_buf, + field_len) - field_len_buf; + iov_dup(field_len_buf, field_len_len); + iov_dup(field, field_len); + *tuple_len += field_len_len + field_len; + break; + } + default: + tnt_raise(ClientError, :ER_PROC_RET, + lua_typename(L, lua_type(L, -1))); + break; + } + lua_pop(L, 1); + } +} + +void iov_add_ret(struct lua_State *L, int index) +{ + int type = lua_type(L, index); + struct box_tuple *tuple; + switch (type) { + case LUA_TTABLE: + { + iov_add_lua_table(L, index); + return; + } + case LUA_TNUMBER: + { + size_t len = sizeof(u32); + u32 num = lua_tointeger(L, index); + tuple = tuple_alloc(len + varint32_sizeof(len)); + tuple->field_count = 1; + memcpy(save_varint32(tuple->data, len), &num, len); + break; + } + case LUA_TCDATA: + { + u64 num = tarantool_lua_tointeger64(L, index); + size_t len = sizeof(u64); + tuple = tuple_alloc(len + varint32_sizeof(len)); + tuple->field_count = 1; + memcpy(save_varint32(tuple->data, len), &num, len); + break; + } + case LUA_TSTRING: + { + size_t len; + const char *str = lua_tolstring(L, index, &len); + tuple = tuple_alloc(len + varint32_sizeof(len)); + tuple->field_count = 1; + memcpy(save_varint32(tuple->data, len), str, len); + break; + } + case LUA_TNIL: + case LUA_TBOOLEAN: + { + const char *str = tarantool_lua_tostring(L, index); + size_t len = strlen(str); + tuple = tuple_alloc(len + varint32_sizeof(len)); + tuple->field_count = 1; + memcpy(save_varint32(tuple->data, len), str, len); + break; + } + case LUA_TUSERDATA: + { + tuple = lua_istuple(L, index); + if (tuple) + break; + } + default: + /* + * LUA_TNONE, LUA_TTABLE, LUA_THREAD, LUA_TFUNCTION + */ + tnt_raise(ClientError, :ER_PROC_RET, lua_typename(L, type)); + break; + } + tuple_txn_ref(in_txn(), tuple); + iov_add(&tuple->bsize, tuple_len(tuple)); +} + +/** + * Add all elements from Lua stack to fiber iov. + * + * To allow clients to understand a complex return from + * a procedure, we are compatible with SELECT protocol, + * and return the number of return values first, and + * then each return value as a tuple. + */ +void +iov_add_multret(struct lua_State *L) +{ + int nargs = lua_gettop(L); + iov_dup(&nargs, sizeof(u32)); + for (int i = 1; i <= nargs; ++i) + iov_add_ret(L, i); +} + +struct port port_iproto = { + iov_add_u32, + iov_dup_u32, + iov_add_tuple, + iov_add_multret +}; + +static void port_null_add_u32(u32 *p_u32 __attribute__((unused))) {} +static void port_null_dup_u32(u32 u32 __attribute__((unused))) {} +static void port_null_add_tuple(struct box_tuple *tuple __attribute__((unused))) {} +static void port_null_add_lua_multret(struct lua_State *L __attribute__((unused))) {} + +struct port port_null = { + port_null_add_u32, + port_null_dup_u32, + port_null_add_tuple, + port_null_add_lua_multret +}; + diff --git a/mod/box/space.h b/mod/box/space.h index b23f6d27607de3140c2477a86d291a564f56a58d..8b7b46d08004238bc2afbcdec4f23717ba4ee69c 100644 --- a/mod/box/space.h +++ b/mod/box/space.h @@ -1,5 +1,5 @@ -#ifndef TARANTOOL_SPACE_H_INCLUDED -#define TARANTOOL_SPACE_H_INCLUDED +#ifndef TARANTOOL_BOX_SPACE_H_INCLUDED +#define TARANTOOL_BOX_SPACE_H_INCLUDED /* * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -145,4 +145,4 @@ i32 check_spaces(struct tarantool_cfg *conf); /* Build secondary keys. */ void build_indexes(void); -#endif /* TARANTOOL_SPACE_H_INCLUDED */ +#endif /* TARANTOOL_BOX_SPACE_H_INCLUDED */ diff --git a/mod/box/space.m b/mod/box/space.m index 7cf0e52742cd5fc83aeb6c197251ee49e313986f..a9bf0034bd7027689445870f190064dc88a450a7 100644 --- a/mod/box/space.m +++ b/mod/box/space.m @@ -300,6 +300,8 @@ space_init(void) void build_indexes(void) { + assert(secondary_indexes_enabled == false); + for (u32 n = 0; n < BOX_SPACE_MAX; ++n) { if (space[n].enabled == false) continue; @@ -316,6 +318,8 @@ build_indexes(void) say_info("Space %"PRIu32": done", n); } + /* enable secondary indexes now */ + secondary_indexes_enabled = true; } i32 diff --git a/mod/box/tree.m b/mod/box/tree.m index 1546651ca07304cc7472edf7eceed3be2fe5434d..9ad7a70897308451c6d52cd932528ba5d9d0c77b 100644 --- a/mod/box/tree.m +++ b/mod/box/tree.m @@ -50,7 +50,7 @@ u64_cmp(u64 a, u64 b) } /** - * Tuple addrress comparison. + * Tuple address comparison. */ static inline int ta_cmp(struct box_tuple *tuple_a, struct box_tuple *tuple_b) diff --git a/src/admin.m b/src/admin.m index 4067c2ee64e3605a48f3bf3524d948d08037528f..bad711f261517e8bcac59ffbd255bef0cc4f9e7c 100644 --- a/src/admin.m +++ b/src/admin.m @@ -1,5 +1,5 @@ -#line 1 "core/admin.rl" +#line 1 "src/admin.rl" /* * Copyright (C) 2010 Mail.RU * Copyright (C) 2010 Yuriy Vostrikov @@ -38,6 +38,7 @@ #include <say.h> #include <stat.h> #include <tarantool.h> +#include <tarantool_lua.h> #include TARANTOOL_CONFIG #include <tbuf.h> #include <util.h> @@ -67,7 +68,7 @@ static const char *help = static const char *unknown_command = "unknown command. try typing help." CRLF; -#line 71 "core/admin.m" +#line 72 "src/admin.m" static const int admin_start = 1; static const int admin_first_final = 135; static const int admin_error = 0; @@ -75,7 +76,7 @@ static const int admin_error = 0; static const int admin_en_main = 1; -#line 70 "core/admin.rl" +#line 71 "src/admin.rl" @@ -137,12 +138,12 @@ admin_dispatch(lua_State *L) p = fiber->rbuf->data; -#line 141 "core/admin.m" +#line 142 "src/admin.m" { cs = admin_start; } -#line 146 "core/admin.m" +#line 147 "src/admin.m" { if ( p == pe ) goto _test_eof; @@ -205,15 +206,15 @@ case 6: } goto st0; tr13: -#line 240 "core/admin.rl" +#line 241 "src/admin.rl" {slab_validate(); ok(out);} goto st135; tr20: -#line 228 "core/admin.rl" +#line 229 "src/admin.rl" {return 0;} goto st135; tr25: -#line 155 "core/admin.rl" +#line 156 "src/admin.rl" { start(out); tbuf_append(out, help, strlen(help)); @@ -221,9 +222,9 @@ tr25: } goto st135; tr36: -#line 214 "core/admin.rl" +#line 215 "src/admin.rl" {strend = p;} -#line 161 "core/admin.rl" +#line 162 "src/admin.rl" { strstart[strend-strstart]='\0'; start(out); @@ -232,7 +233,7 @@ tr36: } goto st135; tr43: -#line 168 "core/admin.rl" +#line 169 "src/admin.rl" { if (reload_cfg(err)) fail(out, err); @@ -241,11 +242,11 @@ tr43: } goto st135; tr67: -#line 238 "core/admin.rl" +#line 239 "src/admin.rl" {coredump(60); ok(out);} goto st135; tr76: -#line 175 "core/admin.rl" +#line 176 "src/admin.rl" { int ret = snapshot(NULL, 0); @@ -260,9 +261,9 @@ tr76: } goto st135; tr98: -#line 224 "core/admin.rl" +#line 225 "src/admin.rl" { state = false; } -#line 188 "core/admin.rl" +#line 189 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -274,9 +275,9 @@ tr98: } goto st135; tr101: -#line 223 "core/admin.rl" +#line 224 "src/admin.rl" { state = true; } -#line 188 "core/admin.rl" +#line 189 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -288,7 +289,7 @@ tr101: } goto st135; tr117: -#line 131 "core/admin.rl" +#line 132 "src/admin.rl" { tarantool_cfg_iterator_t *i; char *key, *value; @@ -308,15 +309,15 @@ tr117: } goto st135; tr131: -#line 231 "core/admin.rl" +#line 232 "src/admin.rl" {start(out); fiber_info(out); end(out);} goto st135; tr137: -#line 230 "core/admin.rl" +#line 231 "src/admin.rl" {start(out); tarantool_info(out); end(out);} goto st135; tr146: -#line 149 "core/admin.rl" +#line 150 "src/admin.rl" { start(out); errinj_info(out); @@ -324,33 +325,33 @@ tr146: } goto st135; tr152: -#line 234 "core/admin.rl" +#line 235 "src/admin.rl" {start(out); palloc_stat(out); end(out);} goto st135; tr160: -#line 233 "core/admin.rl" +#line 234 "src/admin.rl" {start(out); slab_stat(out); end(out);} goto st135; tr164: -#line 235 "core/admin.rl" +#line 236 "src/admin.rl" {start(out); stat_print(out);end(out);} goto st135; st135: if ( ++p == pe ) goto _test_eof135; case 135: -#line 343 "core/admin.m" +#line 344 "src/admin.m" goto st0; tr14: -#line 240 "core/admin.rl" +#line 241 "src/admin.rl" {slab_validate(); ok(out);} goto st7; tr21: -#line 228 "core/admin.rl" +#line 229 "src/admin.rl" {return 0;} goto st7; tr26: -#line 155 "core/admin.rl" +#line 156 "src/admin.rl" { start(out); tbuf_append(out, help, strlen(help)); @@ -358,9 +359,9 @@ tr26: } goto st7; tr37: -#line 214 "core/admin.rl" +#line 215 "src/admin.rl" {strend = p;} -#line 161 "core/admin.rl" +#line 162 "src/admin.rl" { strstart[strend-strstart]='\0'; start(out); @@ -369,7 +370,7 @@ tr37: } goto st7; tr44: -#line 168 "core/admin.rl" +#line 169 "src/admin.rl" { if (reload_cfg(err)) fail(out, err); @@ -378,11 +379,11 @@ tr44: } goto st7; tr68: -#line 238 "core/admin.rl" +#line 239 "src/admin.rl" {coredump(60); ok(out);} goto st7; tr77: -#line 175 "core/admin.rl" +#line 176 "src/admin.rl" { int ret = snapshot(NULL, 0); @@ -397,9 +398,9 @@ tr77: } goto st7; tr99: -#line 224 "core/admin.rl" +#line 225 "src/admin.rl" { state = false; } -#line 188 "core/admin.rl" +#line 189 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -411,9 +412,9 @@ tr99: } goto st7; tr102: -#line 223 "core/admin.rl" +#line 224 "src/admin.rl" { state = true; } -#line 188 "core/admin.rl" +#line 189 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -425,7 +426,7 @@ tr102: } goto st7; tr118: -#line 131 "core/admin.rl" +#line 132 "src/admin.rl" { tarantool_cfg_iterator_t *i; char *key, *value; @@ -445,15 +446,15 @@ tr118: } goto st7; tr132: -#line 231 "core/admin.rl" +#line 232 "src/admin.rl" {start(out); fiber_info(out); end(out);} goto st7; tr138: -#line 230 "core/admin.rl" +#line 231 "src/admin.rl" {start(out); tarantool_info(out); end(out);} goto st7; tr147: -#line 149 "core/admin.rl" +#line 150 "src/admin.rl" { start(out); errinj_info(out); @@ -461,22 +462,22 @@ tr147: } goto st7; tr153: -#line 234 "core/admin.rl" +#line 235 "src/admin.rl" {start(out); palloc_stat(out); end(out);} goto st7; tr161: -#line 233 "core/admin.rl" +#line 234 "src/admin.rl" {start(out); slab_stat(out); end(out);} goto st7; tr165: -#line 235 "core/admin.rl" +#line 236 "src/admin.rl" {start(out); stat_print(out);end(out);} goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 480 "core/admin.m" +#line 481 "src/admin.m" if ( (*p) == 10 ) goto st135; goto st0; @@ -629,28 +630,28 @@ case 23: } goto tr33; tr33: -#line 214 "core/admin.rl" +#line 215 "src/admin.rl" {strstart = p;} goto st24; st24: if ( ++p == pe ) goto _test_eof24; case 24: -#line 640 "core/admin.m" +#line 641 "src/admin.m" switch( (*p) ) { case 10: goto tr36; case 13: goto tr37; } goto st24; tr34: -#line 214 "core/admin.rl" +#line 215 "src/admin.rl" {strstart = p;} goto st25; st25: if ( ++p == pe ) goto _test_eof25; case 25: -#line 654 "core/admin.m" +#line 655 "src/admin.m" switch( (*p) ) { case 10: goto tr36; case 13: goto tr37; @@ -1100,28 +1101,28 @@ case 73: goto tr91; goto st0; tr91: -#line 222 "core/admin.rl" +#line 223 "src/admin.rl" { strstart = p; } goto st74; st74: if ( ++p == pe ) goto _test_eof74; case 74: -#line 1111 "core/admin.m" +#line 1112 "src/admin.m" if ( (*p) == 32 ) goto tr92; if ( 33 <= (*p) && (*p) <= 126 ) goto st74; goto st0; tr92: -#line 222 "core/admin.rl" +#line 223 "src/admin.rl" { strend = p; } goto st75; st75: if ( ++p == pe ) goto _test_eof75; case 75: -#line 1125 "core/admin.m" +#line 1126 "src/admin.m" switch( (*p) ) { case 32: goto st75; case 111: goto st76; @@ -1813,7 +1814,7 @@ case 134: _out: {} } -#line 246 "core/admin.rl" +#line 247 "src/admin.rl" tbuf_ltrim(fiber->rbuf, (void *)pe - (void *)fiber->rbuf->data); diff --git a/src/admin.rl b/src/admin.rl index 59d9573b93c72d80e3ce4b36abb5183010f5c26d..f79cb42291eb14f9a28a6e327e2a31e3c57e4fdf 100644 --- a/src/admin.rl +++ b/src/admin.rl @@ -36,6 +36,7 @@ #include <say.h> #include <stat.h> #include <tarantool.h> +#include <tarantool_lua.h> #include TARANTOOL_CONFIG #include <tbuf.h> #include <util.h> diff --git a/src/tarantool.m b/src/tarantool.m index d7ec42b88d0e775aa6290c4758474772b8d99389..cccf7859f03829b32ec3864e3edbbf43ab256a73 100644 --- a/src/tarantool.m +++ b/src/tarantool.m @@ -58,6 +58,7 @@ #include <third_party/gopt/gopt.h> #include <cfg/warning.h> #include "tarantool_pthread.h" +#include "tarantool_lua.h" static pid_t master_pid; diff --git a/src/tarantool_lua.m b/src/tarantool_lua.m index 7759f2045167a5f1698887037fdfa64dcbb9ab21..e4afd5b20c0a904b5f516129341da6f363096ab0 100644 --- a/src/tarantool_lua.m +++ b/src/tarantool_lua.m @@ -28,7 +28,8 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include "tarantool.h" +#include <tarantool_lua.h> +#include <tarantool.h> #include "lua.h" #include "lauxlib.h"