Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_subr/cache-membuffer.c view on Meta::CPAN
{
apr_status_t status;
if (cache->allow_blocking_writes)
{
status = apr_thread_rwlock_wrlock(cache->lock);
}
else
{
status = apr_thread_rwlock_trywrlock(cache->lock);
if (SVN_LOCK_IS_BUSY(status))
{
*success = FALSE;
status = APR_SUCCESS;
}
}
if (status)
return svn_error_wrap_apr(status,
_("Can't write-lock cache mutex"));
}
#endif
return SVN_NO_ERROR;
}
/* If locking is supported for CACHE, acquire an unconditional write lock
* for it.
*/
static svn_error_t *
force_write_lock_cache(svn_membuffer_t *cache)
{
#if APR_HAS_THREADS
apr_status_t status = apr_thread_rwlock_wrlock(cache->lock);
if (status)
return svn_error_wrap_apr(status,
_("Can't write-lock cache mutex"));
#endif
return SVN_NO_ERROR;
}
/* If locking is supported for CACHE, release the current lock
* (read or write).
*/
static svn_error_t *
unlock_cache(svn_membuffer_t *cache, svn_error_t *err)
{
#if APR_HAS_THREADS
if (cache->lock)
{
apr_status_t status = apr_thread_rwlock_unlock(cache->lock);
if (err)
return err;
if (status)
return svn_error_wrap_apr(status, _("Can't unlock cache mutex"));
}
#endif
return err;
}
/* If supported, guard the execution of EXPR with a read lock to cache.
* Macro has been modeled after SVN_MUTEX__WITH_LOCK.
*/
#define WITH_READ_LOCK(cache, expr) \
do { \
SVN_ERR(read_lock_cache(cache)); \
SVN_ERR(unlock_cache(cache, (expr))); \
} while (0)
/* If supported, guard the execution of EXPR with a write lock to cache.
* Macro has been modeled after SVN_MUTEX__WITH_LOCK.
*
* The write lock process is complicated if we don't allow to wait for
* the lock: If we didn't get the lock, we may still need to remove an
* existing entry for the given key because that content is now stale.
* Once we discovered such an entry, we unconditionally do a blocking
* wait for the write lock. In case no old content could be found, a
* failing lock attempt is simply a no-op and we exit the macro.
*/
#define WITH_WRITE_LOCK(cache, expr) \
do { \
svn_boolean_t got_lock = TRUE; \
SVN_ERR(write_lock_cache(cache, &got_lock)); \
if (!got_lock) \
{ \
svn_boolean_t exists; \
SVN_ERR(entry_exists(cache, group_index, key, &exists)); \
if (exists) \
SVN_ERR(force_write_lock_cache(cache)); \
else \
break; \
} \
SVN_ERR(unlock_cache(cache, (expr))); \
} while (0)
/* Resolve a dictionary entry reference, i.e. return the entry
* for the given IDX.
*/
static APR_INLINE entry_t *
get_entry(svn_membuffer_t *cache, apr_uint32_t idx)
{
return &cache->directory[idx / GROUP_SIZE].entries[idx % GROUP_SIZE];
}
/* Get the entry references for the given ENTRY.
*/
static APR_INLINE apr_uint32_t
get_index(svn_membuffer_t *cache, entry_t *entry)
{
apr_size_t group_index
= ((char *)entry - (char *)cache->directory) / sizeof(entry_group_t);
return (apr_uint32_t)group_index * GROUP_SIZE
+ (apr_uint32_t)(entry - cache->directory[group_index].entries);
}
/* Remove the used ENTRY from the CACHE, i.e. make it "unused".
* In contrast to insertion, removal is possible for any entry.
*/
static void
drop_entry(svn_membuffer_t *cache, entry_t *entry)
{
/* the group that ENTRY belongs to plus a number of useful index values
*/
apr_uint32_t idx = get_index(cache, entry);
apr_uint32_t group_index = idx / GROUP_SIZE;
entry_group_t *group = &cache->directory[group_index];
apr_uint32_t last_in_group = group_index * GROUP_SIZE + group->used - 1;
/* Only valid to be called for used entries.
*/
( run in 0.510 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )