summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDustin Sallings <dustin@spy.net>2009-02-11 18:03:14 -0800
committerDustin Sallings <dustin@spy.net>2009-02-11 18:03:14 -0800
commitbad6c614e58639d0685706f17dc9562323c30f39 (patch)
tree72c54982d8cbc049f0b8353289255842acedc3f3
parented69f308cbf9b562d389c2dfe122551ae4e9cfa2 (diff)
downloadmemcached-bad6c614e58639d0685706f17dc9562323c30f39.tar.gz
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
-rw-r--r--items.c1
-rw-r--r--items.h2
-rw-r--r--memcached.c4
-rw-r--r--t/cas.t27
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");