| | 145 | { |
|---|
| | 146 | diag "MultiGet"; |
|---|
| | 147 | $mc->add('xx', 5, 1, "ex"); |
|---|
| | 148 | $mc->add('wye', 5, 2, "why"); |
|---|
| | 149 | my $rv = $mc->getMulti(qw(xx wye zed)); |
|---|
| | 150 | |
|---|
| | 151 | is_deeply([1, 'ex'], $rv->{xx}, "X is correct"); |
|---|
| | 152 | is_deeply([2, 'why'], $rv->{wye}, "Y is correct"); |
|---|
| | 153 | is(keys(%$rv), 2, "Got only two answers like we expect"); |
|---|
| | 154 | } |
|---|
| | 155 | |
|---|
| 145 | | def testMultiGet(self): |
|---|
| 146 | | """Testing multiget functionality""" |
|---|
| 147 | | self.mc.add("x", 5, 1, "ex") |
|---|
| 148 | | self.mc.add("y", 5, 2, "why") |
|---|
| 149 | | vals=self.mc.getMulti('xyz') |
|---|
| 150 | | self.assertEquals((1, 'ex'), vals['x']) |
|---|
| 151 | | self.assertEquals((2, 'why'), vals['y']) |
|---|
| 152 | | self.assertEquals(2, len(vals)) |
|---|
| 153 | | |
|---|
| 181 | | |
|---|
| 182 | | def testCas(self): |
|---|
| 183 | | """Test CAS operation.""" |
|---|
| 184 | | try: |
|---|
| 185 | | self.mc.cas("x", 5, 19, 0x7fffffffff, "bad value") |
|---|
| 186 | | self.fail("Expected error CASing with no existing value") |
|---|
| 187 | | except MemcachedError, e: |
|---|
| 188 | | self.assertEquals(memcacheConstants.ERR_NOT_FOUND, e.status) |
|---|
| 189 | | self.mc.add("x", 5, 19, "original value") |
|---|
| 190 | | flags, i, val=self.mc.gets("x") |
|---|
| 191 | | self.assertEquals("original value", val) |
|---|
| 192 | | try: |
|---|
| 193 | | self.mc.cas("x", 5, 19, i+1, "broken value") |
|---|
| 194 | | self.fail("Expected error CASing with invalid id") |
|---|
| 195 | | except MemcachedError, e: |
|---|
| 196 | | self.assertEquals(memcacheConstants.ERR_EXISTS, e.status) |
|---|
| 197 | | self.mc.cas("x", 5, 19, i, "new value") |
|---|
| 198 | | newflags, newi, newval=self.mc.gets("x") |
|---|
| 199 | | self.assertEquals("new value", newval) |
|---|
| 200 | | |
|---|
| 201 | | # Test a CAS replay |
|---|
| 202 | | try: |
|---|
| 203 | | self.mc.cas("x", 5, 19, i, "crap value") |
|---|
| 204 | | self.fail("Expected error CASing with invalid id") |
|---|
| 205 | | except MemcachedError, e: |
|---|
| 206 | | self.assertEquals(memcacheConstants.ERR_EXISTS, e.status) |
|---|
| 207 | | newflags, newi, newval=self.mc.gets("x") |
|---|
| 208 | | self.assertEquals("new value", newval) |
|---|
| | 185 | |
|---|
| | 186 | { |
|---|
| | 187 | diag "CAS"; |
|---|
| | 188 | $mc->flush; |
|---|
| | 189 | |
|---|
| | 190 | { |
|---|
| | 191 | my $rv =()= eval { $mc->cas("x", 5, 19, 0x7FFFFFFFFF, "bad value") }; |
|---|
| | 192 | is($rv, 0, "Empty return on expected failure"); |
|---|
| | 193 | ok($@->not_found, "Error was 'not found' as expected"); |
|---|
| | 194 | } |
|---|
| | 195 | |
|---|
| | 196 | $mc->add("x", 5, 19, "original value"); |
|---|
| | 197 | |
|---|
| | 198 | my ($flags, $i, $val) = $mc->gets("x"); |
|---|
| | 199 | is($val, "original value", "->gets returned proper value"); |
|---|
| | 200 | |
|---|
| | 201 | { |
|---|
| | 202 | my $rv =()= eval { $mc->cas("x", 5, 19, $i+1, "broken value") }; |
|---|
| | 203 | is($rv, 0, "Empty return on expected failure (1)"); |
|---|
| | 204 | ok($@->exists, "Expected error state of 'exists' (1)"); |
|---|
| | 205 | } |
|---|
| | 206 | |
|---|
| | 207 | $mc->cas("x", 5, 19, $i, "new value"); |
|---|
| | 208 | |
|---|
| | 209 | my ($newflags, $newi, $newval) = $mc->gets("x"); |
|---|
| | 210 | is($newval, "new value", "CAS properly overwrote value"); |
|---|
| | 211 | |
|---|
| | 212 | { |
|---|
| | 213 | my $rv =()= eval { $mc->cas("x", 5, 19, $i, "replay value") }; |
|---|
| | 214 | is($rv, 0, "Empty return on expected failure (2)"); |
|---|
| | 215 | ok($@->exists, "Expected error state of 'exists' (2)"); |
|---|
| | 216 | } |
|---|
| | 217 | |
|---|
| | 218 | (undef, undef, my $newval2) = $mc->gets("x"); |
|---|
| | 219 | is($newval2, "new value", "CAS replay didn't overwrite value"); |
|---|
| | 220 | } |
|---|
| | 391 | sub getMulti { |
|---|
| | 392 | my $self = shift; |
|---|
| | 393 | my @keys = @_; |
|---|
| | 394 | |
|---|
| | 395 | for (my $i = 0; $i < @keys; $i++) { |
|---|
| | 396 | $self->_sendCmd(::CMD_GETQ, $keys[$i], '', $i); |
|---|
| | 397 | } |
|---|
| | 398 | |
|---|
| | 399 | my $terminal = @keys + 10; |
|---|
| | 400 | $self->_sendCmd(::CMD_NOOP, '', '', $terminal); |
|---|
| | 401 | |
|---|
| | 402 | my %return; |
|---|
| | 403 | |
|---|
| | 404 | while (1) { |
|---|
| | 405 | my ($opaque, $data) = $self->_handleSingleResponse; |
|---|
| | 406 | last if $opaque == $terminal; |
|---|
| | 407 | |
|---|
| | 408 | $return{$keys[$opaque]} = [$self->__parseGet($data)]; |
|---|
| | 409 | } |
|---|
| | 410 | return %return if wantarray; |
|---|
| | 411 | return \%return; |
|---|
| | 412 | } |
|---|
| | 413 | |
|---|
| 392 | | <<EOT; |
|---|
| 393 | | def cas(self, key, exp, flags, oldVal, val): |
|---|
| 394 | | """CAS in a new value for the given key and comparison value.""" |
|---|
| 395 | | self._doCmd(memcacheConstants.CMD_CAS, key, val, |
|---|
| 396 | | struct.pack(CAS_PKT_FMT, flags, exp, oldVal)) |
|---|
| 397 | | |
|---|
| 398 | | def getMulti(self, keys): |
|---|
| 399 | | """Get values for any available keys in the given iterable. |
|---|
| 400 | | |
|---|
| 401 | | Returns a dict of matched keys to their values.""" |
|---|
| 402 | | opaqued=dict(enumerate(keys)) |
|---|
| 403 | | terminal=len(opaqued)+10 |
|---|
| 404 | | # Send all of the keys in quiet |
|---|
| 405 | | for k,v in opaqued.iteritems(): |
|---|
| 406 | | self._sendCmd(memcacheConstants.CMD_GETQ, v, '', k) |
|---|
| 407 | | |
|---|
| 408 | | self._sendCmd(memcacheConstants.CMD_NOOP, '', '', terminal) |
|---|
| 409 | | |
|---|
| 410 | | # Handle the response |
|---|
| 411 | | rv={} |
|---|
| 412 | | done=False |
|---|
| 413 | | while not done: |
|---|
| 414 | | opaque, data=self._handleSingleResponse(None) |
|---|
| 415 | | if opaque != terminal: |
|---|
| 416 | | rv[opaqued[opaque]]=self.__parseGet(data) |
|---|
| 417 | | else: |
|---|
| 418 | | done=True |
|---|
| 419 | | |
|---|
| 420 | | return rv |
|---|
| 421 | | |
|---|
| 422 | | EOT |
|---|
| | 426 | sub cas { |
|---|
| | 427 | my $self = shift; |
|---|
| | 428 | my ($key, $exp, $flags, $oldVal, $val) = @_; |
|---|
| | 429 | |
|---|
| | 430 | my $oldVal_hi = int($oldVal / 2 ** 32); |
|---|
| | 431 | my $oldVal_lo = int($oldVal % 2 ** 32); |
|---|
| | 432 | |
|---|
| | 433 | return $self->_doCmd(::CMD_CAS, $key, $val, pack(::CAS_PKT_FMT, $flags, $exp, $oldVal_hi, $oldVal_lo)); |
|---|
| | 434 | } |
|---|