mjibson/goon — pull request #2 by xStrom (2013-03-27 20:23:12+00:00)
Title: Fixed a common race condition regarding memcache usage.

The previous implementations of ```Goon.DeleteMulti``` and ```Goon.PutMulti``` had a flaw that made them susceptible to a **common race condition**. Specifically, those functions updated the memcache before the datastore.

To illustrate the race condition, consider three parallel requests.

Time Request #1 Request #2 Request #3
T+000ms DeleteMulti() starts
T+010ms memcache cleared
T+020ms Get() starts
T+030ms memcache updated with entity
T+040ms datastore cleared
T+050ms Get() starts
T+060ms entity read from memcache
---
Result: entity == nil entity != nil entity != nil

Like the third request in the example, any further request with a Get() will **incorrectly** belive that the entity still exists, because the cache isn't synchronized with the datastore.

Now, lets look at what happens when my changes are applied.

Time Request #1 Request #2 Request #3
T+000ms DeleteMulti() starts
T+010ms memcache deferred
T+020ms Get() starts
T+030ms memcache updated with entity
T+040ms datastore cleared
T+050ms memcache cleared Get() starts
T+060ms no entity found in memcache/datastore
---
Result: entity == nil entity != nil entity == nil

Like the third request in the example, any further request with a Get() will belive that the entity does not exist, because the cache is **correctly synchronized** with the datastore.