From ccd617739ea6ef795c88e34835a59ef902c50ad7 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja.osipov@gmail.com> Date: Thu, 18 Aug 2011 17:53:58 +0400 Subject: [PATCH] Lua: prepare to intercept box.process results into Lua. Remove dead code from txn_cleanup(), which would check that txn_cleanup() is not called twice: this code is from the time when we used Rename txn_abort() to txn_rollback(). Rename txn_alloc() to txn_begin(). Introduce box_out interface, used to send box results to the client. Lua uses this interface to intercept returned tuples and push as return values to Lua stack. Make iov_add/iov_dup inline, as they used to be. They are now mostly used from within callbacks. Make txn_commit()/txn_rollback() non-static as they are now used in memcached.m. Introduce memcached_get(): implementation of Memcached GET statement. Wrap memcached_get() in proper txn_begin()/txn_commit()/txn_rollback(), and handle failure of memcached_get() by rolling back the transaction. Split BOX_QUIET to two flags: BOX_GC_TXN and BOX_QUIET. BOX_QUIET had a side-effect that txn_cleanup() was done immediately, rather than by fiber_gc(). This had the side effect that txn_commit() could not be used in memcached_get(), because in memcached_get() we need both BOX_QUIET and txn_cleanup() called from fiber_gc(). Now that we have box_out interface, eliminate BOX_QUIET flag completely, and use box_out_quiet set of callbacks instead. --- core/admin.m | 15 + core/fiber.m | 15 - include/errcode.h | 2 +- include/fiber.h | 21 +- mod/box/box.h | 25 +- mod/box/box.m | 194 ++++---- mod/box/memcached-grammar.m | 524 ++++++++++------------ mod/box/memcached-grammar.rl | 86 +--- mod/box/memcached.m | 88 +++- mod/box/tuple.h | 7 + test/box_memcached/multiversioning.result | 4 +- test/box_memcached/multiversioning.test | 5 +- 12 files changed, 488 insertions(+), 498 deletions(-) diff --git a/core/admin.m b/core/admin.m index ba6f905c89..336f3139ad 100644 --- a/core/admin.m +++ b/core/admin.m @@ -1464,6 +1464,17 @@ case 107: return fiber_write(out->data, out->len); } +/** + We need to be able to print from Lua back to the + * administrative console. For that, we register this + * function as Lua 'print'. However, administrative + * console output must be YAML-compatible. If this is + * done automatically, the result is ugly, so we don't + * do it. A creator of Lua procedures has to do it + * herself. Best we can do here is to add a trailing + * \r\n if it's forgotten. + */ + static int lbox_adminprint(struct lua_State *L) { @@ -1482,6 +1493,10 @@ lbox_adminprint(struct lua_State *L) static void admin_handler(void *data __attribute__((unused))) { + /* + * Create a disposable Lua interpreter state + * for every new connection. + */ lua_State *L = tarantool_lua_init(); lua_register(L, "print", lbox_adminprint); @try { diff --git a/core/fiber.m b/core/fiber.m index a525e31d1a..eab0a32b52 100644 --- a/core/fiber.m +++ b/core/fiber.m @@ -693,21 +693,6 @@ fiber_bread(struct tbuf *buf, size_t at_least) return r; } -void -iov_add(const void *buf, size_t len) -{ - iov_ensure(1); - iov_add_unsafe(buf, len); -} - -void -iov_dup(const void *buf, size_t len) -{ - void *copy = palloc(fiber->gc_pool, len); - memcpy(copy, buf, len); - iov_add(copy, len); -} - void iov_reset() { diff --git a/include/errcode.h b/include/errcode.h index c6dfd446d3..f899b2c589 100644 --- a/include/errcode.h +++ b/include/errcode.h @@ -102,7 +102,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 45 */_(ER_UNUSED45, 0, "Unused45") \ /* 46 */_(ER_UNUSED46, 0, "Unused46") \ /* 47 */_(ER_UNUSED47, 0, "Unused47") \ - /* 48 */_(ER_UNUSED48, 0, "Unused48") \ + /* 48 */_(ER_PROC_RET, 2, "Return type '%s' is not supported in the binary protocol") \ /* 49 */_(ER_TUPLE_NOT_FOUND, 2, "Tuple doesn't exist") \ /* 50 */_(ER_NO_SUCH_PROC, 2, "Procedure %.*s is not defined") \ /* 51 */_(ER_PROC_LUA, 2, "Lua error: %s") \ diff --git a/include/fiber.h b/include/fiber.h index d3a2fe7804..5c467eb736 100644 --- a/include/fiber.h +++ b/include/fiber.h @@ -41,6 +41,7 @@ #include "third_party/queue.h" #include "exception.h" +#include "palloc.h" #define FIBER_NAME_MAXLEN 32 @@ -96,6 +97,10 @@ struct fiber { char name[FIBER_NAME_MAXLEN]; void (*f) (void *); void *f_data; + /* Store execution context in a fiber. */ + union { + struct box_txn *txn; + } mod_data; u64 cookie; bool has_peer; @@ -161,8 +166,19 @@ inline static void iov_ensure(size_t count) } /* Add to fiber's iov vector. */ -void iov_add(const void *buf, size_t len); -void iov_dup(const void *buf, size_t len); +inline static void iov_add(const void *buf, size_t len) +{ + iov_ensure(1); + iov_add_unsafe(buf, len); +} + +inline static void iov_dup(const void *buf, size_t len) +{ + void *copy = palloc(fiber->gc_pool, len); + memcpy(copy, buf, len); + iov_add(copy, len); +} + /* Reset the fiber's iov vector. */ ssize_t iov_flush(void); /* Write everything in the fiber's iov vector to fiber socket. */ @@ -176,7 +192,6 @@ 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); -ssize_t fiber_flush_output(void); void fiber_cleanup(void); void fiber_gc(void); void fiber_call(struct fiber *callee); diff --git a/mod/box/box.h b/mod/box/box.h index edc791bf35..c1392d87c4 100644 --- a/mod/box/box.h +++ b/mod/box/box.h @@ -30,6 +30,7 @@ #include "exception.h" #include "iproto.h" #include <tbuf.h> +#include <fiber.h> struct tarantool_cfg; struct box_tuple; @@ -50,10 +51,20 @@ struct namespace { extern struct namespace *namespace; +struct box_out { + void (*add_u32)(u32 *u32); + void (*dup_u32)(u32 u32); + void (*add_tuple)(struct box_tuple *tuple); +}; + +extern struct box_out box_out_quiet; + struct box_txn { u16 op; u32 flags; + struct lua_State *L; + struct box_out *out; struct namespace *namespace; struct index *index; int n; @@ -64,21 +75,17 @@ struct box_txn { struct box_tuple *lock_tuple; struct tbuf req; - - bool in_recover; - bool write_to_wal; }; #define BOX_RETURN_TUPLE 0x01 #define BOX_ADD 0x02 #define BOX_REPLACE 0x04 -#define BOX_QUIET 0x08 #define BOX_NOT_STORE 0x10 +#define BOX_GC_TXN 0x20 #define BOX_ALLOWED_REQUEST_FLAGS (BOX_RETURN_TUPLE | \ BOX_ADD | \ BOX_REPLACE | \ - BOX_QUIET | \ BOX_NOT_STORE) /* @@ -113,9 +120,11 @@ ENUM(messages, MESSAGES); extern iproto_callback rw_callback; -/* These 3 are used to implemente memcached 'GET' */ -struct box_txn *txn_alloc(u32 flags); +/* These are used to implement memcached 'GET' */ +static inline struct box_txn *in_txn() { return fiber->mod_data.txn; } +struct box_txn *txn_begin(); +void txn_commit(struct box_txn *txn); +void txn_rollback(struct box_txn *txn); void tuple_txn_ref(struct box_txn *txn, struct box_tuple *tuple); -void txn_cleanup(struct box_txn *txn); #endif /* TARANTOOL_BOX_H_INCLUDED */ diff --git a/mod/box/box.m b/mod/box/box.m index 2b79572bc5..1bbc68debf 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -59,9 +59,6 @@ static char status[64] = "unknown"; static int stat_base; STRS(messages, MESSAGES); -/* hooks */ -typedef int (*box_hook_t) (struct box_txn * txn); - /* For tuples of size below this threshold, when sending a tuple to the client, make a deep copy of the tuple for the duration @@ -92,8 +89,6 @@ box_snap_row(const struct tbuf *t) return (struct box_snap_row *)t->data; } -static void tuple_iov_add(struct box_txn *txn, struct box_tuple *tuple); - static void lock_tuple(struct box_txn *txn, struct box_tuple *tuple) { @@ -165,7 +160,7 @@ prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data) lock_tuple(txn, txn->tuple); /* * Mark the tuple as ghost before attempting an - * index replace: if it fails, txn_abort() will + * index replace: if it fails, txn_rollback() will * look at the flag and remove the tuple. */ txn->tuple->flags |= GHOST; @@ -183,14 +178,10 @@ prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data) index->replace(index, NULL, txn->tuple); } - if (!(txn->flags & BOX_QUIET)) { - u32 tuples_affected = 1; - - iov_dup(&tuples_affected, sizeof(uint32_t)); + txn->out->dup_u32(1); /* Affected tuples */ - if (txn->flags & BOX_RETURN_TUPLE) - tuple_iov_add(txn, txn->tuple); - } + if (txn->flags & BOX_RETURN_TUPLE) + txn->out->add_tuple(txn->tuple); } static void @@ -433,29 +424,10 @@ prepare_update_fields(struct box_txn *txn, struct tbuf *data) tnt_raise(IllegalParams, :"can't unpack request"); out: - if (!(txn->flags & BOX_QUIET)) { - iov_dup(&tuples_affected, sizeof(uint32_t)); - - if (txn->flags & BOX_RETURN_TUPLE) - tuple_iov_add(txn, txn->tuple); - } -} - -static void -tuple_iov_add(struct box_txn *txn, struct box_tuple *tuple) -{ - size_t len; - - len = tuple->bsize + - field_sizeof(struct box_tuple, bsize) + - field_sizeof(struct box_tuple, cardinality); + txn->out->dup_u32(tuples_affected); - if (len > BOX_REF_THRESHOLD) { - tuple_txn_ref(txn, tuple); - iov_add(&tuple->bsize, len); - } else { - iov_dup(&tuple->bsize, len); - } + if (txn->flags & BOX_RETURN_TUPLE) + txn->out->add_tuple(txn->tuple); } static void __attribute__((noinline)) @@ -468,7 +440,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) tnt_raise(IllegalParams, :"tuple count must be positive"); found = palloc(fiber->gc_pool, sizeof(*found)); - iov_add(found, sizeof(*found)); + txn->out->add_u32(found); *found = 0; if (txn->index->type == TREE) { @@ -501,7 +473,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) continue; } - tuple_iov_add(txn, tuple); + txn->out->add_tuple(tuple); if (limit == ++(*found)) break; @@ -528,7 +500,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) continue; } - tuple_iov_add(txn, tuple); + txn->out->add_tuple(tuple); (*found)++; } } @@ -558,12 +530,10 @@ prepare_delete(struct box_txn *txn, void *key) tuples_affected = 1; } - if (!(txn->flags & BOX_QUIET)) { - iov_dup(&tuples_affected, sizeof(tuples_affected)); + txn->out->dup_u32(tuples_affected); - if (txn->old_tuple && (txn->flags & BOX_RETURN_TUPLE)) - tuple_iov_add(txn, txn->old_tuple); - } + if (txn->old_tuple && (txn->flags & BOX_RETURN_TUPLE)) + txn->out->add_tuple(txn->old_tuple); } static void @@ -583,16 +553,58 @@ op_is_select(u32 op) return op == SELECT || op == SELECT_LIMIT; } +static void +iov_add_u32(u32 *p_u32) +{ + iov_add(p_u32, sizeof(u32)); +} + +static void +iov_dup_u32(u32 u32) +{ + iov_dup(&u32, sizeof(u32)); +} + +static void +iov_add_tuple(struct box_tuple *tuple) +{ + size_t len = tuple_len(tuple); + + if (len > BOX_REF_THRESHOLD) { + tuple_txn_ref(in_txn(), tuple); + iov_add(&tuple->bsize, len); + } else { + iov_dup(&tuple->bsize, len); + } +} + +struct box_out box_out_iproto = { + iov_add_u32, + iov_dup_u32, + iov_add_tuple +}; + +static void box_quiet_add_u32(u32 *p_u32 __attribute__((unused))) {} +static void box_quiet_dup_u32(u32 u32 __attribute__((unused))) {} +static void box_quiet_add_tuple(struct box_tuple *tuple __attribute__((unused))) {} + +struct box_out box_out_quiet = { + box_quiet_add_u32, + box_quiet_dup_u32, + box_quiet_add_tuple +}; + struct box_txn * -txn_alloc(u32 flags) +txn_begin() { + assert(in_txn() == NULL); struct box_txn *txn = p0alloc(fiber->gc_pool, sizeof(*txn)); txn->ref_tuples = tbuf_alloc(fiber->gc_pool); - txn->flags = flags; + assert(fiber->mod_data.txn == NULL); + fiber->mod_data.txn = txn; return txn; } - void txn_assign_n(struct box_txn *txn, struct tbuf *data) { txn->n = read_u32(data); @@ -608,39 +620,17 @@ void txn_assign_n(struct box_txn *txn, struct tbuf *data) txn->index = txn->namespace->index; } -/** - * Validate the request and start a transaction associated with - * that request: - * - * - parse the request, - * - perform a "name resolution", i.e. find the namespace object - * associated with the request. - */ - +/** Remember op code/request in the txn. */ static void -txn_begin(struct box_txn *txn, u16 op, struct tbuf *data) +txn_set_op(struct box_txn *txn, u16 op, struct tbuf *data) { txn->op = op; txn->req = (struct tbuf){ .data = data->data, .len = data->len }; } -void +static void txn_cleanup(struct box_txn *txn) { - /* - * txn_cleanup() may get called twice in the following - * scenario: Several requests are processed by a single - * iproto loop iteration. The first few requests are - * handled successfully, but the next one fails with an - * OOM. In this case, fiber performs fiber_cleanup() for - * every registered callback. We should not run - * txn_cleanup() twice. - */ - if (txn->op == 0) - return; - - unlock_tuples(txn); - struct box_tuple **tuple = txn->ref_tuples->data; int i = txn->ref_tuples->len / sizeof(struct box_txn *); @@ -653,11 +643,12 @@ txn_cleanup(struct box_txn *txn) memset(txn, 0, sizeof(*txn)); } -static void +void txn_commit(struct box_txn *txn) { - if (txn->op == 0) - return; + assert(txn == in_txn()); + assert(txn->op); + fiber->mod_data.txn = 0; if (!op_is_select(txn->op)) { say_debug("box_commit(op:%s)", messages_strs[txn->op]); @@ -686,20 +677,22 @@ txn_commit(struct box_txn *txn) commit_replace(txn); } - if (txn->flags & BOX_QUIET) - txn_cleanup(txn); - else + if (txn->flags & BOX_GC_TXN) fiber_register_cleanup((fiber_cleanup_handler)txn_cleanup, txn); + else + txn_cleanup(txn); } -static void -txn_abort(struct box_txn *txn) +void +txn_rollback(struct box_txn *txn) { + assert(txn == in_txn()); + fiber->mod_data.txn = 0; if (txn->op == 0) return; if (!op_is_select(txn->op)) { - say_debug("box_rollback(op:%s)", messages_strs[txn->op]); + say_debug("txn_rollback(op:%s)", messages_strs[txn->op]); unlock_tuples(txn); @@ -992,20 +985,27 @@ namespace_init(void) memcached_namespace_init(); } -void -box_process(struct box_txn *txn, u32 op, struct tbuf *request_data) +static void +box_process_rw(u32 op, struct tbuf *request_data) { ev_tstamp start = ev_now(), stop; stat_collect(stat_base, op, 1); + struct box_txn *txn = in_txn(); + if (txn == NULL) { + txn = txn_begin(); + txn->flags |= BOX_GC_TXN; + txn->out = &box_out_iproto; + } + @try { - txn_begin(txn, op, request_data); + txn_set_op(txn, op, request_data); box_dispatch(txn, request_data); txn_commit(txn); } @catch (id e) { - txn_abort(txn); + txn_rollback(txn); @throw; } @finally { @@ -1018,19 +1018,16 @@ box_process(struct box_txn *txn, u32 op, struct tbuf *request_data) static void box_process_ro(u32 op, struct tbuf *request_data) { - if (!op_is_select(op)) + if (!op_is_select(op)) { + struct box_txn *txn = in_txn(); + if (txn != NULL) + txn_rollback(txn); tnt_raise(LoggedError, :ER_NONMASTER); + } - return box_process(txn_alloc(0), op, request_data); -} - -static void -box_process_rw(u32 op, struct tbuf *request_data) -{ - return box_process(txn_alloc(0), op, request_data); + return box_process_rw(op, request_data); } - static struct tbuf * convert_snap_row_to_wal(struct tbuf *t) { @@ -1051,9 +1048,6 @@ convert_snap_row_to_wal(struct tbuf *t) static int recover_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t) { - struct box_txn *txn = txn_alloc(BOX_QUIET | BOX_NOT_STORE); - u16 op; - /* drop wal header */ if (tbuf_peek(t, sizeof(struct row_v11)) == NULL) return -1; @@ -1067,10 +1061,14 @@ recover_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t) return -1; } - op = read_u16(t); + u16 op = read_u16(t); + + struct box_txn *txn = txn_begin(); + txn->flags |= BOX_NOT_STORE; + txn->out = &box_out_quiet; @try { - box_process(txn, op, t); + box_process_rw(op, t); } @catch (id e) { return -1; diff --git a/mod/box/memcached-grammar.m b/mod/box/memcached-grammar.m index 886d2d9e24..c8073a479a 100644 --- a/mod/box/memcached-grammar.m +++ b/mod/box/memcached-grammar.m @@ -127,7 +127,7 @@ case 5: goto st0; goto tr15; tr15: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -158,7 +158,7 @@ case 7: goto tr17; goto st0; tr17: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st8; st8: @@ -172,7 +172,7 @@ case 8: goto st8; goto st0; tr18: -#line 312 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st9; st9: @@ -186,7 +186,7 @@ case 9: goto tr21; goto st0; tr21: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st10; st10: @@ -200,7 +200,7 @@ case 10: goto st10; goto st0; tr22: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -218,7 +218,7 @@ case 11: goto tr25; goto st0; tr25: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st12; st12: @@ -235,11 +235,11 @@ case 12: goto st12; goto st0; tr26: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -260,7 +260,7 @@ tr26: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -277,9 +277,9 @@ tr26: } goto st197; tr30: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -300,7 +300,7 @@ tr30: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -317,11 +317,11 @@ tr30: } goto st197; tr39: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -342,7 +342,7 @@ tr39: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -359,11 +359,11 @@ tr39: } goto st197; tr58: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -384,7 +384,7 @@ tr58: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -419,9 +419,9 @@ tr58: } goto st197; tr62: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -442,7 +442,7 @@ tr62: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -477,11 +477,11 @@ tr62: } goto st197; tr71: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -502,7 +502,7 @@ tr71: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -537,11 +537,11 @@ tr71: } goto st197; tr91: -#line 314 "mod/box/memcached-grammar.rl" +#line 252 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -562,7 +562,7 @@ tr91: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -581,9 +581,9 @@ tr91: } goto st197; tr95: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -604,7 +604,7 @@ tr95: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -623,11 +623,11 @@ tr95: } goto st197; tr105: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -648,7 +648,7 @@ tr105: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -667,11 +667,11 @@ tr105: } goto st197; tr118: -#line 315 "mod/box/memcached-grammar.rl" +#line 253 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -734,9 +734,9 @@ tr118: } goto st197; tr122: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -799,11 +799,11 @@ tr122: } goto st197; tr132: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -866,9 +866,9 @@ tr132: } goto st197; tr141: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -894,15 +894,15 @@ tr141: } goto st197; tr146: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) exptime = exptime + ev_now(); } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -928,11 +928,11 @@ tr146: } goto st197; tr157: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -958,15 +958,15 @@ tr157: } goto st197; tr169: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "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 270 "mod/box/memcached-grammar.rl" +#line 208 "mod/box/memcached-grammar.rl" { if (flush_delay > 0) { struct fiber *f = fiber_create("flush_all", -1, -1, flush_all, (void *)flush_delay); @@ -978,17 +978,17 @@ tr169: } goto st197; tr174: -#line 316 "mod/box/memcached-grammar.rl" +#line 254 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "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 270 "mod/box/memcached-grammar.rl" +#line 208 "mod/box/memcached-grammar.rl" { if (flush_delay > 0) { struct fiber *f = fiber_create("flush_all", -1, -1, flush_all, (void *)flush_delay); @@ -1000,17 +1000,17 @@ tr174: } goto st197; tr185: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "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 270 "mod/box/memcached-grammar.rl" +#line 208 "mod/box/memcached-grammar.rl" { if (flush_delay > 0) { struct fiber *f = fiber_create("flush_all", -1, -1, flush_all, (void *)flush_delay); @@ -1022,9 +1022,9 @@ tr185: } goto st197; tr195: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1032,103 +1032,41 @@ tr195: } #line 192 "mod/box/memcached-grammar.rl" { - struct box_txn *txn = txn_alloc(BOX_QUIET); - txn->op = SELECT; - fiber_register_cleanup((void *)txn_cleanup, txn); - stat_collect(stat_base, MEMC_GET, 1); - stats.cmd_get++; - say_debug("ensuring space for %"PRI_SZ" keys", keys_count); - iov_ensure(keys_count * 5 + 1); - while (keys_count-- > 0) { - struct box_tuple *tuple; - struct meta *m; - void *field; - void *value; - void *suffix; - u32 key_len; - u32 value_len; - u32 suffix_len; - u32 _l; - - key = read_field(keys); - tuple = find(key); - key_len = load_varint32(&key); - - if (tuple == NULL || tuple->flags & GHOST) { - stat_collect(stat_base, MEMC_GET_MISS, 1); - stats.get_misses++; - continue; - } - - field = tuple->data; - - /* skip key */ - _l = load_varint32(&field); - field += _l; - - /* metainfo */ - _l = load_varint32(&field); - m = field; - field += _l; - - /* suffix */ - suffix_len = load_varint32(&field); - suffix = field; - field += suffix_len; - - /* value */ - value_len = load_varint32(&field); - value = field; - - if (m->exptime > 0 && m->exptime < ev_now()) { - stats.get_misses++; - stat_collect(stat_base, MEMC_GET_MISS, 1); - continue; - } else { - stats.get_hits++; - stat_collect(stat_base, MEMC_GET_HIT, 1); - } - - tuple_txn_ref(txn, tuple); - - if (show_cas) { - struct tbuf *b = tbuf_alloc(fiber->gc_pool); - tbuf_printf(b, "VALUE %.*s %"PRIu32" %"PRIu32" %"PRIu64"\r\n", key_len, (u8 *)key, m->flags, value_len, m->cas); - iov_add_unsafe(b->data, b->len); - stats.bytes_written += b->len; - } else { - iov_add_unsafe("VALUE ", 6); - iov_add_unsafe(key, key_len); - iov_add_unsafe(suffix, suffix_len); - } - iov_add_unsafe(value, value_len); - iov_add_unsafe("\r\n", 2); - stats.bytes_written += value_len + 2; + struct box_txn *txn = txn_begin(); + txn->flags |= BOX_GC_TXN; + txn->out = &box_out_quiet; + @try { + memcached_get(txn, keys_count, keys, show_cas); + txn_commit(txn); + } @catch (ClientError *e) { + txn_rollback(txn); + iov_reset(); + iov_add("SERVER_ERROR ", 13); + iov_add(e->errmsg, strlen(e->errmsg)); + iov_add("\r\n", 2); } - iov_add_unsafe("END\r\n", 5); - stats.bytes_written += 5; } goto st197; tr213: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "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 284 "mod/box/memcached-grammar.rl" +#line 222 "mod/box/memcached-grammar.rl" { return 0; } goto st197; tr233: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1149,7 +1087,7 @@ tr233: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1166,9 +1104,9 @@ tr233: } goto st197; tr237: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1189,7 +1127,7 @@ tr237: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1206,11 +1144,11 @@ tr237: } goto st197; tr246: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1231,7 +1169,7 @@ tr246: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1248,11 +1186,11 @@ tr246: } goto st197; tr263: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1273,7 +1211,7 @@ tr263: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1286,9 +1224,9 @@ tr263: } goto st197; tr267: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1309,7 +1247,7 @@ tr267: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1322,11 +1260,11 @@ tr267: } goto st197; tr276: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 318 "mod/box/memcached-grammar.rl" +#line 256 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1347,7 +1285,7 @@ tr276: goto exit; } } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "mod/box/memcached-grammar.rl" { done = true; stats.bytes_read += p - (u8 *)fiber->rbuf->data; @@ -1360,15 +1298,15 @@ tr276: } goto st197; tr281: -#line 345 "mod/box/memcached-grammar.rl" +#line 283 "mod/box/memcached-grammar.rl" { p++; } -#line 339 "mod/box/memcached-grammar.rl" +#line 277 "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 280 "mod/box/memcached-grammar.rl" +#line 218 "mod/box/memcached-grammar.rl" { print_stats(); } @@ -1377,33 +1315,33 @@ st197: if ( ++p == pe ) goto _test_eof197; case 197: -#line 1381 "mod/box/memcached-grammar.m" +#line 1319 "mod/box/memcached-grammar.m" goto st0; tr27: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st13; tr40: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st13; st13: if ( ++p == pe ) goto _test_eof13; case 13: -#line 1395 "mod/box/memcached-grammar.m" +#line 1333 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr30; goto st0; tr28: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st14; st14: if ( ++p == pe ) goto _test_eof14; case 14: -#line 1407 "mod/box/memcached-grammar.m" +#line 1345 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st14; case 110: goto st15; @@ -1496,18 +1434,18 @@ case 26: goto tr45; goto st0; tr45: -#line 353 "mod/box/memcached-grammar.rl" +#line 291 "mod/box/memcached-grammar.rl" {append = true; } goto st27; tr209: -#line 354 "mod/box/memcached-grammar.rl" +#line 292 "mod/box/memcached-grammar.rl" {append = false;} goto st27; st27: if ( ++p == pe ) goto _test_eof27; case 27: -#line 1511 "mod/box/memcached-grammar.m" +#line 1449 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st27; @@ -1516,7 +1454,7 @@ case 27: goto st0; goto tr46; tr46: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -1533,7 +1471,7 @@ st28: if ( ++p == pe ) goto _test_eof28; case 28: -#line 1537 "mod/box/memcached-grammar.m" +#line 1475 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st29; goto st0; @@ -1547,49 +1485,49 @@ case 29: goto tr49; goto st0; tr49: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st30; st30: if ( ++p == pe ) goto _test_eof30; case 30: -#line 1558 "mod/box/memcached-grammar.m" +#line 1496 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr50; if ( 48 <= (*p) && (*p) <= 57 ) goto st30; goto st0; tr50: -#line 312 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st31; st31: if ( ++p == pe ) goto _test_eof31; case 31: -#line 1572 "mod/box/memcached-grammar.m" +#line 1510 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st31; if ( 48 <= (*p) && (*p) <= 57 ) goto tr53; goto st0; tr53: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 1586 "mod/box/memcached-grammar.m" +#line 1524 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr54; if ( 48 <= (*p) && (*p) <= 57 ) goto st32; goto st0; tr54: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -1600,21 +1538,21 @@ st33: if ( ++p == pe ) goto _test_eof33; case 33: -#line 1604 "mod/box/memcached-grammar.m" +#line 1542 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st33; if ( 48 <= (*p) && (*p) <= 57 ) goto tr57; goto st0; tr57: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st34; st34: if ( ++p == pe ) goto _test_eof34; case 34: -#line 1618 "mod/box/memcached-grammar.m" +#line 1556 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr58; case 13: goto tr59; @@ -1624,30 +1562,30 @@ case 34: goto st34; goto st0; tr59: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st35; tr72: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st35; st35: if ( ++p == pe ) goto _test_eof35; case 35: -#line 1639 "mod/box/memcached-grammar.m" +#line 1577 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr62; goto st0; tr60: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st36; st36: if ( ++p == pe ) goto _test_eof36; case 36: -#line 1651 "mod/box/memcached-grammar.m" +#line 1589 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st36; case 110: goto st37; @@ -1737,7 +1675,7 @@ case 47: goto st0; goto tr76; tr76: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -1754,7 +1692,7 @@ st48: if ( ++p == pe ) goto _test_eof48; case 48: -#line 1758 "mod/box/memcached-grammar.m" +#line 1696 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st49; goto st0; @@ -1768,49 +1706,49 @@ case 49: goto tr78; goto st0; tr78: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st50; st50: if ( ++p == pe ) goto _test_eof50; case 50: -#line 1779 "mod/box/memcached-grammar.m" +#line 1717 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr79; if ( 48 <= (*p) && (*p) <= 57 ) goto st50; goto st0; tr79: -#line 312 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st51; st51: if ( ++p == pe ) goto _test_eof51; case 51: -#line 1793 "mod/box/memcached-grammar.m" +#line 1731 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st51; if ( 48 <= (*p) && (*p) <= 57 ) goto tr82; goto st0; tr82: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st52; st52: if ( ++p == pe ) goto _test_eof52; case 52: -#line 1807 "mod/box/memcached-grammar.m" +#line 1745 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr83; if ( 48 <= (*p) && (*p) <= 57 ) goto st52; goto st0; tr83: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -1821,49 +1759,49 @@ st53: if ( ++p == pe ) goto _test_eof53; case 53: -#line 1825 "mod/box/memcached-grammar.m" +#line 1763 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st53; if ( 48 <= (*p) && (*p) <= 57 ) goto tr86; goto st0; tr86: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st54; st54: if ( ++p == pe ) goto _test_eof54; case 54: -#line 1839 "mod/box/memcached-grammar.m" +#line 1777 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr87; if ( 48 <= (*p) && (*p) <= 57 ) goto st54; goto st0; tr87: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st55; st55: if ( ++p == pe ) goto _test_eof55; case 55: -#line 1853 "mod/box/memcached-grammar.m" +#line 1791 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st55; if ( 48 <= (*p) && (*p) <= 57 ) goto tr90; goto st0; tr90: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st56; st56: if ( ++p == pe ) goto _test_eof56; case 56: -#line 1867 "mod/box/memcached-grammar.m" +#line 1805 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr91; case 13: goto tr92; @@ -1873,30 +1811,30 @@ case 56: goto st56; goto st0; tr106: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st57; tr92: -#line 314 "mod/box/memcached-grammar.rl" +#line 252 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} goto st57; st57: if ( ++p == pe ) goto _test_eof57; case 57: -#line 1888 "mod/box/memcached-grammar.m" +#line 1826 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr95; goto st0; tr93: -#line 314 "mod/box/memcached-grammar.rl" +#line 252 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} goto st58; st58: if ( ++p == pe ) goto _test_eof58; case 58: -#line 1900 "mod/box/memcached-grammar.m" +#line 1838 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr95; case 13: goto st57; @@ -1957,14 +1895,14 @@ case 65: } goto st0; tr107: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st66; st66: if ( ++p == pe ) goto _test_eof66; case 66: -#line 1968 "mod/box/memcached-grammar.m" +#line 1906 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr95; case 13: goto st57; @@ -2002,18 +1940,18 @@ case 70: goto tr113; goto st0; tr113: -#line 362 "mod/box/memcached-grammar.rl" +#line 300 "mod/box/memcached-grammar.rl" {incr_sign = -1;} goto st71; tr202: -#line 361 "mod/box/memcached-grammar.rl" +#line 299 "mod/box/memcached-grammar.rl" {incr_sign = 1; } goto st71; st71: if ( ++p == pe ) goto _test_eof71; case 71: -#line 2017 "mod/box/memcached-grammar.m" +#line 1955 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st71; @@ -2022,7 +1960,7 @@ case 71: goto st0; goto tr114; tr114: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2039,7 +1977,7 @@ st72: if ( ++p == pe ) goto _test_eof72; case 72: -#line 2043 "mod/box/memcached-grammar.m" +#line 1981 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st73; goto st0; @@ -2053,14 +1991,14 @@ case 73: goto tr117; goto st0; tr117: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st74; st74: if ( ++p == pe ) goto _test_eof74; case 74: -#line 2064 "mod/box/memcached-grammar.m" +#line 2002 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr118; case 13: goto tr119; @@ -2070,30 +2008,30 @@ case 74: goto st74; goto st0; tr133: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st75; tr119: -#line 315 "mod/box/memcached-grammar.rl" +#line 253 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} goto st75; st75: if ( ++p == pe ) goto _test_eof75; case 75: -#line 2085 "mod/box/memcached-grammar.m" +#line 2023 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr122; goto st0; tr120: -#line 315 "mod/box/memcached-grammar.rl" +#line 253 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} goto st76; st76: if ( ++p == pe ) goto _test_eof76; case 76: -#line 2097 "mod/box/memcached-grammar.m" +#line 2035 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr122; case 13: goto st75; @@ -2154,14 +2092,14 @@ case 83: } goto st0; tr134: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st84; st84: if ( ++p == pe ) goto _test_eof84; case 84: -#line 2165 "mod/box/memcached-grammar.m" +#line 2103 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr122; case 13: goto st75; @@ -2208,7 +2146,7 @@ case 89: goto st0; goto tr140; tr140: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2225,7 +2163,7 @@ st90: if ( ++p == pe ) goto _test_eof90; case 90: -#line 2229 "mod/box/memcached-grammar.m" +#line 2167 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2233,7 +2171,7 @@ case 90: } goto st0; tr147: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2241,14 +2179,14 @@ tr147: } goto st91; tr158: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st91; st91: if ( ++p == pe ) goto _test_eof91; case 91: -#line 2252 "mod/box/memcached-grammar.m" +#line 2190 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr141; goto st0; @@ -2266,14 +2204,14 @@ case 92: goto tr144; goto st0; tr144: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st93; st93: if ( ++p == pe ) goto _test_eof93; case 93: -#line 2277 "mod/box/memcached-grammar.m" +#line 2215 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr146; case 13: goto tr147; @@ -2283,7 +2221,7 @@ case 93: goto st93; goto st0; tr148: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2294,7 +2232,7 @@ st94: if ( ++p == pe ) goto _test_eof94; case 94: -#line 2298 "mod/box/memcached-grammar.m" +#line 2236 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2355,14 +2293,14 @@ case 101: } goto st0; tr159: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st102; st102: if ( ++p == pe ) goto _test_eof102; case 102: -#line 2366 "mod/box/memcached-grammar.m" +#line 2304 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2436,18 +2374,18 @@ case 111: } goto st0; tr186: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st112; tr175: -#line 316 "mod/box/memcached-grammar.rl" +#line 254 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} goto st112; st112: if ( ++p == pe ) goto _test_eof112; case 112: -#line 2451 "mod/box/memcached-grammar.m" +#line 2389 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr169; goto st0; @@ -2465,14 +2403,14 @@ case 113: goto tr172; goto st0; tr172: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st114; st114: if ( ++p == pe ) goto _test_eof114; case 114: -#line 2476 "mod/box/memcached-grammar.m" +#line 2414 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr174; case 13: goto tr175; @@ -2482,14 +2420,14 @@ case 114: goto st114; goto st0; tr176: -#line 316 "mod/box/memcached-grammar.rl" +#line 254 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} goto st115; st115: if ( ++p == pe ) goto _test_eof115; case 115: -#line 2493 "mod/box/memcached-grammar.m" +#line 2431 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr169; case 13: goto st112; @@ -2550,14 +2488,14 @@ case 122: } goto st0; tr187: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st123; st123: if ( ++p == pe ) goto _test_eof123; case 123: -#line 2561 "mod/box/memcached-grammar.m" +#line 2499 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr169; case 13: goto st112; @@ -2588,18 +2526,18 @@ case 126: } goto st0; tr191: -#line 358 "mod/box/memcached-grammar.rl" +#line 296 "mod/box/memcached-grammar.rl" {show_cas = false;} goto st127; tr198: -#line 359 "mod/box/memcached-grammar.rl" +#line 297 "mod/box/memcached-grammar.rl" {show_cas = true;} goto st127; st127: if ( ++p == pe ) goto _test_eof127; case 127: -#line 2603 "mod/box/memcached-grammar.m" +#line 2541 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st127; @@ -2608,7 +2546,7 @@ case 127: goto st0; goto tr193; tr193: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2625,7 +2563,7 @@ st128: if ( ++p == pe ) goto _test_eof128; case 128: -#line 2629 "mod/box/memcached-grammar.m" +#line 2567 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr195; case 13: goto st129; @@ -2832,7 +2770,7 @@ case 155: goto st0; goto tr222; tr222: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2849,7 +2787,7 @@ st156: if ( ++p == pe ) goto _test_eof156; case 156: -#line 2853 "mod/box/memcached-grammar.m" +#line 2791 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st157; goto st0; @@ -2863,49 +2801,49 @@ case 157: goto tr224; goto st0; tr224: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st158; st158: if ( ++p == pe ) goto _test_eof158; case 158: -#line 2874 "mod/box/memcached-grammar.m" +#line 2812 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr225; if ( 48 <= (*p) && (*p) <= 57 ) goto st158; goto st0; tr225: -#line 312 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st159; st159: if ( ++p == pe ) goto _test_eof159; case 159: -#line 2888 "mod/box/memcached-grammar.m" +#line 2826 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st159; if ( 48 <= (*p) && (*p) <= 57 ) goto tr228; goto st0; tr228: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st160; st160: if ( ++p == pe ) goto _test_eof160; case 160: -#line 2902 "mod/box/memcached-grammar.m" +#line 2840 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr229; if ( 48 <= (*p) && (*p) <= 57 ) goto st160; goto st0; tr229: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2916,21 +2854,21 @@ st161: if ( ++p == pe ) goto _test_eof161; case 161: -#line 2920 "mod/box/memcached-grammar.m" +#line 2858 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st161; if ( 48 <= (*p) && (*p) <= 57 ) goto tr232; goto st0; tr232: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st162; st162: if ( ++p == pe ) goto _test_eof162; case 162: -#line 2934 "mod/box/memcached-grammar.m" +#line 2872 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr233; case 13: goto tr234; @@ -2940,30 +2878,30 @@ case 162: goto st162; goto st0; tr234: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st163; tr247: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st163; st163: if ( ++p == pe ) goto _test_eof163; case 163: -#line 2955 "mod/box/memcached-grammar.m" +#line 2893 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr237; goto st0; tr235: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st164; st164: if ( ++p == pe ) goto _test_eof164; case 164: -#line 2967 "mod/box/memcached-grammar.m" +#line 2905 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st164; case 110: goto st165; @@ -3055,7 +2993,7 @@ case 175: goto st0; goto tr252; tr252: -#line 289 "mod/box/memcached-grammar.rl" +#line 227 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -3072,7 +3010,7 @@ st176: if ( ++p == pe ) goto _test_eof176; case 176: -#line 3076 "mod/box/memcached-grammar.m" +#line 3014 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st177; goto st0; @@ -3086,49 +3024,49 @@ case 177: goto tr254; goto st0; tr254: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st178; st178: if ( ++p == pe ) goto _test_eof178; case 178: -#line 3097 "mod/box/memcached-grammar.m" +#line 3035 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr255; if ( 48 <= (*p) && (*p) <= 57 ) goto st178; goto st0; tr255: -#line 312 "mod/box/memcached-grammar.rl" +#line 250 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st179; st179: if ( ++p == pe ) goto _test_eof179; case 179: -#line 3111 "mod/box/memcached-grammar.m" +#line 3049 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st179; if ( 48 <= (*p) && (*p) <= 57 ) goto tr258; goto st0; tr258: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st180; st180: if ( ++p == pe ) goto _test_eof180; case 180: -#line 3125 "mod/box/memcached-grammar.m" +#line 3063 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr259; if ( 48 <= (*p) && (*p) <= 57 ) goto st180; goto st0; tr259: -#line 305 "mod/box/memcached-grammar.rl" +#line 243 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -3139,21 +3077,21 @@ st181: if ( ++p == pe ) goto _test_eof181; case 181: -#line 3143 "mod/box/memcached-grammar.m" +#line 3081 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st181; if ( 48 <= (*p) && (*p) <= 57 ) goto tr262; goto st0; tr262: -#line 288 "mod/box/memcached-grammar.rl" +#line 226 "mod/box/memcached-grammar.rl" { fstart = p; } goto st182; st182: if ( ++p == pe ) goto _test_eof182; case 182: -#line 3157 "mod/box/memcached-grammar.m" +#line 3095 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr263; case 13: goto tr264; @@ -3163,30 +3101,30 @@ case 182: goto st182; goto st0; tr264: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st183; tr277: -#line 347 "mod/box/memcached-grammar.rl" +#line 285 "mod/box/memcached-grammar.rl" { noreply = true; } goto st183; st183: if ( ++p == pe ) goto _test_eof183; case 183: -#line 3178 "mod/box/memcached-grammar.m" +#line 3116 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr267; goto st0; tr265: -#line 313 "mod/box/memcached-grammar.rl" +#line 251 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st184; st184: if ( ++p == pe ) goto _test_eof184; case 184: -#line 3190 "mod/box/memcached-grammar.m" +#line 3128 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st184; case 110: goto st185; @@ -3482,7 +3420,7 @@ case 196: _out: {} } -#line 372 "mod/box/memcached-grammar.rl" +#line 310 "mod/box/memcached-grammar.rl" if (!done) { diff --git a/mod/box/memcached-grammar.rl b/mod/box/memcached-grammar.rl index 380982624a..5eb1e5c998 100644 --- a/mod/box/memcached-grammar.rl +++ b/mod/box/memcached-grammar.rl @@ -190,81 +190,19 @@ memcached_dispatch() } action get { - struct box_txn *txn = txn_alloc(BOX_QUIET); - txn->op = SELECT; - fiber_register_cleanup((void *)txn_cleanup, txn); - stat_collect(stat_base, MEMC_GET, 1); - stats.cmd_get++; - say_debug("ensuring space for %"PRI_SZ" keys", keys_count); - iov_ensure(keys_count * 5 + 1); - while (keys_count-- > 0) { - struct box_tuple *tuple; - struct meta *m; - void *field; - void *value; - void *suffix; - u32 key_len; - u32 value_len; - u32 suffix_len; - u32 _l; - - key = read_field(keys); - tuple = find(key); - key_len = load_varint32(&key); - - if (tuple == NULL || tuple->flags & GHOST) { - stat_collect(stat_base, MEMC_GET_MISS, 1); - stats.get_misses++; - continue; - } - - field = tuple->data; - - /* skip key */ - _l = load_varint32(&field); - field += _l; - - /* metainfo */ - _l = load_varint32(&field); - m = field; - field += _l; - - /* suffix */ - suffix_len = load_varint32(&field); - suffix = field; - field += suffix_len; - - /* value */ - value_len = load_varint32(&field); - value = field; - - if (m->exptime > 0 && m->exptime < ev_now()) { - stats.get_misses++; - stat_collect(stat_base, MEMC_GET_MISS, 1); - continue; - } else { - stats.get_hits++; - stat_collect(stat_base, MEMC_GET_HIT, 1); - } - - tuple_txn_ref(txn, tuple); - - if (show_cas) { - struct tbuf *b = tbuf_alloc(fiber->gc_pool); - tbuf_printf(b, "VALUE %.*s %"PRIu32" %"PRIu32" %"PRIu64"\r\n", key_len, (u8 *)key, m->flags, value_len, m->cas); - iov_add_unsafe(b->data, b->len); - stats.bytes_written += b->len; - } else { - iov_add_unsafe("VALUE ", 6); - iov_add_unsafe(key, key_len); - iov_add_unsafe(suffix, suffix_len); - } - iov_add_unsafe(value, value_len); - iov_add_unsafe("\r\n", 2); - stats.bytes_written += value_len + 2; + struct box_txn *txn = txn_begin(); + txn->flags |= BOX_GC_TXN; + txn->out = &box_out_quiet; + @try { + memcached_get(txn, keys_count, keys, show_cas); + txn_commit(txn); + } @catch (ClientError *e) { + txn_rollback(txn); + iov_reset(); + iov_add("SERVER_ERROR ", 13); + iov_add(e->errmsg, strlen(e->errmsg)); + iov_add("\r\n", 2); } - iov_add_unsafe("END\r\n", 5); - stats.bytes_written += 5; } action flush_all { diff --git a/mod/box/memcached.m b/mod/box/memcached.m index 287bf1d28b..a135b05d3b 100644 --- a/mod/box/memcached.m +++ b/mod/box/memcached.m @@ -68,7 +68,8 @@ natoq(const u8 *start, const u8 *end) static void store(void *key, u32 exptime, u32 flags, u32 bytes, u8 *data) { - u32 box_flags = BOX_QUIET, cardinality = 4; + u32 box_flags = 0; + u32 cardinality = 4; static u64 cas = 42; struct meta m; @@ -97,6 +98,9 @@ store(void *key, u32 exptime, u32 flags, u32 bytes, u8 *data) int key_len = load_varint32(&key); say_debug("memcached/store key:(%i)'%.*s' exptime:%"PRIu32" flags:%"PRIu32" cas:%"PRIu64, key_len, key_len, (u8 *)key, exptime, flags, cas); + + struct box_txn *txn = txn_begin(); + txn->out = &box_out_quiet; /* * Use a box dispatch wrapper which handles correctly * read-only/read-write modes. @@ -108,7 +112,7 @@ static void delete(void *key) { u32 key_len = 1; - u32 box_flags = BOX_QUIET; + u32 box_flags = 0; struct tbuf *req = tbuf_alloc(fiber->gc_pool); tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); @@ -116,6 +120,9 @@ delete(void *key) tbuf_append(req, &key_len, sizeof(key_len)); tbuf_append_field(req, key); + struct box_txn *txn = txn_begin(); + txn->out = &box_out_quiet; + rw_callback(DELETE, req); } @@ -192,6 +199,83 @@ print_stats() iov_add(out->data, out->len); } +void memcached_get(struct box_txn *txn, size_t keys_count, struct tbuf *keys, + bool show_cas) +{ + txn->op = SELECT; + stat_collect(stat_base, MEMC_GET, 1); + stats.cmd_get++; + say_debug("ensuring space for %"PRI_SZ" keys", keys_count); + iov_ensure(keys_count * 5 + 1); + while (keys_count-- > 0) { + struct box_tuple *tuple; + struct meta *m; + void *field; + void *value; + void *suffix; + u32 key_len; + u32 value_len; + u32 suffix_len; + u32 _l; + + void *key = read_field(keys); + tuple = find(key); + key_len = load_varint32(&key); + + if (tuple == NULL || tuple->flags & GHOST) { + stat_collect(stat_base, MEMC_GET_MISS, 1); + stats.get_misses++; + continue; + } + + field = tuple->data; + + /* skip key */ + _l = load_varint32(&field); + field += _l; + + /* metainfo */ + _l = load_varint32(&field); + m = field; + field += _l; + + /* suffix */ + suffix_len = load_varint32(&field); + suffix = field; + field += suffix_len; + + /* value */ + value_len = load_varint32(&field); + value = field; + + if (m->exptime > 0 && m->exptime < ev_now()) { + stats.get_misses++; + stat_collect(stat_base, MEMC_GET_MISS, 1); + continue; + } + stats.get_hits++; + stat_collect(stat_base, MEMC_GET_HIT, 1); + + tuple_txn_ref(txn, tuple); + + if (show_cas) { + struct tbuf *b = tbuf_alloc(fiber->gc_pool); + tbuf_printf(b, "VALUE %.*s %"PRIu32" %"PRIu32" %"PRIu64"\r\n", key_len, (u8 *)key, m->flags, value_len, m->cas); + iov_add_unsafe(b->data, b->len); + stats.bytes_written += b->len; + } else { + iov_add_unsafe("VALUE ", 6); + iov_add_unsafe(key, key_len); + iov_add_unsafe(suffix, suffix_len); + } + iov_add_unsafe(value, value_len); + iov_add_unsafe("\r\n", 2); + stats.bytes_written += value_len + 2; + } + iov_add_unsafe("END\r\n", 5); + stats.bytes_written += 5; +} + static void flush_all(void *data) { diff --git a/mod/box/tuple.h b/mod/box/tuple.h index 15d2f1352e..0a3ed5ca73 100644 --- a/mod/box/tuple.h +++ b/mod/box/tuple.h @@ -92,5 +92,12 @@ tuple_field(struct box_tuple *tuple, size_t i); */ void tuple_print(struct tbuf *buf, uint8_t cardinality, void *f); + +/** Tuple length when adding to iov. */ +static inline size_t tuple_len(struct box_tuple *tuple) +{ + return tuple->bsize + sizeof(tuple->bsize) + + sizeof(tuple->cardinality); +} #endif /* TARANTOOL_BOX_TUPLE_H_INCLUDED */ diff --git a/test/box_memcached/multiversioning.result b/test/box_memcached/multiversioning.result index b115dd902b..5fccf79ed9 100644 --- a/test/box_memcached/multiversioning.result +++ b/test/box_memcached/multiversioning.result @@ -13,8 +13,8 @@ set big 0 0 262144 <big-value-upper-case> STORED -# recv reply 'get big' from firs memcached client -succes: buf == reply +# recv reply 'get big' from the first memcached client +success: buf == reply show stat --- statistics: diff --git a/test/box_memcached/multiversioning.test b/test/box_memcached/multiversioning.test index 13a9cf08e0..f9f322a4d3 100644 --- a/test/box_memcached/multiversioning.test +++ b/test/box_memcached/multiversioning.test @@ -22,13 +22,14 @@ print """# Store big in lower case via first memcached client """ print "set big 0 0 %d\r\n<big-value-upper-case>" % buf_size print exec memcached2 silent "set big 0 0 %d\r\n%s\r\n" % (buf_size, buf_upper) -print """# recv reply 'get big' from firs memcached client """ +print """# recv reply 'get big' from the first memcached client """ reply = recv memcached1 silent reply_buf = reply.split('\r\n')[1] if buf == reply_buf: - print "succes: buf == reply" + print "success: buf == reply" else: print "fail: buf != reply" + print len(buf), len(reply_buf) # resore default suite config server.stop() -- GitLab