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.
