Author: stefan2
Date: Fri Apr 13 17:52:59 2012
New Revision: 1325870
URL: http://svn.apache.org/viewvc?rev=1325870&view=rev
Log:
Minimize hash key creation overhead by directly applying MD5 instead of
copying / duplicating the key. Also, check for NULL keys directly on the
interface.
* subversion/libsvn_subr/cache-membuffer.c
(get_group_index): don't calculate the 16 byte hash; require it to come in
(membuffer_cache_set, membuffer_cache_get,
membuffer_cache_get_partial, membuffer_cache_set_partial):
adapt callers; invalid groups are impossible now
(svn_membuffer_cache_t): ensure proper alignment for prefix;
add temp buffer for combined key
(combine_key): calculate & combine hashes
(svn_membuffer_cache_get, svn_membuffer_cache_set,
svn_membuffer_cache_get_partial, svn_membuffer_cache_set_partial):
adapt callers; handle NULL keys
Modified:
subversion/trunk/subversion/libsvn_subr/cache-membuffer.c
Modified: subversion/trunk/subversion/libsvn_subr/cache-membuffer.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/cache-membuffer.c?rev=1325870&r1=1325869&r2=1325870&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/trunk/subversion/libsvn_subr/cache-membuffer.c Fri Apr 13
17:52:59 2012
@@ -589,38 +589,21 @@ insert_entry(svn_membuffer_t *cache, ent
*/
static apr_uint32_t
get_group_index(svn_membuffer_t **cache,
- const void *key,
- apr_size_t len,
- unsigned char *to_find,
+ const apr_uint32_t *key,
apr_pool_t *pool)
{
- apr_uint32_t hash = 0;
- int i;
-
- /* calculate a hash value for the key */
- svn_checksum_t *checksum;
- svn_error_t *err;
-
- if (key == NULL)
- return NO_INDEX;
-
- err = svn_checksum(&checksum, svn_checksum_md5, key, len, pool);
- if (err != NULL)
- {
- svn_error_clear(err);
- return NO_INDEX;
- }
-
- memcpy(to_find, checksum->digest, APR_MD5_DIGESTSIZE);
-
- /* select the cache segment to use */
- *cache = &(*cache)[to_find[0] & ((*cache)->segment_count -1)];
+ apr_uint32_t hash;
/* Get the group that *must* contain the entry. Fold the hash value
* just to be sure (it should not be necessary for perfect hashes).
*/
- for (i = 0; i < sizeof(to_find) / sizeof(apr_uint32_t); ++i)
- hash += ((apr_uint32_t*)to_find)[i] ^ ((hash >> 19) || (hash << 13));
+ hash = key[0];
+ hash = key[1] ^ ((hash >> 19) || (hash << 13));
+ hash = key[2] ^ ((hash >> 19) || (hash << 13));
+ hash = key[3] ^ ((hash >> 19) || (hash << 13));
+
+ /* select the cache segment to use */
+ *cache = &(*cache)[key[0] & ((*cache)->segment_count -1)];
return hash % (*cache)->group_count;
}
@@ -1154,22 +1137,18 @@ membuffer_cache_set_internal(svn_membuff
static svn_error_t *
membuffer_cache_set(svn_membuffer_t *cache,
const void *key,
- apr_size_t key_len,
void *item,
svn_cache__serialize_func_t serializer,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
apr_pool_t *scratch_pool)
{
apr_uint32_t group_index;
- unsigned char to_find[KEY_SIZE];
void *buffer = NULL;
apr_size_t size;
/* find the entry group that will hold the key.
*/
- group_index = get_group_index(&cache, key, key_len, to_find, scratch_pool);
- if (group_index == NO_INDEX)
- return SVN_NO_ERROR;
+ group_index = get_group_index(&cache, key, scratch_pool);
/* Serialize data data.
*/
@@ -1180,7 +1159,7 @@ membuffer_cache_set(svn_membuffer_t *cac
*/
SVN_MUTEX__WITH_LOCK(cache->mutex,
membuffer_cache_set_internal(cache,
- to_find,
+ key,
group_index,
buffer,
size,
@@ -1262,32 +1241,22 @@ membuffer_cache_get_internal(svn_membuff
static svn_error_t *
membuffer_cache_get(svn_membuffer_t *cache,
const void *key,
- apr_size_t key_len,
void **item,
svn_cache__deserialize_func_t deserializer,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
apr_pool_t *result_pool)
{
apr_uint32_t group_index;
- unsigned char to_find[KEY_SIZE];
char *buffer;
apr_size_t size;
/* find the entry group that will hold the key.
*/
- group_index = get_group_index(&cache, key, key_len, to_find, result_pool);
- if (group_index == NO_INDEX)
- {
- /* Some error occured, return "item not found".
- */
- *item = NULL;
- return SVN_NO_ERROR;
- }
-
+ group_index = get_group_index(&cache, key, result_pool);
SVN_MUTEX__WITH_LOCK(cache->mutex,
membuffer_cache_get_internal(cache,
group_index,
- to_find,
+ key,
&buffer,
&size,
DEBUG_CACHE_MEMBUFFER_TAG
@@ -1378,7 +1347,6 @@ membuffer_cache_get_partial_internal(svn
static svn_error_t *
membuffer_cache_get_partial(svn_membuffer_t *cache,
const void *key,
- apr_size_t key_len,
void **item,
svn_boolean_t *found,
svn_cache__partial_getter_func_t deserializer,
@@ -1386,17 +1354,13 @@ membuffer_cache_get_partial(svn_membuffe
DEBUG_CACHE_MEMBUFFER_TAG_ARG
apr_pool_t *result_pool)
{
- apr_uint32_t group_index;
- unsigned char to_find[KEY_SIZE];
+ apr_uint32_t group_index = get_group_index(&cache, key, result_pool);
- group_index = get_group_index(&cache, key, key_len, to_find, result_pool);
-
- if (group_index != NO_INDEX)
- SVN_MUTEX__WITH_LOCK(cache->mutex,
- membuffer_cache_get_partial_internal
- (cache, group_index, to_find, item, found,
- deserializer, baton, DEBUG_CACHE_MEMBUFFER_TAG
- result_pool));
+ SVN_MUTEX__WITH_LOCK(cache->mutex,
+ membuffer_cache_get_partial_internal
+ (cache, group_index, key, item, found,
+ deserializer, baton, DEBUG_CACHE_MEMBUFFER_TAG
+ result_pool));
return SVN_NO_ERROR;
}
@@ -1515,25 +1479,19 @@ membuffer_cache_set_partial_internal(svn
static svn_error_t *
membuffer_cache_set_partial(svn_membuffer_t *cache,
const void *key,
- apr_size_t key_len,
svn_cache__partial_setter_func_t func,
void *baton,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
apr_pool_t *scratch_pool)
{
- apr_uint32_t group_index;
- unsigned char to_find[KEY_SIZE];
-
/* cache item lookup
*/
- group_index = get_group_index(&cache, key, key_len, to_find, scratch_pool);
-
- if (group_index != NO_INDEX)
- SVN_MUTEX__WITH_LOCK(cache->mutex,
- membuffer_cache_set_partial_internal
- (cache, group_index, to_find, func, baton,
- DEBUG_CACHE_MEMBUFFER_TAG_ARG
- scratch_pool));
+ apr_uint32_t group_index = get_group_index(&cache, key, scratch_pool);
+ SVN_MUTEX__WITH_LOCK(cache->mutex,
+ membuffer_cache_set_partial_internal
+ (cache, group_index, key, func, baton,
+ DEBUG_CACHE_MEMBUFFER_TAG_ARG
+ scratch_pool));
/* done here -> unlock the cache
*/
@@ -1576,7 +1534,7 @@ typedef struct svn_membuffer_cache_t
* This makes (very likely) our keys different from all keys used
* by other svn_membuffer_cache_t instances.
*/
- unsigned char prefix [APR_MD5_DIGESTSIZE];
+ apr_uint64_t prefix [APR_MD5_DIGESTSIZE / sizeof(apr_uint64_t)];
/* A copy of the unmodified prefix. It is being used as a user-visible
* ID for this cache instance.
@@ -1588,6 +1546,10 @@ typedef struct svn_membuffer_cache_t
*/
apr_ssize_t key_len;
+ /* Temporary buffer containing the hash key for the current access
+ */
+ apr_uint64_t combined_key [APR_MD5_DIGESTSIZE / sizeof(apr_uint64_t)];
+
/* a pool for temporary allocations during get() and set()
*/
apr_pool_t *pool;
@@ -1619,30 +1581,17 @@ typedef struct svn_membuffer_cache_t
* Allocations will be made in POOL.
*/
static void
-combine_key(const void *prefix,
- apr_size_t prefix_len,
+combine_key(svn_membuffer_cache_t *cache,
const void *key,
- apr_ssize_t key_len,
- void **full_key,
- apr_size_t *full_key_len,
- apr_pool_t *pool)
+ apr_ssize_t key_len)
{
- if (key == NULL)
- {
- *full_key = NULL;
- *full_key_len = 0;
- }
- else
- {
- if (key_len == APR_HASH_KEY_STRING)
- key_len = strlen((const char *) key);
+ if (key_len == APR_HASH_KEY_STRING)
+ key_len = strlen((const char *) key);
- *full_key_len = prefix_len + key_len;
- *full_key = apr_palloc(pool, *full_key_len);
+ apr_md5((unsigned char*)cache->combined_key, key, key_len);
- memcpy(*full_key, prefix, prefix_len);
- memcpy((char *)*full_key + prefix_len, key, key_len);
- }
+ cache->combined_key[0] ^= cache->prefix[0];
+ cache->combined_key[1] ^= cache->prefix[1];
}
/* Implement svn_cache__vtable_t.get (not thread-safe)
@@ -1656,26 +1605,25 @@ svn_membuffer_cache_get(void **value_p,
{
svn_membuffer_cache_t *cache = cache_void;
+ DEBUG_CACHE_MEMBUFFER_INIT_TAG
+
+ /* special case */
+ if (key == NULL)
+ {
+ *value_p = NULL;
+ *found = FALSE;
+
+ return SVN_NO_ERROR;
+ }
+
/* construct the full, i.e. globally unique, key by adding
* this cache instances' prefix
*/
- void *full_key;
- apr_size_t full_key_len;
-
- DEBUG_CACHE_MEMBUFFER_INIT_TAG
-
- combine_key(cache->prefix,
- sizeof(cache->prefix),
- key,
- cache->key_len,
- &full_key,
- &full_key_len,
- cache->pool);
+ combine_key(cache, key, cache->key_len);
/* Look the item up. */
SVN_ERR(membuffer_cache_get(cache->membuffer,
- full_key,
- full_key_len,
+ cache->combined_key,
value_p,
cache->deserializer,
DEBUG_CACHE_MEMBUFFER_TAG
@@ -1706,11 +1654,12 @@ svn_membuffer_cache_set(void *cache_void
{
svn_membuffer_cache_t *cache = cache_void;
- void *full_key;
- apr_size_t full_key_len;
-
DEBUG_CACHE_MEMBUFFER_INIT_TAG
+ /* special case */
+ if (key == NULL)
+ return SVN_NO_ERROR;
+
/* we do some allocations below, so increase the allocation counter
* by a slightly larger amount. Free allocated memory every now and then.
*/
@@ -1724,20 +1673,13 @@ svn_membuffer_cache_set(void *cache_void
/* construct the full, i.e. globally unique, key by adding
* this cache instances' prefix
*/
- combine_key(cache->prefix,
- sizeof(cache->prefix),
- key,
- cache->key_len,
- &full_key,
- &full_key_len,
- cache->pool);
+ combine_key(cache, key, cache->key_len);
/* (probably) add the item to the cache. But there is no real guarantee
* that the item will actually be cached afterwards.
*/
return membuffer_cache_set(cache->membuffer,
- full_key,
- full_key_len,
+ cache->combined_key,
value,
cache->serializer,
DEBUG_CACHE_MEMBUFFER_TAG
@@ -1770,28 +1712,25 @@ svn_membuffer_cache_get_partial(void **v
{
svn_membuffer_cache_t *cache = cache_void;
- void *full_key;
- apr_size_t full_key_len;
-
DEBUG_CACHE_MEMBUFFER_INIT_TAG
+ if (key == NULL)
+ {
+ *value_p = NULL;
+ *found = FALSE;
+
+ return SVN_NO_ERROR;
+ }
+
if (++cache->alloc_counter > ALLOCATIONS_PER_POOL_CLEAR)
{
apr_pool_clear(cache->pool);
cache->alloc_counter = 0;
}
- combine_key(cache->prefix,
- sizeof(cache->prefix),
- key,
- cache->key_len,
- &full_key,
- &full_key_len,
- cache->pool);
-
+ combine_key(cache, key, cache->key_len);
SVN_ERR(membuffer_cache_get_partial(cache->membuffer,
- full_key,
- full_key_len,
+ cache->combined_key,
value_p,
found,
func,
@@ -1813,27 +1752,18 @@ svn_membuffer_cache_set_partial(void *ca
{
svn_membuffer_cache_t *cache = cache_void;
- void *full_key;
- apr_size_t full_key_len;
-
DEBUG_CACHE_MEMBUFFER_INIT_TAG
- combine_key(cache->prefix,
- sizeof(cache->prefix),
- key,
- cache->key_len,
- &full_key,
- &full_key_len,
- scratch_pool);
-
- SVN_ERR(membuffer_cache_set_partial(cache->membuffer,
- full_key,
- full_key_len,
- func,
- baton,
- DEBUG_CACHE_MEMBUFFER_TAG
- scratch_pool));
-
+ if (key != NULL)
+ {
+ combine_key(cache, key, cache->key_len);
+ SVN_ERR(membuffer_cache_set_partial(cache->membuffer,
+ cache->combined_key,
+ func,
+ baton,
+ DEBUG_CACHE_MEMBUFFER_TAG
+ scratch_pool));
+ }
return SVN_NO_ERROR;
}