I guess it depends on how much throughput you're expecting through the
bit of the system which requires the lock - I agree that if there is
huge contention then this isn't the way to go, although I'd argue that
you should be changing your design anyway since synchronizing across a
distributed architecture for a lot of threads is just unadvisable.

Memcache API calls currently take ~3ms according to the status page -
running a quick (and dirty ;) ) test with 100 threads attempting to
lock using the above method averages out at ~40ms for one of the
threads to obtain the lock.  If the API call times increase from 3 to
10ms, the time taken for one of the threads to obtain the lock
actually decreases to ~30ms!  The biggest risk you run is that because
it isn't FIFO, there may be a large portion of time before a
particular thread obtains the lock and so it may time out.

On Dec 15, 3:06 pm, Jay Young <[email protected]> wrote:
> I considered the increment decrement approach, but it creates a race
> condition with the counter.  Having many different threads/tasks
> trying to grab the lock at the same time  could increment the number
> above one, even when no one has the lock because there is still a
> period of time between the increment() and decrement().  Remember,
> these are RPC calls going over the network.  If any part of that
> interaction is slow, there will be even longer periods between the +1
> and -1.  I think this method errs on the side of accidentally locking
> when there isn't a lock.  The only negatives I see would apply to any
> lock that's implemented in a cache.
>
> On Dec 15, 8:23 am, Simon <[email protected]> wrote:
>
> > Hi,
>
> > I think the following should work with the following caveats:
> > - there's a small danger that if the server blows up before it
> > releases the lock, that no threads would be able to update your cache,
> > but since it's only a cache of data. This is easily mitigated by
> > introducing a task which periodically resets the lock.
> > - I still believe that there's the possibility that separate instances
> > will get a non-updated object, even if you use the locking, since I'm
> > assuming it takes x-amount of time for the changes in MemCache to
> > propagate throughout the instances.  I may be wrong in this assumption
> > however.
>
> > Anyway, your code would go something like:
>
> > boolean lockAcquired = false;
>
> > try {
> >     lockAcquired = acquireLock();
> >     doStuff();} finally {
>
> >     if (lockAcquired) {
> >         releaseLock();
> >     }
>
> > }
>
> > With the locking code being:
>
> >     public static boolean acquireLock() {
>
> >         boolean lockAcquired = true;
> >         try {
> >             while (increment() != 1) {
> >                 decrement();
> >                 Thread.sleep(500);
> >             }
> >         } catch (Throwable t) {
> >             // Log error
> >             lockAcquired = false;
> >         }
>
> >         return lockAcquired;
> >     }
>
> >     public static void releaseLock() {
> >         decrement();
> >     }
>
> >     private static void decrement() {
> >         MemcacheServiceFactory.getMemcacheService().increment("LOCK",
> > -1, 0L);
> >     }
>
> >     private static Long increment() {
> >         return
> > MemcacheServiceFactory.getMemcacheService().increment("LOCK", 1, 0L);
> >     }
>
> > On Dec 14, 9:56 pm, Jay Young <[email protected]> wrote:
>
> > > Grr.  Just noticed another issue.  The cache item that you get the
> > > index is not the same item as the lock, so really you need two
> > > different cache items, one to make sure you have a unique value for
> > > the lock, and the lock itself.  The code above is correct, you just
> > > need different keys for the first two cache reads.
>
> > > If you can generate a guaranteed-unique name (maybe the thread ID +
> > > time?), you can drop the first cache item and use that as the lock
> > > value.  This would also prevent the issue with the code above if the
> > > lockIndex item is ever evicted and re-read at the same time (thus
> > > returning 0 for both), or if it overflows the long.
>
> > > (I honestly don't know if this is iron-clad, but intuitively it seems
> > > like it would work with only very minor edge cases.)
>
> > > On Dec 14, 4:08 pm, Andrei Cosmin Fifiiþã <[email protected]>
> > > wrote:
>
> > > > Hmmmm, super...
> > > > I was thinking of smth like (val mod 2) == 0/1 (true/false), but the 
> > > > lock
> > > > reading wasn't safe.
> > > > Thanks!
>
> > > > On 14 December 2010 20:57, Jay Young <[email protected]> wrote:
>
> > > > > Except return lockIndex should just be return true.
>
> > > > > --
> > > > > You received this message because you are subscribed to the Google 
> > > > > Groups
> > > > > "Google App Engine for Java" group.
> > > > > To post to this group, send email to
> > > > > [email protected].
> > > > > To unsubscribe from this group, send email to
> > > > > [email protected]<google-appengine-java%2B
> > > > >  [email protected]>
> > > > > .
> > > > > For more options, visit this group at
> > > > >http://groups.google.com/group/google-appengine-java?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine for Java" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to