diff options
author | Dustin Sallings <dustin@spy.net> | 2011-09-28 01:07:55 -0700 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2011-09-28 01:26:45 -0700 |
commit | 2096c491453f4278fdc2fc03759fccfd98ad4168 (patch) | |
tree | 46611e7b8575dd20d4a67f3e34a1e00dad2f4f99 | |
parent | cff1f1403a1e575955993854ea087bc83ec6ebaf (diff) | |
download | memcached-2096c491453f4278fdc2fc03759fccfd98ad4168.tar.gz |
bug220: incr would sometimes return the previous item's CAS
This happens when we allocate a new item instead of reusing the space
of an existing one, but consistently set the CAS from the original
item's CAS (which is being discarded).
-rw-r--r-- | memcached.c | 3 | ||||
-rwxr-xr-x | t/binary.t | 40 |
2 files changed, 39 insertions, 4 deletions
diff --git a/memcached.c b/memcached.c index 95a0124..a578b10 100644 --- a/memcached.c +++ b/memcached.c @@ -3069,6 +3069,9 @@ enum delta_result_type do_add_delta(conn *c, const char *key, const size_t nkey, memcpy(ITEM_data(new_it), buf, res); memcpy(ITEM_data(new_it) + res, "\r\n", 2); item_replace(it, new_it); + // Overwrite the older item's CAS with our new CAS since we're + // returning the CAS of the old item below. + ITEM_set_cas(it, (settings.use_cas) ? ITEM_get_cas(new_it) : 0); do_item_remove(new_it); /* release our reference */ } else { /* replace in-place */ /* When changing the value without replacing the item, we @@ -2,7 +2,7 @@ use strict; use warnings; -use Test::More tests => 3450; +use Test::More tests => 3470; use FindBin qw($Bin); use lib "$Bin/lib"; use MemcachedTest; @@ -200,6 +200,22 @@ is($mc->decr("x"), 4, "Decrease by one"); is($mc->decr("x", 211), 0, "Floor is zero"); { + # diag "bug220 + my ($rv, $cas) = $mc->set("bug220", "100", 0, 0); + my ($irv, $icas) = $mc->incr_cas("bug220", 999); + ok($icas != $cas); + is($irv, 1099, "Incr amount failed"); + my ($flags, $val, $gcas) = $mc->get("bug220"); + is($gcas, $icas, "CAS didn't match after incr/gets"); + + ($irv, $icas) = $mc->incr_cas("bug220", 999); + ok($icas != $cas); + is($irv, 2098, "Incr amount failed"); + ($flags, $val, $gcas) = $mc->get("bug220"); + is($gcas, $icas, "CAS didn't match after incr/gets"); +} + +{ # diag "bug21"; $mc->add("bug21", "9223372036854775807", 0, 0); is($mc->incr("bug21"), 9223372036854775808, "First incr for bug21."); @@ -620,18 +636,24 @@ sub _incrdecr_header { return $extra_header; } -sub _incrdecr { +sub _incrdecr_cas { my $self = shift; my ($cmd, $key, $amt, $init, $exp) = @_; - my ($data, undef) = $self->_do_command($cmd, $key, '', + my ($data, $rcas) = $self->_do_command($cmd, $key, '', $self->_incrdecr_header($amt, $init, $exp)); my $header = substr $data, 0, 8, ''; my ($resp_hi, $resp_lo) = unpack "NN", $header; my $resp = ($resp_hi * 2 ** 32) + $resp_lo; - return $resp; + return $resp, $rcas; +} + +sub _incrdecr { + my $self = shift; + my ($v, $c) = $self->_incrdecr_cas(@_); + return $v } sub silent_incrdecr { @@ -779,6 +801,16 @@ sub incr { return $self->_incrdecr(::CMD_INCR, $key, $amt, $init, $exp); } +sub incr_cas { + my $self = shift; + my ($key, $amt, $init, $exp) = @_; + $amt = 1 unless defined $amt; + $init = 0 unless defined $init; + $exp = 0 unless defined $exp; + + return $self->_incrdecr_cas(::CMD_INCR, $key, $amt, $init, $exp); +} + sub decr { my $self = shift; my ($key, $amt, $init, $exp) = @_; |