In inprocess-cache.c the following pattern is common: svn_error_t *inprocess_callback() { SVN_ERR(lock_cache(cache)); SVN_ERR(body()); SVN_ERR(unlock_cache(cache)); return something; }
So, if an error occurs, then all future cache calls deadlock; and it's easy to forget to balance lock/unlock calls even by accident. Suggestions: * Move to a with_cache_locked() callback paradigm, as already done in FSFS and libsvn_wc. This is harder to read but will encourage minimizing critical sections and will ensure that the cache is properly unlocked on non-fatal error conditions (i.e., those that don't correspond to a corrupted cache). * Alternatively, add SVN_ERR_ASSERT(cache->is_locked) to relevant helper functions. This will ensure that locks are either cleared or (if stale) noisily complained about, but not deadlock. * If body() discovers a fatal error condition... well, we could just SVN_ERR_ASSERT() out. Or we could set cache->malfunctioning := TRUE and then check that at all entry points. * [ this is somewhat orthogonal ] The cache passes through (unmodified) all errors from the serialize/deserialize functions. Aren't them some conditions that we'd like those callbacks to be able to signal (to the cache or to the cache's user)? For example: SVN_ERR_CACHE_CORRUPT SVN_ERR_CACHE_DESERIALIZE_SAID_NOT_FOUND SVN_ERR_CACHE_DESERIALIZE_FAILED Thoughts? Barring objections I'll look into implementing something that eliminates the potential deadlock.