Is incr/decr atomic in multithread mode?

dormando dormando at rydia.net
Mon Feb 25 16:41:44 UTC 2008


The delta add can't really use atomic routines in this case, but the 
mutex could be split up more finely (we're only really locking that 
_item_, not the entire cache).

There *are* a number of places where atomic tests (from gcc and from 
solaris) would allow us to remove some locks. I think at least a few 
people from the list know where these parts are, and folks are just 
looking for time.

-Dormando

Paul van den Bogaard wrote:
> if there are too many mutex calls these can become scalability issues. 
> Solaris 10 has some atomic routines that could be helpfull.
> See 
> http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/sys/atomic.h 
> 
> 
> for the routines.
> 
> Of course if multiple operations are needed that need the protection of 
> a mutex than a atomic operation is no alternative, besides a CPU 
> consuming polling device. And sometimes these come in handy too.
> 
> --Paul
> 
> 
> On 25-feb-2008, at 10:53, Steve Chu wrote:
> 
>> On Mon, Feb 25, 2008 at 4:28 PM, dormando <dormando at rydia.net> wrote:
>>> 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)
>>
>> Here I am confused. Every thread has a local var 'temp' and here
>> 'temp' should hold 2.  'temp' is independent, and doesn't share
>> between threads. So thread B should overwrite the value in the
>> slabber. Am I right?
>>
>>>  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
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>>
>>
>> -- 
>> Steve Chu
>> http://stvchu.org
> 
> --------------------------------------------------------------------------------------------- 
> 
> Paul van den Bogaard                               
> Paul.vandenBogaard at sun.com
> ISV-E  -- ISV Engineering, Opensource Engineering group
> 
> Sun Microsystems, Inc                              phone:        +31 334 
> 515 918
> Saturnus 1                                                 extentsion: x 
> (70)15918
> 3824 ME Amersfoort                                 mobile:       +31 651 
> 913 354
> The Netherlands                                        fax:            
> +31 334 515 001
> 



More information about the memcached mailing list