Index: memcached.c =================================================================== --- memcached.c (revision 1) +++ memcached.c (revision 16) @@ -715,8 +715,8 @@ char *key = ITEM_key(it); bool delete_locked = false; item *old_it = do_item_get_notedeleted(key, it->nkey, &delete_locked); - int stored = 0; - + int stored = 0; + if (old_it != NULL && comm == NREAD_ADD) { /* add only adds a nonexistent item, but promote to head of LRU */ do_item_update(old_it); @@ -1052,13 +1052,14 @@ } /* ntokens is overwritten here... shrug.. */ -static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens) { +static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_key_ptr) { char *key; size_t nkey; int i = 0; item *it; token_t *key_token = &tokens[KEY_TOKEN]; - + char suffix[255]; + uint32_t in_memory_ptr; assert(c != NULL); if (settings.managed) { @@ -1108,12 +1109,30 @@ * key * " " + flags + " " + data length + "\r\n" + data (with \r\n) */ - if (add_iov(c, "VALUE ", 6) != 0 || - add_iov(c, ITEM_key(it), it->nkey) != 0 || - add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0) - { - break; - } + + if(return_key_ptr == true) + { + in_memory_ptr = (uint32_t)item_get(key, nkey); + sprintf(suffix," %d %d %lu\r\n", atoi(ITEM_suffix(it) + 1), it->nbytes - 2, in_memory_ptr); + if (add_iov(c, "VALUE ", 6) != 0 || + add_iov(c, ITEM_key(it), it->nkey) != 0 || + add_iov(c, suffix, strlen(suffix)) != 0 || + add_iov(c, ITEM_data(it), it->nbytes) != 0) + { + break; + } + } + else + { + if (add_iov(c, "VALUE ", 6) != 0 || + add_iov(c, ITEM_key(it), it->nkey) != 0 || + add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0) + { + break; + } + } + + if (settings.verbose > 1) fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it)); @@ -1152,6 +1171,7 @@ fprintf(stderr, ">%d END\n", c->sfd); add_iov(c, "END\r\n", 5); + if (c->udp && build_udp_headers(c) != 0) { out_string(c, "SERVER_ERROR out of memory"); } @@ -1162,14 +1182,16 @@ return; } -static void process_update_command(conn *c, token_t *tokens, const size_t ntokens, int comm) { +static void process_update_command(conn *c, token_t *tokens, const size_t ntokens, int comm, bool handle_cas) { char *key; size_t nkey; int flags; time_t exptime; int vlen; + uint32_t req_memory_ptr, in_memory_ptr; + item *it; - + assert(c != NULL); if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) { @@ -1184,6 +1206,12 @@ exptime = strtol(tokens[3].value, NULL, 10); vlen = strtol(tokens[4].value, NULL, 10); + // does cas value exist? + if(tokens[5].value) + { + req_memory_ptr = strtoull(tokens[5].value, NULL, 10); + } + if(errno == ERANGE || ((flags == 0 || exptime == 0) && errno == EINVAL)) { out_string(c, "CLIENT_ERROR bad command line format"); return; @@ -1208,6 +1236,38 @@ it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2); + /* HANDLE_CAS VALIDATION */ + if(handle_cas == true) + { + item *itmp=item_get(key, it->nkey); + /* Release the reference */ + if(itmp) { + item_remove(itmp); + } + in_memory_ptr = (uint32_t)itmp; + if(in_memory_ptr == req_memory_ptr) + { + // validates allow the set + } + else if(in_memory_ptr) + { + out_string(c, "EXISTS"); + + /* swallow the data line */ + c->write_and_go = conn_swallow; + c->sbytes = vlen + 2; + return; + } + else + { + out_string(c, "NOT FOUND"); + /* swallow the data line */ + c->write_and_go = conn_swallow; + c->sbytes = vlen + 2; + return; + } + } + if (it == 0) { if (! item_size_ok(nkey, flags, vlen + 2)) out_string(c, "SERVER_ERROR object too large for cache"); @@ -1446,24 +1506,31 @@ } ntokens = tokenize_command(command, tokens, MAX_TOKENS); - if (ntokens >= 3 && ((strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) || (strcmp(tokens[COMMAND_TOKEN].value, "bget") == 0))) { - process_get_command(c, tokens, ntokens); + process_get_command(c, tokens, ntokens, false); } else if (ntokens == 6 && ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) { + + process_update_command(c, tokens, ntokens, comm, false); - process_update_command(c, tokens, ntokens, comm); + } else if (ntokens == 6 && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0)) { + process_update_command(c, tokens, ntokens, comm, true); + } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) { process_arithmetic_command(c, tokens, ntokens, 1); + } else if (ntokens >= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0)) { + + process_get_command(c, tokens, ntokens, true); + } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) { process_arithmetic_command(c, tokens, ntokens, 0);