Is incr/decr atomic in multithread mode?

dormando dormando at rydia.net
Mon Feb 25 08:28:02 UTC 2008


Steve Chu wrote:
> On Mon, Feb 25, 2008 at 2:51 PM, dormando <dormando at rydia.net> wrote:
>> I think this is fine?
>>
>>  Since the operations are independently atomic, it's perfectly valid for
>>  two threads to incr the same value.
>>
> 
> But for client api, they seems NOT atomic, because when Thread A just
> has 'item_get' done but before 'add_delta', Thread B can still do
> item_get.
> 
> X-> set "foo" 1
> A-> item_get "foo"
> B-> item_get "foo"
> A-> add_delta "foo" by 1
> B-> add_delta "foo" by 1
> 
> then A and B both hold value 2, which one should be stored?
> 
> And the exact value we need is 3, right? I am not quit sure, correct
> me if i am wrong:)

The result gets copied into the thread-local 'temp' buffer, then copied
into that connection (implicitly atomic)'s output buffer.

So actually I read the code wrong the first time. This _should_ do the
right thing:

We have threads (A, B, X):

X -> set 'foo' 1

A -> process_arithmetic_command()
note thread local storage (char temp[])
B -> same.

A -> it = item_get(key, nkey)
(atomically increments the refcount for that item, returns a reference
to it)
B -> same, same time.
(same)

A -> out_string(c, add_delta(it, incr, delta, temp));
add_delta runs atomically, copies the result of the addition into the
thread local 'temp' buffer and _returns the 'temp' buffer_ (which
contains 2)
B -> out_string(c, add_delta(it, incr, delta, temp));
Gets serialized behind A, and its 'temp' then holds a value one higher
than A's (containing 3)
A -> runs out_string(c, temp), with 'temp' having the atomically
incremented value.
A -> inside out_string, copy's the contents of the original 'temp'
buffer into the connection's local write buffer, then sets the
connection into write mode (which will flush its buffer before doing
further processing). Then returns.
A -> returns to the state machine, 'temp' goes to the wolves, etc.
A -> sends value '2' to its client.

B -> Same thing. Client should receive a '3'.

Apologies to the original patch author and the list for the confusion :)
I had mentally confused "normal" responses and "get" responses, which
operate differently.

-Dormando

>>  It's possible that with two threads (A, B):
>>
>>  X -> set "foo" 1
>>  A -> incr "foo" by 1
>>  B -> incr "foo" by 1
>>
>>  A -> returns 3
>>  B -> returns 3
>>
>>  The only guarantee the slabber makes for returning values, is that they
>>  won't get deleted before being transferred through the network.
>>
>>  Could be wrong, but that's my impression from checking the sources.
>>
>>  -Dormando
>>
>>
>>
>>  Steve Chu wrote:
>>  > In 'process_arithmetic_command' function:
>>  > We first do item_get from slabs and then do add_delta to incr/decr the value.
>>  >
>>  > My question is:
>>  > Is this atomic in multithread mode? Item_get is atomic and so is
>>  > add_delta because they are protected by mutex. But the entire two
>>  > operations seems NOT atomic. Two threads can both do item_get with
>>  > same key, then both incr it, and write back.
>>  >
>>  > Anybody can tell me whether it is a bug or not?
>>  >
>>  > Regards,
>>  >
>>  > Steve Chu
>>
>>
> 



More information about the memcached mailing list