Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_fs_fs/tree.c view on Meta::CPAN
lock->pool = pool;
lock->next = cache->first_lock;
lock->prev = NULL;
if (cache->first_lock)
cache->first_lock->prev = lock;
cache->first_lock = lock;
/* instruct POOL to remove the look upon cleanup */
apr_pool_cleanup_register(pool,
lock,
unlock_cache,
apr_pool_cleanup_null);
}
/* Clears the CACHE at regular intervals (destroying all cached nodes)
*/
static void
auto_clear_dag_cache(fs_fs_dag_cache_t* cache)
{
if (cache->first_lock == NULL && cache->insertions > BUCKET_COUNT)
{
svn_pool_clear(cache->pool);
memset(cache->buckets, 0, sizeof(cache->buckets));
cache->insertions = 0;
}
}
/* For the given REVISION and PATH, return the respective entry in CACHE.
If the entry is empty, its NODE member will be NULL and the caller
may then set it to the corresponding DAG node allocated in CACHE->POOL.
*/
static cache_entry_t *
cache_lookup( fs_fs_dag_cache_t *cache
, svn_revnum_t revision
, const char *path)
{
apr_size_t i, bucket_index;
apr_size_t path_len = strlen(path);
apr_uint32_t hash_value = (apr_uint32_t)revision;
#if SVN_UNALIGNED_ACCESS_IS_OK
/* "randomizing" / distributing factor used in our hash function */
const apr_uint32_t factor = 0xd1f3da69;
#endif
/* optimistic lookup: hit the same bucket again? */
cache_entry_t *result = &cache->buckets[cache->last_hit];
if ( (result->revision == revision)
&& (result->path_len == path_len)
&& !memcmp(result->path, path, path_len))
{
return result;
}
/* need to do a full lookup. Calculate the hash value
(HASH_VALUE has been initialized to REVISION). */
i = 0;
#if SVN_UNALIGNED_ACCESS_IS_OK
/* We relax the dependency chain between iterations by processing
two chunks from the input per hash_value self-multiplication.
The HASH_VALUE update latency is now 1 MUL latency + 1 ADD latency
per 2 chunks instead of 1 chunk.
*/
for (; i + 8 <= path_len; i += 8)
hash_value = hash_value * factor * factor
+ ( *(const apr_uint32_t*)(path + i) * factor
+ *(const apr_uint32_t*)(path + i + 4));
#endif
for (; i < path_len; ++i)
/* Help GCC to minimize the HASH_VALUE update latency by splitting the
MUL 33 of the naive implementation: h = h * 33 + path[i]. This
shortens the dependency chain from 1 shift + 2 ADDs to 1 shift + 1 ADD.
*/
hash_value = hash_value * 32 + (hash_value + (unsigned char)path[i]);
bucket_index = hash_value + (hash_value >> 16);
bucket_index = (bucket_index + (bucket_index >> 8)) % BUCKET_COUNT;
/* access the corresponding bucket and remember its location */
result = &cache->buckets[bucket_index];
cache->last_hit = bucket_index;
/* if it is *NOT* a match, clear the bucket, expect the caller to fill
in the node and count it as an insertion */
if ( (result->hash_value != hash_value)
|| (result->revision != revision)
|| (result->path_len != path_len)
|| memcmp(result->path, path, path_len))
{
result->hash_value = hash_value;
result->revision = revision;
if (result->path_len < path_len)
result->path = apr_palloc(cache->pool, path_len + 1);
result->path_len = path_len;
memcpy(result->path, path, path_len + 1);
result->node = NULL;
cache->insertions++;
}
return result;
}
/* 2nd level cache */
/* Find and return the DAG node cache for ROOT and the key that
should be used for PATH. */
static void
locate_cache(svn_cache__t **cache,
const char **key,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool)
{
if (root->is_txn_root)
{
fs_txn_root_data_t *frd = root->fsap_data;
( run in 0.527 second using v1.01-cache-2.11-cpan-71847e10f99 )