Author: stefan2
Date: Mon Jul 11 21:34:18 2011
New Revision: 1145366
URL: http://svn.apache.org/viewvc?rev=1145366&view=rev
Log:
On svn_mutex branch:
Switch cache_membuffer to the safer __WITH_LOCK macro.
Simplify locking-related code when possible.
* subversion/libsvn_subr/cache-membuffer.c
(find_entry): mark const parameter as such
(membuffer_cache_set_internal): to-be-sync'ed part of membuffer_cache_set
(membuffer_cache_set): remainder
(membuffer_cache_get_internal): to-be-sync'ed part of membuffer_cache_get
(membuffer_cache_get): remainder
(membuffer_cache_get_partial_internal): to-be-sync'ed part of
membuffer_cache_get_partial
(membuffer_cache_get_partial): remainder
(membuffer_cache_set_partial_internal): to-be-sync'ed part of
membuffer_cache_set_partial
(membuffer_cache_set_partial): remainder
(svn_membuffer_get_segment_info): to-be-sync'ed part of
svn_membuffer_cache_get_info
(svn_membuffer_cache_get_info): remainder
Modified:
subversion/branches/svn_mutex/subversion/libsvn_subr/cache-membuffer.c
Modified: subversion/branches/svn_mutex/subversion/libsvn_subr/cache-membuffer.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_subr/cache-membuffer.c?rev=1145366&r1=1145365&r2=1145366&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_subr/cache-membuffer.c
(original)
+++ subversion/branches/svn_mutex/subversion/libsvn_subr/cache-membuffer.c Mon
Jul 11 21:34:18 2011
@@ -675,7 +675,7 @@ initialize_group(svn_membuffer_t *cache,
static entry_t *
find_entry(svn_membuffer_t *cache,
apr_uint32_t group_index,
- unsigned char *to_find,
+ const unsigned char *to_find,
svn_boolean_t find_empty)
{
entry_t *group;
@@ -1051,48 +1051,30 @@ svn_cache__membuffer_cache_create(svn_me
}
-/* Try to insert the ITEM and use the KEY to unqiuely identify it.
+/* Try to insert the serialized item given in BUFFER with SIZE into
+ * the group GROUP_INDEX of CACHE and uniquely identify it by hash
+ * value TO_FIND.
+ *
* However, there is no guarantee that it will actually be put into
- * the cache. If there is already some data associated to the KEY,
+ * the cache. If there is already some data associated with TO_FIND,
* it will be removed from the cache even if the new data cannot
* be inserted.
- *
- * The SERIALIZER is called to transform the ITEM into a single,
- * flat data buffer. Temporary allocations may be done in POOL.
+ *
+ * Note: This function requires the caller to serialization access.
+ * Don't call it directly, call membuffer_cache_get_partial instead.
*/
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)
+membuffer_cache_set_internal(svn_membuffer_t *cache,
+ const unsigned char *to_find,
+ apr_uint32_t group_index,
+ char *buffer,
+ apr_size_t size,
+ DEBUG_CACHE_MEMBUFFER_TAG_ARG
+ apr_pool_t *scratch_pool)
{
- apr_uint32_t group_index;
- unsigned char to_find[KEY_SIZE];
- entry_t *entry;
- 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, scratch_pool);
- if (group_index == NO_INDEX)
- return SVN_NO_ERROR;
-
- /* Serialize data data.
- */
- if (item)
- SVN_ERR(serializer(&buffer, &size, item, scratch_pool));
-
- /* The actual cache data access needs to sync'ed
- */
- SVN_ERR(svn_mutex__lock(cache->mutex));
-
/* if necessary, enlarge the insertion window.
*/
- if ( item != NULL
+ if ( buffer != NULL
&& cache->data_size / 4 > size
&& ensure_data_insertable(cache, size))
{
@@ -1100,7 +1082,7 @@ membuffer_cache_set(svn_membuffer_t *cac
* Get an unused entry for the key and and initialize it with
* the serialized item's (future) posion within data buffer.
*/
- entry = find_entry(cache, group_index, to_find, TRUE);
+ entry_t *entry = find_entry(cache, group_index, to_find, TRUE);
entry->size = size;
entry->offset = cache->current_data;
@@ -1129,44 +1111,76 @@ membuffer_cache_set(svn_membuffer_t *cac
*/
find_entry(cache, group_index, to_find, TRUE);
}
-
- /* done here -> unlock the cache
- */
- return svn_mutex__unlock(cache->mutex, SVN_NO_ERROR);
}
-/* Look for the *ITEM identified by KEY. If no item has been stored
- * for KEY, *ITEM will be NULL. Otherwise, the DESERIALIZER is called
- * re-construct the proper object from the serialized data.
- * Allocations will be done in POOL.
+/* Try to insert the ITEM and use the KEY to unqiuely identify it.
+ * However, there is no guarantee that it will actually be put into
+ * the cache. If there is already some data associated to the KEY,
+ * it will be removed from the cache even if the new data cannot
+ * be inserted.
+ *
+ * The SERIALIZER is called to transform the ITEM into a single,
+ * flat data buffer. Temporary allocations may be done in POOL.
*/
static svn_error_t *
-membuffer_cache_get(svn_membuffer_t *cache,
+membuffer_cache_set(svn_membuffer_t *cache,
const void *key,
apr_size_t key_len,
- void **item,
- svn_cache__deserialize_func_t deserializer,
+ void *item,
+ svn_cache__serialize_func_t serializer,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
- apr_pool_t *result_pool)
+ apr_pool_t *scratch_pool)
{
apr_uint32_t group_index;
unsigned char to_find[KEY_SIZE];
entry_t *entry;
- char *buffer;
+ char *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, result_pool);
+ group_index = get_group_index(&cache, key, key_len, to_find, scratch_pool);
if (group_index == NO_INDEX)
- {
- /* Some error occured, return "item not found".
- */
- *item = NULL;
- return SVN_NO_ERROR;
- }
+ return SVN_NO_ERROR;
- SVN_ERR(svn_mutex__lock(cache->mutex));
+ /* Serialize data data.
+ */
+ if (item)
+ SVN_ERR(serializer(&buffer, &size, item, scratch_pool));
+
+ /* The actual cache data access needs to sync'ed
+ */
+ SVN_MUTEX__WITH_LOCK(cache->mutex,
+ membuffer_cache_set_internal(cache,
+ to_find,
+ group_index,
+ buffer,
+ size,
+ DEBUG_CACHE_MEMBUFFER_TAG
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND. If no item has been stored for KEY,
+ * *BUFFER will be NULL. Otherwise, return a copy of the serialized
+ * data in *BUFFER and return its size in *ITEM_SIZE. Allocations will
+ * be done in POOL.
+ *
+ * Note: This function requires the caller to serialization access.
+ * Don't call it directly, call membuffer_cache_get_partial instead.
+ */
+static svn_error_t *
+membuffer_cache_get_internal(svn_membuffer_t *cache,
+ apr_uint32_t group_index,
+ const unsigned char *to_find,
+ char **buffer,
+ apr_size_t *item_size,
+ DEBUG_CACHE_MEMBUFFER_TAG_ARG
+ apr_pool_t *result_pool)
+{
+ entry_t *entry;
+ apr_size_t size;
/* The actual cache data access needs to sync'ed
*/
@@ -1176,13 +1190,15 @@ membuffer_cache_get(svn_membuffer_t *cac
{
/* no such entry found.
*/
- *item = NULL;
- return svn_mutex__unlock(cache->mutex, SVN_NO_ERROR);
+ *buffer = NULL;
+ *item_size = 0;
+
+ return SVN_NO_ERROR;
}
-
+
size = ALIGN_VALUE(entry->size);
- buffer = ALIGN_POINTER(apr_palloc(result_pool, size + ITEM_ALIGNMENT-1));
- memcpy(buffer, (const char*)cache->data + entry->offset, size);
+ *buffer = ALIGN_POINTER(apr_palloc(result_pool, size + ITEM_ALIGNMENT-1));
+ memcpy(*buffer, (const char*)cache->data + entry->offset, size);
#ifdef SVN_DEBUG_CACHE_MEMBUFFER
@@ -1205,45 +1221,91 @@ membuffer_cache_get(svn_membuffer_t *cac
cache->hit_count++;
cache->total_hits++;
- SVN_ERR(svn_mutex__unlock(cache->mutex, SVN_NO_ERROR));
-
- /* re-construct the original data object from its serialized form.
- */
- return deserializer(item, buffer, entry->size, result_pool);
+ *item_size = entry->size;
+
+ return SVN_NO_ERROR;
}
-/* Look for the cache entry identified by KEY and KEY_LEN. FOUND indicates
- * whether that entry exists. If not found, *ITEM will be NULL. Otherwise,
- * the DESERIALIZER is called with that entry and the BATON provided
- * and will extract the desired information. The result is set in *ITEM.
+/* Look for the *ITEM identified by KEY. If no item has been stored
+ * for KEY, *ITEM will be NULL. Otherwise, the DESERIALIZER is called
+ * re-construct the proper object from the serialized data.
* Allocations will be done in POOL.
*/
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,
- void *baton,
- DEBUG_CACHE_MEMBUFFER_TAG_ARG
- apr_pool_t *result_pool)
+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];
- entry_t *entry;
- svn_error_t *err = SVN_NO_ERROR;
+ 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;
+ }
- SVN_ERR(svn_mutex__lock(cache->mutex));
+ SVN_MUTEX__WITH_LOCK(cache->mutex,
+ membuffer_cache_get_internal(cache,
+ group_index,
+ to_find,
+ &buffer,
+ &size,
+ DEBUG_CACHE_MEMBUFFER_TAG
+ result_pool));
- entry = find_entry(cache, group_index, to_find, FALSE);
+ /* re-construct the original data object from its serialized form.
+ */
+ if (buffer == NULL)
+ {
+ *item = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ return deserializer(item, buffer, size, result_pool);
+}
+
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND. FOUND indicates whether that entry exists.
+ * If not found, *ITEM will be NULL.
+ *
+ * Otherwise, the DESERIALIZER is called with that entry and the BATON
+ * provided and will extract the desired information. The result is set
+ * in *ITEM. Allocations will be done in POOL.
+ *
+ * Note: This function requires the caller to serialization access.
+ * Don't call it directly, call membuffer_cache_get_partial instead.
+ */
+static svn_error_t *
+membuffer_cache_get_partial_internal(svn_membuffer_t *cache,
+ apr_uint32_t group_index,
+ const unsigned char *to_find,
+ void **item,
+ svn_boolean_t *found,
+ svn_cache__partial_getter_func_t
deserializer,
+ void *baton,
+ DEBUG_CACHE_MEMBUFFER_TAG_ARG
+ apr_pool_t *result_pool)
+{
+ entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
cache->total_reads++;
if (entry == NULL)
{
*item = NULL;
*found = FALSE;
+
+ return SVN_NO_ERROR;
}
else
{
@@ -1271,50 +1333,75 @@ membuffer_cache_get_partial(svn_membuffe
#endif
- err = deserializer(item,
- (const char*)cache->data + entry->offset,
- entry->size,
- baton,
- result_pool);
+ return deserializer(item,
+ (const char*)cache->data + entry->offset,
+ entry->size,
+ baton,
+ result_pool);
}
-
- /* done here -> unlock the cache
- */
- return svn_mutex__unlock(cache->mutex, err);
}
-/* Look for the cache entry identified by KEY and KEY_LEN. If no entry
- * has been found, the function returns without modifying the cache.
- * Otherwise, FUNC is called with that entry and the BATON provided
- * and may modify the cache entry. Allocations will be done in POOL.
+/* Look for the cache entry identified by KEY and KEY_LEN. FOUND indicates
+ * whether that entry exists. If not found, *ITEM will be NULL. Otherwise,
+ * the DESERIALIZER is called with that entry and the BATON provided
+ * and will extract the desired information. The result is set in *ITEM.
+ * Allocations will be done in POOL.
*/
static svn_error_t *
-membuffer_cache_set_partial(svn_membuffer_t *cache,
+membuffer_cache_get_partial(svn_membuffer_t *cache,
const void *key,
apr_size_t key_len,
- svn_cache__partial_setter_func_t func,
+ void **item,
+ svn_boolean_t *found,
+ svn_cache__partial_getter_func_t deserializer,
void *baton,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
- apr_pool_t *scratch_pool)
+ apr_pool_t *result_pool)
{
apr_uint32_t group_index;
unsigned char to_find[KEY_SIZE];
- entry_t *entry;
- svn_error_t *err = SVN_NO_ERROR;
- /* cache item lookup
- */
- group_index = get_group_index(&cache, key, key_len, to_find, scratch_pool);
+ group_index = get_group_index(&cache, key, key_len, to_find, result_pool);
- SVN_ERR(svn_mutex__lock(cache->mutex));
+ 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));
- entry = find_entry(cache, group_index, to_find, FALSE);
+ return SVN_NO_ERROR;
+}
+
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND. If no entry has been found, the function
+ * returns without modifying the cache.
+ *
+ * Otherwise, FUNC is called with that entry and the BATON provided
+ * and may modify the cache entry. Allocations will be done in POOL.
+ *
+ * Note: This function requires the caller to serialization access.
+ * Don't call it directly, call membuffer_cache_set_partial instead.
+ */
+static svn_error_t *
+membuffer_cache_set_partial_internal(svn_membuffer_t *cache,
+ apr_uint32_t group_index,
+ const unsigned char *to_find,
+ svn_cache__partial_setter_func_t func,
+ void *baton,
+ DEBUG_CACHE_MEMBUFFER_TAG_ARG
+ apr_pool_t *scratch_pool)
+{
+ /* cache item lookup
+ */
+ entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
cache->total_reads++;
/* this function is a no-op if the item is not in cache
*/
if (entry != NULL)
{
+ svn_error_t *err;
+
/* access the serialized cache item */
char *data = (char*)cache->data + entry->offset;
char *orig_data = data;
@@ -1388,9 +1475,41 @@ membuffer_cache_set_partial(svn_membuffe
}
}
+ return SVN_NO_ERROR;
+}
+
+/* Look for the cache entry identified by KEY and KEY_LEN. If no entry
+ * has been found, the function returns without modifying the cache.
+ * Otherwise, FUNC is called with that entry and the BATON provided
+ * and may modify the cache entry. Allocations will be done in POOL.
+ */
+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];
+ entry_t *entry;
+ svn_error_t *err = SVN_NO_ERROR;
+
+ /* cache item lookup
+ */
+ group_index = get_group_index(&cache, key, key_len, to_find, scratch_pool);
+
+ 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));
+
/* done here -> unlock the cache
*/
- return svn_mutex__unlock(cache->mutex, err);
+ return SVN_NO_ERROR;
}
/* Implement the svn_cache__t interface on top of a shared membuffer cache.
@@ -1693,6 +1812,23 @@ svn_membuffer_cache_is_cachable(void *ca
&& (size < APR_UINT32_MAX - ITEM_ALIGNMENT);
}
+/* Add statistics of SEGMENT to INFO.
+ */
+static svn_error_t *
+svn_membuffer_get_segment_info(svn_membuffer_t *segment,
+ svn_cache__info_t *info)
+{
+ info->data_size += segment->data_size;
+ info->used_size += segment->data_used;
+ info->total_size += segment->data_size +
+ segment->group_count * GROUP_SIZE * sizeof(entry_t);
+
+ info->used_entries += segment->used_entries;
+ info->total_entries += segment->group_count * GROUP_SIZE;
+
+ return SVN_NO_ERROR;
+}
+
/* Implement svn_cache__vtable_t.get_info
*/
static svn_error_t *
@@ -1720,18 +1856,8 @@ svn_membuffer_cache_get_info(void *cache
for (i = 0; i < cache->membuffer->segment_count; ++i)
{
svn_membuffer_t *segment = cache->membuffer + i;
-
- SVN_ERR(svn_mutex__lock(segment->mutex));
-
- info->data_size += segment->data_size;
- info->used_size += segment->data_used;
- info->total_size += segment->data_size +
- segment->group_count * GROUP_SIZE * sizeof(entry_t);
-
- info->used_entries += segment->used_entries;
- info->total_entries += segment->group_count * GROUP_SIZE;
-
- SVN_ERR(svn_mutex__unlock(segment->mutex, SVN_NO_ERROR));
+ SVN_MUTEX__WITH_LOCK(segment->mutex,
+ svn_membuffer_get_segment_info(segment, info));
}
return SVN_NO_ERROR;