ndb needs to do multiple memcache sets and gets in order to avoid potential race conditions because there are no Datastore-memcache transactions. In order to do this correctly, ndb needs to lock memcache and ensure that only one ndb tasklet actually updates the memcache entry.
When you perform a get()
for an entity not in memcache, the following happens:
- Check memcache for entity.
- The entity wasn't found, write a LOCK value to the memcache key for this entity.
- Do another immediate memcache get to get the cas token.
- Do a get from datastore.
- Put the entity in memcache with compare and swap.
The extra Set
(step 2) is from locking the memcache entry associated with the entity while you get it from the datastore.
The extra Get
(step 3) is to get the compare and swap token. This ensures that if the memcache entry was updated between steps 2 and 5, the tasklet will not overwrite the memcache entry.
If you're interested, I would recommend looking at the code that does this.