diff --git a/mod/box/CMakeLists.txt b/mod/box/CMakeLists.txt index 61214958604ea220bb43a528deedaa5252d8d20b..82d3da9715f07456b6d1451a4204bd2c47c2aca5 100644 --- a/mod/box/CMakeLists.txt +++ b/mod/box/CMakeLists.txt @@ -7,6 +7,9 @@ add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/mod/box/memcached-grammar.m set_property(DIRECTORY PROPERTY CLEAN_NO_CUSTOM 1) set_source_files_properties(memcached-grammar.m + PROPERTIES HEADER_FILE_ONLY true) + +set_source_files_properties(memcached.m PROPERTIES COMPILE_FLAGS "-Wno-uninitialized") -tarantool_module("box" index.m box.m memcached-grammar.m) +tarantool_module("box" index.m box.m memcached.m memcached-grammar.m) diff --git a/mod/box/memcached-grammar.m b/mod/box/memcached-grammar.m index 649532593997ab14e9c1722a7bcca5b4f5c9b694..63bc26fbf6955fab51bb98552e2ee465332399c7 100644 --- a/mod/box/memcached-grammar.m +++ b/mod/box/memcached-grammar.m @@ -1,5 +1,5 @@ -#line 1 "mod/box/memcached.rl" +#line 1 "mod/box/memcached-grammar.rl" /* * Copyright (C) 2010, 2011 Mail.RU * Copyright (C) 2010, 2011 Yuriy Vostrikov @@ -26,49 +26,8 @@ * SUCH DAMAGE. */ -#include <stdio.h> -#include <string.h> -#include <stdbool.h> -#include <unistd.h> -#include <stdlib.h> -#include <errcode.h> -#include <salloc.h> -#include <palloc.h> -#include <fiber.h> -#include <util.h> -#include <pickle.h> -#include "say.h" - -#include <tarantool.h> -#include <cfg/tarantool_box_cfg.h> -#include <mod/box/box.h> -#include <stat.h> - - -#define STAT(_) \ - _(MEMC_GET, 1) \ - _(MEMC_GET_MISS, 2) \ - _(MEMC_GET_HIT, 3) \ - _(MEMC_EXPIRED_KEYS, 4) - -ENUM(memcached_stat, STAT); -STRS(memcached_stat, STAT); -int stat_base; - -struct index *memcached_index; - -/* memcached tuple format: - <key, meta, data> */ - -struct meta { - u32 exptime; - u32 flags; - u64 cas; -} __packed__; - - -#line 72 "mod/box/memcached.m" +#line 31 "mod/box/memcached-grammar.m" static const int memcached_start = 1; static const int memcached_first_final = 197; static const int memcached_error = 0; @@ -76,153 +35,7 @@ static const int memcached_error = 0; static const int memcached_en_main = 1; -#line 71 "mod/box/memcached.rl" - - - -static u64 -natoq(const u8 *start, const u8 *end) -{ - u64 num = 0; - while (start < end) - num = num * 10 + (*start++ - '0'); - return num; -} - -static void -store(struct box_txn *txn, void *key, u32 exptime, u32 flags, u32 bytes, u8 *data) -{ - u32 box_flags = BOX_QUIET, cardinality = 4; - static u64 cas = 42; - struct meta m; - - struct tbuf *req = tbuf_alloc(fiber->pool); - - tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); - tbuf_append(req, &box_flags, sizeof(box_flags)); - tbuf_append(req, &cardinality, sizeof(cardinality)); - - tbuf_append_field(req, key); - - m.exptime = exptime; - m.flags = flags; - m.cas = cas++; - write_varint32(req, sizeof(m)); - tbuf_append(req, &m, sizeof(m)); - - char b[43]; - sprintf(b, " %"PRIu32" %"PRIu32"\r\n", flags, bytes); - write_varint32(req, strlen(b)); - tbuf_append(req, b, strlen(b)); - - write_varint32(req, bytes); - tbuf_append(req, data, bytes); - - 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); - box_process(txn, INSERT, req); /* FIXME: handle RW/RO */ -} - -static void -delete(struct box_txn *txn, void *key) -{ - u32 key_len = 1; - struct tbuf *req = tbuf_alloc(fiber->pool); - - tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); - tbuf_append(req, &key_len, sizeof(key_len)); - tbuf_append_field(req, key); - - box_process(txn, DELETE, req); -} - -static struct box_tuple * -find(void *key) -{ - return memcached_index->find(memcached_index, key); -} - -static struct meta * -meta(struct box_tuple *tuple) -{ - void *field = tuple_field(tuple, 1); - return field + 1; -} - -static bool -expired(struct box_tuple *tuple) -{ - struct meta *m = meta(tuple); - return m->exptime == 0 ? 0 : m->exptime < ev_now(); -} - -static bool -is_numeric(void *field, u32 value_len) -{ - for (int i = 0; i < value_len; i++) - if (*((u8 *)field + i) < '0' || '9' < *((u8 *)field + i)) - return false; - return true; -} - -static struct stats { - u64 total_items; - u32 curr_connections; - u32 total_connections; - u64 cmd_get; - u64 cmd_set; - u64 get_hits; - u64 get_misses; - u64 evictions; - u64 bytes_read; - u64 bytes_written; -} stats; - -static void -print_stats() -{ - u64 bytes_used, items; - struct tbuf *out = tbuf_alloc(fiber->pool); - slab_stat2(&bytes_used, &items); - - tbuf_printf(out, "STAT pid %"PRIu32"\r\n", (u32)getpid()); - tbuf_printf(out, "STAT uptime %"PRIu32"\r\n", (u32)tarantool_uptime()); - tbuf_printf(out, "STAT time %"PRIu32"\r\n", (u32)ev_now()); - tbuf_printf(out, "STAT version 1.2.5 (tarantool/box)\r\n"); - tbuf_printf(out, "STAT pointer_size %"PRI_SZ"\r\n", sizeof(void *)*8); - tbuf_printf(out, "STAT curr_items %"PRIu64"\r\n", items); - tbuf_printf(out, "STAT total_items %"PRIu64"\r\n", stats.total_items); - tbuf_printf(out, "STAT bytes %"PRIu64"\r\n", bytes_used); - tbuf_printf(out, "STAT curr_connections %"PRIu32"\r\n", stats.curr_connections); - tbuf_printf(out, "STAT total_connections %"PRIu32"\r\n", stats.total_connections); - tbuf_printf(out, "STAT connection_structures %"PRIu32"\r\n", stats.curr_connections); /* lie a bit */ - tbuf_printf(out, "STAT cmd_get %"PRIu64"\r\n", stats.cmd_get); - tbuf_printf(out, "STAT cmd_set %"PRIu64"\r\n", stats.cmd_set); - tbuf_printf(out, "STAT get_hits %"PRIu64"\r\n", stats.get_hits); - tbuf_printf(out, "STAT get_misses %"PRIu64"\r\n", stats.get_misses); - tbuf_printf(out, "STAT evictions %"PRIu64"\r\n", stats.evictions); - tbuf_printf(out, "STAT bytes_read %"PRIu64"\r\n", stats.bytes_read); - tbuf_printf(out, "STAT bytes_written %"PRIu64"\r\n", stats.bytes_written); - tbuf_printf(out, "STAT limit_maxbytes %"PRIu64"\r\n", (u64)(cfg.slab_alloc_arena * (1 << 30))); - tbuf_printf(out, "STAT threads 1\r\n"); - tbuf_printf(out, "END\r\n"); - add_iov(out->data, out->len); -} - -static void -flush_all(void *data) -{ - uintptr_t delay = (uintptr_t)data; - fiber_sleep(delay - ev_now()); - khash_t(lstr_ptr_map) *map = memcached_index->idx.str_hash; - for (khiter_t i = kh_begin(map); i != kh_end(map); i++) { - if (kh_exist(map, i)) { - struct box_tuple *tuple = kh_value(map, i); - meta(tuple)->exptime = 1; - } - } -} +#line 30 "mod/box/memcached-grammar.rl" static int __attribute__((noinline)) @@ -250,32 +63,13 @@ memcached_dispatch(struct box_txn *txn) say_debug("memcached_dispatch '%.*s'", MIN((int)(pe - p), 40) , p); -#define STORE \ -do { \ - stats.cmd_set++; \ - if (bytes > (1<<20)) { \ - add_iov("SERVER_ERROR object too large for cache\r\n", 41); \ - } else { \ - @try { \ - store(txn, key, exptime, flags, bytes, data); \ - stats.total_items++; \ - add_iov("STORED\r\n", 8); \ - } \ - @catch (ClientError *e) { \ - add_iov("SERVER_ERROR ", 13); \ - add_iov(e->errmsg, strlen(e->errmsg)); \ - add_iov("\r\n", 2); \ - } \ - } \ -} while (0) - -#line 274 "mod/box/memcached.m" +#line 68 "mod/box/memcached-grammar.m" { cs = memcached_start; } -#line 279 "mod/box/memcached.m" +#line 73 "mod/box/memcached-grammar.m" { if ( p == pe ) goto _test_eof; @@ -333,7 +127,7 @@ case 5: goto st0; goto tr15; tr15: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -350,7 +144,7 @@ st6: if ( ++p == pe ) goto _test_eof6; case 6: -#line 354 "mod/box/memcached.m" +#line 148 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st7; goto st0; @@ -364,49 +158,49 @@ case 7: goto tr17; goto st0; tr17: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st8; st8: if ( ++p == pe ) goto _test_eof8; case 8: -#line 375 "mod/box/memcached.m" +#line 169 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr18; if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; tr18: -#line 517 "mod/box/memcached.rl" +#line 311 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st9; st9: if ( ++p == pe ) goto _test_eof9; case 9: -#line 389 "mod/box/memcached.m" +#line 183 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st9; if ( 48 <= (*p) && (*p) <= 57 ) goto tr21; goto st0; tr21: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st10; st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 403 "mod/box/memcached.m" +#line 197 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr22; if ( 48 <= (*p) && (*p) <= 57 ) goto st10; goto st0; tr22: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -417,21 +211,21 @@ st11: if ( ++p == pe ) goto _test_eof11; case 11: -#line 421 "mod/box/memcached.m" +#line 215 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st11; if ( 48 <= (*p) && (*p) <= 57 ) goto tr25; goto st0; tr25: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st12; st12: if ( ++p == pe ) goto _test_eof12; case 12: -#line 435 "mod/box/memcached.m" +#line 229 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr26; case 13: goto tr27; @@ -441,11 +235,11 @@ case 12: goto st12; goto st0; tr26: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -466,13 +260,13 @@ tr26: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 269 "mod/box/memcached.rl" +#line 63 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -483,9 +277,9 @@ tr26: } goto st197; tr30: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -506,13 +300,13 @@ tr30: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 269 "mod/box/memcached.rl" +#line 63 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -523,11 +317,11 @@ tr30: } goto st197; tr39: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -548,13 +342,13 @@ tr39: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 269 "mod/box/memcached.rl" +#line 63 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -565,11 +359,11 @@ tr39: } goto st197; tr58: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -590,13 +384,13 @@ tr58: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 298 "mod/box/memcached.rl" +#line 92 "mod/box/memcached-grammar.rl" { struct tbuf *b; void *value; @@ -625,9 +419,9 @@ tr58: } goto st197; tr62: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -648,13 +442,13 @@ tr62: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 298 "mod/box/memcached.rl" +#line 92 "mod/box/memcached-grammar.rl" { struct tbuf *b; void *value; @@ -683,11 +477,11 @@ tr62: } goto st197; tr71: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -708,13 +502,13 @@ tr71: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 298 "mod/box/memcached.rl" +#line 92 "mod/box/memcached-grammar.rl" { struct tbuf *b; void *value; @@ -743,11 +537,11 @@ tr71: } goto st197; tr91: -#line 519 "mod/box/memcached.rl" +#line 313 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -768,13 +562,13 @@ tr91: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 287 "mod/box/memcached.rl" +#line 81 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -787,9 +581,9 @@ tr91: } goto st197; tr95: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -810,13 +604,13 @@ tr95: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 287 "mod/box/memcached.rl" +#line 81 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -829,11 +623,11 @@ tr95: } goto st197; tr105: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -854,13 +648,13 @@ tr105: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 287 "mod/box/memcached.rl" +#line 81 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -873,17 +667,17 @@ tr105: } goto st197; tr118: -#line 520 "mod/box/memcached.rl" +#line 314 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 325 "mod/box/memcached.rl" +#line 119 "mod/box/memcached-grammar.rl" { struct meta *m; struct tbuf *b; @@ -940,15 +734,15 @@ tr118: } goto st197; tr122: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 325 "mod/box/memcached.rl" +#line 119 "mod/box/memcached-grammar.rl" { struct meta *m; struct tbuf *b; @@ -1005,17 +799,17 @@ tr122: } goto st197; tr132: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 325 "mod/box/memcached.rl" +#line 119 "mod/box/memcached-grammar.rl" { struct meta *m; struct tbuf *b; @@ -1072,15 +866,15 @@ tr132: } goto st197; tr141: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 380 "mod/box/memcached.rl" +#line 174 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -1100,21 +894,21 @@ tr141: } goto st197; tr146: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) exptime = exptime + ev_now(); } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 380 "mod/box/memcached.rl" +#line 174 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -1134,17 +928,17 @@ tr146: } goto st197; tr157: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 380 "mod/box/memcached.rl" +#line 174 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -1164,15 +958,15 @@ tr157: } goto st197; tr169: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 475 "mod/box/memcached.rl" +#line 269 "mod/box/memcached-grammar.rl" { if (flush_delay > 0) { struct fiber *f = fiber_create("flush_all", -1, -1, flush_all, (void *)flush_delay); @@ -1184,17 +978,17 @@ tr169: } goto st197; tr174: -#line 521 "mod/box/memcached.rl" +#line 315 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 475 "mod/box/memcached.rl" +#line 269 "mod/box/memcached-grammar.rl" { if (flush_delay > 0) { struct fiber *f = fiber_create("flush_all", -1, -1, flush_all, (void *)flush_delay); @@ -1206,17 +1000,17 @@ tr174: } goto st197; tr185: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 475 "mod/box/memcached.rl" +#line 269 "mod/box/memcached-grammar.rl" { if (flush_delay > 0) { struct fiber *f = fiber_create("flush_all", -1, -1, flush_all, (void *)flush_delay); @@ -1228,15 +1022,15 @@ tr185: } goto st197; tr195: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 398 "mod/box/memcached.rl" +#line 192 "mod/box/memcached-grammar.rl" { txn->op = SELECT; fiber_register_cleanup((void *)txn_cleanup, txn); @@ -1315,25 +1109,25 @@ tr195: } goto st197; tr213: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 489 "mod/box/memcached.rl" +#line 283 "mod/box/memcached-grammar.rl" { return 0; } goto st197; tr233: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1354,13 +1148,13 @@ tr233: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 278 "mod/box/memcached.rl" +#line 72 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -1371,9 +1165,9 @@ tr233: } goto st197; tr237: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1394,13 +1188,13 @@ tr237: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 278 "mod/box/memcached.rl" +#line 72 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -1411,11 +1205,11 @@ tr237: } goto st197; tr246: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1436,13 +1230,13 @@ tr246: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 278 "mod/box/memcached.rl" +#line 72 "mod/box/memcached-grammar.rl" { key = read_field(keys); struct box_tuple *tuple = find(key); @@ -1453,11 +1247,11 @@ tr246: } goto st197; tr263: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1478,22 +1272,22 @@ tr263: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 264 "mod/box/memcached.rl" +#line 58 "mod/box/memcached-grammar.rl" { key = read_field(keys); STORE; } goto st197; tr267: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1514,24 +1308,24 @@ tr267: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 264 "mod/box/memcached.rl" +#line 58 "mod/box/memcached-grammar.rl" { key = read_field(keys); STORE; } goto st197; tr276: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 523 "mod/box/memcached.rl" +#line 317 "mod/box/memcached-grammar.rl" { size_t parsed = p - (u8 *)fiber->rbuf->data; while (fiber->rbuf->len - parsed < bytes + 2) { @@ -1552,28 +1346,28 @@ tr276: goto exit; } } -#line 544 "mod/box/memcached.rl" +#line 338 "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 264 "mod/box/memcached.rl" +#line 58 "mod/box/memcached-grammar.rl" { key = read_field(keys); STORE; } goto st197; tr281: -#line 550 "mod/box/memcached.rl" +#line 344 "mod/box/memcached-grammar.rl" { p++; } -#line 544 "mod/box/memcached.rl" +#line 338 "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 485 "mod/box/memcached.rl" +#line 279 "mod/box/memcached-grammar.rl" { print_stats(); } @@ -1582,33 +1376,33 @@ st197: if ( ++p == pe ) goto _test_eof197; case 197: -#line 1586 "mod/box/memcached.m" +#line 1380 "mod/box/memcached-grammar.m" goto st0; tr27: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st13; tr40: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st13; st13: if ( ++p == pe ) goto _test_eof13; case 13: -#line 1600 "mod/box/memcached.m" +#line 1394 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr30; goto st0; tr28: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st14; st14: if ( ++p == pe ) goto _test_eof14; case 14: -#line 1612 "mod/box/memcached.m" +#line 1406 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st14; case 110: goto st15; @@ -1701,18 +1495,18 @@ case 26: goto tr45; goto st0; tr45: -#line 558 "mod/box/memcached.rl" +#line 352 "mod/box/memcached-grammar.rl" {append = true; } goto st27; tr209: -#line 559 "mod/box/memcached.rl" +#line 353 "mod/box/memcached-grammar.rl" {append = false;} goto st27; st27: if ( ++p == pe ) goto _test_eof27; case 27: -#line 1716 "mod/box/memcached.m" +#line 1510 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st27; @@ -1721,7 +1515,7 @@ case 27: goto st0; goto tr46; tr46: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -1738,7 +1532,7 @@ st28: if ( ++p == pe ) goto _test_eof28; case 28: -#line 1742 "mod/box/memcached.m" +#line 1536 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st29; goto st0; @@ -1752,49 +1546,49 @@ case 29: goto tr49; goto st0; tr49: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st30; st30: if ( ++p == pe ) goto _test_eof30; case 30: -#line 1763 "mod/box/memcached.m" +#line 1557 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr50; if ( 48 <= (*p) && (*p) <= 57 ) goto st30; goto st0; tr50: -#line 517 "mod/box/memcached.rl" +#line 311 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st31; st31: if ( ++p == pe ) goto _test_eof31; case 31: -#line 1777 "mod/box/memcached.m" +#line 1571 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st31; if ( 48 <= (*p) && (*p) <= 57 ) goto tr53; goto st0; tr53: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 1791 "mod/box/memcached.m" +#line 1585 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr54; if ( 48 <= (*p) && (*p) <= 57 ) goto st32; goto st0; tr54: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -1805,21 +1599,21 @@ st33: if ( ++p == pe ) goto _test_eof33; case 33: -#line 1809 "mod/box/memcached.m" +#line 1603 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st33; if ( 48 <= (*p) && (*p) <= 57 ) goto tr57; goto st0; tr57: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st34; st34: if ( ++p == pe ) goto _test_eof34; case 34: -#line 1823 "mod/box/memcached.m" +#line 1617 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr58; case 13: goto tr59; @@ -1829,30 +1623,30 @@ case 34: goto st34; goto st0; tr59: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st35; tr72: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st35; st35: if ( ++p == pe ) goto _test_eof35; case 35: -#line 1844 "mod/box/memcached.m" +#line 1638 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr62; goto st0; tr60: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st36; st36: if ( ++p == pe ) goto _test_eof36; case 36: -#line 1856 "mod/box/memcached.m" +#line 1650 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st36; case 110: goto st37; @@ -1942,7 +1736,7 @@ case 47: goto st0; goto tr76; tr76: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -1959,7 +1753,7 @@ st48: if ( ++p == pe ) goto _test_eof48; case 48: -#line 1963 "mod/box/memcached.m" +#line 1757 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st49; goto st0; @@ -1973,49 +1767,49 @@ case 49: goto tr78; goto st0; tr78: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st50; st50: if ( ++p == pe ) goto _test_eof50; case 50: -#line 1984 "mod/box/memcached.m" +#line 1778 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr79; if ( 48 <= (*p) && (*p) <= 57 ) goto st50; goto st0; tr79: -#line 517 "mod/box/memcached.rl" +#line 311 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st51; st51: if ( ++p == pe ) goto _test_eof51; case 51: -#line 1998 "mod/box/memcached.m" +#line 1792 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st51; if ( 48 <= (*p) && (*p) <= 57 ) goto tr82; goto st0; tr82: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st52; st52: if ( ++p == pe ) goto _test_eof52; case 52: -#line 2012 "mod/box/memcached.m" +#line 1806 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr83; if ( 48 <= (*p) && (*p) <= 57 ) goto st52; goto st0; tr83: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2026,49 +1820,49 @@ st53: if ( ++p == pe ) goto _test_eof53; case 53: -#line 2030 "mod/box/memcached.m" +#line 1824 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st53; if ( 48 <= (*p) && (*p) <= 57 ) goto tr86; goto st0; tr86: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st54; st54: if ( ++p == pe ) goto _test_eof54; case 54: -#line 2044 "mod/box/memcached.m" +#line 1838 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr87; if ( 48 <= (*p) && (*p) <= 57 ) goto st54; goto st0; tr87: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st55; st55: if ( ++p == pe ) goto _test_eof55; case 55: -#line 2058 "mod/box/memcached.m" +#line 1852 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st55; if ( 48 <= (*p) && (*p) <= 57 ) goto tr90; goto st0; tr90: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st56; st56: if ( ++p == pe ) goto _test_eof56; case 56: -#line 2072 "mod/box/memcached.m" +#line 1866 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr91; case 13: goto tr92; @@ -2078,30 +1872,30 @@ case 56: goto st56; goto st0; tr106: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st57; tr92: -#line 519 "mod/box/memcached.rl" +#line 313 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} goto st57; st57: if ( ++p == pe ) goto _test_eof57; case 57: -#line 2093 "mod/box/memcached.m" +#line 1887 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr95; goto st0; tr93: -#line 519 "mod/box/memcached.rl" +#line 313 "mod/box/memcached-grammar.rl" {cas = natoq(fstart, p);} goto st58; st58: if ( ++p == pe ) goto _test_eof58; case 58: -#line 2105 "mod/box/memcached.m" +#line 1899 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr95; case 13: goto st57; @@ -2162,14 +1956,14 @@ case 65: } goto st0; tr107: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st66; st66: if ( ++p == pe ) goto _test_eof66; case 66: -#line 2173 "mod/box/memcached.m" +#line 1967 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr95; case 13: goto st57; @@ -2207,18 +2001,18 @@ case 70: goto tr113; goto st0; tr113: -#line 567 "mod/box/memcached.rl" +#line 361 "mod/box/memcached-grammar.rl" {incr_sign = -1;} goto st71; tr202: -#line 566 "mod/box/memcached.rl" +#line 360 "mod/box/memcached-grammar.rl" {incr_sign = 1; } goto st71; st71: if ( ++p == pe ) goto _test_eof71; case 71: -#line 2222 "mod/box/memcached.m" +#line 2016 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st71; @@ -2227,7 +2021,7 @@ case 71: goto st0; goto tr114; tr114: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2244,7 +2038,7 @@ st72: if ( ++p == pe ) goto _test_eof72; case 72: -#line 2248 "mod/box/memcached.m" +#line 2042 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st73; goto st0; @@ -2258,14 +2052,14 @@ case 73: goto tr117; goto st0; tr117: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st74; st74: if ( ++p == pe ) goto _test_eof74; case 74: -#line 2269 "mod/box/memcached.m" +#line 2063 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr118; case 13: goto tr119; @@ -2275,30 +2069,30 @@ case 74: goto st74; goto st0; tr133: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st75; tr119: -#line 520 "mod/box/memcached.rl" +#line 314 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} goto st75; st75: if ( ++p == pe ) goto _test_eof75; case 75: -#line 2290 "mod/box/memcached.m" +#line 2084 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr122; goto st0; tr120: -#line 520 "mod/box/memcached.rl" +#line 314 "mod/box/memcached-grammar.rl" {incr = natoq(fstart, p);} goto st76; st76: if ( ++p == pe ) goto _test_eof76; case 76: -#line 2302 "mod/box/memcached.m" +#line 2096 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr122; case 13: goto st75; @@ -2359,14 +2153,14 @@ case 83: } goto st0; tr134: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st84; st84: if ( ++p == pe ) goto _test_eof84; case 84: -#line 2370 "mod/box/memcached.m" +#line 2164 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr122; case 13: goto st75; @@ -2413,7 +2207,7 @@ case 89: goto st0; goto tr140; tr140: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2430,7 +2224,7 @@ st90: if ( ++p == pe ) goto _test_eof90; case 90: -#line 2434 "mod/box/memcached.m" +#line 2228 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2438,7 +2232,7 @@ case 90: } goto st0; tr147: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2446,14 +2240,14 @@ tr147: } goto st91; tr158: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st91; st91: if ( ++p == pe ) goto _test_eof91; case 91: -#line 2457 "mod/box/memcached.m" +#line 2251 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr141; goto st0; @@ -2471,14 +2265,14 @@ case 92: goto tr144; goto st0; tr144: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st93; st93: if ( ++p == pe ) goto _test_eof93; case 93: -#line 2482 "mod/box/memcached.m" +#line 2276 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr146; case 13: goto tr147; @@ -2488,7 +2282,7 @@ case 93: goto st93; goto st0; tr148: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -2499,7 +2293,7 @@ st94: if ( ++p == pe ) goto _test_eof94; case 94: -#line 2503 "mod/box/memcached.m" +#line 2297 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2560,14 +2354,14 @@ case 101: } goto st0; tr159: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st102; st102: if ( ++p == pe ) goto _test_eof102; case 102: -#line 2571 "mod/box/memcached.m" +#line 2365 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr141; case 13: goto st91; @@ -2641,18 +2435,18 @@ case 111: } goto st0; tr186: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st112; tr175: -#line 521 "mod/box/memcached.rl" +#line 315 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} goto st112; st112: if ( ++p == pe ) goto _test_eof112; case 112: -#line 2656 "mod/box/memcached.m" +#line 2450 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr169; goto st0; @@ -2670,14 +2464,14 @@ case 113: goto tr172; goto st0; tr172: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st114; st114: if ( ++p == pe ) goto _test_eof114; case 114: -#line 2681 "mod/box/memcached.m" +#line 2475 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr174; case 13: goto tr175; @@ -2687,14 +2481,14 @@ case 114: goto st114; goto st0; tr176: -#line 521 "mod/box/memcached.rl" +#line 315 "mod/box/memcached-grammar.rl" {flush_delay = natoq(fstart, p);} goto st115; st115: if ( ++p == pe ) goto _test_eof115; case 115: -#line 2698 "mod/box/memcached.m" +#line 2492 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr169; case 13: goto st112; @@ -2755,14 +2549,14 @@ case 122: } goto st0; tr187: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st123; st123: if ( ++p == pe ) goto _test_eof123; case 123: -#line 2766 "mod/box/memcached.m" +#line 2560 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr169; case 13: goto st112; @@ -2793,18 +2587,18 @@ case 126: } goto st0; tr191: -#line 563 "mod/box/memcached.rl" +#line 357 "mod/box/memcached-grammar.rl" {show_cas = false;} goto st127; tr198: -#line 564 "mod/box/memcached.rl" +#line 358 "mod/box/memcached-grammar.rl" {show_cas = true;} goto st127; st127: if ( ++p == pe ) goto _test_eof127; case 127: -#line 2808 "mod/box/memcached.m" +#line 2602 "mod/box/memcached-grammar.m" switch( (*p) ) { case 13: goto st0; case 32: goto st127; @@ -2813,7 +2607,7 @@ case 127: goto st0; goto tr193; tr193: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -2830,7 +2624,7 @@ st128: if ( ++p == pe ) goto _test_eof128; case 128: -#line 2834 "mod/box/memcached.m" +#line 2628 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr195; case 13: goto st129; @@ -3037,7 +2831,7 @@ case 155: goto st0; goto tr222; tr222: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -3054,7 +2848,7 @@ st156: if ( ++p == pe ) goto _test_eof156; case 156: -#line 3058 "mod/box/memcached.m" +#line 2852 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st157; goto st0; @@ -3068,49 +2862,49 @@ case 157: goto tr224; goto st0; tr224: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st158; st158: if ( ++p == pe ) goto _test_eof158; case 158: -#line 3079 "mod/box/memcached.m" +#line 2873 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr225; if ( 48 <= (*p) && (*p) <= 57 ) goto st158; goto st0; tr225: -#line 517 "mod/box/memcached.rl" +#line 311 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st159; st159: if ( ++p == pe ) goto _test_eof159; case 159: -#line 3093 "mod/box/memcached.m" +#line 2887 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st159; if ( 48 <= (*p) && (*p) <= 57 ) goto tr228; goto st0; tr228: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st160; st160: if ( ++p == pe ) goto _test_eof160; case 160: -#line 3107 "mod/box/memcached.m" +#line 2901 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr229; if ( 48 <= (*p) && (*p) <= 57 ) goto st160; goto st0; tr229: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -3121,21 +2915,21 @@ st161: if ( ++p == pe ) goto _test_eof161; case 161: -#line 3125 "mod/box/memcached.m" +#line 2919 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st161; if ( 48 <= (*p) && (*p) <= 57 ) goto tr232; goto st0; tr232: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st162; st162: if ( ++p == pe ) goto _test_eof162; case 162: -#line 3139 "mod/box/memcached.m" +#line 2933 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr233; case 13: goto tr234; @@ -3145,30 +2939,30 @@ case 162: goto st162; goto st0; tr234: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st163; tr247: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st163; st163: if ( ++p == pe ) goto _test_eof163; case 163: -#line 3160 "mod/box/memcached.m" +#line 2954 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr237; goto st0; tr235: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st164; st164: if ( ++p == pe ) goto _test_eof164; case 164: -#line 3172 "mod/box/memcached.m" +#line 2966 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st164; case 110: goto st165; @@ -3260,7 +3054,7 @@ case 175: goto st0; goto tr252; tr252: -#line 494 "mod/box/memcached.rl" +#line 288 "mod/box/memcached-grammar.rl" { fstart = p; for (; p < pe && *p != ' ' && *p != '\r' && *p != '\n'; p++); @@ -3277,7 +3071,7 @@ st176: if ( ++p == pe ) goto _test_eof176; case 176: -#line 3281 "mod/box/memcached.m" +#line 3075 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st177; goto st0; @@ -3291,49 +3085,49 @@ case 177: goto tr254; goto st0; tr254: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st178; st178: if ( ++p == pe ) goto _test_eof178; case 178: -#line 3302 "mod/box/memcached.m" +#line 3096 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr255; if ( 48 <= (*p) && (*p) <= 57 ) goto st178; goto st0; tr255: -#line 517 "mod/box/memcached.rl" +#line 311 "mod/box/memcached-grammar.rl" {flags = natoq(fstart, p);} goto st179; st179: if ( ++p == pe ) goto _test_eof179; case 179: -#line 3316 "mod/box/memcached.m" +#line 3110 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st179; if ( 48 <= (*p) && (*p) <= 57 ) goto tr258; goto st0; tr258: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st180; st180: if ( ++p == pe ) goto _test_eof180; case 180: -#line 3330 "mod/box/memcached.m" +#line 3124 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto tr259; if ( 48 <= (*p) && (*p) <= 57 ) goto st180; goto st0; tr259: -#line 510 "mod/box/memcached.rl" +#line 304 "mod/box/memcached-grammar.rl" { exptime = natoq(fstart, p); if (exptime > 0 && exptime <= 60*60*24*30) @@ -3344,21 +3138,21 @@ st181: if ( ++p == pe ) goto _test_eof181; case 181: -#line 3348 "mod/box/memcached.m" +#line 3142 "mod/box/memcached-grammar.m" if ( (*p) == 32 ) goto st181; if ( 48 <= (*p) && (*p) <= 57 ) goto tr262; goto st0; tr262: -#line 493 "mod/box/memcached.rl" +#line 287 "mod/box/memcached-grammar.rl" { fstart = p; } goto st182; st182: if ( ++p == pe ) goto _test_eof182; case 182: -#line 3362 "mod/box/memcached.m" +#line 3156 "mod/box/memcached-grammar.m" switch( (*p) ) { case 10: goto tr263; case 13: goto tr264; @@ -3368,30 +3162,30 @@ case 182: goto st182; goto st0; tr264: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st183; tr277: -#line 552 "mod/box/memcached.rl" +#line 346 "mod/box/memcached-grammar.rl" { noreply = true; } goto st183; st183: if ( ++p == pe ) goto _test_eof183; case 183: -#line 3383 "mod/box/memcached.m" +#line 3177 "mod/box/memcached-grammar.m" if ( (*p) == 10 ) goto tr267; goto st0; tr265: -#line 518 "mod/box/memcached.rl" +#line 312 "mod/box/memcached-grammar.rl" {bytes = natoq(fstart, p);} goto st184; st184: if ( ++p == pe ) goto _test_eof184; case 184: -#line 3395 "mod/box/memcached.m" +#line 3189 "mod/box/memcached-grammar.m" switch( (*p) ) { case 32: goto st184; case 110: goto st185; @@ -3687,7 +3481,7 @@ case 196: _out: {} } -#line 577 "mod/box/memcached.rl" +#line 371 "mod/box/memcached-grammar.rl" if (!done) { @@ -3716,120 +3510,6 @@ case 196: return 1; } -void -memcached_handler(void *_data __attribute__((unused))) -{ - struct box_txn *txn; - stats.total_connections++; - stats.curr_connections++; - int r, p; - 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; - } - - dispatch: - txn = txn_alloc(BOX_QUIET); - p = memcached_dispatch(txn); - if (p < 0) { - say_debug("negative dispatch, closing connection"); - goto exit; - } - - if (p == 0 && batch_count == 0) /* we havn't successfully parsed any requests */ - continue; - - if (p == 1) { - batch_count++; - /* some unparsed commands remain and batch count less than 20 */ - if (fiber->rbuf->len > 0 && batch_count < 20) - goto dispatch; - } - - r = fiber_flush_output(); - if (r < 0) { - say_debug("flush_output failed, closing connection"); - goto exit; - } - - stats.bytes_written += r; - fiber_gc(); - - if (p == 1 && fiber->rbuf->len > 0) { - batch_count = 0; - goto dispatch; - } - } -exit: - fiber_flush_output(); - fiber_sleep(0.01); - say_debug("exit"); - stats.curr_connections--; /* FIXME: nonlocal exit via exception will leak this counter */ -} - -void -memcached_init(void) -{ - stat_base = stat_register(memcached_stat_strs, memcached_stat_MAX); -} - -void -memcached_expire(void *data __attribute__((unused))) -{ - static khiter_t i; - khash_t(lstr_ptr_map) *map = memcached_index->idx.str_hash; - - say_info("memcached expire fiber started"); - for (;;) { - if (i > kh_end(map)) - i = kh_begin(map); - - struct tbuf *keys_to_delete = tbuf_alloc(fiber->pool); - int expired_keys = 0; - - for (int j = 0; j < cfg.memcached_expire_per_loop; j++, i++) { - if (i == kh_end(map)) { - i = kh_begin(map); - break; - } - - if (!kh_exist(map, i)) - continue; - - struct box_tuple *tuple = kh_value(map, i); - - if (!expired(tuple)) - continue; - - say_debug("expire tuple %p", tuple); - tbuf_append_field(keys_to_delete, tuple->data); - } - - while (keys_to_delete->len > 0) { - struct box_txn *txn = txn_alloc(BOX_QUIET); - @try { - delete(txn, read_field(keys_to_delete)); - expired_keys++; - } - @catch (id e) { - /* The error is already logged. */ - } - } - stat_collect(stat_base, MEMC_EXPIRED_KEYS, expired_keys); - - fiber_gc(); - - double delay = (double)cfg.memcached_expire_per_loop * cfg.memcached_expire_full_sweep / (map->size + 1); - if (delay > 1) - delay = 1; - fiber_sleep(delay); - } -} - /* * Local Variables: * mode: c diff --git a/mod/box/memcached-grammar.rl b/mod/box/memcached-grammar.rl index a698f056f776e0be2a5ddae3e8657aafa1cd3411..76bedfb69ff17243035c2342b1184ed8d9955744 100644 --- a/mod/box/memcached-grammar.rl +++ b/mod/box/memcached-grammar.rl @@ -24,198 +24,11 @@ * SUCH DAMAGE. */ -#include <stdio.h> -#include <string.h> -#include <stdbool.h> -#include <unistd.h> -#include <stdlib.h> - -#include <errcode.h> -#include <salloc.h> -#include <palloc.h> -#include <fiber.h> -#include <util.h> -#include <pickle.h> -#include "say.h" - -#include <tarantool.h> -#include <cfg/tarantool_box_cfg.h> -#include <mod/box/box.h> -#include <stat.h> - - -#define STAT(_) \ - _(MEMC_GET, 1) \ - _(MEMC_GET_MISS, 2) \ - _(MEMC_GET_HIT, 3) \ - _(MEMC_EXPIRED_KEYS, 4) - -ENUM(memcached_stat, STAT); -STRS(memcached_stat, STAT); -int stat_base; - -struct index *memcached_index; - -/* memcached tuple format: - <key, meta, data> */ - -struct meta { - u32 exptime; - u32 flags; - u64 cas; -} __packed__; - %%{ machine memcached; write data; }%% - -static u64 -natoq(const u8 *start, const u8 *end) -{ - u64 num = 0; - while (start < end) - num = num * 10 + (*start++ - '0'); - return num; -} - -static void -store(struct box_txn *txn, void *key, u32 exptime, u32 flags, u32 bytes, u8 *data) -{ - u32 box_flags = BOX_QUIET, cardinality = 4; - static u64 cas = 42; - struct meta m; - - struct tbuf *req = tbuf_alloc(fiber->pool); - - tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); - tbuf_append(req, &box_flags, sizeof(box_flags)); - tbuf_append(req, &cardinality, sizeof(cardinality)); - - tbuf_append_field(req, key); - - m.exptime = exptime; - m.flags = flags; - m.cas = cas++; - write_varint32(req, sizeof(m)); - tbuf_append(req, &m, sizeof(m)); - - char b[43]; - sprintf(b, " %"PRIu32" %"PRIu32"\r\n", flags, bytes); - write_varint32(req, strlen(b)); - tbuf_append(req, b, strlen(b)); - - write_varint32(req, bytes); - tbuf_append(req, data, bytes); - - 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); - box_process(txn, INSERT, req); /* FIXME: handle RW/RO */ -} - -static void -delete(struct box_txn *txn, void *key) -{ - u32 key_len = 1; - struct tbuf *req = tbuf_alloc(fiber->pool); - - tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); - tbuf_append(req, &key_len, sizeof(key_len)); - tbuf_append_field(req, key); - - box_process(txn, DELETE, req); -} - -static struct box_tuple * -find(void *key) -{ - return memcached_index->find(memcached_index, key); -} - -static struct meta * -meta(struct box_tuple *tuple) -{ - void *field = tuple_field(tuple, 1); - return field + 1; -} - -static bool -expired(struct box_tuple *tuple) -{ - struct meta *m = meta(tuple); - return m->exptime == 0 ? 0 : m->exptime < ev_now(); -} - -static bool -is_numeric(void *field, u32 value_len) -{ - for (int i = 0; i < value_len; i++) - if (*((u8 *)field + i) < '0' || '9' < *((u8 *)field + i)) - return false; - return true; -} - -static struct stats { - u64 total_items; - u32 curr_connections; - u32 total_connections; - u64 cmd_get; - u64 cmd_set; - u64 get_hits; - u64 get_misses; - u64 evictions; - u64 bytes_read; - u64 bytes_written; -} stats; - -static void -print_stats() -{ - u64 bytes_used, items; - struct tbuf *out = tbuf_alloc(fiber->pool); - slab_stat2(&bytes_used, &items); - - tbuf_printf(out, "STAT pid %"PRIu32"\r\n", (u32)getpid()); - tbuf_printf(out, "STAT uptime %"PRIu32"\r\n", (u32)tarantool_uptime()); - tbuf_printf(out, "STAT time %"PRIu32"\r\n", (u32)ev_now()); - tbuf_printf(out, "STAT version 1.2.5 (tarantool/box)\r\n"); - tbuf_printf(out, "STAT pointer_size %"PRI_SZ"\r\n", sizeof(void *)*8); - tbuf_printf(out, "STAT curr_items %"PRIu64"\r\n", items); - tbuf_printf(out, "STAT total_items %"PRIu64"\r\n", stats.total_items); - tbuf_printf(out, "STAT bytes %"PRIu64"\r\n", bytes_used); - tbuf_printf(out, "STAT curr_connections %"PRIu32"\r\n", stats.curr_connections); - tbuf_printf(out, "STAT total_connections %"PRIu32"\r\n", stats.total_connections); - tbuf_printf(out, "STAT connection_structures %"PRIu32"\r\n", stats.curr_connections); /* lie a bit */ - tbuf_printf(out, "STAT cmd_get %"PRIu64"\r\n", stats.cmd_get); - tbuf_printf(out, "STAT cmd_set %"PRIu64"\r\n", stats.cmd_set); - tbuf_printf(out, "STAT get_hits %"PRIu64"\r\n", stats.get_hits); - tbuf_printf(out, "STAT get_misses %"PRIu64"\r\n", stats.get_misses); - tbuf_printf(out, "STAT evictions %"PRIu64"\r\n", stats.evictions); - tbuf_printf(out, "STAT bytes_read %"PRIu64"\r\n", stats.bytes_read); - tbuf_printf(out, "STAT bytes_written %"PRIu64"\r\n", stats.bytes_written); - tbuf_printf(out, "STAT limit_maxbytes %"PRIu64"\r\n", (u64)(cfg.slab_alloc_arena * (1 << 30))); - tbuf_printf(out, "STAT threads 1\r\n"); - tbuf_printf(out, "END\r\n"); - add_iov(out->data, out->len); -} - -static void -flush_all(void *data) -{ - uintptr_t delay = (uintptr_t)data; - fiber_sleep(delay - ev_now()); - khash_t(lstr_ptr_map) *map = memcached_index->idx.str_hash; - for (khiter_t i = kh_begin(map); i != kh_end(map); i++) { - if (kh_exist(map, i)) { - struct box_tuple *tuple = kh_value(map, i); - meta(tuple)->exptime = 1; - } - } -} - - static int __attribute__((noinline)) memcached_dispatch(struct box_txn *txn) { @@ -241,25 +54,6 @@ memcached_dispatch(struct box_txn *txn) say_debug("memcached_dispatch '%.*s'", MIN((int)(pe - p), 40) , p); -#define STORE \ -do { \ - stats.cmd_set++; \ - if (bytes > (1<<20)) { \ - add_iov("SERVER_ERROR object too large for cache\r\n", 41); \ - } else { \ - @try { \ - store(txn, key, exptime, flags, bytes, data); \ - stats.total_items++; \ - add_iov("STORED\r\n", 8); \ - } \ - @catch (ClientError *e) { \ - add_iov("SERVER_ERROR ", 13); \ - add_iov(e->errmsg, strlen(e->errmsg)); \ - add_iov("\r\n", 2); \ - } \ - } \ -} while (0) - %%{ action set { key = read_field(keys); @@ -602,120 +396,6 @@ do { \ return 1; } -void -memcached_handler(void *_data __attribute__((unused))) -{ - struct box_txn *txn; - stats.total_connections++; - stats.curr_connections++; - int r, p; - 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; - } - - dispatch: - txn = txn_alloc(BOX_QUIET); - p = memcached_dispatch(txn); - if (p < 0) { - say_debug("negative dispatch, closing connection"); - goto exit; - } - - if (p == 0 && batch_count == 0) /* we havn't successfully parsed any requests */ - continue; - - if (p == 1) { - batch_count++; - /* some unparsed commands remain and batch count less than 20 */ - if (fiber->rbuf->len > 0 && batch_count < 20) - goto dispatch; - } - - r = fiber_flush_output(); - if (r < 0) { - say_debug("flush_output failed, closing connection"); - goto exit; - } - - stats.bytes_written += r; - fiber_gc(); - - if (p == 1 && fiber->rbuf->len > 0) { - batch_count = 0; - goto dispatch; - } - } -exit: - fiber_flush_output(); - fiber_sleep(0.01); - say_debug("exit"); - stats.curr_connections--; /* FIXME: nonlocal exit via exception will leak this counter */ -} - -void -memcached_init(void) -{ - stat_base = stat_register(memcached_stat_strs, memcached_stat_MAX); -} - -void -memcached_expire(void *data __attribute__((unused))) -{ - static khiter_t i; - khash_t(lstr_ptr_map) *map = memcached_index->idx.str_hash; - - say_info("memcached expire fiber started"); - for (;;) { - if (i > kh_end(map)) - i = kh_begin(map); - - struct tbuf *keys_to_delete = tbuf_alloc(fiber->pool); - int expired_keys = 0; - - for (int j = 0; j < cfg.memcached_expire_per_loop; j++, i++) { - if (i == kh_end(map)) { - i = kh_begin(map); - break; - } - - if (!kh_exist(map, i)) - continue; - - struct box_tuple *tuple = kh_value(map, i); - - if (!expired(tuple)) - continue; - - say_debug("expire tuple %p", tuple); - tbuf_append_field(keys_to_delete, tuple->data); - } - - while (keys_to_delete->len > 0) { - struct box_txn *txn = txn_alloc(BOX_QUIET); - @try { - delete(txn, read_field(keys_to_delete)); - expired_keys++; - } - @catch (id e) { - /* The error is already logged. */ - } - } - stat_collect(stat_base, MEMC_EXPIRED_KEYS, expired_keys); - - fiber_gc(); - - double delay = (double)cfg.memcached_expire_per_loop * cfg.memcached_expire_full_sweep / (map->size + 1); - if (delay > 1) - delay = 1; - fiber_sleep(delay); - } -} - /* * Local Variables: * mode: c diff --git a/mod/box/memcached.m b/mod/box/memcached.m new file mode 100644 index 0000000000000000000000000000000000000000..0643b6d32f0cace213a43153fcc2ba69562405dc --- /dev/null +++ b/mod/box/memcached.m @@ -0,0 +1,342 @@ + +#line 1 "mod/box/memcached.rl" +/* + * Copyright (C) 2010, 2011 Mail.RU + * Copyright (C) 2010, 2011 Yuriy Vostrikov + * + * 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 AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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 "tarantool.h" +#include "box.h" +#include "fiber.h" +#include "cfg/warning.h" +#include "cfg/tarantool_box_cfg.h" +#include "say.h" +#include "stat.h" +#include "salloc.h" + +#define STAT(_) \ + _(MEMC_GET, 1) \ + _(MEMC_GET_MISS, 2) \ + _(MEMC_GET_HIT, 3) \ + _(MEMC_EXPIRED_KEYS, 4) + +ENUM(memcached_stat, STAT); +STRS(memcached_stat, STAT); +int stat_base; + +struct index *memcached_index; + +/* memcached tuple format: + <key, meta, data> */ + +struct meta { + u32 exptime; + u32 flags; + u64 cas; +} __packed__; + +static u64 +natoq(const u8 *start, const u8 *end) +{ + u64 num = 0; + while (start < end) + num = num * 10 + (*start++ - '0'); + return num; +} + +static void +store(struct box_txn *txn, void *key, u32 exptime, u32 flags, u32 bytes, u8 *data) +{ + u32 box_flags = BOX_QUIET, cardinality = 4; + static u64 cas = 42; + struct meta m; + + struct tbuf *req = tbuf_alloc(fiber->pool); + + tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); + tbuf_append(req, &box_flags, sizeof(box_flags)); + tbuf_append(req, &cardinality, sizeof(cardinality)); + + tbuf_append_field(req, key); + + m.exptime = exptime; + m.flags = flags; + m.cas = cas++; + write_varint32(req, sizeof(m)); + tbuf_append(req, &m, sizeof(m)); + + char b[43]; + sprintf(b, " %"PRIu32" %"PRIu32"\r\n", flags, bytes); + write_varint32(req, strlen(b)); + tbuf_append(req, b, strlen(b)); + + write_varint32(req, bytes); + tbuf_append(req, data, bytes); + + 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); + box_process(txn, INSERT, req); /* FIXME: handle RW/RO */ +} + +static void +delete(struct box_txn *txn, void *key) +{ + u32 key_len = 1; + struct tbuf *req = tbuf_alloc(fiber->pool); + + tbuf_append(req, &cfg.memcached_namespace, sizeof(u32)); + tbuf_append(req, &key_len, sizeof(key_len)); + tbuf_append_field(req, key); + + box_process(txn, DELETE, req); +} + +static struct box_tuple * +find(void *key) +{ + return memcached_index->find(memcached_index, key); +} + +static struct meta * +meta(struct box_tuple *tuple) +{ + void *field = tuple_field(tuple, 1); + return field + 1; +} + +static bool +expired(struct box_tuple *tuple) +{ + struct meta *m = meta(tuple); + return m->exptime == 0 ? 0 : m->exptime < ev_now(); +} + +static bool +is_numeric(void *field, u32 value_len) +{ + for (int i = 0; i < value_len; i++) + if (*((u8 *)field + i) < '0' || '9' < *((u8 *)field + i)) + return false; + return true; +} + +static struct stats { + u64 total_items; + u32 curr_connections; + u32 total_connections; + u64 cmd_get; + u64 cmd_set; + u64 get_hits; + u64 get_misses; + u64 evictions; + u64 bytes_read; + u64 bytes_written; +} stats; + +static void +print_stats() +{ + u64 bytes_used, items; + struct tbuf *out = tbuf_alloc(fiber->pool); + slab_stat2(&bytes_used, &items); + + tbuf_printf(out, "STAT pid %"PRIu32"\r\n", (u32)getpid()); + tbuf_printf(out, "STAT uptime %"PRIu32"\r\n", (u32)tarantool_uptime()); + tbuf_printf(out, "STAT time %"PRIu32"\r\n", (u32)ev_now()); + tbuf_printf(out, "STAT version 1.2.5 (tarantool/box)\r\n"); + tbuf_printf(out, "STAT pointer_size %"PRI_SZ"\r\n", sizeof(void *)*8); + tbuf_printf(out, "STAT curr_items %"PRIu64"\r\n", items); + tbuf_printf(out, "STAT total_items %"PRIu64"\r\n", stats.total_items); + tbuf_printf(out, "STAT bytes %"PRIu64"\r\n", bytes_used); + tbuf_printf(out, "STAT curr_connections %"PRIu32"\r\n", stats.curr_connections); + tbuf_printf(out, "STAT total_connections %"PRIu32"\r\n", stats.total_connections); + tbuf_printf(out, "STAT connection_structures %"PRIu32"\r\n", stats.curr_connections); /* lie a bit */ + tbuf_printf(out, "STAT cmd_get %"PRIu64"\r\n", stats.cmd_get); + tbuf_printf(out, "STAT cmd_set %"PRIu64"\r\n", stats.cmd_set); + tbuf_printf(out, "STAT get_hits %"PRIu64"\r\n", stats.get_hits); + tbuf_printf(out, "STAT get_misses %"PRIu64"\r\n", stats.get_misses); + tbuf_printf(out, "STAT evictions %"PRIu64"\r\n", stats.evictions); + tbuf_printf(out, "STAT bytes_read %"PRIu64"\r\n", stats.bytes_read); + tbuf_printf(out, "STAT bytes_written %"PRIu64"\r\n", stats.bytes_written); + tbuf_printf(out, "STAT limit_maxbytes %"PRIu64"\r\n", (u64)(cfg.slab_alloc_arena * (1 << 30))); + tbuf_printf(out, "STAT threads 1\r\n"); + tbuf_printf(out, "END\r\n"); + add_iov(out->data, out->len); +} + +static void +flush_all(void *data) +{ + uintptr_t delay = (uintptr_t)data; + fiber_sleep(delay - ev_now()); + khash_t(lstr_ptr_map) *map = memcached_index->idx.str_hash; + for (khiter_t i = kh_begin(map); i != kh_end(map); i++) { + if (kh_exist(map, i)) { + struct box_tuple *tuple = kh_value(map, i); + meta(tuple)->exptime = 1; + } + } +} + +#define STORE \ +do { \ + stats.cmd_set++; \ + if (bytes > (1<<20)) { \ + add_iov("SERVER_ERROR object too large for cache\r\n", 41); \ + } else { \ + @try { \ + store(txn, key, exptime, flags, bytes, data); \ + stats.total_items++; \ + add_iov("STORED\r\n", 8); \ + } \ + @catch (ClientError *e) { \ + add_iov("SERVER_ERROR ", 13); \ + add_iov(e->errmsg, strlen(e->errmsg)); \ + add_iov("\r\n", 2); \ + } \ + } \ +} while (0) + +#include "memcached-grammar.m" + +void +memcached_handler(void *_data __attribute__((unused))) +{ + struct box_txn *txn; + stats.total_connections++; + stats.curr_connections++; + int r, p; + 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; + } + + dispatch: + txn = txn_alloc(BOX_QUIET); + p = memcached_dispatch(txn); + if (p < 0) { + say_debug("negative dispatch, closing connection"); + goto exit; + } + + if (p == 0 && batch_count == 0) /* we havn't successfully parsed any requests */ + continue; + + if (p == 1) { + batch_count++; + /* some unparsed commands remain and batch count less than 20 */ + if (fiber->rbuf->len > 0 && batch_count < 20) + goto dispatch; + } + + r = fiber_flush_output(); + if (r < 0) { + say_debug("flush_output failed, closing connection"); + goto exit; + } + + stats.bytes_written += r; + fiber_gc(); + + if (p == 1 && fiber->rbuf->len > 0) { + batch_count = 0; + goto dispatch; + } + } +exit: + fiber_flush_output(); + fiber_sleep(0.01); + say_debug("exit"); + stats.curr_connections--; /* FIXME: nonlocal exit via exception will leak this counter */ +} + +void +memcached_init(void) +{ + stat_base = stat_register(memcached_stat_strs, memcached_stat_MAX); +} + +void +memcached_expire(void *data __attribute__((unused))) +{ + static khiter_t i; + khash_t(lstr_ptr_map) *map = memcached_index->idx.str_hash; + + say_info("memcached expire fiber started"); + for (;;) { + if (i > kh_end(map)) + i = kh_begin(map); + + struct tbuf *keys_to_delete = tbuf_alloc(fiber->pool); + int expired_keys = 0; + + for (int j = 0; j < cfg.memcached_expire_per_loop; j++, i++) { + if (i == kh_end(map)) { + i = kh_begin(map); + break; + } + + if (!kh_exist(map, i)) + continue; + + struct box_tuple *tuple = kh_value(map, i); + + if (!expired(tuple)) + continue; + + say_debug("expire tuple %p", tuple); + tbuf_append_field(keys_to_delete, tuple->data); + } + + while (keys_to_delete->len > 0) { + struct box_txn *txn = txn_alloc(BOX_QUIET); + @try { + delete(txn, read_field(keys_to_delete)); + expired_keys++; + } + @catch (id e) { + /* The error is already logged. */ + } + } + stat_collect(stat_base, MEMC_EXPIRED_KEYS, expired_keys); + + fiber_gc(); + + double delay = (double)cfg.memcached_expire_per_loop * cfg.memcached_expire_full_sweep / (map->size + 1); + if (delay > 1) + delay = 1; + fiber_sleep(delay); + } +} + +/* + * Local Variables: + * mode: c + * End: + * vim: syntax=objc + */