From bad6c614e58639d0685706f17dc9562323c30f39 Mon Sep 17 00:00:00 2001 From: Dustin Sallings Date: Wed, 11 Feb 2009 18:03:14 -0800 Subject: Update CAS on non-replace incr/decr. This fixes a problem reported as bug 15 where incr and decr do not change CAS values when they aren't completely replacing the item (which is the typical case). http://code.google.com/p/memcached/issues/detail?id=15 --- items.c | 1 - items.h | 2 ++ memcached.c | 4 ++++ t/cas.t | 27 ++++++++++++++++++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/items.c b/items.c index 8c69384..79e93cf 100644 --- a/items.c +++ b/items.c @@ -17,7 +17,6 @@ /* Forward Declarations */ static void item_link_q(item *it); static void item_unlink_q(item *it); -static uint64_t get_cas_id(void); /* * We only reposition items in the LRU queue if they haven't been repositioned diff --git a/items.h b/items.h index 660cc8a..0c680a2 100644 --- a/items.h +++ b/items.h @@ -1,5 +1,7 @@ /* See items.c */ void item_init(void); +uint64_t get_cas_id(void); + /*@null@*/ item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_time_t exptime, const int nbytes); void item_free(item *it); diff --git a/memcached.c b/memcached.c index 508f04d..a5fc781 100644 --- a/memcached.c +++ b/memcached.c @@ -2633,6 +2633,10 @@ char *do_add_delta(conn *c, item *it, const bool incr, const int64_t delta, char item_replace(it, new_it); do_item_remove(new_it); /* release our reference */ } else { /* replace in-place */ + /* When changing the value without replacing the item, we + need to update the CAS on the existing item. */ + ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0); + memcpy(ITEM_data(it), buf, res); memset(ITEM_data(it) + res, ' ', it->nbytes - res - 2); } diff --git a/t/cas.t b/t/cas.t index 9208c1e..a84fdd9 100644 --- a/t/cas.t +++ b/t/cas.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use strict; -use Test::More tests => 30; +use Test::More tests => 39; use FindBin qw($Bin); use lib "$Bin/lib"; use MemcachedTest; @@ -115,3 +115,28 @@ ok( ( $res1 eq "STORED\r\n" && $res2 eq "EXISTS\r\n") || ( $res1 eq "EXISTS\r\n" && $res2 eq "STORED\r\n"), "cas on same item from two sockets"); +### bug 15: http://code.google.com/p/memcached/issues/detail?id=15 + +# set foo +print $sock "set bug15 0 0 1\r\n0\r\n"; +is(scalar <$sock>, "STORED\r\n", "stored 0"); + +# Check out the first gets. +print $sock "gets bug15\r\n"; +ok(scalar <$sock> =~ /VALUE bug15 0 1 (\d+)\r\n/, "gets bug15 regexp success"); +my $bug15_cas = $1; +is(scalar <$sock>, "0\r\n", "gets bug15 data is 0"); +is(scalar <$sock>, "END\r\n","gets bug15 END"); + +# Increment +print $sock "incr bug15 1\r\n"; +is(scalar <$sock>, "1\r\n", "incr worked"); + +# Validate a changed CAS +print $sock "gets bug15\r\n"; +ok(scalar <$sock> =~ /VALUE bug15 0 1 (\d+)\r\n/, "gets bug15 regexp success"); +my $next_bug15_cas = $1; +is(scalar <$sock>, "1\r\n", "gets bug15 data is 0"); +is(scalar <$sock>, "END\r\n","gets bug15 END"); + +ok($bug15_cas != $next_bug15_cas, "CAS changed"); -- cgit v1.2.1