On 10/09/2011 08:26 AM, Jim Fulton wrote: > On Sat, Oct 8, 2011 at 4:34 PM, Shane Hathaway<sh...@hathawaymix.org> wrote: >> On 10/05/2011 11:40 AM, Pedro Ferreira wrote: >>> Hello all, >>> >>> While doing some googling on ZEO + memcache I came across this: >>> >>> https://github.com/eleddy/zeo.memcache >>> >>> Has anybody ever tried it? >> >> Having implemented memcache integration for RelStorage, I now know what >> it takes to make a decent connection between memcache and ZODB. The >> code at the link above does not look sufficient to me. >> >> I could adapt the cache code in RelStorage for ZEO. I don't think it >> would be very difficult. How many people would be interested in such a >> thing? > > This would be of broad interest! > > Can you briefly describe the strategy? How do you arrange that > the client sees a consistent view of the current tid for a given > oid?
(Sorry for not replying sooner--I've been busy.) As I see it, a cache of this type can take 2 basic approaches: it can either store {oid: (state, tid)}, or it can store {(oid, tid): (state, last_tid)}. The former approach is much simpler, but since memcache has no transaction guarantees whatsoever, it would lead to consistency errors. The latter approach makes it possible to avoid all consistency errors even with memcache, but it requires interesting algorithms to make efficient use of the cache. I chose the latter. Given the choice to structure the cache as {(oid, tid): (state, last_tid)}, a simple way to use the cache would be to get the last committed tid from the database and use that tid for the lookup key. This would be extremely efficient until the next commit, at which point the entire cache would become irrelevant and would have to be rebuilt. Therefore, most of the interesting parts of the cache code in RelStorage are focused on simply choosing a good tid for the cache lookup operation. It caches the following things in memcache: 1. A pair of checkpoints. 2. A state and last committed transaction ID for a given transaction ID and object ID. 3. A commit counter. The checkpoints are two arbitrary committed transaction IDs. Clients can use any pair of committed transaction IDs as checkpoints (so it's OK if the checkpoints disappear from the cache), but the cache is much more efficient if all clients use the same checkpoints. Each storage object holds a pair of "delta" mappings, where each delta contains {oid: tid}. The deltas contain information about what objects have changed since the checkpoints: delta0 lists the changes since checkpoint0 and delta1 lists the changes between checkpoint1 and checkpoint0. Within each transaction, the delta0 mapping must be updated before reading from the database. When retrieving an object, the cache tries to discover the object's current tid by looking first in delta0. If it's there, then the cache asks memcache for the object state at that exact tid. If not, the cache asks memcache for the object state and tid at the current checkpoints. It is not actually necessary to have 2 checkpoints. It could work with more checkpoints or only 1 checkpoint, but if there were only 1, each checkpoint shift would be equivalent to flushing the cache. With more checkpoints, the cache would often query many keys for each read operation. 2 checkpoints seems like a good balance. I wrote more notes about the caching strategy here: http://svn.zope.org/relstorage/trunk/notes/caching.txt As I review all of this, I wonder at the moment why I chose to create delta1. It seems like the system would work without it. I probably added it because I thought it would improve cache efficiency, but today I'd rather simplify as much as possible even at the cost of a little theoretical efficiency. The commit counter is not very related, but since I brought it up, I'll explain it briefly: it serves as a way for clients to discover whether the database has changed without actually reading anything from the database. It is a counter rather than a transaction ID because that choice avoids a race condition. Shane _______________________________________________ For more information about ZODB, see http://zodb.org/ ZODB-Dev mailing list - ZODB-Dev@zope.org https://mail.zope.org/mailman/listinfo/zodb-dev