diff --git a/CMakeLists.txt b/CMakeLists.txt index d0b2c5eb0b0aa38acabf51bc03008f9cc9951555..7d2f2b9b278eff79fdc36d9cb3060d6b73a3249d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,8 @@ find_program(POD2MAN pod2man) set (TARANTOOL_PRODUCT "box") set (TARANTOOL_MODULES "box") set (TARANTOOL_CLIENTS "") +# Define PACKAGE macro in config.h +set (PACKAGE "Tarantool") # # Set default build type to Debug. This is to ease a developer's @@ -79,11 +81,11 @@ add_custom_target(TAGS COMMAND ctags -R --langmap=ObjectiveC:.m -e -f TAGS WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) # -# Define TARANTOOL_VERSION -- a string constant with tarantool version. +# Define PACKAGE_VERSION -- a string constant with tarantool version. # -set (TARANTOOL_VERSION "") +set (PACKAGE_VERSION "") execute_process (COMMAND ${GIT} describe HEAD - OUTPUT_VARIABLE TARANTOOL_VERSION + OUTPUT_VARIABLE PACKAGE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) # @@ -93,8 +95,8 @@ execute_process (COMMAND ${GIT} describe HEAD set (CPACK_PACKAGE_VERSION_MAJOR "1") set (CPACK_PACKAGE_VERSION_MINOR "4") set (CPACK_PACKAGE_VERSION_PATCH "7") -if (TARANTOOL_VERSION STREQUAL "") - set (TARANTOOL_VERSION +if (PACKAGE_VERSION STREQUAL "") + set (PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") endif() @@ -158,7 +160,9 @@ if (ENABLE_BACKTRACE) endif() # Use GNU bfd if present. check_library_exists (bfd bfd_init "" HAVE_BFD_LIB) + set(CMAKE_REQUIRED_DEFINITIONS -DPACKAGE=${PACKAGE} -DPACKAGE_VERSION=${PACKAGE_VERSION}) check_include_file(bfd.h HAVE_BFD_H) + set(CMAKE_REQUIRED_DEFINITIONS) if (HAVE_BFD_LIB AND HAVE_BFD_H) set (HAVE_BFD True) endif() @@ -213,7 +217,7 @@ configure_file( message (STATUS "") message (STATUS "Tarantool configuration is complete:") message (STATUS "") -message (STATUS "VERSION: ${TARANTOOL_VERSION}") +message (STATUS "VERSION: ${PACKAGE_VERSION}") message (STATUS "BUILD: ${TARANTOOL_BUILD}") message (STATUS "COMPILER: ${TARANTOOL_COMPILER}") message (STATUS "CFLAGS:${CMAKE_C_FLAGS} ${core_cflags}") diff --git a/debian/changelog b/debian/changelog index 350b7acbeaf182dbc7011295f7aa081bdee3d755..d9f11e9b92d38f2849cd33752f96edb8c2bf9164 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +tarantool (1.4.7+20121010.2202-1) unstable; urgency=low + + * New snapshot (Don't exit on a trivial socket error). + + -- Dmitry E. Oboukhov <unera@debian.org> Wed, 10 Oct 2012 22:01:58 +0400 + +tarantool (1.4.7+20121010-1) unstable; urgency=low + + * New snapshot. + + -- Dmitry E. Oboukhov <unera@debian.org> Wed, 10 Oct 2012 17:22:26 +0400 + tarantool (1.4.7+20120918-1) unstable; urgency=low * New snapshot (some fixes in lua:box.slab). diff --git a/doc/user/data-and-persistence.xml b/doc/user/data-and-persistence.xml index b2a61856ad8d3ce9ff50d5d99a1732bedfa84816..99f05c566547bddae6480f6eb6d15198ba4f73a2 100644 --- a/doc/user/data-and-persistence.xml +++ b/doc/user/data-and-persistence.xml @@ -6,7 +6,7 @@ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="data-and-persistence"> -<title>Data model and data persitence</title> +<title>Data model and data persistence</title> <blockquote><para> This chapter describes how Tarantool stores values and what operations with data it supports. diff --git a/include/assoc.h b/include/assoc.h index 305e39df373e3b1dc0e453737e7f6ca9383545e1..9432a43eeb0d1810814b9909160a74a917924717 100644 --- a/include/assoc.h +++ b/include/assoc.h @@ -68,3 +68,4 @@ static inline int lstrcmp(void *a, void *b) #define mh_hash(key) ({ void *_k = (key); unsigned l = load_varint32(&_k); MurmurHash2(_k, l, 13); }) #define mh_eq(a, b) (lstrcmp((a), (b)) == 0) #include <mhash.h> + diff --git a/include/coio.h b/include/coio.h new file mode 100644 index 0000000000000000000000000000000000000000..5907e8c0707ea966875651541f7d851534ef52a2 --- /dev/null +++ b/include/coio.h @@ -0,0 +1,97 @@ +#ifndef TARANTOOL_COIO_H_INCLUDED +#define TARANTOOL_COIO_H_INCLUDED +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "evio.h" +/* + * Co-operative I/O + * Yield the current fiber until IO is ready. + */ +struct coio +{ + struct ev_io ev; +}; + +struct coio_service +{ + struct evio_service evio_service; + /* Fiber function. */ + void (*handler)(va_list ap); + /** Passed to the created fiber. */ + void *handler_param; +}; + +void +coio_clear(struct coio *coio); + +static inline bool +coio_is_connected(struct coio *coio) +{ + return coio->ev.fd >= 0; +} + +void +coio_connect(struct coio *coio, struct sockaddr_in *addr); + +void +coio_init(struct coio *coio, int fd); + +void +coio_close(struct coio *coio); + +ssize_t +coio_read_ahead(struct coio *coio, void *buf, size_t sz, size_t bufsiz); + +ssize_t +coio_readn_ahead(struct coio *coio, void *buf, size_t sz, size_t bufsiz); + +static inline ssize_t +coio_read(struct coio *coio, void *buf, size_t sz) +{ + return coio_read_ahead(coio, buf, sz, sz); +} + +static inline ssize_t +coio_readn(struct coio *coio, void *buf, size_t sz) +{ + return coio_readn_ahead(coio, buf, sz, sz); +} + +void +coio_write(struct coio *coio, const void *buf, size_t sz); + +ssize_t +coio_writev(struct coio *coio, struct iovec *iov, int iovcnt); + +void +coio_service_init(struct coio_service *service, const char *name, + const char *host, int port, + void (*handler)(va_list ap), void *handler_param); + +#endif /* TARANTOOL_COIO_H_INCLUDED */ diff --git a/include/coio_buf.h b/include/coio_buf.h new file mode 100644 index 0000000000000000000000000000000000000000..8c8e8ffb5df551eacbf43a1352dc876bdf9bb34c --- /dev/null +++ b/include/coio_buf.h @@ -0,0 +1,63 @@ +#ifndef TARANTOOL_COIO_BUF_H_INCLUDED +#define TARANTOOL_COIO_BUF_H_INCLUDED +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "coio.h" +#include "tbuf.h" +/** Buffered cooperative IO */ + +extern int coio_readahead; + +static inline void +coio_binit(int readahead) +{ + coio_readahead = readahead; +} + +static inline ssize_t +coio_bread(struct coio *coio, struct tbuf *buf, size_t sz) +{ + tbuf_ensure(buf, MAX(sz, coio_readahead)); + ssize_t n = coio_read_ahead(coio, tbuf_end(buf), + sz, tbuf_unused(buf)); + buf->size += n; + return n; +} + +static inline ssize_t +coio_breadn(struct coio *coio, struct tbuf *buf, size_t sz) +{ + tbuf_ensure(buf, MAX(sz, coio_readahead)); + ssize_t n = coio_readn_ahead(coio, tbuf_end(buf), + sz, tbuf_unused(buf)); + buf->size += n; + return n; +} + +#endif /* TARANTOOL_COIO_BUF_H_INCLUDED */ diff --git a/include/config.h.cmake b/include/config.h.cmake index bdceae95f74074cfaa62ff8080820e13bfb55bda..73fed9f71134a5787acd8a4927446336835cf631 100644 --- a/include/config.h.cmake +++ b/include/config.h.cmake @@ -8,7 +8,8 @@ * A string with major-minor-patch-commit-id identifier of the * release. */ -#define TARANTOOL_VERSION "@TARANTOOL_VERSION@" +#define PACKAGE_VERSION "@PACKAGE_VERSION@" +#define PACKAGE "@PACKAGE@" /* Defined if building for Linux */ #cmakedefine TARGET_OS_LINUX 1 /* Defined if building for FreeBSD */ diff --git a/include/errcode.h b/include/errcode.h index 6e368f5077b96860c9e91ad7a5f31dec6197ee42..72ae7d9420e31529cb52afaeedf0eb5df2566eea 100644 --- a/include/errcode.h +++ b/include/errcode.h @@ -108,7 +108,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 53 */_(ER_NO_SUCH_INDEX, 2, "No index #%u is defined in space %u") \ /* 54 */_(ER_NO_SUCH_FIELD, 2, "Field %u was not found in the tuple") \ /* 55 */_(ER_TUPLE_FOUND, 2, "Tuple already exists") \ - /* 56 */_(ER_INDEX_VIOLATION, 2, "Duplicate key exists in a unique index") \ + /* 56 */_(ER_INDEX_VIOLATION, 2, "Duplicate key exists in unique index %d") \ /* 57 */_(ER_NO_SUCH_SPACE, 2, "Space %u does not exist") diff --git a/include/evio.h b/include/evio.h index 7f12c7f2ec2e18fe46dafc9657d8bc24068b5b3f..333ee2821c3d81d7c6eb9783c5e37ef64b1696db 100644 --- a/include/evio.h +++ b/include/evio.h @@ -78,7 +78,8 @@ struct evio_service * when it happens, the exception is logged, and the * accepted socket is closed. */ - void (*on_accept)(void *, int, struct sockaddr_in *); + void (*on_accept)(struct evio_service *, int, + struct sockaddr_in *); void *on_accept_param; /** libev timer object for the bind retry delay. */ @@ -91,7 +92,8 @@ struct evio_service void evio_service_init(struct evio_service *service, const char *name, const char *host, int port, - void (*on_accept)(void *, int, struct sockaddr_in *), + void (*on_accept)(struct evio_service *, + int, struct sockaddr_in *), void *on_accept_param); /** Set an optional callback to be invoked upon a successful bind. */ diff --git a/include/fiber.h b/include/fiber.h index 1b61654a1d852fc916690e57b0aeeac4bb83d0cd..c0fb463c3819ad08db711098aa301f81f84a79a9 100644 --- a/include/fiber.h +++ b/include/fiber.h @@ -63,7 +63,6 @@ @end struct fiber { - ev_io io; ev_async async; #ifdef ENABLE_BACKTRACE void *last_stack_frame; @@ -73,7 +72,6 @@ struct fiber { /* A garbage-collected memory pool. */ struct palloc_pool *gc_pool; uint32_t fid; - int fd; ev_timer timer; ev_child cw; @@ -88,15 +86,9 @@ struct fiber { /* ASCIIZ name of this fiber. */ char name[FIBER_NAME_MAXLEN]; - void (*f) (void *); - void *f_data; - u64 cookie; - bool has_peer; - /* ASCIIZ name of the peer, if there is one. */ - char peer_name[32]; - + void (*f) (va_list); + va_list f_data; u32 flags; - struct fiber *waiter; }; @@ -112,19 +104,10 @@ extern __thread struct fiber *fiber; void fiber_init(void); void fiber_free(void); -struct fiber *fiber_create(const char *name, int fd, void (*f) (void *), void *); +struct fiber *fiber_create(const char *name, void (*f) (va_list)); void fiber_set_name(struct fiber *fiber, const char *name); void wait_for_child(pid_t pid); -void -fiber_io_start(int fd, int events); - -void -fiber_io_yield(); - -void -fiber_io_stop(int fd, int events); - void fiber_yield(void); @@ -133,8 +116,6 @@ fiber_yield_to(struct fiber *f); void fiber_destroy_all(); -ssize_t fiber_bread(struct tbuf *, size_t v); - bool fiber_is_cancelled(); inline static void iov_add_unsafe(const void *buf, size_t len) @@ -167,18 +148,15 @@ inline static void iov_dup(const void *buf, size_t len) iov_add(copy, len); } +struct coio; /* Reset the fiber's iov vector. */ -ssize_t iov_flush(void); +ssize_t iov_flush(struct coio *coio); /* Write everything in the fiber's iov vector to fiber socket. */ void iov_reset(); -const char *fiber_peer_name(struct fiber *fiber); -ssize_t fiber_read(void *buf, size_t count); -ssize_t fiber_write(const void *buf, size_t count); -int fiber_close(void); void fiber_cleanup(void); void fiber_gc(void); -void fiber_call(struct fiber *callee); +void fiber_call(struct fiber *callee, ...); void fiber_wakeup(struct fiber *f); struct fiber *fiber_find(int fid); /** Cancel a fiber. A cancelled fiber will have @@ -198,29 +176,10 @@ void fiber_testcancel(void); * return previous state. */ bool fiber_setcancellable(bool enable); -int fiber_connect(struct sockaddr_in *addr); +void fiber_setcancelstate(bool enable); void fiber_sleep(ev_tstamp s); void fiber_info(struct tbuf *out); -int set_nonblock(int sock); - -typedef void (*fiber_server_callback)(void *); - -struct fiber *fiber_server(const char *name, int port, - fiber_server_callback callback, void *, - void (*on_bind) (void *)); - -/** - * Create server socket and bind his on port. cfd.bind_ipaddr param using as IP address. - * - * @param type the fiber server type (TCP or UDP) - * @param port the bind ip port. - * @param retry the retry flag, if flag up the function will be try again to bind - * socket after delay. - * @param delay the bind socket retry delay in sec. - * - * @return on success, zero is returned. on error, -1 is returned. - */ -int -fiber_serv_socket(struct fiber *fiber, unsigned short port, bool retry, ev_tstamp delay); +void +fiber_schedule(ev_watcher *watcher, int event __attribute__((unused))); #endif /* TARANTOOL_FIBER_H_INCLUDED */ diff --git a/include/iproto.h b/include/iproto.h index 165899c86d8af5edc0f228047fd2e4f11db7854c..e36b463befe4b73f9d5d2de38111f3e319a91658 100644 --- a/include/iproto.h +++ b/include/iproto.h @@ -64,6 +64,6 @@ static inline struct iproto_header *iproto(const struct tbuf *t) typedef void (*iproto_callback) (uint32_t msg_code, struct tbuf *request); -void iproto_interact(iproto_callback callback); +void iproto_interact(va_list ap); #endif diff --git a/include/mhash.h b/include/mhash.h index 3e8f035d1473a5931ee9933349798a2c832e2203..e0b932fbb2c7ec94b855472397cb6cc2337f2174 100644 --- a/include/mhash.h +++ b/include/mhash.h @@ -121,6 +121,31 @@ struct _mh(t) { #define mh_begin(h) ({ 0; }) #define mh_end(h) ({ (h)->n_buckets; }) + +#define mh_first(h) ({ \ + mh_int_t i; \ + for (i = 0; i < mh_end(h); i++) { \ + if (mh_exist(h, i)) \ + break; \ + } \ + i; \ +}) + +#define mh_next(h, i) ({ \ + mh_int_t n = i; \ + if (n < mh_end(h)) { \ + for (n = i + 1; n < mh_end(h); n++) { \ + if (mh_exist(h, n)) \ + break; \ + } \ + } \ + n; \ +}) + +#define mh_foreach(h, i) \ + for (i = mh_first(h); i < mh_end(h); i = mh_next(h, i)) + + #define MH_DENSITY 0.7 struct _mh(t) * _mh(init)(); diff --git a/include/sio.h b/include/sio.h index df79d177185d88779a78acb35c405393200d5259..ca2b7e48b1e600c59a63afdc6c9a6d2cc2c3bfbb 100644 --- a/include/sio.h +++ b/include/sio.h @@ -33,9 +33,10 @@ * Provide better error logging and I/O statistics. */ #include <stdbool.h> +#include <sys/types.h> +#include <sys/socket.h> #include <netinet/in.h> #include <fcntl.h> -#include <netinet/tcp.h> /* TCP_NODELAY */ #include "exception.h" enum { SERVICE_NAME_MAXLEN = 32 }; diff --git a/mod/box/box.m b/mod/box/box.m index 55bd73856e9fde38119b89120ab130db1788492f..9a4b448d1f84ec34b4c1bae281a77ca845e6a384 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -47,6 +47,7 @@ #include "port.h" #include "request.h" #include "txn.h" +#include "coio.h" static void box_process_replica(struct txn *txn, struct port *port, u32 op, struct tbuf *request_data); @@ -277,7 +278,7 @@ recover_snap_row(struct tbuf *t) tuple->field_count = row->tuple_size; struct space *space = space_find(row->space); - Index *index = space->index[0]; + Index *index = space_index(space, 0); [index buildNext: tuple]; tuple_ref(tuple, 1); } @@ -518,22 +519,33 @@ mod_init(void) } /* run primary server */ - if (cfg.primary_port != 0) - fiber_server("primary", cfg.primary_port, - (fiber_server_callback) iproto_interact, - iproto_primary_port_handler, - box_leave_local_standby_mode); + if (cfg.primary_port != 0) { + static struct coio_service primary; + coio_service_init(&primary, "primary", + cfg.bind_ipaddr, cfg.primary_port, + iproto_interact, iproto_primary_port_handler); + evio_service_on_bind(&primary.evio_service, + box_leave_local_standby_mode, NULL); + evio_service_start(&primary.evio_service); + } /* run secondary server */ - if (cfg.secondary_port != 0) - fiber_server("secondary", cfg.secondary_port, - (fiber_server_callback) iproto_interact, - iproto_secondary_port_handler, NULL); + if (cfg.secondary_port != 0) { + static struct coio_service secondary; + coio_service_init(&secondary, "secondary", + cfg.bind_ipaddr, cfg.primary_port, + iproto_interact, iproto_secondary_port_handler); + evio_service_start(&secondary.evio_service); + } /* run memcached server */ - if (cfg.memcached_port != 0) - fiber_server("memcached", cfg.memcached_port, - memcached_handler, NULL, NULL); + if (cfg.memcached_port != 0) { + static struct coio_service memcached; + coio_service_init(&memcached, "memcached", + cfg.bind_ipaddr, cfg.memcached_port, + memcached_handler, NULL); + evio_service_start(&memcached.evio_service); + } } int @@ -558,6 +570,20 @@ snapshot_write_tuple(struct log_io *l, struct fio_batch *batch, tuple->data, tuple->bsize); } + +static void +snapshot_space(struct space *sp, void *udata) +{ + struct tuple *tuple; + struct { struct log_io *l; struct fio_batch *batch; } *ud = udata; + Index *pk = space_index(sp, 0); + struct iterator *it = pk->position; + [pk initIterator: it :ITER_FORWARD]; + + while ((tuple = it->next(it))) + snapshot_write_tuple(ud->l, ud->batch, space_n(sp), tuple); +} + void mod_snapshot(struct log_io *l, struct fio_batch *batch) { @@ -565,20 +591,9 @@ mod_snapshot(struct log_io *l, struct fio_batch *batch) if (primary_indexes_enabled == false) return; - for (uint32_t n = 0; n < BOX_SPACE_MAX; ++n) { - if (!spaces[n].enabled) - continue; - - Index *pk = spaces[n].index[0]; + struct { struct log_io *l; struct fio_batch *batch; } ud = { l, batch }; - struct iterator *it = pk->position; - [pk initIterator: it :ITER_FORWARD]; - - struct tuple *tuple; - while ((tuple = it->next(it))) { - snapshot_write_tuple(l, batch, n, tuple); - } - } + space_foreach(snapshot_space, &ud); } void diff --git a/mod/box/box_lua.m b/mod/box/box_lua.m index b17a6dafe7492a948411d043733f700cf5d8ef2b..8d60bb840ec0b0b139c49149a29f14606bcd0d3d 100644 --- a/mod/box/box_lua.m +++ b/mod/box/box_lua.m @@ -78,6 +78,9 @@ static lua_State *root_L; static const char *tuplelib_name = "box.tuple"; +static void +lbox_pushtuple(struct lua_State *L, struct tuple *tuple); + static inline struct tuple * lua_checktuple(struct lua_State *L, int narg) { @@ -161,8 +164,6 @@ lbox_tuple_slice(struct lua_State *L) return end - start; } -static void -lbox_pushtuple(struct lua_State *L, struct tuple *tuple); /** * Given a tuple, range of fields to remove (start and end field @@ -224,7 +225,7 @@ static inline void transform_set_field(u8 **ptr, const void *data, size_t size) { *ptr = save_varint32(*ptr, size); - memcpy(*ptr, data, size); + memcpy(*ptr, data, size); *ptr += size; } @@ -558,15 +559,16 @@ lbox_index_new(struct lua_State *L) int n = luaL_checkint(L, 1); /* get space id */ int idx = luaL_checkint(L, 2); /* get index id in */ /* locate the appropriate index */ - if (n >= BOX_SPACE_MAX || !spaces[n].enabled || - idx >= BOX_INDEX_MAX || spaces[n].index[idx] == nil) - tnt_raise(LoggedError, :ER_NO_SUCH_INDEX, idx, n); + struct space *sp = space_find(n); + Index *index = index_find(sp, idx); + /* create a userdata object */ void **ptr = lua_newuserdata(L, sizeof(void *)); - *ptr = spaces[n].index[idx]; + *ptr = index; /* set userdata object metatable to indexlib */ luaL_getmetatable(L, indexlib_name); lua_setmetatable(L, -2); + return 1; } diff --git a/mod/box/index.m b/mod/box/index.m index 5eb805f74a81cb78d321e31e36eb16feeaaefea1..ca67def06477c481d5127e5a2bb62815f7d4e0b6 100644 --- a/mod/box/index.m +++ b/mod/box/index.m @@ -281,7 +281,7 @@ hash_iterator_next(struct iterator *iterator) assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); - while (it->h_pos != mh_end(it->hash)) { + while (it->h_pos < mh_end(it->hash)) { if (mh_exist(it->hash, it->h_pos)) return mh_value(it->hash, it->h_pos++); it->h_pos++; diff --git a/mod/box/memcached-grammar.m b/mod/box/memcached-grammar.m index cab9b1e4f0f0340005fbc88a21f89cdce68ac6d8..a4a76e46a4691fb1b45eb75448894715d9e96c8e 100644 --- a/mod/box/memcached-grammar.m +++ b/mod/box/memcached-grammar.m @@ -42,7 +42,7 @@ static const int memcached_en_main = 1; static int __attribute__((noinline)) -memcached_dispatch() +memcached_dispatch(struct coio *coio) { int cs; u8 *p, *pe; @@ -56,7 +56,6 @@ memcached_dispatch() bool noreply = false; u8 *data = NULL; bool done = false; - int r; size_t saved_iov_cnt = fiber->iov_cnt; uintptr_t flush_delay = 0; size_t keys_count = 0; @@ -67,12 +66,12 @@ memcached_dispatch() say_debug("memcached_dispatch '%.*s'", MIN((int)(pe - p), 40) , p); -#line 71 "mod/box/memcached-grammar.m" +#line 70 "mod/box/memcached-grammar.m" { cs = memcached_start; } -#line 76 "mod/box/memcached-grammar.m" +#line 75 "mod/box/memcached-grammar.m" { if ( p == pe ) goto _test_eof; @@ -144,7 +143,7 @@ case 5: goto st0; goto tr15; tr15: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -161,7 +160,7 @@ st6: if ( ++p == pe ) goto _test_eof6; case 6: -#line 165 "mod/box/memcached-grammar.m" +#line 164 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st7; goto st0; @@ -175,49 +174,49 @@ case 7: goto tr17; goto st0; tr17: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st8; st8: if ( ++p == pe ) goto _test_eof8; case 8: -#line 186 "mod/box/memcached-grammar.m" +#line 185 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr18; if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; tr18: -#line 248 "mod/box/memcached-grammar.rl" +#line 244 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st9; st9: if ( ++p == pe ) goto _test_eof9; case 9: -#line 200 "mod/box/memcached-grammar.m" +#line 199 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st9; if ( 48 <= (*p) && (*p) <= 57 ) goto tr21; goto st0; tr21: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st10; st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 214 "mod/box/memcached-grammar.m" +#line 213 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr22; if ( 48 <= (*p) && (*p) <= 57 ) goto st10; goto st0; tr22: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -228,21 +227,21 @@ st11: if ( ++p == pe ) goto _test_eof11; case 11: -#line 232 "mod/box/memcached-grammar.m" +#line 231 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st11; if ( 48 <= (*p) && (*p) <= 57 ) goto tr25; goto st0; tr25: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st12; st12: if ( ++p == pe ) goto _test_eof12; case 12: -#line 246 "mod/box/memcached-grammar.m" +#line 245 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr26; case 13: goto tr27; @@ -252,18 +251,16 @@ case 12: goto st12; goto st0; tr26: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -277,13 +274,13 @@ tr26: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 66 "mod/box/memcached-grammar.rl" +#line 65 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -294,16 +291,14 @@ tr26: } goto st197; tr30: -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -317,13 +312,13 @@ tr30: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 66 "mod/box/memcached-grammar.rl" +#line 65 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -334,18 +329,16 @@ tr30: } goto st197; tr39: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -359,13 +352,13 @@ tr39: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 66 "mod/box/memcached-grammar.rl" +#line 65 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -376,18 +369,16 @@ tr39: } goto st197; tr58: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -401,13 +392,13 @@ tr58: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 95 "mod/box/memcached-grammar.rl" +#line 94 "mod/box/memcached-grammar.rl" { struct tbuf *b; void *value; @@ -436,16 +427,14 @@ tr58: } goto st197; tr62: -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -459,13 +448,13 @@ tr62: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 95 "mod/box/memcached-grammar.rl" +#line 94 "mod/box/memcached-grammar.rl" { struct tbuf *b; void *value; @@ -494,18 +483,16 @@ tr62: } goto st197; tr71: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -519,13 +506,13 @@ tr71: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 95 "mod/box/memcached-grammar.rl" +#line 94 "mod/box/memcached-grammar.rl" { struct tbuf *b; void *value; @@ -554,18 +541,16 @@ tr71: } goto st197; tr91: -#line 250 "mod/box/memcached-grammar.rl" +#line 246 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -579,13 +564,13 @@ tr91: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 84 "mod/box/memcached-grammar.rl" +#line 83 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -598,16 +583,14 @@ tr91: } goto st197; tr95: -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -621,13 +604,13 @@ tr95: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 84 "mod/box/memcached-grammar.rl" +#line 83 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -640,18 +623,16 @@ tr95: } goto st197; tr105: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -665,13 +646,13 @@ tr105: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 84 "mod/box/memcached-grammar.rl" +#line 83 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -684,17 +665,17 @@ tr105: } goto st197; tr118: -#line 251 "mod/box/memcached-grammar.rl" +#line 247 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 122 "mod/box/memcached-grammar.rl" +#line 121 "mod/box/memcached-grammar.rl" { struct meta *m; struct tbuf *b; @@ -751,15 +732,15 @@ tr118: } goto st197; tr122: -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 122 "mod/box/memcached-grammar.rl" +#line 121 "mod/box/memcached-grammar.rl" { struct meta *m; struct tbuf *b; @@ -816,17 +797,17 @@ tr122: } goto st197; tr132: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 122 "mod/box/memcached-grammar.rl" +#line 121 "mod/box/memcached-grammar.rl" { struct meta *m; struct tbuf *b; @@ -883,15 +864,15 @@ tr132: } goto st197; tr141: -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 177 "mod/box/memcached-grammar.rl" +#line 176 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -911,21 +892,21 @@ tr141: } goto st197; tr146: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) exptime = exptime + ev_now(); } -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 177 "mod/box/memcached-grammar.rl" +#line 176 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -945,17 +926,17 @@ tr146: } goto st197; tr157: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 177 "mod/box/memcached-grammar.rl" +#line 176 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -975,79 +956,70 @@ tr157: } goto st197; tr169: -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 206 "mod/box/memcached-grammar.rl" +#line 205 "mod/box/memcached-grammar.rl" { - if (flush_delay > 0) { - struct fiber *f = fiber_create("flush_all", -1, flush_all, (void *)flush_delay); - if (f) - fiber_call(f); - } else - flush_all((void *)0); + struct fiber *f = fiber_create("flush_all", flush_all); + if (f) + fiber_call(f, flush_delay); iov_add("OK\r\n", 4); } goto st197; tr174: -#line 252 "mod/box/memcached-grammar.rl" +#line 248 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 206 "mod/box/memcached-grammar.rl" +#line 205 "mod/box/memcached-grammar.rl" { - if (flush_delay > 0) { - struct fiber *f = fiber_create("flush_all", -1, flush_all, (void *)flush_delay); - if (f) - fiber_call(f); - } else - flush_all((void *)0); + struct fiber *f = fiber_create("flush_all", flush_all); + if (f) + fiber_call(f, flush_delay); iov_add("OK\r\n", 4); } goto st197; tr185: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 206 "mod/box/memcached-grammar.rl" +#line 205 "mod/box/memcached-grammar.rl" { - if (flush_delay > 0) { - struct fiber *f = fiber_create("flush_all", -1, flush_all, (void *)flush_delay); - if (f) - fiber_call(f); - } else - flush_all((void *)0); + struct fiber *f = fiber_create("flush_all", flush_all); + if (f) + fiber_call(f, flush_delay); iov_add("OK\r\n", 4); } goto st197; tr195: -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 195 "mod/box/memcached-grammar.rl" +#line 194 "mod/box/memcached-grammar.rl" { @try { memcached_get(keys_count, keys, show_cas); @@ -1060,32 +1032,30 @@ tr195: } goto st197; tr213: -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 220 "mod/box/memcached-grammar.rl" +#line 216 "mod/box/memcached-grammar.rl" { - return 0; + return -1; } goto st197; tr233: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -1099,13 +1069,13 @@ tr233: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 75 "mod/box/memcached-grammar.rl" +#line 74 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -1116,16 +1086,14 @@ tr233: } goto st197; tr237: -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -1139,13 +1107,13 @@ tr237: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 75 "mod/box/memcached-grammar.rl" +#line 74 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -1156,18 +1124,16 @@ tr237: } goto st197; tr246: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -1181,13 +1147,13 @@ tr246: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 75 "mod/box/memcached-grammar.rl" +#line 74 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct tuple *tuple = find(key); @@ -1198,18 +1164,16 @@ tr246: } goto st197; tr263: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -1223,29 +1187,27 @@ tr263: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 61 "mod/box/memcached-grammar.rl" +#line 60 "mod/box/memcached-grammar.rl" { key = read_field(keys); STORE; } goto st197; tr267: -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -1259,31 +1221,29 @@ tr267: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 61 "mod/box/memcached-grammar.rl" +#line 60 "mod/box/memcached-grammar.rl" { key = read_field(keys); STORE; } goto st197; tr276: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 281 "mod/box/memcached-grammar.rl" +#line 275 "mod/box/memcached-grammar.rl" { p++; } -#line 254 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -1297,28 +1257,28 @@ tr276: goto exit; } } -#line 275 "mod/box/memcached-grammar.rl" +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 61 "mod/box/memcached-grammar.rl" +#line 60 "mod/box/memcached-grammar.rl" { key = read_field(keys); STORE; } goto st197; tr281: -#line 281 "mod/box/memcached-grammar.rl" - { p++; } #line 275 "mod/box/memcached-grammar.rl" + { p++; } +#line 269 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf.data; tbuf_peek(&fiber->rbuf, p - (u8 *)fiber->rbuf.data); } -#line 216 "mod/box/memcached-grammar.rl" +#line 212 "mod/box/memcached-grammar.rl" { print_stats(); } @@ -1327,33 +1287,33 @@ st197: if ( ++p == pe ) goto _test_eof197; case 197: -#line 1331 "mod/box/memcached-grammar.m" +#line 1291 "mod/box/memcached-grammar.m" goto st0; tr27: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st13; tr40: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st13; st13: if ( ++p == pe ) goto _test_eof13; case 13: -#line 1345 "mod/box/memcached-grammar.m" +#line 1305 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr30; goto st0; tr28: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st14; st14: if ( ++p == pe ) goto _test_eof14; case 14: -#line 1357 "mod/box/memcached-grammar.m" +#line 1317 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st14; case 78: goto st15; @@ -1467,18 +1427,18 @@ case 26: goto tr45; goto st0; tr45: -#line 289 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" {append = true; } goto st27; tr209: -#line 290 "mod/box/memcached-grammar.rl" +#line 284 "mod/box/memcached-grammar.rl" {append = false;} goto st27; st27: if ( ++p == pe ) goto _test_eof27; case 27: -#line 1482 "mod/box/memcached-grammar.m" +#line 1442 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st27; @@ -1487,7 +1447,7 @@ case 27: goto st0; goto tr46; tr46: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -1504,7 +1464,7 @@ st28: if ( ++p == pe ) goto _test_eof28; case 28: -#line 1508 "mod/box/memcached-grammar.m" +#line 1468 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st29; goto st0; @@ -1518,49 +1478,49 @@ case 29: goto tr49; goto st0; tr49: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st30; st30: if ( ++p == pe ) goto _test_eof30; case 30: -#line 1529 "mod/box/memcached-grammar.m" +#line 1489 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr50; if ( 48 <= (*p) && (*p) <= 57 ) goto st30; goto st0; tr50: -#line 248 "mod/box/memcached-grammar.rl" +#line 244 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st31; st31: if ( ++p == pe ) goto _test_eof31; case 31: -#line 1543 "mod/box/memcached-grammar.m" +#line 1503 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st31; if ( 48 <= (*p) && (*p) <= 57 ) goto tr53; goto st0; tr53: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 1557 "mod/box/memcached-grammar.m" +#line 1517 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr54; if ( 48 <= (*p) && (*p) <= 57 ) goto st32; goto st0; tr54: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -1571,21 +1531,21 @@ st33: if ( ++p == pe ) goto _test_eof33; case 33: -#line 1575 "mod/box/memcached-grammar.m" +#line 1535 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st33; if ( 48 <= (*p) && (*p) <= 57 ) goto tr57; goto st0; tr57: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st34; st34: if ( ++p == pe ) goto _test_eof34; case 34: -#line 1589 "mod/box/memcached-grammar.m" +#line 1549 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr58; case 13: goto tr59; @@ -1595,30 +1555,30 @@ case 34: goto st34; goto st0; tr59: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st35; tr72: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st35; st35: if ( ++p == pe ) goto _test_eof35; case 35: -#line 1610 "mod/box/memcached-grammar.m" +#line 1570 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr62; goto st0; tr60: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st36; st36: if ( ++p == pe ) goto _test_eof36; case 36: -#line 1622 "mod/box/memcached-grammar.m" +#line 1582 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st36; case 78: goto st37; @@ -1725,7 +1685,7 @@ case 47: goto st0; goto tr76; tr76: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -1742,7 +1702,7 @@ st48: if ( ++p == pe ) goto _test_eof48; case 48: -#line 1746 "mod/box/memcached-grammar.m" +#line 1706 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st49; goto st0; @@ -1756,49 +1716,49 @@ case 49: goto tr78; goto st0; tr78: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st50; st50: if ( ++p == pe ) goto _test_eof50; case 50: -#line 1767 "mod/box/memcached-grammar.m" +#line 1727 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr79; if ( 48 <= (*p) && (*p) <= 57 ) goto st50; goto st0; tr79: -#line 248 "mod/box/memcached-grammar.rl" +#line 244 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st51; st51: if ( ++p == pe ) goto _test_eof51; case 51: -#line 1781 "mod/box/memcached-grammar.m" +#line 1741 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st51; if ( 48 <= (*p) && (*p) <= 57 ) goto tr82; goto st0; tr82: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st52; st52: if ( ++p == pe ) goto _test_eof52; case 52: -#line 1795 "mod/box/memcached-grammar.m" +#line 1755 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr83; if ( 48 <= (*p) && (*p) <= 57 ) goto st52; goto st0; tr83: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -1809,49 +1769,49 @@ st53: if ( ++p == pe ) goto _test_eof53; case 53: -#line 1813 "mod/box/memcached-grammar.m" +#line 1773 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st53; if ( 48 <= (*p) && (*p) <= 57 ) goto tr86; goto st0; tr86: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st54; st54: if ( ++p == pe ) goto _test_eof54; case 54: -#line 1827 "mod/box/memcached-grammar.m" +#line 1787 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr87; if ( 48 <= (*p) && (*p) <= 57 ) goto st54; goto st0; tr87: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st55; st55: if ( ++p == pe ) goto _test_eof55; case 55: -#line 1841 "mod/box/memcached-grammar.m" +#line 1801 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st55; if ( 48 <= (*p) && (*p) <= 57 ) goto tr90; goto st0; tr90: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st56; st56: if ( ++p == pe ) goto _test_eof56; case 56: -#line 1855 "mod/box/memcached-grammar.m" +#line 1815 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr91; case 13: goto tr92; @@ -1861,30 +1821,30 @@ case 56: goto st56; goto st0; tr106: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st57; tr92: -#line 250 "mod/box/memcached-grammar.rl" +#line 246 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} goto st57; st57: if ( ++p == pe ) goto _test_eof57; case 57: -#line 1876 "mod/box/memcached-grammar.m" +#line 1836 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr95; goto st0; tr93: -#line 250 "mod/box/memcached-grammar.rl" +#line 246 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} goto st58; st58: if ( ++p == pe ) goto _test_eof58; case 58: -#line 1888 "mod/box/memcached-grammar.m" +#line 1848 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr95; case 13: goto st57; @@ -1958,14 +1918,14 @@ case 65: } goto st0; tr107: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st66; st66: if ( ++p == pe ) goto _test_eof66; case 66: -#line 1969 "mod/box/memcached-grammar.m" +#line 1929 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr95; case 13: goto st57; @@ -2009,18 +1969,18 @@ case 70: goto tr113; goto st0; tr113: -#line 298 "mod/box/memcached-grammar.rl" +#line 292 "mod/box/memcached-grammar.rl" {incr_sign = -1;} goto st71; tr202: -#line 297 "mod/box/memcached-grammar.rl" +#line 291 "mod/box/memcached-grammar.rl" {incr_sign = 1; } goto st71; st71: if ( ++p == pe ) goto _test_eof71; case 71: -#line 2024 "mod/box/memcached-grammar.m" +#line 1984 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st71; @@ -2029,7 +1989,7 @@ case 71: goto st0; goto tr114; tr114: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2046,7 +2006,7 @@ st72: if ( ++p == pe ) goto _test_eof72; case 72: -#line 2050 "mod/box/memcached-grammar.m" +#line 2010 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st73; goto st0; @@ -2060,14 +2020,14 @@ case 73: goto tr117; goto st0; tr117: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st74; st74: if ( ++p == pe ) goto _test_eof74; case 74: -#line 2071 "mod/box/memcached-grammar.m" +#line 2031 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr118; case 13: goto tr119; @@ -2077,30 +2037,30 @@ case 74: goto st74; goto st0; tr133: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st75; tr119: -#line 251 "mod/box/memcached-grammar.rl" +#line 247 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} goto st75; st75: if ( ++p == pe ) goto _test_eof75; case 75: -#line 2092 "mod/box/memcached-grammar.m" +#line 2052 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr122; goto st0; tr120: -#line 251 "mod/box/memcached-grammar.rl" +#line 247 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} goto st76; st76: if ( ++p == pe ) goto _test_eof76; case 76: -#line 2104 "mod/box/memcached-grammar.m" +#line 2064 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr122; case 13: goto st75; @@ -2174,14 +2134,14 @@ case 83: } goto st0; tr134: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st84; st84: if ( ++p == pe ) goto _test_eof84; case 84: -#line 2185 "mod/box/memcached-grammar.m" +#line 2145 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr122; case 13: goto st75; @@ -2234,7 +2194,7 @@ case 89: goto st0; goto tr140; tr140: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2251,7 +2211,7 @@ st90: if ( ++p == pe ) goto _test_eof90; case 90: -#line 2255 "mod/box/memcached-grammar.m" +#line 2215 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2259,7 +2219,7 @@ case 90: } goto st0; tr147: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2267,14 +2227,14 @@ tr147: } goto st91; tr158: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st91; st91: if ( ++p == pe ) goto _test_eof91; case 91: -#line 2278 "mod/box/memcached-grammar.m" +#line 2238 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr141; goto st0; @@ -2293,14 +2253,14 @@ case 92: goto tr144; goto st0; tr144: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st93; st93: if ( ++p == pe ) goto _test_eof93; case 93: -#line 2304 "mod/box/memcached-grammar.m" +#line 2264 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr146; case 13: goto tr147; @@ -2310,7 +2270,7 @@ case 93: goto st93; goto st0; tr148: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2321,7 +2281,7 @@ st94: if ( ++p == pe ) goto _test_eof94; case 94: -#line 2325 "mod/box/memcached-grammar.m" +#line 2285 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2395,14 +2355,14 @@ case 101: } goto st0; tr159: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st102; st102: if ( ++p == pe ) goto _test_eof102; case 102: -#line 2406 "mod/box/memcached-grammar.m" +#line 2366 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2490,18 +2450,18 @@ case 111: } goto st0; tr186: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st112; tr175: -#line 252 "mod/box/memcached-grammar.rl" +#line 248 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} goto st112; st112: if ( ++p == pe ) goto _test_eof112; case 112: -#line 2505 "mod/box/memcached-grammar.m" +#line 2465 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr169; goto st0; @@ -2520,14 +2480,14 @@ case 113: goto tr172; goto st0; tr172: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st114; st114: if ( ++p == pe ) goto _test_eof114; case 114: -#line 2531 "mod/box/memcached-grammar.m" +#line 2491 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr174; case 13: goto tr175; @@ -2537,14 +2497,14 @@ case 114: goto st114; goto st0; tr176: -#line 252 "mod/box/memcached-grammar.rl" +#line 248 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} goto st115; st115: if ( ++p == pe ) goto _test_eof115; case 115: -#line 2548 "mod/box/memcached-grammar.m" +#line 2508 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr169; case 13: goto st112; @@ -2618,14 +2578,14 @@ case 122: } goto st0; tr187: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st123; st123: if ( ++p == pe ) goto _test_eof123; case 123: -#line 2629 "mod/box/memcached-grammar.m" +#line 2589 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr169; case 13: goto st112; @@ -2661,18 +2621,18 @@ case 126: } goto st0; tr191: -#line 294 "mod/box/memcached-grammar.rl" +#line 288 "mod/box/memcached-grammar.rl" {show_cas = false;} goto st127; tr198: -#line 295 "mod/box/memcached-grammar.rl" +#line 289 "mod/box/memcached-grammar.rl" {show_cas = true;} goto st127; st127: if ( ++p == pe ) goto _test_eof127; case 127: -#line 2676 "mod/box/memcached-grammar.m" +#line 2636 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st127; @@ -2681,7 +2641,7 @@ case 127: goto st0; goto tr193; tr193: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2698,7 +2658,7 @@ st128: if ( ++p == pe ) goto _test_eof128; case 128: -#line 2702 "mod/box/memcached-grammar.m" +#line 2662 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr195; case 13: goto st129; @@ -2941,7 +2901,7 @@ case 155: goto st0; goto tr222; tr222: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2958,7 +2918,7 @@ st156: if ( ++p == pe ) goto _test_eof156; case 156: -#line 2962 "mod/box/memcached-grammar.m" +#line 2922 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st157; goto st0; @@ -2972,49 +2932,49 @@ case 157: goto tr224; goto st0; tr224: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st158; st158: if ( ++p == pe ) goto _test_eof158; case 158: -#line 2983 "mod/box/memcached-grammar.m" +#line 2943 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr225; if ( 48 <= (*p) && (*p) <= 57 ) goto st158; goto st0; tr225: -#line 248 "mod/box/memcached-grammar.rl" +#line 244 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st159; st159: if ( ++p == pe ) goto _test_eof159; case 159: -#line 2997 "mod/box/memcached-grammar.m" +#line 2957 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st159; if ( 48 <= (*p) && (*p) <= 57 ) goto tr228; goto st0; tr228: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st160; st160: if ( ++p == pe ) goto _test_eof160; case 160: -#line 3011 "mod/box/memcached-grammar.m" +#line 2971 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr229; if ( 48 <= (*p) && (*p) <= 57 ) goto st160; goto st0; tr229: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -3025,21 +2985,21 @@ st161: if ( ++p == pe ) goto _test_eof161; case 161: -#line 3029 "mod/box/memcached-grammar.m" +#line 2989 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st161; if ( 48 <= (*p) && (*p) <= 57 ) goto tr232; goto st0; tr232: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st162; st162: if ( ++p == pe ) goto _test_eof162; case 162: -#line 3043 "mod/box/memcached-grammar.m" +#line 3003 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr233; case 13: goto tr234; @@ -3049,30 +3009,30 @@ case 162: goto st162; goto st0; tr234: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st163; tr247: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st163; st163: if ( ++p == pe ) goto _test_eof163; case 163: -#line 3064 "mod/box/memcached-grammar.m" +#line 3024 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr237; goto st0; tr235: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st164; st164: if ( ++p == pe ) goto _test_eof164; case 164: -#line 3076 "mod/box/memcached-grammar.m" +#line 3036 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st164; case 78: goto st165; @@ -3181,7 +3141,7 @@ case 175: goto st0; goto tr252; tr252: -#line 225 "mod/box/memcached-grammar.rl" +#line 221 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -3198,7 +3158,7 @@ st176: if ( ++p == pe ) goto _test_eof176; case 176: -#line 3202 "mod/box/memcached-grammar.m" +#line 3162 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st177; goto st0; @@ -3212,49 +3172,49 @@ case 177: goto tr254; goto st0; tr254: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st178; st178: if ( ++p == pe ) goto _test_eof178; case 178: -#line 3223 "mod/box/memcached-grammar.m" +#line 3183 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr255; if ( 48 <= (*p) && (*p) <= 57 ) goto st178; goto st0; tr255: -#line 248 "mod/box/memcached-grammar.rl" +#line 244 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st179; st179: if ( ++p == pe ) goto _test_eof179; case 179: -#line 3237 "mod/box/memcached-grammar.m" +#line 3197 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st179; if ( 48 <= (*p) && (*p) <= 57 ) goto tr258; goto st0; tr258: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st180; st180: if ( ++p == pe ) goto _test_eof180; case 180: -#line 3251 "mod/box/memcached-grammar.m" +#line 3211 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr259; if ( 48 <= (*p) && (*p) <= 57 ) goto st180; goto st0; tr259: -#line 241 "mod/box/memcached-grammar.rl" +#line 237 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -3265,21 +3225,21 @@ st181: if ( ++p == pe ) goto _test_eof181; case 181: -#line 3269 "mod/box/memcached-grammar.m" +#line 3229 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st181; if ( 48 <= (*p) && (*p) <= 57 ) goto tr262; goto st0; tr262: -#line 224 "mod/box/memcached-grammar.rl" +#line 220 "mod/box/memcached-grammar.rl" { fstart = p; } goto st182; st182: if ( ++p == pe ) goto _test_eof182; case 182: -#line 3283 "mod/box/memcached-grammar.m" +#line 3243 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr263; case 13: goto tr264; @@ -3289,30 +3249,30 @@ case 182: goto st182; goto st0; tr264: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st183; tr277: -#line 283 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { noreply = true; } goto st183; st183: if ( ++p == pe ) goto _test_eof183; case 183: -#line 3304 "mod/box/memcached-grammar.m" +#line 3264 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr267; goto st0; tr265: -#line 249 "mod/box/memcached-grammar.rl" +#line 245 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st184; st184: if ( ++p == pe ) goto _test_eof184; case 184: -#line 3316 "mod/box/memcached-grammar.m" +#line 3276 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st184; case 78: goto st185; @@ -3627,7 +3587,7 @@ case 196: _out: {} } -#line 308 "mod/box/memcached-grammar.rl" +#line 302 "mod/box/memcached-grammar.rl" if (!done) { @@ -3652,7 +3612,6 @@ case 196: fiber->iov_cnt = saved_iov_cnt; fiber->iov.size = saved_iov_cnt * sizeof(struct iovec); } - return 1; } diff --git a/mod/box/memcached-grammar.rl b/mod/box/memcached-grammar.rl index f6678863836ca18de730d8bbf514a4f2195231cc..70046b2a774d8afd1ea6513be2249ddda94f40da 100644 --- a/mod/box/memcached-grammar.rl +++ b/mod/box/memcached-grammar.rl @@ -33,7 +33,7 @@ }%% static int __attribute__((noinline)) -memcached_dispatch() +memcached_dispatch(struct coio *coio) { int cs; u8 *p, *pe; @@ -47,7 +47,6 @@ memcached_dispatch() bool noreply = false; u8 *data = NULL; bool done = false; - int r; size_t saved_iov_cnt = fiber->iov_cnt; uintptr_t flush_delay = 0; size_t keys_count = 0; @@ -204,12 +203,9 @@ memcached_dispatch() } action flush_all { - if (flush_delay > 0) { - struct fiber *f = fiber_create("flush_all", -1, flush_all, (void *)flush_delay); - if (f) - fiber_call(f); - } else - flush_all((void *)0); + struct fiber *f = fiber_create("flush_all", flush_all); + if (f) + fiber_call(f, flush_delay); iov_add("OK\r\n", 4); } @@ -218,7 +214,7 @@ memcached_dispatch() } action quit { - return 0; + return -1; } action fstart { fstart = p; } @@ -254,10 +250,8 @@ memcached_dispatch() action read_data { size_t parsed = p - (u8 *)fiber->rbuf.data; while (fiber->rbuf.size - parsed < bytes + 2) { - if ((r = fiber_bread(&fiber->rbuf, bytes + 2 - (pe - p))) <= 0) { - say_debug("read returned %i, closing connection", r); - return 0; - } + if (coio_bread(coio, &fiber->rbuf, bytes + 2 - (pe - p)) <= 0) + return -1; } p = fiber->rbuf.data + parsed; @@ -329,7 +323,6 @@ memcached_dispatch() fiber->iov_cnt = saved_iov_cnt; fiber->iov.size = saved_iov_cnt * sizeof(struct iovec); } - return 1; } diff --git a/mod/box/memcached.h b/mod/box/memcached.h index 10d4df108c2bd1a8c1fd9e6a581c018195dccc59..6563841d6e0944207b47dd916a0b98f284244d8f 100644 --- a/mod/box/memcached.h +++ b/mod/box/memcached.h @@ -28,6 +28,8 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include <stdarg.h> + struct tarantool_cfg; void @@ -45,6 +47,6 @@ memcached_check_config(struct tarantool_cfg *conf); void memcached_start_expire(); void memcached_stop_expire(); -void memcached_handler(void * /* data */); +void memcached_handler(va_list ap); #endif /* TARANTOOL_MEMCACHED_H_INCLUDED */ diff --git a/mod/box/memcached.m b/mod/box/memcached.m index e76242a2806b681c3873c3ba4cc37e8a744b8239..b2b876af07af63840df4efda3ad3a08f62226862 100644 --- a/mod/box/memcached.m +++ b/mod/box/memcached.m @@ -26,6 +26,7 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include "memcached.h" #include "tarantool.h" #include <limits.h> @@ -43,6 +44,7 @@ #include "pickle.h" #include "space.h" #include "port.h" +#include "coio_buf.h" #define STAT(_) \ _(MEMC_GET, 1) \ @@ -298,9 +300,9 @@ void memcached_get(size_t keys_count, struct tbuf *keys, } static void -flush_all(void *data) +flush_all(va_list ap) { - uintptr_t delay = (uintptr_t)data; + uintptr_t delay = va_arg(ap, uintptr_t); fiber_sleep(delay - ev_now()); struct tuple *tuple; struct iterator *it = [memcached_index allocIterator]; @@ -333,59 +335,68 @@ do { \ #include "memcached-grammar.m" void -memcached_handler(void *_data __attribute__((unused))) +memcached_loop(struct coio *coio) { - stats.total_connections++; - stats.curr_connections++; - int r, p; + int rc; + int bytes_written; int batch_count; for (;;) { batch_count = 0; - if ((r = fiber_bread(&fiber->rbuf, 1)) <= 0) { - say_debug("read returned %i, closing connection", r); - goto exit; - } + if (coio_bread(coio, &fiber->rbuf, 1) <= 0) + return; dispatch: - p = memcached_dispatch(); - if (p < 0) { + rc = memcached_dispatch(coio); + if (rc < 0) { say_debug("negative dispatch, closing connection"); - goto exit; + return; } - if (p == 0 && batch_count == 0) /* we havn't successfully parsed any requests */ + if (rc == 0 && batch_count == 0) /* we haven't successfully parsed any requests */ continue; - if (p == 1) { + if (rc == 1) { batch_count++; /* some unparsed commands remain and batch count less than 20 */ if (fiber->rbuf.size > 0 && batch_count < 20) goto dispatch; } - r = iov_flush(); - if (r < 0) { - say_debug("flush_output failed, closing connection"); - goto exit; - } + bytes_written = iov_flush(coio); - stats.bytes_written += r; + stats.bytes_written += bytes_written; fiber_gc(); - if (p == 1 && fiber->rbuf.size > 0) { + if (rc == 1 && fiber->rbuf.size > 0) { batch_count = 0; goto dispatch; } } -exit: - iov_flush(); - fiber_sleep(0.01); - say_debug("exit"); - stats.curr_connections--; /* FIXME: nonlocal exit via exception will leak this counter */ } +void memcached_handler(va_list ap) +{ + struct coio coio = va_arg(ap, struct coio); + stats.total_connections++; + stats.curr_connections++; + + @try { + memcached_loop(&coio); + iov_flush(&coio); + } @catch (FiberCancelException *e) { + @throw; + } @catch (tnt_Exception *e) { + [e log]; + } @finally { + iov_reset(); + fiber_sleep(0.01); + stats.curr_connections--; + coio_close(&coio); + } +} + int memcached_check_config(struct tarantool_cfg *conf) { @@ -401,13 +412,6 @@ memcached_check_config(struct tarantool_cfg *conf) } /* check memcached space number: it shoud be in segment [0, max_space] */ - if ((conf->memcached_space < 0) || - (conf->memcached_space > BOX_SPACE_MAX)) { - /* invalid space number */ - out_warning(0, "invalid memcached space number: %i", - conf->memcached_space); - return -1; - } if (conf->memcached_expire_per_loop <= 0) { /* invalid expire per loop value */ @@ -435,7 +439,8 @@ memcached_init(void) stat_base = stat_register(memcached_stat_strs, memcached_stat_MAX); - memcached_index = spaces[cfg.memcached_space].index[0]; + struct space *sp = space_by_n(cfg.memcached_space); + memcached_index = space_index(sp, 0); } void @@ -451,19 +456,9 @@ memcached_space_init() if (cfg.memcached_port == 0) return; - /* Configure memcached space. */ - struct space *memc_s = &spaces[cfg.memcached_space]; - memc_s->enabled = true; - memc_s->arity = 4; - - memc_s->key_count = 1; - memc_s->key_defs = malloc(sizeof(struct key_def)); - if (memc_s->key_defs == NULL) - panic("out of memory when configuring memcached_space"); - - struct key_def *key_def = memc_s->key_defs; /* Configure memcached index key. */ + struct key_def *key_def = malloc(sizeof(struct key_def)); key_def->part_count = 1; key_def->is_unique = true; @@ -479,8 +474,13 @@ memcached_space_init() key_def->max_fieldno = 1; key_def->cmp_order[0] = 0; - /* Configure memcached index. */ - Index *memc_index = memc_s->index[0] = [Index alloc: HASH :key_def :memc_s]; + + struct space *memc_s = + space_create(cfg.memcached_space, key_def, 1, 4); + + Index *memc_index = [Index alloc: HASH :key_def :memc_s]; + space_set_index(memc_s, 0, memc_index); + [memc_index init: key_def :memc_s]; } @@ -515,7 +515,7 @@ memcached_delete_expired_keys(struct tbuf *keys_to_delete) } void -memcached_expire_loop(void *data __attribute__((unused))) +memcached_expire_loop(va_list ap __attribute__((unused))) { struct tuple *tuple = NULL; @@ -556,8 +556,8 @@ void memcached_start_expire() return; assert(memcached_expire == NULL); - memcached_expire = fiber_create("memcached_expire", -1, - memcached_expire_loop, NULL); + memcached_expire = fiber_create("memcached_expire", + memcached_expire_loop); if (memcached_expire == NULL) say_error("can't start the expire fiber"); fiber_call(memcached_expire); diff --git a/mod/box/request.m b/mod/box/request.m index 63555e1b6b78d4ab4dbd0e76c3775749ba62e909..ac0ac4a56abbe12b52457d4759dddf0810ae4153 100644 --- a/mod/box/request.m +++ b/mod/box/request.m @@ -97,7 +97,9 @@ execute_replace(struct request *request, struct txn *txn, struct port *port) txn->new_tuple->field_count = field_count; memcpy(txn->new_tuple->data, data->data, data->size); - struct tuple *old_tuple = [sp->index[0] findByTuple: txn->new_tuple]; + /* Try to find tuple by primary key */ + Index *pk = space_index(sp, 0); + struct tuple *old_tuple = [pk findByTuple: txn->new_tuple]; if (flags & BOX_ADD && old_tuple != NULL) tnt_raise(ClientError, :ER_TUPLE_FOUND); @@ -711,9 +713,10 @@ execute_update(struct request *request, struct txn *txn, struct port *port) u32 key_part_count; read_key(data, &key, &key_part_count); - /* Try to find the tuple. */ - struct tuple *old_tuple = - [sp->index[0] findByKey :key :key_part_count]; + + Index *pk = space_index(sp, 0); + /* Try to find the tuple by primary key. */ + struct tuple *old_tuple = [pk findByKey :key :key_part_count]; if (old_tuple != NULL) { /* number of operations */ @@ -801,8 +804,9 @@ execute_delete(struct request *request, struct txn *txn, struct port *port) u32 key_part_count; void *key; read_key(data, &key, &key_part_count); - /* try to find tuple in primary index */ - struct tuple *old_tuple = [sp->index[0] findByKey :key :key_part_count]; + /* Try to find tuple by primary key */ + Index *pk = space_index(sp, 0); + struct tuple *old_tuple = [pk findByKey :key :key_part_count]; txn_add_undo(txn, sp, old_tuple, NULL); diff --git a/mod/box/space.h b/mod/box/space.h index 4ca67a5c0b346da89dafcdeb956c85ad478678c3..dec54040830ba05593935d4bacd85b2ffaf46e44 100644 --- a/mod/box/space.h +++ b/mod/box/space.h @@ -33,9 +33,9 @@ struct tarantool_cfg; + enum { BOX_INDEX_MAX = 10, - BOX_SPACE_MAX = 256, }; struct space { @@ -77,18 +77,13 @@ struct space { */ int max_fieldno; - bool enabled; + /** Space number. */ + i32 no; }; -extern struct space *spaces; /** Get space ordinal number. */ -static inline int -space_n(struct space *sp) -{ - assert(sp >= spaces && sp < (spaces + BOX_SPACE_MAX)); - return sp - spaces; -} +static inline i32 space_n(struct space *sp) { return sp->no; } void space_validate(struct space *sp, struct tuple *old_tuple, struct tuple *new_tuple); @@ -96,6 +91,47 @@ void space_replace(struct space *sp, struct tuple *old_tuple, struct tuple *new_tuple); void space_remove(struct space *sp, struct tuple *tuple); + +/** + * Get index by index number. + * @return NULL if index not found. + */ +static inline Index * +space_index(struct space *sp, int index_no) +{ + if (index_no >= 0 && index_no < BOX_INDEX_MAX) + return sp->index[index_no]; + return NULL; +} + +/** Set index by index no. */ +void +space_set_index(struct space *sp, int index_no, Index *idx); + +/** + * 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. + */ +struct space *space_by_n(i32 space_no); + +static inline struct space * +space_find(i32 space_no) +{ + struct space *s = space_by_n(space_no); + if (s) + return s; + + tnt_raise(ClientError, :ER_NO_SUCH_SPACE, space_no); +} + + /** Get key_def ordinal number. */ static inline int key_def_n(struct space *sp, struct key_def *kp) @@ -104,6 +140,23 @@ key_def_n(struct space *sp, struct key_def *kp) return kp - sp->key_defs; } +static inline int +space_max_fieldno(struct space *sp) +{ + return sp->max_fieldno; +} + +static inline enum field_data_type +space_field_type(struct space *sp, int no) +{ + return sp->field_types[no]; +} + + +struct space * +space_create(i32 space_no, struct key_def *key_defs, int key_count, int arity); + + /** Get index ordinal number in space. */ static inline int index_n(Index *index) @@ -129,21 +182,6 @@ extern bool secondary_indexes_enabled; */ extern bool primary_indexes_enabled; -static inline int -index_count(struct space *sp) -{ - if (!secondary_indexes_enabled) { - /* If secondary indexes are not enabled yet, - we can use only the primary index. So return - 1 if there is at least one index (which - must be primary) and return 0 otherwise. */ - return sp->key_count > 0; - } else { - /* Return the actual number of indexes. */ - return sp->key_count; - } -} - void space_init(void); void space_free(void); i32 check_spaces(struct tarantool_cfg *conf); @@ -152,26 +190,15 @@ void begin_build_primary_indexes(void); void end_build_primary_indexes(void); void build_secondary_indexes(void); -static inline struct space * -space_find(u32 space_no) -{ - if (space_no >= BOX_SPACE_MAX) - tnt_raise(ClientError, :ER_NO_SUCH_SPACE, space_no); - - struct space *sp = &spaces[space_no]; - - if (!sp->enabled) - tnt_raise(ClientError, :ER_SPACE_DISABLED, space_no); - return sp; -} static inline Index * -index_find(struct space *sp, u32 index_no) +index_find(struct space *sp, int index_no) { - if (index_no >= sp->key_count) + Index *idx = space_index(sp, index_no); + if (idx == NULL) tnt_raise(LoggedError, :ER_NO_SUCH_INDEX, index_no, space_n(sp)); - return sp->index[index_no]; + return idx; } #endif /* TARANTOOL_BOX_SPACE_H_INCLUDED */ diff --git a/mod/box/space.m b/mod/box/space.m index 276686071d44dbe4c654c7ecc199c65e4499ffd9..048bb2dbf18160e78ab02dac4eed0c578ec99d2f 100644 --- a/mod/box/space.m +++ b/mod/box/space.m @@ -36,11 +36,83 @@ #include "tuple.h" #include <pickle.h> #include <palloc.h> +#include <assoc.h> -struct space *spaces = NULL; + + +static struct mh_i32ptr_t *spaces; bool secondary_indexes_enabled = false; bool primary_indexes_enabled = false; + + +struct space * +space_create(i32 space_no, struct key_def *key_defs, int key_count, int arity) +{ + + struct space *space = space_by_n(space_no); + if (space) + panic("Space %d is already exists", space_no); + space = calloc(sizeof(struct space), 1); + space->no = space_no; + + mh_i32ptr_put(spaces, space->no, space, NULL); + + space->arity = arity; + space->key_defs = key_defs; + space->key_count = key_count; + + return space; +} + + +/* return space by its number */ +struct space * +space_by_n(i32 n) +{ + mh_int_t space = mh_i32ptr_get(spaces, n); + if (space == mh_end(spaces)) + return NULL; + return mh_value(spaces, space); +} + +/** Return the number of active indexes in a space. */ +static inline int +index_count(struct space *sp) +{ + if (!secondary_indexes_enabled) { + /* If secondary indexes are not enabled yet, + we can use only the primary index. So return + 1 if there is at least one index (which + must be primary) and return 0 otherwise. */ + return sp->key_count > 0; + } else { + /* Return the actual number of indexes. */ + return sp->key_count; + } +} + +/** + * Visit all enabled 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 = mh_value(spaces, i); + func(space, udata); + } +} + +/** Set index by index no */ +void +space_set_index(struct space *sp, int index_no, Index *idx) +{ + assert(index_no >= 0 && index_no < BOX_INDEX_MAX); + sp->index[index_no] = idx; +} + /** Free a key definition. */ static void key_free(struct key_def *key_def) @@ -103,7 +175,8 @@ space_validate(struct space *sp, struct tuple *old_tuple, if (index->key_def->is_unique) { struct tuple *tuple = [index findByTuple: new_tuple]; if (tuple != NULL && tuple != old_tuple) - tnt_raise(ClientError, :ER_INDEX_VIOLATION); + tnt_raise(ClientError, :ER_INDEX_VIOLATION, + index_n(index)); } } } @@ -121,21 +194,24 @@ space_remove(struct space *sp, struct tuple *tuple) void space_free(void) { - int i; - for (i = 0 ; i < BOX_SPACE_MAX ; i++) { - if (!spaces[i].enabled) - continue; + mh_int_t i; + + mh_foreach(spaces, i) { + struct space *space = mh_value(spaces, i); + mh_i32ptr_del(spaces, i); int j; - for (j = 0 ; j < spaces[i].key_count; j++) { - Index *index = spaces[i].index[j]; + for (j = 0 ; j < space->key_count; j++) { + Index *index = space->index[j]; [index free]; - key_free(&spaces[i].key_defs[j]); + key_free(&space->key_defs[j]); } - free(spaces[i].key_defs); - free(spaces[i].field_types); + free(space->key_defs); + free(space->field_types); + free(space); } + } static void @@ -184,7 +260,8 @@ key_init(struct key_def *def, struct tarantool_cfg_space_index *cfg_index) def->parts[k].fieldno = cfg_key->fieldno; def->parts[k].type = STR2ENUM(field_data_type, cfg_key->type); /* fill compare order */ - def->cmp_order[cfg_key->fieldno] = k; + if (def->cmp_order[cfg_key->fieldno] == -1) + def->cmp_order[cfg_key->fieldno] = k; } def->is_unique = cfg_index->unique; } @@ -255,39 +332,47 @@ space_config() assert(cfg.memcached_port == 0 || i != cfg.memcached_space); - spaces[i].enabled = true; - spaces[i].arity = cfg_space->cardinality; + struct space *space = space_by_n(i); + if (space) + panic("space %i is already exists", i); + + space = calloc(sizeof(struct space), 1); + space->no = i; + space->arity = cfg_space->cardinality; /* * Collect key/field info. We need aggregate * information on all keys before we can create * indexes. */ - spaces[i].key_count = 0; + space->key_count = 0; for (int j = 0; cfg_space->index[j] != NULL; ++j) { - ++spaces[i].key_count; + ++space->key_count; } - spaces[i].key_defs = malloc(spaces[i].key_count * + + space->key_defs = malloc(space->key_count * sizeof(struct key_def)); - if (spaces[i].key_defs == NULL) { + if (space->key_defs == NULL) { panic("can't allocate key def array"); } for (int j = 0; cfg_space->index[j] != NULL; ++j) { typeof(cfg_space->index[j]) cfg_index = cfg_space->index[j]; - key_init(&spaces[i].key_defs[j], cfg_index); + key_init(&space->key_defs[j], cfg_index); } - space_init_field_types(&spaces[i]); + space_init_field_types(space); /* fill space indexes */ for (int j = 0; cfg_space->index[j] != NULL; ++j) { typeof(cfg_space->index[j]) cfg_index = cfg_space->index[j]; enum index_type type = STR2ENUM(index_type, cfg_index->type); - struct key_def *key_def = &spaces[i].key_defs[j]; - Index *index = [Index alloc: type :key_def :&spaces[i]]; - [index init: key_def :&spaces[i]]; - spaces[i].index[j] = index; + struct key_def *key_def = &space->key_defs[j]; + Index *index = [Index alloc: type :key_def :space]; + [index init: key_def :space]; + space->index[j] = index; } + + mh_i32ptr_put(spaces, space->no, space, NULL); say_info("space %i successfully configured", i); } } @@ -295,8 +380,7 @@ space_config() void space_init(void) { - /* Allocate and initialize space memory. */ - spaces = p0alloc(eter_pool, sizeof(struct space) * BOX_SPACE_MAX); + spaces = mh_i32ptr_init(); /* configure regular spaces */ space_config(); @@ -306,24 +390,24 @@ void begin_build_primary_indexes(void) { assert(primary_indexes_enabled == false); - for (u32 n = 0; n < BOX_SPACE_MAX; ++n) { - if (spaces[n].enabled == false) - continue; - Index *pk = spaces[n].index[0]; - [pk beginBuild]; + mh_int_t i; + + mh_foreach(spaces, i) { + struct space *space = mh_value(spaces, i); + Index *index = space->index[0]; + [index beginBuild]; } } void end_build_primary_indexes(void) { - for (u32 n = 0; n < BOX_SPACE_MAX; ++n) { - if (spaces[n].enabled == false) - continue; - - Index *pk = spaces[n].index[0]; - [pk endBuild]; + mh_int_t i; + mh_foreach(spaces, i) { + struct space *space = mh_value(spaces, i); + Index *index = space->index[0]; + [index endBuild]; } primary_indexes_enabled = true; } @@ -334,21 +418,22 @@ build_secondary_indexes(void) assert(primary_indexes_enabled == true); assert(secondary_indexes_enabled == false); - for (u32 n = 0; n < BOX_SPACE_MAX; ++n) { - if (spaces[n].enabled == false) - continue; - if (spaces[n].key_count <= 1) + mh_int_t i; + mh_foreach(spaces, i) { + struct space *space = mh_value(spaces, i); + + if (space->key_count <= 1) continue; /* no secondary keys */ - say_info("Building secondary keys in space %" PRIu32 "...", n); + say_info("Building secondary keys in space %d...", space->no); - Index *pk = spaces[n].index[0]; - for (int i = 1; i < spaces[n].key_count; i++) { - Index *index = spaces[n].index[i]; + Index *pk = space->index[0]; + for (int j = 1; j < space->key_count; j++) { + Index *index = space->index[j]; [index build: pk]; } - say_info("Space %"PRIu32": done", n); + say_info("Space %d: done", space->no); } /* enable secondary indexes now */ @@ -376,14 +461,6 @@ check_spaces(struct tarantool_cfg *conf) continue; } - /* check space bound */ - if (i >= BOX_SPACE_MAX) { - /* maximum space is reached */ - out_warning(0, "(space = %zu) " - "too many spaces (%i maximum)", i, space); - return -1; - } - if (conf->memcached_port && i == conf->memcached_space) { out_warning(0, "Space %i is already used as " "memcached_space.", i); diff --git a/mod/box/tree.m b/mod/box/tree.m index e4efc5dcd9c7930c848b32d731945450ed4ccb08..88377abaea0f97abb0ab9e9f2e6ac03fc421a1da 100644 --- a/mod/box/tree.m +++ b/mod/box/tree.m @@ -201,15 +201,15 @@ find_fixed_offset(struct space *space, int fieldno, int skip) while (i < fieldno) { /* if the field is unknown give up on it */ - if (i >= space->max_fieldno || space->field_types[i] == UNKNOWN) { + if (i >= space_max_fieldno(space) || space_field_type(space, i) == UNKNOWN) { return -1; } /* On a fixed length field account for the appropiate varint length code and for the actual data length */ - if (space->field_types[i] == NUM) { + if (space_field_type(space, i) == NUM) { offset += 1 + 4; - } else if (space->field_types[i] == NUM64) { + } else if (space_field_type(space, i) == NUM64) { offset += 1 + 8; } /* On a variable length field give up */ @@ -1047,6 +1047,7 @@ tree_iterator_free(struct iterator *iterator) [pk initIterator: it :ITER_FORWARD]; struct tuple *tuple; + for (u32 i = 0; (tuple = it->next(it)) != NULL; ++i) { void *node = ((u8 *) nodes + i * node_size); [self fold: node :tuple]; diff --git a/mod/box/txn.m b/mod/box/txn.m index 369ca6ed6b328366c9cb950a9f60a70dc22a2b1b..6adab7c56bd7f8f3fdc9a558ef74412b32eb2914 100644 --- a/mod/box/txn.m +++ b/mod/box/txn.m @@ -100,10 +100,8 @@ txn_commit(struct txn *txn) if (txn->op == 0) /* Nothing to do. */ return; if (! (txn->txn_flags & BOX_NOT_STORE)) { - fiber_peer_name(fiber); /* fill the cookie */ - int64_t lsn = next_lsn(recovery_state); - int res = wal_write(recovery_state, lsn, fiber->cookie, + int res = wal_write(recovery_state, lsn, 0, txn->op, &txn->req); confirm_lsn(recovery_state, lsn, res == 0); if (res) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97e5313b78d0b563f95746bb13dec5aaf79b1170..42d30d4e775e97d5da0ce0cb92206f6a0de51235 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,6 +87,8 @@ set (common_sources util.m sio.m evio.m + coio.m + coio_buf.m salloc.m pickle.m coro.m diff --git a/src/admin.m b/src/admin.m index 0bddc9977909bcfbc0ced77077ce7ffe72546636..cfc9d66955ca594aa9f7289f31af616c07ff3b1d 100644 --- a/src/admin.m +++ b/src/admin.m @@ -46,6 +46,7 @@ #include <tbuf.h> #include <util.h> #include <errinj.h> +#include "coio_buf.h" #include "lua.h" #include "lauxlib.h" @@ -71,7 +72,7 @@ static const char *help = static const char *unknown_command = "unknown command. try typing help." CRLF; -#line 75 "src/admin.m" +#line 76 "src/admin.m" static const int admin_start = 1; static const int admin_first_final = 135; static const int admin_error = 0; @@ -79,7 +80,7 @@ static const int admin_error = 0; static const int admin_en_main = 1; -#line 74 "src/admin.rl" +#line 75 "src/admin.rl" struct salloc_stat_admin_cb_ctx { @@ -197,7 +198,7 @@ show_stat(struct tbuf *buf) } static int -admin_dispatch(lua_State *L) +admin_dispatch(struct coio *coio, lua_State *L) { struct tbuf *out = tbuf_alloc(fiber->gc_pool); struct tbuf *err = tbuf_alloc(fiber->gc_pool); @@ -207,20 +208,20 @@ admin_dispatch(lua_State *L) bool state; while ((pe = memchr(fiber->rbuf.data, '\n', fiber->rbuf.size)) == NULL) { - if (fiber_bread(&fiber->rbuf, 1) <= 0) - return 0; + if (coio_bread(coio, &fiber->rbuf, 1) <= 0) + return -1; } pe++; p = fiber->rbuf.data; -#line 219 "src/admin.m" +#line 220 "src/admin.m" { cs = admin_start; } -#line 224 "src/admin.m" +#line 225 "src/admin.m" { if ( p == pe ) goto _test_eof; @@ -283,15 +284,15 @@ case 6: } goto st0; tr13: -#line 318 "src/admin.rl" +#line 319 "src/admin.rl" {slab_validate(); ok(out);} goto st135; tr20: -#line 306 "src/admin.rl" +#line 307 "src/admin.rl" {return 0;} goto st135; tr25: -#line 233 "src/admin.rl" +#line 234 "src/admin.rl" { start(out); tbuf_append(out, help, strlen(help)); @@ -299,9 +300,9 @@ tr25: } goto st135; tr36: -#line 292 "src/admin.rl" +#line 293 "src/admin.rl" {strend = p;} -#line 239 "src/admin.rl" +#line 240 "src/admin.rl" { strstart[strend-strstart]='\0'; start(out); @@ -310,7 +311,7 @@ tr36: } goto st135; tr43: -#line 246 "src/admin.rl" +#line 247 "src/admin.rl" { if (reload_cfg(err)) fail(out, err); @@ -319,11 +320,11 @@ tr43: } goto st135; tr67: -#line 316 "src/admin.rl" +#line 317 "src/admin.rl" {coredump(60); ok(out);} goto st135; tr76: -#line 253 "src/admin.rl" +#line 254 "src/admin.rl" { int ret = snapshot(NULL, 0); @@ -338,9 +339,9 @@ tr76: } goto st135; tr98: -#line 302 "src/admin.rl" +#line 303 "src/admin.rl" { state = false; } -#line 266 "src/admin.rl" +#line 267 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -352,9 +353,9 @@ tr98: } goto st135; tr101: -#line 301 "src/admin.rl" +#line 302 "src/admin.rl" { state = true; } -#line 266 "src/admin.rl" +#line 267 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -366,7 +367,7 @@ tr101: } goto st135; tr117: -#line 209 "src/admin.rl" +#line 210 "src/admin.rl" { tarantool_cfg_iterator_t *i; char *key, *value; @@ -386,15 +387,15 @@ tr117: } goto st135; tr131: -#line 309 "src/admin.rl" +#line 310 "src/admin.rl" {start(out); fiber_info(out); end(out);} goto st135; tr137: -#line 308 "src/admin.rl" +#line 309 "src/admin.rl" {start(out); tarantool_info(out); end(out);} goto st135; tr146: -#line 227 "src/admin.rl" +#line 228 "src/admin.rl" { start(out); errinj_info(out); @@ -402,33 +403,33 @@ tr146: } goto st135; tr152: -#line 312 "src/admin.rl" +#line 313 "src/admin.rl" {start(out); palloc_stat(out); end(out);} goto st135; tr160: -#line 311 "src/admin.rl" +#line 312 "src/admin.rl" {start(out); show_slab(out); end(out);} goto st135; tr164: -#line 313 "src/admin.rl" +#line 314 "src/admin.rl" {start(out); show_stat(out);end(out);} goto st135; st135: if ( ++p == pe ) goto _test_eof135; case 135: -#line 421 "src/admin.m" +#line 422 "src/admin.m" goto st0; tr14: -#line 318 "src/admin.rl" +#line 319 "src/admin.rl" {slab_validate(); ok(out);} goto st7; tr21: -#line 306 "src/admin.rl" +#line 307 "src/admin.rl" {return 0;} goto st7; tr26: -#line 233 "src/admin.rl" +#line 234 "src/admin.rl" { start(out); tbuf_append(out, help, strlen(help)); @@ -436,9 +437,9 @@ tr26: } goto st7; tr37: -#line 292 "src/admin.rl" +#line 293 "src/admin.rl" {strend = p;} -#line 239 "src/admin.rl" +#line 240 "src/admin.rl" { strstart[strend-strstart]='\0'; start(out); @@ -447,7 +448,7 @@ tr37: } goto st7; tr44: -#line 246 "src/admin.rl" +#line 247 "src/admin.rl" { if (reload_cfg(err)) fail(out, err); @@ -456,11 +457,11 @@ tr44: } goto st7; tr68: -#line 316 "src/admin.rl" +#line 317 "src/admin.rl" {coredump(60); ok(out);} goto st7; tr77: -#line 253 "src/admin.rl" +#line 254 "src/admin.rl" { int ret = snapshot(NULL, 0); @@ -475,9 +476,9 @@ tr77: } goto st7; tr99: -#line 302 "src/admin.rl" +#line 303 "src/admin.rl" { state = false; } -#line 266 "src/admin.rl" +#line 267 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -489,9 +490,9 @@ tr99: } goto st7; tr102: -#line 301 "src/admin.rl" +#line 302 "src/admin.rl" { state = true; } -#line 266 "src/admin.rl" +#line 267 "src/admin.rl" { strstart[strend-strstart] = '\0'; if (errinj_set_byname(strstart, state)) { @@ -503,7 +504,7 @@ tr102: } goto st7; tr118: -#line 209 "src/admin.rl" +#line 210 "src/admin.rl" { tarantool_cfg_iterator_t *i; char *key, *value; @@ -523,15 +524,15 @@ tr118: } goto st7; tr132: -#line 309 "src/admin.rl" +#line 310 "src/admin.rl" {start(out); fiber_info(out); end(out);} goto st7; tr138: -#line 308 "src/admin.rl" +#line 309 "src/admin.rl" {start(out); tarantool_info(out); end(out);} goto st7; tr147: -#line 227 "src/admin.rl" +#line 228 "src/admin.rl" { start(out); errinj_info(out); @@ -539,22 +540,22 @@ tr147: } goto st7; tr153: -#line 312 "src/admin.rl" +#line 313 "src/admin.rl" {start(out); palloc_stat(out); end(out);} goto st7; tr161: -#line 311 "src/admin.rl" +#line 312 "src/admin.rl" {start(out); show_slab(out); end(out);} goto st7; tr165: -#line 313 "src/admin.rl" +#line 314 "src/admin.rl" {start(out); show_stat(out);end(out);} goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 558 "src/admin.m" +#line 559 "src/admin.m" if ( (*p) == 10 ) goto st135; goto st0; @@ -707,28 +708,28 @@ case 23: } goto tr33; tr33: -#line 292 "src/admin.rl" +#line 293 "src/admin.rl" {strstart = p;} goto st24; st24: if ( ++p == pe ) goto _test_eof24; case 24: -#line 718 "src/admin.m" +#line 719 "src/admin.m" switch( (*p) ) { case 10: goto tr36; case 13: goto tr37; } goto st24; tr34: -#line 292 "src/admin.rl" +#line 293 "src/admin.rl" {strstart = p;} goto st25; st25: if ( ++p == pe ) goto _test_eof25; case 25: -#line 732 "src/admin.m" +#line 733 "src/admin.m" switch( (*p) ) { case 10: goto tr36; case 13: goto tr37; @@ -1178,28 +1179,28 @@ case 73: goto tr91; goto st0; tr91: -#line 300 "src/admin.rl" +#line 301 "src/admin.rl" { strstart = p; } goto st74; st74: if ( ++p == pe ) goto _test_eof74; case 74: -#line 1189 "src/admin.m" +#line 1190 "src/admin.m" if ( (*p) == 32 ) goto tr92; if ( 33 <= (*p) && (*p) <= 126 ) goto st74; goto st0; tr92: -#line 300 "src/admin.rl" +#line 301 "src/admin.rl" { strend = p; } goto st75; st75: if ( ++p == pe ) goto _test_eof75; case 75: -#line 1203 "src/admin.m" +#line 1204 "src/admin.m" switch( (*p) ) { case 32: goto st75; case 111: goto st76; @@ -1891,7 +1892,7 @@ case 134: _out: {} } -#line 324 "src/admin.rl" +#line 325 "src/admin.rl" tbuf_ltrim(&fiber->rbuf, (void *)pe - (void *)fiber->rbuf.data); @@ -1902,37 +1903,37 @@ case 134: end(out); } - return fiber_write(out->data, out->size); + coio_write(coio, out->data, out->size); + return 0; } static void -admin_handler(void *data __attribute__((unused))) +admin_handler(va_list ap) { + struct coio coio = va_arg(ap, struct coio); lua_State *L = lua_newthread(tarantool_L); int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); @try { for (;;) { - if (admin_dispatch(L) <= 0) + if (admin_dispatch(&coio, L) < 0) return; fiber_gc(); } } @finally { luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref); + coio_close(&coio); } } -int +void admin_init(void) { - if (fiber_server("admin", cfg.admin_port, admin_handler, NULL, NULL) == NULL) { - say_syserror("can't bind to %d", cfg.admin_port); - return -1; - } - return 0; + static struct coio_service admin; + coio_service_init(&admin, "admin", cfg.bind_ipaddr, + cfg.admin_port, admin_handler, NULL); + evio_service_start(&admin.evio_service); } - - /* * Local Variables: * mode: c diff --git a/src/admin.rl b/src/admin.rl index f058e2aeed1e3238ee8a68c51e0d9978a8fda6e1..f1deecde6a86e19aa7ec59e9bc230600cdcd5ad9 100644 --- a/src/admin.rl +++ b/src/admin.rl @@ -44,6 +44,7 @@ #include <tbuf.h> #include <util.h> #include <errinj.h> +#include "coio_buf.h" #include "lua.h" #include "lauxlib.h" @@ -188,7 +189,7 @@ show_stat(struct tbuf *buf) } static int -admin_dispatch(lua_State *L) +admin_dispatch(struct coio *coio, lua_State *L) { struct tbuf *out = tbuf_alloc(fiber->gc_pool); struct tbuf *err = tbuf_alloc(fiber->gc_pool); @@ -198,8 +199,8 @@ admin_dispatch(lua_State *L) bool state; while ((pe = memchr(fiber->rbuf.data, '\n', fiber->rbuf.size)) == NULL) { - if (fiber_bread(&fiber->rbuf, 1) <= 0) - return 0; + if (coio_bread(coio, &fiber->rbuf, 1) <= 0) + return -1; } pe++; @@ -331,37 +332,37 @@ admin_dispatch(lua_State *L) end(out); } - return fiber_write(out->data, out->size); + coio_write(coio, out->data, out->size); + return 0; } static void -admin_handler(void *data __attribute__((unused))) +admin_handler(va_list ap) { + struct coio coio = va_arg(ap, struct coio); lua_State *L = lua_newthread(tarantool_L); int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); @try { for (;;) { - if (admin_dispatch(L) <= 0) + if (admin_dispatch(&coio, L) < 0) return; fiber_gc(); } } @finally { luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref); + coio_close(&coio); } } -int +void admin_init(void) { - if (fiber_server("admin", cfg.admin_port, admin_handler, NULL, NULL) == NULL) { - say_syserror("can't bind to %d", cfg.admin_port); - return -1; - } - return 0; + static struct coio_service admin; + coio_service_init(&admin, "admin", cfg.bind_ipaddr, + cfg.admin_port, admin_handler, NULL); + evio_service_start(&admin.evio_service); } - - /* * Local Variables: * mode: c diff --git a/src/coio.m b/src/coio.m new file mode 100644 index 0000000000000000000000000000000000000000..d863b4d7f841471a3465a3ff5be717c504e7a524 --- /dev/null +++ b/src/coio.m @@ -0,0 +1,298 @@ +/* + * 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 "coio.h" + +#include <netinet/tcp.h> +#include <stdio.h> + +#include "fiber.h" +#include "sio.h" + +void +coio_clear(struct coio *coio) +{ + ev_init(&coio->ev, (void *) fiber_schedule); + coio->ev.data = fiber; + coio->ev.fd = -1; +} + +/** Note: this function does not throw */ +void +coio_init(struct coio *coio, int fd) +{ + assert(fd >= 0); + + /* Prepare for ev events. */ + coio->ev.data = fiber; + ev_init(&coio->ev, (void *) fiber_schedule); + coio->ev.fd = fd; +} + +/** Note: this function does not throw. */ +void +coio_close(struct coio *coio) +{ + /* Stop I/O events. Safe to do even if not started. */ + ev_io_stop(&coio->ev); + + /* Close the socket. */ + close(coio->ev.fd); + /* Make sure coio_is_connected() returns a proper value. */ + coio->ev.fd = -1; +} + +/** + * Connect to a host and initialize coio with connected + * socket. + */ +void +coio_connect(struct coio *coio, struct sockaddr_in *addr) +{ + int fd = sio_socket(); + @try { + coio_init(coio, fd); + + int on = 1; + /* libev is non-blocking */ + sio_setfl(fd, O_NONBLOCK, on); + + /* + * SO_KEEPALIVE to ensure connections don't hang + * around for too long when a link goes away + */ + sio_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + &on, sizeof(on)); + /* + * Lower latency is more important than higher + * bandwidth, and we usually write entire + * request/response in a single syscall. + */ + sio_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, + &on, sizeof(on)); + + if (sio_connect(fd, addr, sizeof(*addr)) < 0) { + assert(errno == EINPROGRESS); + /* Wait until socket is ready for writing. */ + ev_io_set(&coio->ev, fd, EV_WRITE); + ev_io_start(&coio->ev); + fiber_yield(); + ev_io_stop(&coio->ev); + fiber_testcancel(); + + int error = EINPROGRESS; + socklen_t sz = sizeof(error); + sio_getsockopt(fd, SOL_SOCKET, SO_ERROR, + &error, &sz); + if (error != 0) { + errno = error; + tnt_raise(SocketError, :fd in:"connect"); + } + } + } @catch (tnt_Exception *e) { + coio_close(coio); + @throw; + } +} + +/** + * Read at least sz bytes from socket with readahead. + * + * In case of EOF returns 0. + * Can read up to bufsiz bytes. + * + * Returns the number of bytes read. + */ +ssize_t +coio_read_ahead(struct coio *coio, void *buf, size_t sz, size_t bufsiz) +{ + assert(sz <= bufsiz); + + ssize_t to_read = (ssize_t) sz; + @try { + while (true) { + /* + * Sic: assume the socket is ready: since + * the user called read(), some data must + * be expected. + */ + ssize_t nrd = sio_read(coio->ev.fd, buf, bufsiz); + if (nrd > 0) { + to_read -= nrd; + if (to_read <= 0) + return sz - to_read; + buf += nrd; + bufsiz -= nrd; + } else if (nrd == 0) { + return 0; + } + /* The socket is not ready, yield */ + if (! ev_is_active(&coio->ev)) { + ev_io_set(&coio->ev, coio->ev.fd, EV_READ); + ev_io_start(&coio->ev); + } + fiber_yield(); + fiber_testcancel(); + } + } @finally { + ev_io_stop(&coio->ev); + } +} + +/** + * Read at least sz bytes, with readahead. + * + * Treats EOF as an error, and throws an exception. + * + * @retval the number of bytes read, > 0. + */ +ssize_t +coio_readn_ahead(struct coio *coio, void *buf, size_t sz, size_t bufsiz) +{ + ssize_t nrd = coio_read_ahead(coio, buf, sz, bufsiz); + if (nrd < sz) { + errno = EPIPE; + tnt_raise(SocketError, :coio->ev.fd in:"unexpected EOF when reading " + "from socket"); + } + return nrd; +} + + +/** Write sz bytes to socket. + * + * Throws SocketError in case of write error. If + * the socket is not ready, yields the current + * fiber until the socket becomes ready, until + * all data is written. + */ +void +coio_write(struct coio *coio, const void *buf, size_t sz) +{ + @try { + while (true) { + /* + * Sic: write as much data as possible, + * assuming the socket is ready. + */ + ssize_t nwr = sio_write(coio->ev.fd, buf, sz); + if (nwr > 0) { + /* Go past the data just written. */ + if (nwr >= sz) + return; + sz -= nwr; + buf += nwr; + } + if (! ev_is_active(&coio->ev)) { + ev_io_set(&coio->ev, coio->ev.fd, EV_WRITE); + ev_io_start(&coio->ev); + } + /* Yield control to other fibers. */ + fiber_yield(); + fiber_testcancel(); + } + } @finally { + ev_io_stop(&coio->ev); + } +} + +ssize_t +coio_writev(struct coio *coio, struct iovec *iov, int iovcnt) +{ + ssize_t total = 0; + @try { + /* Avoid a syscall in case of 0 iovcnt. */ + while (iovcnt) { + /* Write as much data as possible. */ + ssize_t nwr = sio_writev(coio->ev.fd, iov, iovcnt); + if (nwr >= 0) { + total += nwr; + iov = sio_advance_iov(iov, &iovcnt, nwr); + if (iovcnt == 0) + break; + } + if (! ev_is_active(&coio->ev)) { + ev_io_set(&coio->ev, coio->ev.fd, EV_WRITE); + ev_io_start(&coio->ev); + } + /* Yield control to other fibers. */ + fiber_yield(); + fiber_testcancel(); + } + } @finally { + ev_io_stop(&coio->ev); + } + return total; +} + +void +coio_service_on_accept(struct evio_service *evio_service, + int fd, struct sockaddr_in *addr) +{ + struct coio_service *service = evio_service->on_accept_param; + struct coio coio; + + coio_init(&coio, fd); + + /* Set connection name. */ + char name[SERVICE_NAME_MAXLEN]; + snprintf(name, sizeof(name), + "%s/%s", evio_service->name, sio_strfaddr(addr)); + + /* Create the worker fiber. */ + struct fiber *f = fiber_create(name, service->handler); + if (f == NULL) + goto error; + /* + * The coio is passed on to the created fiber, reset the + * libev callback param to point at it. + */ + coio.ev.data = f; + /* + * Start the created fiber. It becomes the coio object owner + * and will have to close it and free before termination. + */ + fiber_call(f, coio, service->handler_param); + return; + +error: + say_error("can't create a handler fiber, dropping client connection"); + close(fd); +} + +void +coio_service_init(struct coio_service *service, const char *name, + const char *host, int port, + void (*handler)(va_list ap), void *handler_param) +{ + evio_service_init(&service->evio_service, name, host, port, + coio_service_on_accept, service); + service->handler = handler; + service->handler_param = handler_param; +} + diff --git a/src/coio_buf.m b/src/coio_buf.m new file mode 100644 index 0000000000000000000000000000000000000000..ac0e5d5c7303c1295129a2814c361d4f368bb226 --- /dev/null +++ b/src/coio_buf.m @@ -0,0 +1,31 @@ +/* + * 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 "coio_buf.h" + +int coio_readahead; diff --git a/src/evio.m b/src/evio.m index 891f516b6a1ee50fcb2aba204ecbba4b4c2fd49d..68f64333e6653eae2849fffb6f61e7d54c9c672c 100644 --- a/src/evio.m +++ b/src/evio.m @@ -28,8 +28,8 @@ */ #include "evio.h" #include <stdio.h> -#include <sys/socket.h> #include <netinet/in.h> +#include <netinet/tcp.h> #include <arpa/inet.h> #define BIND_RETRY_DELAY 0.1 @@ -79,7 +79,7 @@ evio_service_accept_cb(ev_io *watcher, * Invoke the callback and pass it the accepted * socket. */ - service->on_accept(service->on_accept_param, fd, &addr); + service->on_accept(service, fd, &addr); } @catch (tnt_Exception *e) { if (fd >= 0) @@ -155,7 +155,8 @@ evio_service_timer_cb(ev_timer *watcher, int revents __attribute__((unused))) void evio_service_init(struct evio_service *service, const char *name, const char *host, int port, - void (*on_accept)(void *, int, struct sockaddr_in *), + void (*on_accept)(struct evio_service *, int, + struct sockaddr_in *), void *on_accept_param) { memset(service, 0, sizeof(struct evio_service)); diff --git a/src/exception.m b/src/exception.m index e233b8a433cb22ca8e904906bf9169f03b282706..2ca41a0ab90baf23242caeefe088a50f87056e0f 100644 --- a/src/exception.m +++ b/src/exception.m @@ -83,7 +83,7 @@ - (void) log { - say(S_ERROR, strerror(errnum), "%s", errmsg); + say(S_ERROR, strerror(errnum), "%s in %s", object_getClassName(self), errmsg); } - (const char *) errmsg diff --git a/src/fiber.m b/src/fiber.m index 0603f573251e801701de6639e8ee906cf05d6f38..2b1e52617d3819fefc6f88fdae23235855c98885 100644 --- a/src/fiber.m +++ b/src/fiber.m @@ -56,12 +56,12 @@ #include <util.h> #include <stat.h> #include <pickle.h> +#include "coio_buf.h" @implementation FiberCancelException @end - -#define FIBER_CALL_STACK 16 +enum { FIBER_CALL_STACK = 16 }; static struct fiber sched; __thread struct fiber *fiber = &sched; @@ -80,7 +80,7 @@ struct fiber_cleanup { struct fiber_server { int port; void *data; - void (*handler) (void *data); + void (*handler) (va_list ap); void (*on_bind) (void *data); }; @@ -95,7 +95,7 @@ update_last_stack_frame(struct fiber *fiber) } void -fiber_call(struct fiber *callee) +fiber_call(struct fiber *callee, ...) { struct fiber *caller = fiber; @@ -108,7 +108,10 @@ fiber_call(struct fiber *callee) update_last_stack_frame(caller); callee->csw++; + + va_start(fiber->f_data, callee); coro_transfer(&caller->coro.ctx, &callee->coro.ctx); + va_end(fiber->f_data); } @@ -269,46 +272,8 @@ wait_for_child(pid_t pid) fiber_testcancel(); } - -void -fiber_io_start(int fd, int events) -{ - ev_io *io = &fiber->io; - - assert (!ev_is_active(io)); - - ev_io_set(io, fd, events); - ev_io_start(io); -} - -/** @note: this is a cancellation point. - */ - -void -fiber_io_yield() -{ - assert(ev_is_active(&fiber->io)); - - fiber_yield(); - - if (fiber_is_cancelled()) { - ev_io_stop(&fiber->io); - fiber_testcancel(); - } -} - void -fiber_io_stop(int fd __attribute__((unused)), int events __attribute__((unused))) -{ - ev_io *io = &fiber->io; - - assert(ev_is_active(io) && io->fd == fd && (io->events & events)); - - ev_io_stop(io); -} - -static void -ev_schedule(ev_watcher *watcher, int event __attribute__((unused))) +fiber_schedule(ev_watcher *watcher, int event __attribute__((unused))) { assert(fiber == &sched); fiber_call(watcher->data); @@ -426,16 +391,16 @@ fiber_loop(void *data __attribute__((unused))) assert(fiber != NULL && fiber->f != NULL && fiber->fid != 0); @try { fiber->f(fiber->f_data); - } - @catch (FiberCancelException *e) { + } @catch (FiberCancelException *e) { say_info("fiber `%s' has been cancelled", fiber->name); say_info("fiber `%s': exiting", fiber->name); - } - @catch (id e) { + } @catch (tnt_Exception *e) { + [e log]; + } @catch (id e) { say_error("fiber `%s': exception `%s'", fiber->name, object_getClassName(e)); panic("fiber `%s': exiting", fiber->name); } - fiber_close(); + tbuf_reset(&fiber->rbuf); fiber_zombificate(); fiber_yield(); /* give control back to scheduler */ } @@ -457,7 +422,7 @@ fiber_set_name(struct fiber *fiber, const char *name) /* fiber never dies, just become zombie */ struct fiber * -fiber_create(const char *name, int fd, void (*f) (void *), void *f_data) +fiber_create(const char *name, void (*f) (va_list)) { struct fiber *fiber = NULL; @@ -476,19 +441,16 @@ fiber_create(const char *name, int fd, void (*f) (void *), void *f_data) fiber->gc_pool = palloc_create_pool(""); fiber_alloc(fiber); - ev_init(&fiber->io, (void *)ev_schedule); - ev_async_init(&fiber->async, (void *)ev_schedule); + ev_async_init(&fiber->async, (void *)fiber_schedule); ev_async_start(&fiber->async); - ev_init(&fiber->timer, (void *)ev_schedule); - ev_init(&fiber->cw, (void *)ev_schedule); - fiber->io.data = fiber->async.data = fiber->timer.data = fiber->cw.data = fiber; + ev_init(&fiber->timer, (void *)fiber_schedule); + ev_init(&fiber->cw, (void *)fiber_schedule); + fiber->async.data = fiber->timer.data = fiber->cw.data = fiber; SLIST_INSERT_HEAD(&fibers, fiber, link); } - fiber->fd = fd; fiber->f = f; - fiber->f_data = f_data; while (++last_used_fid <= 100) ; /* fids from 0 to 100 are reserved */ fiber->fid = last_used_fid; fiber->flags = 0; @@ -525,90 +487,6 @@ fiber_destroy_all() fiber_destroy(f); } - -const char * -fiber_peer_name(struct fiber *fiber) -{ - struct sockaddr_in peer; - socklen_t peer_len = sizeof(peer); - - if (!fiber->has_peer || fiber->fd < 3) - return NULL; - - if (fiber->peer_name[0] != 0) - return fiber->peer_name; - - memset(&peer, 0, peer_len); - if (getpeername(fiber->fd, (struct sockaddr *)&peer, &peer_len) < 0) - return NULL; - - uint32_t zero = 0; - if (memcmp(&peer.sin_addr, &zero, sizeof(zero)) == 0) - return NULL; - - snprintf(fiber->peer_name, sizeof(fiber->peer_name), - "%s:%d", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port)); - - fiber->cookie = 0; - memcpy(&fiber->cookie, &peer, MIN(sizeof(peer), sizeof(fiber->cookie))); - return fiber->peer_name; -} - -int -fiber_close(void) -{ - if (fiber->fd < 0) - return 0; - - /* We don't know if IO is active if there was an error. */ - if (ev_is_active(&fiber->io)) - fiber_io_stop(fiber->fd, -1); - - int r = close(fiber->fd); - - fiber->fd = -1; - fiber->has_peer = false; - fiber->peer_name[0] = 0; - tbuf_reset(&fiber->rbuf); - - return r; -} - -/** - * Read at least at_least bytes from a socket. - * - * @retval 0 socket is closed by the sender - * @reval -1 a system error - * @retval >0 success, size of the last read chunk is returned - * - * @note: this is a cancellation point. - */ - -ssize_t -fiber_bread(struct tbuf *buf, size_t at_least) -{ - ssize_t r = 0; - tbuf_ensure(buf, MAX(cfg.readahead, at_least)); - size_t stop_at = buf->size + at_least; - - fiber_io_start(fiber->fd, EV_READ); - - while (buf->size < stop_at) { - fiber_io_yield(); - - r = read(fiber->fd, buf->data + buf->size, buf->capacity - buf->size); - if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) - continue; - else if (r <= 0) - break; - - buf->size += r; - } - fiber_io_stop(fiber->fd, EV_READ); - - return r; -} - void iov_reset() { @@ -621,345 +499,14 @@ iov_reset() */ ssize_t -iov_flush(void) +iov_flush(struct coio *coio) { - ssize_t result, r = 0, bytes = 0; struct iovec *iov = iovec(&fiber->iov); size_t iov_cnt = fiber->iov_cnt; - fiber_io_start(fiber->fd, EV_WRITE); - while (iov_cnt > 0) { - fiber_io_yield(); - bytes += r = writev(fiber->fd, iov, MIN(iov_cnt, IOV_MAX)); - if (r <= 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else - break; - } - - while (iov_cnt > 0) { - if (iov->iov_len > r) { - iov->iov_base += r; - iov->iov_len -= r; - break; - } else { - r -= iov->iov_len; - iov++; - iov_cnt--; - } - } - } - fiber_io_stop(fiber->fd, EV_WRITE); - - if (r < 0) { - size_t rem = 0; - for (int i = 0; i < iov_cnt; i++) - rem += iov[i].iov_len; - - say_syserror("client unexpectedly gone, %" PRI_SZ " bytes unwritten", rem); - result = r; - } else - result = bytes; - + ssize_t nwr = coio_writev(coio, iov, iov_cnt); iov_reset(); - return result; -} - -/** - * @note: this is a cancellation point. - */ - -ssize_t -fiber_read(void *buf, size_t count) -{ - ssize_t r, done = 0; - - fiber_io_start(fiber->fd, EV_READ); - while (count != done) { - - fiber_io_yield(); - - if ((r = read(fiber->fd, buf + done, count - done)) <= 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else - break; - } - done += r; - } - fiber_io_stop(fiber->fd, EV_READ); - - return done; -} - -/** - * @note: this is a cancellation point. - */ - -ssize_t -fiber_write(const void *buf, size_t count) -{ - int r; - unsigned int done = 0; - - fiber_io_start(fiber->fd, EV_WRITE); - - while (count != done) { - fiber_io_yield(); - if ((r = write(fiber->fd, buf + done, count - done)) == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else - break; - } - done += r; - } - fiber_io_stop(fiber->fd, EV_WRITE); - - return done; -} - -/** - * @note: this is a cancellation point. - */ - -int -fiber_connect(struct sockaddr_in *addr) -{ - fiber->fd = socket(AF_INET, SOCK_STREAM, 0); - if (fiber->fd < 0) - goto error; - - if (set_nonblock(fiber->fd) < 0) - goto error; - - /* set SO_KEEPALIVE flag */ - int keepalive = 1; - if (setsockopt(fiber->fd, SOL_SOCKET, SO_KEEPALIVE, - &keepalive, sizeof(int)) != 0) - /* just print error, it's not critical error */ - say_syserror("setsockopt()"); - - if (connect(fiber->fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { - - if (errno != EINPROGRESS) - goto error; - - fiber_io_start(fiber->fd, EV_WRITE); - fiber_io_yield(); - fiber_io_stop(fiber->fd, EV_WRITE); - - int error; - socklen_t error_size = sizeof(error); - - if (getsockopt(fiber->fd, SOL_SOCKET, SO_ERROR, - &error, &error_size) < 0) - goto error; - - assert(error_size == sizeof(error)); - - if (error != 0) { - errno = error; - goto error; - } - } - - return fiber->fd; - - error: - fiber_close(); - return fiber->fd; -} - -int -set_nonblock(int sock) -{ - int flags; - if ((flags = fcntl(sock, F_GETFL, 0)) < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) - return -1; - return sock; -} - -static void -tcp_server_handler(void *data) -{ - struct fiber_server *server = (void*) data; - struct fiber *h; - char name[FIBER_NAME_MAXLEN]; - int fd; - int one = 1; - - if (fiber_serv_socket(fiber, server->port, true, 0.1) != 0) { - say_error("init server socket on port %i fail", server->port); - exit(EX_OSERR); - } - - if (server->on_bind != NULL) { - server->on_bind(server->data); - } - - fiber_io_start(fiber->fd, EV_READ); - for (;;) { - fiber_io_yield(); - - while ((fd = accept(fiber->fd, NULL, NULL)) > 0) { - if (set_nonblock(fd) == -1) { - say_error("can't set nonblock"); - close(fd); - continue; - } - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - &one, sizeof(one)) == -1) { - say_syserror("setsockopt failed"); - /* Do nothing, not a fatal error. */ - } - - snprintf(name, sizeof(name), "%i/handler", server->port); - h = fiber_create(name, fd, server->handler, server->data); - if (h == NULL) { - say_error("can't create handler fiber, dropping client connection"); - close(fd); - continue; - } - - h->has_peer = true; - fiber_call(h); - } - if (fd < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - say_syserror("accept"); - continue; - } - } - fiber_io_stop(fiber->fd, EV_READ); -} - -struct fiber * -fiber_server(const char *name, int port, void (*handler) (void *data), void *data, - void (*on_bind) (void *data)) -{ - char server_name[FIBER_NAME_MAXLEN]; - struct fiber_server *server; - struct fiber *s; - - snprintf(server_name, sizeof(server_name), "%i/%s", port, name); - server = palloc(eter_pool, sizeof(struct fiber_server)); - assert(server != NULL); - server->data = data; - server->port = port; - server->handler = handler; - server->on_bind = on_bind; - s = fiber_create(server_name, -1, tcp_server_handler, server); - - fiber_call(s); /* give a handler a chance */ - return s; -} - -/** create new fiber's socket and set standat options. */ -static int -create_socket(struct fiber *fiber) -{ - if (fiber->fd != -1) { - say_error("fiber is already has socket"); - goto create_socket_fail; - } - - fiber->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (fiber->fd == -1) { - say_syserror("socket"); - goto create_socket_fail; - } - - int one = 1; - if (setsockopt(fiber->fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) { - say_syserror("setsockopt"); - goto create_socket_fail; - } - - struct linger ling = { 0, 0 }; - if (setsockopt(fiber->fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)) != 0 || - setsockopt(fiber->fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0 || - setsockopt(fiber->fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) != 0) { - say_syserror("setsockopt"); - goto create_socket_fail; - } - - if (set_nonblock(fiber->fd) == -1) { - goto create_socket_fail; - } - - return 0; - -create_socket_fail: - - if (fiber->fd != -1) { - close(fiber->fd); - } - return -1; -} - -/** Create server socket and bind his on port. */ -int -fiber_serv_socket(struct fiber *fiber, unsigned short port, bool retry, ev_tstamp delay) -{ - const ev_tstamp min_delay = 0.001; /* minimal delay is 1 msec */ - struct sockaddr_in sin; - bool warning_said = false; - - if (delay < min_delay) { - delay = min_delay; - } - - if (create_socket(fiber) != 0) { - return -1; - } - - /* clean sockaddr_in struct */ - memset(&sin, 0, sizeof(struct sockaddr_in)); - - /* fill sockaddr_in struct */ - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - if (strcmp(cfg.bind_ipaddr, "INADDR_ANY") == 0) { - sin.sin_addr.s_addr = INADDR_ANY; - } else { - if (!inet_aton(cfg.bind_ipaddr, &sin.sin_addr)) { - say_syserror("inet_aton"); - return -1; - } - } - - while (true) { - if (bind(fiber->fd, (struct sockaddr *)&sin, sizeof(sin)) != 0) { - if (retry && (errno == EADDRINUSE)) { - /* retry mode, try, to bind after delay */ - goto sleep_and_retry; - } - say_syserror("bind"); - return -1; - } - if (listen(fiber->fd, cfg.backlog) != 0) { - if (retry && (errno == EADDRINUSE)) { - /* retry mode, try, to bind after delay */ - goto sleep_and_retry; - } - say_syserror("listen"); - return -1; - } - - say_info("bound to port %i", port); - break; - - sleep_and_retry: - if (!warning_said) { - say_warn("port %i is already in use, " - "will retry binding after %lf seconds.", port, delay); - warning_said = true; - } - fiber_sleep(delay); - } - - return 0; + return nwr; } void @@ -974,8 +521,6 @@ fiber_info(struct tbuf *out) tbuf_printf(out, " - fid: %4i" CRLF, fiber->fid); tbuf_printf(out, " csw: %i" CRLF, fiber->csw); tbuf_printf(out, " name: %s" CRLF, fiber->name); - tbuf_printf(out, " fd: %4i" CRLF, fiber->fd); - tbuf_printf(out, " peer: %s" CRLF, fiber_peer_name(fiber)); tbuf_printf(out, " stack: %p" CRLF, stack_top); #ifdef ENABLE_BACKTRACE tbuf_printf(out, " backtrace:" CRLF "%s", @@ -1001,6 +546,8 @@ fiber_init(void) sp = call_stack; fiber = &sched; last_used_fid = 100; + + coio_binit(cfg.readahead); } void diff --git a/src/iproto.m b/src/iproto.m index 66e321167e7588e47991a6d5e7bc61e2f424c61c..cb6ea44cfdbbacc4d7d01d0f02cef5f11debaaf8 100644 --- a/src/iproto.m +++ b/src/iproto.m @@ -37,6 +37,7 @@ #include <fiber.h> #include <tbuf.h> #include <say.h> +#include "coio_buf.h" const uint32_t msg_ping = 0xff00; @@ -45,51 +46,51 @@ static void iproto_reply(iproto_callback callback, struct tbuf *request); static void iproto_validate_header(struct iproto_header *header); -inline static int -iproto_flush(ssize_t to_read) +inline static void +iproto_flush(struct coio *coio, ssize_t to_read) { /* * Flush output and garbage collect before reading * next header. */ if (to_read > 0) { - if (iov_flush() < 0) { - say_warn("io_error: %s", strerror(errno)); - return -1; - } + iov_flush(coio); fiber_gc(); } - return 0; } void -iproto_interact(iproto_callback callback) +iproto_interact(va_list ap) { + struct coio coio = va_arg(ap, struct coio); + iproto_callback callback = va_arg(ap, iproto_callback); struct tbuf *in = &fiber->rbuf; ssize_t to_read = sizeof(struct iproto_header); + @try { + for (;;) { + if (to_read > 0 && coio_bread(&coio, in, to_read) <= 0) + break; - for (;;) { - if (to_read > 0 && fiber_bread(in, to_read) <= 0) - break; + /* validating iproto package header */ + iproto_validate_header(iproto(in)); - /* validating iproto package header */ - iproto_validate_header(iproto(in)); + ssize_t request_len = sizeof(struct iproto_header) + + iproto(in)->len; + to_read = request_len - in->size; - ssize_t request_len = sizeof(struct iproto_header) - + iproto(in)->len; - to_read = request_len - in->size; + iproto_flush(&coio, to_read); - if (iproto_flush(to_read) == -1) - break; - if (to_read > 0 && fiber_bread(in, to_read) <= 0) - break; + if (to_read > 0 && coio_bread(&coio, in, to_read) <= 0) + break; - struct tbuf *request = tbuf_split(in, request_len); - iproto_reply(callback, request); + struct tbuf *request = tbuf_split(in, request_len); + iproto_reply(callback, request); - to_read = sizeof(struct iproto_header) - in->size; - if (iproto_flush(to_read) == -1) - break; + to_read = sizeof(struct iproto_header) - in->size; + iproto_flush(&coio, to_read); + } + } @finally { + coio_close(&coio); } } diff --git a/src/replica.m b/src/replica.m index 965edb7cb1e195c48ee4881decacbc2173dbf89c..41675e3af2c96303876f55d40737f362d2831f8a 100644 --- a/src/replica.m +++ b/src/replica.m @@ -35,112 +35,96 @@ #include "log_io.h" #include "fiber.h" #include "pickle.h" +#include "coio_buf.h" -static int +static void remote_apply_row(struct recovery_state *r, struct tbuf *row); static struct tbuf * -remote_row_reader_v11() +remote_read_row(struct coio *coio) { ssize_t to_read = sizeof(struct header_v11) - fiber->rbuf.size; - if (to_read > 0 && fiber_bread(&fiber->rbuf, to_read) <= 0) - goto error; + if (to_read > 0) + coio_breadn(coio, &fiber->rbuf, to_read); ssize_t request_len = header_v11(&fiber->rbuf)->len + sizeof(struct header_v11); to_read = request_len - fiber->rbuf.size; - if (to_read > 0 && fiber_bread(&fiber->rbuf, to_read) <= 0) - goto error; + if (to_read > 0) + coio_breadn(coio, &fiber->rbuf, to_read); - say_debug("read row bytes:%" PRI_SSZ, request_len); return tbuf_split(&fiber->rbuf, request_len); -error: - say_error("unexpected eof reading row header"); - return NULL; } -static struct tbuf * -remote_read_row(struct sockaddr_in *remote_addr, i64 initial_lsn) +static void +remote_connect(struct coio *coio, struct sockaddr_in *remote_addr, + i64 initial_lsn, const char **err) { - struct tbuf *row; - bool warning_said = false; - const int reconnect_delay = 1; - const char *err = NULL; - u32 version; - - for (;;) { - if (fiber->fd < 0) { - if (fiber_connect(remote_addr) < 0) { - err = "can't connect to master"; - goto err; - } + *err = "can't connect to master"; + coio_connect(coio, remote_addr); - if (fiber_write(&initial_lsn, sizeof(initial_lsn)) != sizeof(initial_lsn)) { - err = "can't write version"; - goto err; - } - - if (fiber_read(&version, sizeof(version)) != sizeof(version)) { - err = "can't read version"; - goto err; - } - - if (version != default_version) { - err = "remote version mismatch"; - goto err; - } - - say_crit("successfully connected to master"); - say_crit("starting replication from lsn:%" PRIi64, initial_lsn); - - warning_said = false; - err = NULL; - } + *err = "can't write version"; + coio_write(coio, &initial_lsn, sizeof(initial_lsn)); - row = remote_row_reader_v11(); - if (row == NULL) { - err = "can't read row"; - goto err; - } - - return row; - - err: - if (err != NULL && !warning_said) { - say_info("%s", err); - say_info("will retry every %i second", reconnect_delay); - warning_said = true; - } - fiber_close(); - fiber_sleep(reconnect_delay); - } + u32 version; + *err = "can't read version"; + coio_readn(coio, &version, sizeof(version)); + *err = NULL; + if (version != default_version) + tnt_raise(SystemError, :"remote version mismatch"); + + say_crit("successfully connected to master"); + say_crit("starting replication from lsn: %" PRIi64, initial_lsn); } static void -pull_from_remote(void *state) +pull_from_remote(va_list ap) { - struct recovery_state *r = state; - struct tbuf *row; + struct recovery_state *r = va_arg(ap, struct recovery_state *); + struct coio coio; + bool warning_said = false; + const int reconnect_delay = 1; + coio_clear(&coio); for (;;) { - fiber_setcancellable(true); - row = remote_read_row(&r->remote->addr, r->confirmed_lsn + 1); - fiber_setcancellable(false); - - r->remote->recovery_lag = ev_now() - header_v11(row)->tm; - r->remote->recovery_last_update_tstamp = ev_now(); + const char *err = NULL; + @try { + fiber_setcancellable(true); + if (! coio_is_connected(&coio)) { + remote_connect(&coio, &r->remote->addr, + r->confirmed_lsn + 1, &err); + warning_said = false; + } + err = "can't read row"; + struct tbuf *row = remote_read_row(&coio); + fiber_setcancellable(false); + err = NULL; - if (remote_apply_row(r, row) < 0) { - fiber_close(); - continue; + r->remote->recovery_lag = ev_now() - header_v11(row)->tm; + r->remote->recovery_last_update_tstamp = ev_now(); + + remote_apply_row(r, row); + + fiber_gc(); + } @catch (FiberCancelException *e) { + coio_close(&coio); + @throw; + } @catch (tnt_Exception *e) { + [e log]; + if (! warning_said) { + if (err != NULL) + say_info("%s", err); + say_info("will retry every %i second", reconnect_delay); + warning_said = true; + } + coio_close(&coio); + fiber_sleep(reconnect_delay); } - - fiber_gc(); } } -static int +static void remote_apply_row(struct recovery_state *r, struct tbuf *row) { struct tbuf *data; @@ -166,8 +150,6 @@ remote_apply_row(struct recovery_state *r, struct tbuf *row) panic("replication failure: can't write row to WAL"); set_lsn(r, lsn); - - return 0; } void @@ -185,7 +167,7 @@ recovery_follow_remote(struct recovery_state *r, const char *addr) say_crit("initializing the replica, WAL master %s", addr); snprintf(name, sizeof(name), "replica/%s", addr); - f = fiber_create(name, -1, pull_from_remote, r); + f = fiber_create(name, pull_from_remote); if (f == NULL) return; @@ -206,7 +188,7 @@ recovery_follow_remote(struct recovery_state *r, const char *addr) memcpy(&remote.cookie, &remote.addr, MIN(sizeof(remote.cookie), sizeof(remote.addr))); remote.reader = f; r->remote = &remote; - fiber_call(f); + fiber_call(f, r); } void diff --git a/src/replication.m b/src/replication.m index 6c2fc086379ab563ba053b8d44052c4fcb3aa66c..557de40e581660d31572118dfe7ca364924a0c35 100644 --- a/src/replication.m +++ b/src/replication.m @@ -81,7 +81,7 @@ static int master_to_spawner_socket; * to the spawner. */ static void -replication_on_accept(void *data __attribute__((unused)), +replication_on_accept(struct evio_service *service __attribute__((unused)), int fd, struct sockaddr_in *addr __attribute__((unused))); /** Send a file descriptor to replication relay spawner. @@ -225,8 +225,9 @@ replication_init() /** Replication acceptor fiber handler. */ static void -replication_on_accept(void *data __attribute__((unused)), - int fd, struct sockaddr_in *addr __attribute__((unused))) +replication_on_accept(struct evio_service *service __attribute__((unused)), + int fd, + struct sockaddr_in *addr __attribute__((unused))) { /* * Drop the O_NONBLOCK flag, which was possibly diff --git a/src/say.m b/src/say.m index 79c72c4e734d8cc38387598a291d52416c7b7ea4..6d081873494526fb0c5fadb8eb4123c2872874d0 100644 --- a/src/say.m +++ b/src/say.m @@ -41,6 +41,7 @@ #include <fiber.h> #include TARANTOOL_CONFIG #include "tarantool.h" +#include "sio.h" int sayfd = STDERR_FILENO; pid_t logger_pid; @@ -112,7 +113,7 @@ say_logger_init(int nonblock) } out: if (nonblock) - set_nonblock(sayfd); + sio_setfl(sayfd, O_NONBLOCK, 1); setvbuf(stderr, NULL, _IONBF, 0); } @@ -120,7 +121,6 @@ say_logger_init(int nonblock) void vsay(int level, const char *filename, int line, const char *error, const char *format, va_list ap) { - const char *peer_name = fiber_peer_name(fiber); size_t p = 0, len = PIPE_BUF; const char *f; static __thread char buf[PIPE_BUF]; @@ -136,9 +136,6 @@ vsay(int level, const char *filename, int line, const char *error, const char *f ev_now_update(); - if (peer_name == NULL) - peer_name = "_"; - for (f = filename; *f; f++) if (*f == '/' && *(f + 1) != '\0') filename = f + 1; @@ -152,8 +149,8 @@ vsay(int level, const char *filename, int line, const char *error, const char *f p += snprintf(buf + p, len - p, ":%06.3f", ev_now() - now + tm.tm_sec); - p += snprintf(buf + p, len - p, " [%i] %i/%s %s", getpid(), - fiber->fid, fiber->name, peer_name); + p += snprintf(buf + p, len - p, " [%i] %i/%s", getpid(), + fiber->fid, fiber->name); if (level == S_WARN || level == S_ERROR) p += snprintf(buf + p, len - p, " %s:%i", filename, line); diff --git a/src/sio.m b/src/sio.m index f548dc82e0efedd05b3d162730f8904ed593871c..2ab890198f5bbb936cc704f3d33fea3ed9873564 100644 --- a/src/sio.m +++ b/src/sio.m @@ -28,11 +28,10 @@ */ #include "sio.h" +#include <sys/uio.h> #include <errno.h> #include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> +#include <netinet/tcp.h> /* TCP_NODELAY */ #include <arpa/inet.h> /* inet_ntoa */ #include "say.h" @@ -73,7 +72,7 @@ sio_socketname(int fd) va_end(ap); const char *socketname = sio_socketname(fd); errno = save_errno; - self = [self init: "in %s, called on %s", buf, socketname]; + self = [self init: "%s, called on %s", buf, socketname]; return self; } @end diff --git a/src/tarantool.m b/src/tarantool.m index 2c29e568b33d3c13ea1da8860d2a155436945272..662f5c724dfa501900c0df651e004374bdcd9b30 100644 --- a/src/tarantool.m +++ b/src/tarantool.m @@ -256,7 +256,7 @@ reload_cfg(struct tbuf *out) const char * tarantool_version(void) { - return TARANTOOL_VERSION; + return PACKAGE_VERSION; } static double start_time; @@ -829,7 +829,8 @@ main(int argc, char **argv) start_time = ev_now(); ev_loop(0); } @catch (tnt_Exception *e) { - panic("%s", [e errmsg]); + [e log]; + panic("%s", "Fatal error, exiting loop"); } say_crit("exiting loop"); /* freeing resources */ diff --git a/src/tarantool_lua.m b/src/tarantool_lua.m index 507bd23b517da6ee295518392793127ab5502d2c..55cf0b3c5551712e8e5d5a302846812a923b0ff0 100644 --- a/src/tarantool_lua.m +++ b/src/tarantool_lua.m @@ -127,6 +127,9 @@ tarantool_lua_tointeger64(struct lua_State *L, int idx) } case LUA_TCDATA: { + /* Calculate absolute value in the stack. */ + if (idx < 0) + idx = lua_gettop(L) + idx + 1; GCcdata *cd = cdataV(L->base + idx - 1); if (cd->typeid != CTID_INT64 && cd->typeid != CTID_UINT64) { luaL_error(L, @@ -680,7 +683,7 @@ lbox_fiber_detach(struct lua_State *L) } static void -box_lua_fiber_run(void *arg __attribute__((unused))) +box_lua_fiber_run(va_list ap __attribute__((unused))) { fiber_testcancel(); fiber_setcancellable(false); @@ -782,7 +785,7 @@ lbox_fiber_create(struct lua_State *L) luaL_error(L, "fiber.create(function): recursion limit" " reached"); - struct fiber *f = fiber_create("lua", -1, box_lua_fiber_run, NULL); + struct fiber *f = fiber_create("lua", box_lua_fiber_run); /* Initially the fiber is cancellable */ f->flags |= FIBER_USER_MODE | FIBER_CANCELLABLE; @@ -1428,9 +1431,9 @@ tarantool_lua_load_cfg(struct lua_State *L, struct tarantool_cfg *cfg) * Load start-up file routine. */ static void -load_init_script(void *L_ptr) +load_init_script(va_list ap) { - struct lua_State *L = (struct lua_State *) L_ptr; + struct lua_State *L = va_arg(ap, struct lua_State *); char path[PATH_MAX + 1]; snprintf(path, PATH_MAX, "%s/%s", @@ -1486,9 +1489,9 @@ tarantool_lua_load_init_script(struct lua_State *L) * To work this problem around we must run init script in * a separate fiber. */ - struct fiber *loader = fiber_create(TARANTOOL_LUA_INIT_SCRIPT, -1, - load_init_script, L); - fiber_call(loader); + struct fiber *loader = fiber_create(TARANTOOL_LUA_INIT_SCRIPT, + load_init_script); + fiber_call(loader, L); /* Outside the startup file require() or ffi are not * allowed. */ diff --git a/src/tarantool_lua_slab.m b/src/tarantool_lua_slab.m index bca1da9cc106c69a817e5aa021772468a67c59ef..8f234873ceb88962b33920bfe88281dcd0a7234a 100644 --- a/src/tarantool_lua_slab.m +++ b/src/tarantool_lua_slab.m @@ -43,7 +43,7 @@ salloc_stat_lua_cb(const struct slab_class_stats *cstat, void *cb_ctx) * Create a Lua table for every slab class. A class is * defined by its item size. */ - luaL_pushnumber64(L, cstat->item_size); + lua_pushnumber(L, cstat->item_size); lua_newtable(L); lua_pushstring(L, "slabs"); diff --git a/test/box/lua.result b/test/box/lua.result index f3c97514d47ff8a0a0d4a279b4cdc5f9e1c768ab..8761d1e6a216a9953f6063b32637c3dbbcc251a4 100644 --- a/test/box/lua.result +++ b/test/box/lua.result @@ -466,7 +466,7 @@ error: 'bad argument #1 to ''?'' (number expected, got string)' ... lua box.index.new(1, 2) --- -error: 'No index #2 is defined in space 1' +error: 'Space 1 does not exist' ... lua box.index.new(0, 1) --- @@ -922,7 +922,7 @@ lua box.crossjoin = nil lua pcall(box.insert, 99, 1, 'test') --- - false - - Space 99 is disabled + - Space 99 does not exist ... lua pcall(box.insert, 0, 1, 'hello') --- @@ -1683,13 +1683,13 @@ error: '' lua old_name = box.fiber.name() --- ... -lua box.fiber.name() +lua box.fiber.name() == old_name --- - - 33015/handler + - true ... -lua box.fiber.self():name() +lua box.fiber.self():name() == old_name --- - - 33015/handler + - true ... lua box.fiber.name('hello fiber') --- @@ -1721,3 +1721,12 @@ lua bit.bor(1, 2) --- - 3 ... +# A test case for Bug#1061747 'tonumber64 is not transitive' +lua tonumber64(tonumber64(2)) +--- + - 2 +... +lua tostring(tonumber64(tonumber64(3))) +--- + - 3ULL +... diff --git a/test/box/lua.test b/test/box/lua.test index 78fe92535cb3e8eb08b5100d19e927cd4c087bed..5b869eb5ed4ad752d8263ce2f31ef8cc621cc488 100644 --- a/test/box/lua.test +++ b/test/box/lua.test @@ -561,8 +561,8 @@ print """# A test case for Bug#1043804 lua error() -> server crash""" exec admin "lua error()" print """# Test box.fiber.name()""" exec admin "lua old_name = box.fiber.name()" -exec admin "lua box.fiber.name()" -exec admin "lua box.fiber.self():name()" +exec admin "lua box.fiber.name() == old_name" +exec admin "lua box.fiber.self():name() == old_name" exec admin "lua box.fiber.name('hello fiber')" exec admin "lua box.fiber.name()" exec admin "lua box.fiber.self():name('bye fiber')" @@ -573,3 +573,7 @@ print """# A test case for bitwise operations """ exec admin "lua bit.lshift(1, 32)" exec admin "lua bit.band(1, 3)" exec admin "lua bit.bor(1, 2)" + +print """# A test case for Bug#1061747 'tonumber64 is not transitive'""" +exec admin "lua tonumber64(tonumber64(2))" +exec admin "lua tostring(tonumber64(tonumber64(3)))" diff --git a/test/box/sql.result b/test/box/sql.result index 9b4a3738608a984276101b6df57a8d7e41067687..510f39df71b992ca5fdd4f80365f276fdcfc8f5d 100644 --- a/test/box/sql.result +++ b/test/box/sql.result @@ -91,7 +91,7 @@ Delete OK, 1 row affected # select * from t1 where k0 = 0 -An error occurred: ER_SPACE_DISABLED, 'Space 1 is disabled' +An error occurred: ER_NO_SUCH_SPACE, 'Space 1 does not exist' select * from t65537 where k0 = 0 An error occurred: ER_NO_SUCH_SPACE, 'Space 65537 does not exist' select * from t4294967295 where k0 = 0 diff --git a/test/box_big/lua.result b/test/box_big/lua.result index cf8393e7b003b7194878e7ccc670d97a6a8a76cc..6698c0b0fdd27fa686b9f4ea6f2367fddede0481 100644 --- a/test/box_big/lua.result +++ b/test/box_big/lua.result @@ -533,7 +533,7 @@ lua push_collection(5, 1038784, 'hey') --- - 1038784: {26984, 'hey', 'hey', 'hey', 'hey'} ... -A test case for Bug#1060967: truncation of 64-bit numbers +# A test case for Bug#1060967: truncation of 64-bit numbers lua box.space[5]:insert(2^51, 'hello', 'world') --- - 2251799813685248: {'hello', 'world'} @@ -545,3 +545,15 @@ lua box.space[5]:select(0, 2^51) lua box.space[5]:truncate() --- ... +# Test that we print index number in error ER_INDEX_VIOLATION +lua box.space[1]:insert(1, 'hello', 'world') +--- + - 1: {'hello', 'world'} +... +lua box.space[1]:insert(2, 'hello', 'world') +--- +error: 'Duplicate key exists in unique index 1' +... +lua box.space[1]:truncate() +--- +... diff --git a/test/box_big/lua.test b/test/box_big/lua.test index e57494235f98a994a1d4b66fab5ebb87e105ad0f..4ccc898075e0cb2e941b7d1d071f7c2b48549600 100644 --- a/test/box_big/lua.test +++ b/test/box_big/lua.test @@ -197,7 +197,11 @@ exec admin "lua push_collection(5, 1038784, 'hey')" exec admin "lua push_collection(5, 1038784, 'hey')" exec admin "lua push_collection(5, 1038784, 'hey')" -print """A test case for Bug#1060967: truncation of 64-bit numbers""" +print """# A test case for Bug#1060967: truncation of 64-bit numbers""" exec admin "lua box.space[5]:insert(2^51, 'hello', 'world')" exec admin "lua box.space[5]:select(0, 2^51)" exec admin "lua box.space[5]:truncate()" +print """# Test that we print index number in error ER_INDEX_VIOLATION""" +exec admin "lua box.space[1]:insert(1, 'hello', 'world')" +exec admin "lua box.space[1]:insert(2, 'hello', 'world')" +exec admin "lua box.space[1]:truncate()"