You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2013/05/10 16:58:56 UTC
svn commit: r1481041 [19/38] - in /subversion/branches/master-passphrase: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
contrib/client-side/svncopy/ contrib/hook-scripts/
contrib/server-side/fsfsfixer/ contrib/server-side/fsfsf...
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c Fri May 10 14:58:47 2013
@@ -26,6 +26,7 @@
#include <apr_tables.h>
#include <apr_strings.h>
+#include "svn_hash.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
@@ -35,6 +36,7 @@
#include "svn_dso.h"
#include "svn_version.h"
#include "private/svn_auth_private.h"
+#include "private/svn_dep_compat.h"
#include "auth.h"
@@ -152,17 +154,14 @@ svn_auth_open(svn_auth_baton_t **auth_ba
provider = APR_ARRAY_IDX(providers, i, svn_auth_provider_object_t *);
/* Add it to the appropriate table in the auth_baton */
- table = apr_hash_get(ab->tables,
- provider->vtable->cred_kind, APR_HASH_KEY_STRING);
+ table = svn_hash_gets(ab->tables, provider->vtable->cred_kind);
if (! table)
{
table = apr_pcalloc(pool, sizeof(*table));
table->providers
= apr_array_make(pool, 1, sizeof(svn_auth_provider_object_t *));
- apr_hash_set(ab->tables,
- provider->vtable->cred_kind, APR_HASH_KEY_STRING,
- table);
+ svn_hash_sets(ab->tables, provider->vtable->cred_kind, table);
}
APR_ARRAY_PUSH(table->providers, svn_auth_provider_object_t *)
= provider;
@@ -178,17 +177,26 @@ svn_auth_set_parameter(svn_auth_baton_t
const char *name,
const void *value)
{
- apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
+ svn_hash_sets(auth_baton->parameters, name, value);
}
const void *
svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
const char *name)
{
- return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
+ return svn_hash_gets(auth_baton->parameters, name);
}
+/* Return the key used to address the in-memory cache of auth
+ credentials of type CRED_KIND and associated with REALMSTRING. */
+static const char *
+make_cache_key(const char *cred_kind,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
+}
svn_error_t *
svn_auth_first_credentials(void **credentials,
@@ -208,16 +216,15 @@ svn_auth_first_credentials(void **creden
const char *cache_key;
/* Get the appropriate table of providers for CRED_KIND. */
- table = apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING);
+ table = svn_hash_gets(auth_baton->tables, cred_kind);
if (! table)
return svn_error_createf(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
_("No provider registered for '%s' credentials"),
cred_kind);
/* First, see if we have cached creds in the auth_baton. */
- cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
- creds = apr_hash_get(auth_baton->creds_cache,
- cache_key, APR_HASH_KEY_STRING);
+ cache_key = make_cache_key(cred_kind, realmstring, pool);
+ creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
if (creds)
{
got_first = FALSE;
@@ -230,9 +237,11 @@ svn_auth_first_credentials(void **creden
{
provider = APR_ARRAY_IDX(table->providers, i,
svn_auth_provider_object_t *);
- SVN_ERR(provider->vtable->first_credentials
- (&creds, &iter_baton, provider->provider_baton,
- auth_baton->parameters, realmstring, auth_baton->pool));
+ SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton,
+ provider->provider_baton,
+ auth_baton->parameters,
+ realmstring,
+ auth_baton->pool));
if (creds != NULL)
{
@@ -258,10 +267,9 @@ svn_auth_first_credentials(void **creden
*state = iterstate;
/* Put the creds in the cache */
- apr_hash_set(auth_baton->creds_cache,
- apr_pstrdup(auth_baton->pool, cache_key),
- APR_HASH_KEY_STRING,
- creds);
+ svn_hash_sets(auth_baton->creds_cache,
+ apr_pstrdup(auth_baton->pool, cache_key),
+ creds);
}
*credentials = creds;
@@ -290,27 +298,24 @@ svn_auth_next_credentials(void **credent
svn_auth_provider_object_t *);
if (! state->got_first)
{
- SVN_ERR(provider->vtable->first_credentials
- (&creds, &(state->provider_iter_baton),
- provider->provider_baton, auth_baton->parameters,
- state->realmstring, auth_baton->pool));
+ SVN_ERR(provider->vtable->first_credentials(
+ &creds, &(state->provider_iter_baton),
+ provider->provider_baton, auth_baton->parameters,
+ state->realmstring, auth_baton->pool));
state->got_first = TRUE;
}
- else
+ else if (provider->vtable->next_credentials)
{
- if (provider->vtable->next_credentials)
- SVN_ERR(provider->vtable->next_credentials
- (&creds, state->provider_iter_baton,
- provider->provider_baton, auth_baton->parameters,
- state->realmstring, auth_baton->pool));
+ SVN_ERR(provider->vtable->next_credentials(
+ &creds, state->provider_iter_baton,
+ provider->provider_baton, auth_baton->parameters,
+ state->realmstring, auth_baton->pool));
}
if (creds != NULL)
{
/* Put the creds in the cache */
- apr_hash_set(auth_baton->creds_cache,
- state->cache_key, APR_HASH_KEY_STRING,
- creds);
+ svn_hash_sets(auth_baton->creds_cache, state->cache_key, creds);
break;
}
@@ -338,15 +343,13 @@ svn_auth_save_credentials(svn_auth_iters
return SVN_NO_ERROR;
auth_baton = state->auth_baton;
- creds = apr_hash_get(state->auth_baton->creds_cache,
- state->cache_key, APR_HASH_KEY_STRING);
+ creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
if (! creds)
return SVN_NO_ERROR;
/* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
- no_auth_cache = apr_hash_get(auth_baton->parameters,
- SVN_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING);
+ no_auth_cache = svn_hash_gets(auth_baton->parameters,
+ SVN_AUTH_PARAM_NO_AUTH_CACHE);
if (no_auth_cache)
return SVN_NO_ERROR;
@@ -389,6 +392,32 @@ svn_auth_save_credentials(svn_auth_iters
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_auth_forget_credentials(svn_auth_baton_t *auth_baton,
+ const char *cred_kind,
+ const char *realmstring,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring));
+
+ /* If we have a CRED_KIND and REALMSTRING, we clear out just the
+ cached item (if any). Otherwise, empty the whole hash. */
+ if (cred_kind)
+ {
+ svn_hash_sets(auth_baton->creds_cache,
+ make_cache_key(cred_kind, realmstring, scratch_pool),
+ NULL);
+ }
+ else
+ {
+ apr_hash_clear(auth_baton->creds_cache);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
svn_auth_ssl_server_cert_info_t *
svn_auth_ssl_server_cert_info_dup
(const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
@@ -619,20 +648,3 @@ svn_auth_get_platform_specific_client_pr
return SVN_NO_ERROR;
}
-
-svn_error_t *
-svn_auth_cleanup_walk(svn_auth_baton_t *baton,
- svn_auth_cleanup_callback cleanup,
- void *cleanup_baton,
- apr_pool_t *scratch_pool)
-{
-
- if (apr_hash_get(baton->tables, SVN_AUTH_CRED_SIMPLE, APR_HASH_KEY_STRING))
- {
- SVN_ERR(svn_auth__simple_cleanup_walk(baton, cleanup, cleanup_baton,
- baton->creds_cache, scratch_pool));
- }
- /* ### Maybe add support for other providers? */
-
- return SVN_NO_ERROR;
-}
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/auth.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/auth.h?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/auth.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/auth.h Fri May 10 14:58:47 2013
@@ -21,8 +21,12 @@
* ====================================================================
*/
-#ifndef SVN_SUBR_AUTH_H
-#define SVN_SUBR_AUTH_H
+#ifndef SVN_LIBSVN_SUBR_AUTH_H
+#define SVN_LIBSVN_SUBR_AUTH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
#include "svn_auth.h"
@@ -37,13 +41,9 @@ svn_auth__file_path(const char **path,
const char *config_dir,
apr_pool_t *pool);
-/* Implementation of svn_auth_cleanup_walk() for the "simple" provider */
-svn_error_t *
-svn_auth__simple_cleanup_walk(svn_auth_baton_t *baton,
- svn_auth_cleanup_callback cleanup,
- void *cleanup_baton,
- apr_hash_t *creds_cache,
- apr_pool_t *scratch_pool);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
-#endif
+#endif /* SVN_LIBSVN_SUBR_AUTH_H */
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cache-inprocess.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cache-inprocess.c Fri May 10 14:58:47 2013
@@ -214,7 +214,7 @@ inprocess_cache_get(void **value_p,
{
inprocess_cache_t *cache = cache_void;
char* buffer = NULL;
- apr_size_t size;
+ apr_size_t size = 0;
if (key)
SVN_MUTEX__WITH_LOCK(cache->mutex,
@@ -642,6 +642,7 @@ svn_cache__create_inprocess(svn_cache__t
wrapper->vtable = &inprocess_cache_vtable;
wrapper->cache_internal = cache;
+ wrapper->pretend_empty = !!getenv("SVN_X_DOES_NOT_MARK_THE_SPOT");
*cache_p = wrapper;
return SVN_NO_ERROR;
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cache-membuffer.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cache-membuffer.c Fri May 10 14:58:47 2013
@@ -45,6 +45,8 @@
*
* 1. A linear data buffer containing cached items in a serialized
* representation. There may be arbitrary gaps between entries.
+ * This buffer is sub-devided into (currently two) cache levels.
+ *
* 2. A directory of cache entries. This is organized similar to CPU
* data caches: for every possible key, there is exactly one group
* of entries that may contain the header info for an item with
@@ -56,23 +58,30 @@
* between different processes and / or to persist them on disk. These
* out-of-process features have not been implemented, yet.
*
+ * Superficially, cache levels are being used as usual: insertion happens
+ * into L1 and evictions will promote items to L2. But their whole point
+ * is a different one. L1 uses a circular buffer, i.e. we have perfect
+ * caching for the last N bytes where N is the size of L1. L2 uses a more
+ * elaborate scheme based on priorities and hit counts as described below.
+ *
* The data buffer usage information is implicitly given by the directory
* entries. Every USED entry has a reference to the previous and the next
* used dictionary entry and this double-linked list is ordered by the
* offsets of their item data within the data buffer. So removing data,
* for instance, is done simply by unlinking it from the chain, implicitly
* marking the entry as well as the data buffer section previously
- * associated to it as unused.
+ * associated to it as unused. First and last element of that chain are
+ * being referenced from the respective cache level.
*
- * Insertion can occur at only one, sliding position. It is marked by its
- * offset in the data buffer plus the index of the first used entry at or
- * behind that position. If this gap is too small to accommodate the new
- * item, the insertion window is extended as described below. The new entry
- * will always be inserted at the bottom end of the window and since the
- * next used entry is known, properly sorted insertion is possible.
+ * Insertion can occur at only one, sliding position per cache level. It is
+ * marked by its offset in the data buffer and the index of the first used
+ * entry at or behind that position. If this gap is too small to accommodate
+ * the new item, the insertion window is extended as described below. The new
+ * entry will always be inserted at the bottom end of the window and since
+ * the next used entry is known, properly sorted insertion is possible.
*
* To make the cache perform robustly in a wide range of usage scenarios,
- * a randomized variant of LFU is used (see ensure_data_insertable for
+ * L2 uses a randomized variant of LFU (see ensure_data_insertable_l2 for
* details). Every item holds a read hit counter and there is a global read
* hit counter. The more hits an entry has in relation to the average, the
* more it is likely to be kept using a rand()-based condition. The test is
@@ -86,10 +95,10 @@
* they get not used for a while. Also, even a cache thrashing situation
* about 50% of the content survives every 50% of the cache being re-written
* with new entries. For details on the fine-tuning involved, see the
- * comments in ensure_data_insertable().
+ * comments in ensure_data_insertable_l2().
*
* To limit the entry size and management overhead, not the actual item keys
- * but only their MD5 checksums will not be stored. This is reasonably safe
+ * but only their MD5-based hashes will be stored. This is reasonably safe
* to do since users have only limited control over the full keys, even if
* these contain folder paths. So, it is very hard to deliberately construct
* colliding keys. Random checksum collisions can be shown to be extremely
@@ -116,11 +125,11 @@
/* By default, don't create cache segments smaller than this value unless
* the total cache size itself is smaller.
*/
-#define DEFAULT_MIN_SEGMENT_SIZE 0x2000000ull
+#define DEFAULT_MIN_SEGMENT_SIZE APR_UINT64_C(0x2000000)
/* The minimum segment size we will allow for multi-segmented caches
*/
-#define MIN_SEGMENT_SIZE 0x10000ull
+#define MIN_SEGMENT_SIZE APR_UINT64_C(0x10000)
/* The maximum number of segments allowed. Larger numbers reduce the size
* of each segment, in turn reducing the max size of a cachable item.
@@ -133,7 +142,7 @@
/* As of today, APR won't allocate chunks of 4GB or more. So, limit the
* segment size to slightly below that.
*/
-#define MAX_SEGMENT_SIZE 0xffff0000ull
+#define MAX_SEGMENT_SIZE APR_UINT64_C(0xffff0000)
/* We don't mark the initialization status for every group but initialize
* a number of groups at once. That will allow for a very small init flags
@@ -313,7 +322,7 @@ static svn_error_t* assert_equal_tags(co
/* A single dictionary entry. Since all entries will be allocated once
* during cache creation, those entries might be either used or unused.
* An entry is used if and only if it is contained in the doubly-linked
- * list of used entries.
+ * list of used entries per cache level.
*/
typedef struct entry_t
{
@@ -321,7 +330,8 @@ typedef struct entry_t
*/
entry_key_t key;
- /* The offset of the cached item's serialized data within the data buffer.
+ /* The offset of the cached item's serialized data within the caches
+ * DATA buffer.
*/
apr_uint64_t offset;
@@ -337,15 +347,15 @@ typedef struct entry_t
/* Reference to the next used entry in the order defined by offset.
* NO_INDEX indicates the end of the list; this entry must be referenced
- * by the caches membuffer_cache_t.last member. NO_INDEX also implies
- * that the data buffer is not used beyond offset+size.
+ * by the caches cache_level_t.last member. NO_INDEX also implies that
+ * the data buffer is not used beyond offset+size.
* Only valid for used entries.
*/
apr_uint32_t next;
/* Reference to the previous used entry in the order defined by offset.
* NO_INDEX indicates the end of the list; this entry must be referenced
- * by the caches membuffer_cache_t.first member.
+ * by the caches cache_level_t.first member.
* Only valid for used entries.
*/
apr_uint32_t previous;
@@ -368,28 +378,12 @@ typedef struct entry_group_t
entry_t entries[GROUP_SIZE];
} entry_group_t;
-/* The cache header structure.
+/* Per-cache level header structure. Instances of this are members of
+ * svn_membuffer_t and will use non-overlapping sections of its DATA buffer.
+ * All offset values are global / absolute to that whole buffer.
*/
-struct svn_membuffer_t
+typedef struct cache_level_t
{
- /* Number of cache segments. Must be a power of 2.
- Please note that this structure represents only one such segment
- and that all segments must / will report the same values here. */
- apr_uint32_t segment_count;
-
- /* The dictionary, GROUP_SIZE * group_count entries long. Never NULL.
- */
- entry_group_t *directory;
-
- /* Flag array with group_count / GROUP_INIT_GRANULARITY _bit_ elements.
- * Allows for efficiently marking groups as "not initialized".
- */
- unsigned char *group_initialized;
-
- /* Size of dictionary in groups. Must be > 0.
- */
- apr_uint32_t group_count;
-
/* Reference to the first (defined by the order content in the data
* buffer) dictionary entry used by any data item.
* NO_INDEX for an empty cache.
@@ -410,18 +404,46 @@ struct svn_membuffer_t
apr_uint32_t next;
- /* Pointer to the data buffer, data_size bytes long. Never NULL.
+ /* First offset in the caches DATA buffer that belongs to this level.
*/
- unsigned char *data;
+ apr_uint64_t start_offset;
- /* Size of data buffer in bytes. Must be > 0.
+ /* Size of data buffer allocated to this level in bytes. Must be > 0.
*/
- apr_uint64_t data_size;
+ apr_uint64_t size;
/* Offset in the data buffer where the next insertion shall occur.
*/
apr_uint64_t current_data;
+} cache_level_t;
+
+/* The cache header structure.
+ */
+struct svn_membuffer_t
+{
+ /* Number of cache segments. Must be a power of 2.
+ Please note that this structure represents only one such segment
+ and that all segments must / will report the same values here. */
+ apr_uint32_t segment_count;
+
+ /* The dictionary, GROUP_SIZE * group_count entries long. Never NULL.
+ */
+ entry_group_t *directory;
+
+ /* Flag array with group_count / GROUP_INIT_GRANULARITY _bit_ elements.
+ * Allows for efficiently marking groups as "not initialized".
+ */
+ unsigned char *group_initialized;
+
+ /* Size of dictionary in groups. Must be > 0.
+ */
+ apr_uint32_t group_count;
+
+ /* Pointer to the data buffer, data_size bytes long. Never NULL.
+ */
+ unsigned char *data;
+
/* Total number of data buffer bytes in use. This is for statistics only.
*/
apr_uint64_t data_used;
@@ -431,6 +453,24 @@ struct svn_membuffer_t
*/
apr_uint64_t max_entry_size;
+ /* The cache levels, organized as sub-buffers. Since entries in the
+ * DIRECTORY use offsets in DATA for addressing, a cache lookup does
+ * not need to know the cache level of a specific item. Cache levels
+ * are only used to implement a hybrid insertion / eviction strategy.
+ */
+
+ /* First cache level, i.e. most insertions happen here. Very large
+ * items might get inserted directly into L2. L1 is a strict FIFO
+ * ring buffer that does not care about item priorities. All evicted
+ * items get a chance to be promoted to L2.
+ */
+ cache_level_t l1;
+
+ /* Second cache level, i.e. data evicted from L1 will be added here
+ * if the item is "important" enough or the L2 insertion window is large
+ * enough.
+ */
+ cache_level_t l2;
/* Number of used dictionary entries, i.e. number of cached items.
* In conjunction with hit_count, this is used calculate the average
@@ -521,7 +561,7 @@ write_lock_cache(svn_membuffer_t *cache,
status = APR_SUCCESS;
}
}
-
+
if (status)
return svn_error_wrap_apr(status,
_("Can't write-lock cache mutex"));
@@ -621,6 +661,96 @@ get_index(svn_membuffer_t *cache, entry_
+ (apr_uint32_t)(entry - cache->directory[group_index].entries);
}
+/* Return the cache level of ENTRY in CACHE.
+ */
+static cache_level_t *
+get_cache_level(svn_membuffer_t *cache, entry_t *entry)
+{
+ return entry->offset < cache->l1.size ? &cache->l1
+ : &cache->l2;
+}
+
+/* Insert ENTRY to the chain of items that belong to LEVEL in CACHE. IDX
+ * is ENTRY's item index and is only given for efficiency. The insertion
+ * takes place just before LEVEL->NEXT. *CACHE will not be modified.
+ */
+static void
+chain_entry(svn_membuffer_t *cache,
+ cache_level_t *level,
+ entry_t *entry,
+ apr_uint32_t idx)
+{
+ /* insert ENTRY before this item */
+ entry_t *next = level->next == NO_INDEX
+ ? NULL
+ : get_entry(cache, level->next);
+ assert(idx == get_index(cache, entry));
+
+ /* update entry chain
+ */
+ entry->next = level->next;
+ if (level->first == NO_INDEX)
+ {
+ /* insert as the first entry and only in the chain
+ */
+ entry->previous = NO_INDEX;
+ level->last = idx;
+ level->first = idx;
+ }
+ else if (next == NULL)
+ {
+ /* insert as the last entry in the chain.
+ * Note that it cannot also be at the beginning of the chain.
+ */
+ entry->previous = level->last;
+ get_entry(cache, level->last)->next = idx;
+ level->last = idx;
+ }
+ else
+ {
+ /* insert either at the start of a non-empty list or
+ * somewhere in the middle
+ */
+ entry->previous = next->previous;
+ next->previous = idx;
+
+ if (entry->previous != NO_INDEX)
+ get_entry(cache, entry->previous)->next = idx;
+ else
+ level->first = idx;
+ }
+}
+
+/* Remove ENTRY from the chain of items that belong to LEVEL in CACHE. IDX
+ * is ENTRY's item index and is only given for efficiency. Please note
+ * that neither *CACHE nor *ENTRY will not be modified.
+ */
+static void
+unchain_entry(svn_membuffer_t *cache,
+ cache_level_t *level,
+ entry_t *entry,
+ apr_uint32_t idx)
+{
+ assert(idx == get_index(cache, entry));
+
+ /* update
+ */
+ if (level->next == idx)
+ level->next = entry->next;
+
+ /* unlink it from the chain of used entries
+ */
+ if (entry->previous == NO_INDEX)
+ level->first = entry->next;
+ else
+ get_entry(cache, entry->previous)->next = entry->next;
+
+ if (entry->next == NO_INDEX)
+ level->last = entry->previous;
+ else
+ get_entry(cache, entry->next)->previous = entry->previous;
+}
+
/* Remove the used ENTRY from the CACHE, i.e. make it "unused".
* In contrast to insertion, removal is possible for any entry.
*/
@@ -633,6 +763,7 @@ drop_entry(svn_membuffer_t *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;
+ cache_level_t *level = get_cache_level(cache, entry);
/* Only valid to be called for used entries.
*/
@@ -646,39 +777,31 @@ drop_entry(svn_membuffer_t *cache, entry
/* extend the insertion window, if the entry happens to border it
*/
- if (idx == cache->next)
- cache->next = entry->next;
+ if (idx == level->next)
+ level->next = entry->next;
else
- if (entry->next == cache->next)
+ if (entry->next == level->next)
{
/* insertion window starts right behind the entry to remove
*/
if (entry->previous == NO_INDEX)
{
/* remove the first entry -> insertion may start at pos 0, now */
- cache->current_data = 0;
+ level->current_data = level->start_offset;
}
else
{
/* insertion may start right behind the previous entry */
entry_t *previous = get_entry(cache, entry->previous);
- cache->current_data = ALIGN_VALUE( previous->offset
+ level->current_data = ALIGN_VALUE( previous->offset
+ previous->size);
}
}
/* unlink it from the chain of used entries
*/
- if (entry->previous == NO_INDEX)
- cache->first = entry->next;
- else
- get_entry(cache, entry->previous)->next = entry->next;
-
- if (entry->next == NO_INDEX)
- cache->last = entry->previous;
- else
- get_entry(cache, entry->next)->previous = entry->previous;
-
+ unchain_entry(cache, level, entry, idx);
+
/* Move last entry into hole (if the removed one is not the last used).
* We need to do this since all used entries are at the beginning of
* the group's entries array.
@@ -689,18 +812,22 @@ drop_entry(svn_membuffer_t *cache, entry
*/
*entry = group->entries[group->used-1];
+ /* this ENTRY may belong to a different cache level than the entry
+ * we have just removed */
+ level = get_cache_level(cache, entry);
+
/* update foreign links to new index
*/
- if (last_in_group == cache->next)
- cache->next = idx;
+ if (last_in_group == level->next)
+ level->next = idx;
if (entry->previous == NO_INDEX)
- cache->first = idx;
+ level->first = idx;
else
get_entry(cache, entry->previous)->next = idx;
-
+
if (entry->next == NO_INDEX)
- cache->last = idx;
+ level->last = idx;
else
get_entry(cache, entry->next)->previous = idx;
}
@@ -722,16 +849,14 @@ insert_entry(svn_membuffer_t *cache, ent
apr_uint32_t idx = get_index(cache, entry);
apr_uint32_t group_index = idx / GROUP_SIZE;
entry_group_t *group = &cache->directory[group_index];
- entry_t *next = cache->next == NO_INDEX
- ? NULL
- : get_entry(cache, cache->next);
+ cache_level_t *level = get_cache_level(cache, entry);
/* The entry must start at the beginning of the insertion window.
* It must also be the first unused entry in the group.
*/
- assert(entry->offset == cache->current_data);
+ assert(entry->offset == level->current_data);
assert(idx == group_index * GROUP_SIZE + group->used);
- cache->current_data = ALIGN_VALUE(entry->offset + entry->size);
+ level->current_data = ALIGN_VALUE(entry->offset + entry->size);
/* update usage counters
*/
@@ -742,42 +867,12 @@ insert_entry(svn_membuffer_t *cache, ent
/* update entry chain
*/
- entry->next = cache->next;
- if (cache->first == NO_INDEX)
- {
- /* insert as the first entry and only in the chain
- */
- entry->previous = NO_INDEX;
- cache->last = idx;
- cache->first = idx;
- }
- else if (next == NULL)
- {
- /* insert as the last entry in the chain.
- * Note that it cannot also be at the beginning of the chain.
- */
- entry->previous = cache->last;
- get_entry(cache, cache->last)->next = idx;
- cache->last = idx;
- }
- else
- {
- /* insert either at the start of a non-empty list or
- * somewhere in the middle
- */
- entry->previous = next->previous;
- next->previous = idx;
-
- if (entry->previous != NO_INDEX)
- get_entry(cache, entry->previous)->next = idx;
- else
- cache->first = idx;
- }
+ chain_entry(cache, level, entry, idx);
/* The current insertion position must never point outside our
* data buffer.
*/
- assert(cache->current_data <= cache->data_size);
+ assert(level->current_data <= level->start_offset + level->size);
}
/* Map a KEY of 16 bytes to the CACHE and group that shall contain the
@@ -788,10 +883,13 @@ get_group_index(svn_membuffer_t **cache,
entry_key_t key)
{
svn_membuffer_t *segment0 = *cache;
-
- /* select the cache segment to use. they have all the same group_count */
- *cache = &segment0[key[0] & (segment0->segment_count -1)];
- return key[1] % segment0->group_count;
+
+ /* select the cache segment to use. they have all the same group_count.
+ * Since key may not be well-distributed, pre-fold it to a smaller but
+ * "denser" ranger. The divisors are primes larger than the largest
+ * counts. */
+ *cache = &segment0[(key[1] % 2809637ull) & (segment0->segment_count - 1)];
+ return (key[0] % 5030895599ull) % segment0->group_count;
}
/* Reduce the hit count of ENTRY and update the accumulated hit info
@@ -912,6 +1010,8 @@ find_entry(svn_membuffer_t *cache,
*/
if (group->used == GROUP_SIZE)
{
+ static int count = 0;
+
/* every entry gets the same chance of being removed.
* Otherwise, we free the first entry, fill it and
* remove it again on the next occasion without considering
@@ -931,6 +1031,7 @@ find_entry(svn_membuffer_t *cache,
let_entry_age(cache, entry);
drop_entry(cache, entry);
+ printf("%d\n", ++count);
}
/* initialize entry for the new key
@@ -950,6 +1051,7 @@ static void
move_entry(svn_membuffer_t *cache, entry_t *entry)
{
apr_size_t size = ALIGN_VALUE(entry->size);
+ cache_level_t *level = get_cache_level(cache, entry);
/* This entry survived this cleansing run. Reset half of its
* hit count so that its removal gets more likely in the next
@@ -963,41 +1065,75 @@ move_entry(svn_membuffer_t *cache, entry
* Size-aligned moves tend to be faster than non-aligned ones
* because no "odd" bytes at the end need to special treatment.
*/
- if (entry->offset != cache->current_data)
+ if (entry->offset != level->current_data)
{
- memmove(cache->data + cache->current_data,
+ memmove(cache->data + level->current_data,
cache->data + entry->offset,
size);
- entry->offset = cache->current_data;
+ entry->offset = level->current_data;
}
/* The insertion position is now directly behind this entry.
*/
- cache->current_data = entry->offset + size;
- cache->next = entry->next;
+ level->current_data = entry->offset + size;
+ level->next = entry->next;
/* The current insertion position must never point outside our
* data buffer.
*/
- assert(cache->current_data <= cache->data_size);
+ assert(level->current_data <= level->start_offset + level->size);
}
-/* If necessary, enlarge the insertion window until it is at least
- * SIZE bytes long. SIZE must not exceed the data buffer size.
- * Return TRUE if enough room could be found or made. A FALSE result
+/* Move ENTRY in CACHE from L1 to L2.
+ */
+static void
+promote_entry(svn_membuffer_t *cache, entry_t *entry)
+{
+ apr_uint32_t idx = get_index(cache, entry);
+ apr_size_t size = ALIGN_VALUE(entry->size);
+ assert(get_cache_level(cache, entry) == &cache->l1);
+
+ /* copy item from the current location in L1 to the start of L2's
+ * insertion window */
+ memmove(cache->data + cache->l2.current_data,
+ cache->data + entry->offset,
+ size);
+ entry->offset = cache->l2.current_data;
+
+ /* The insertion position is now directly behind this entry.
+ */
+ cache->l2.current_data += size;
+
+ /* remove ENTRY from chain of L1 entries and put it into L2
+ */
+ unchain_entry(cache, &cache->l1, entry, idx);
+ chain_entry(cache, &cache->l2, entry, idx);
+}
+
+/* This function implements the cache insertion / eviction strategy for L2.
+ *
+ * If necessary, enlarge the insertion window of CACHE->L2 until it is at
+ * least TO_FIT_IN->SIZE bytes long. TO_FIT_IN->SIZE must not exceed the
+ * data buffer size allocated to CACHE->L2. IDX is the item index of
+ * TO_FIT_IN and is given for performance reasons.
+ *
+ * Return TRUE if enough room could be found or made. A FALSE result
* indicates that the respective item shall not be added.
*/
static svn_boolean_t
-ensure_data_insertable(svn_membuffer_t *cache, apr_size_t size)
+ensure_data_insertable_l2(svn_membuffer_t *cache,
+ entry_t *to_fit_in,
+ apr_uint32_t idx)
{
entry_t *entry;
apr_uint64_t average_hit_value;
apr_uint64_t threshold;
- /* accumulated size of the entries that have been removed to make
- * room for the new one.
- */
- apr_size_t drop_size = 0;
+ /* accumulated "worth" of items dropped so far */
+ apr_size_t drop_hits = 0;
+
+ /* verify parameters */
+ assert(idx == get_index(cache, to_fit_in));
/* This loop will eventually terminate because every cache entry
* would get dropped eventually:
@@ -1015,41 +1151,37 @@ ensure_data_insertable(svn_membuffer_t *
{
/* first offset behind the insertion window
*/
- apr_uint64_t end = cache->next == NO_INDEX
- ? cache->data_size
- : get_entry(cache, cache->next)->offset;
+ apr_uint64_t end = cache->l2.next == NO_INDEX
+ ? cache->l2.start_offset + cache->l2.size
+ : get_entry(cache, cache->l2.next)->offset;
/* leave function as soon as the insertion window is large enough
*/
- if (end >= size + cache->current_data)
+ if (end >= to_fit_in->size + cache->l2.current_data)
return TRUE;
- /* Don't be too eager to cache data. Smaller items will fit into
- * the cache after dropping a single item. Of the larger ones, we
- * will only accept about 50%. They are also likely to get evicted
- * soon due to their notoriously low hit counts.
- *
- * As long as enough similarly or even larger sized entries already
- * exist in the cache, much less insert requests will be rejected.
+ /* if the net worth (in hits) of items removed is already larger
+ * than what we want to insert, reject TO_FIT_IN because it still
+ * does not fit in.
*/
- if (2 * drop_size > size)
+ if (drop_hits > to_fit_in->hit_count)
return FALSE;
/* try to enlarge the insertion window
*/
- if (cache->next == NO_INDEX)
+ if (cache->l2.next == NO_INDEX)
{
/* We reached the end of the data buffer; restart at the beginning.
* Due to the randomized nature of our LFU implementation, very
* large data items may require multiple passes. Therefore, SIZE
* should be restricted to significantly less than data_size.
*/
- cache->current_data = 0;
- cache->next = cache->first;
+ cache->l2.current_data = cache->l2.start_offset;
+ cache->l2.next = cache->l2.first;
}
else
{
- entry = get_entry(cache, cache->next);
+ entry = get_entry(cache, cache->l2.next);
/* Keep entries that are very small. Those are likely to be data
* headers or similar management structures. So, they are probably
@@ -1061,14 +1193,24 @@ ensure_data_insertable(svn_membuffer_t *
{
move_entry(cache, entry);
}
+ else if (cache->l2.next / GROUP_SIZE == idx / GROUP_SIZE)
+ {
+ /* Special case: we cannot drop entries that are in the same
+ * group as TO_FIT_IN because that might the latter to become
+ * invalidated it it happens to be the highest used entry in
+ * the group. So, we must keep ENTRY unconditionally.
+ * (this is a very rare condition)
+ */
+ move_entry(cache, entry);
+ }
else
{
svn_boolean_t keep;
if (cache->hit_count > cache->used_entries)
{
- /* Roll the dice and determine a threshold somewhere from 0 up
- * to 2 times the average hit count.
+ /* Roll the dice and determine a threshold somewhere from
+ * 0 up to 2 times the average hit count.
*/
average_hit_value = cache->hit_count / cache->used_entries;
threshold = (average_hit_value+1) * (rand() % 4096) / 2048;
@@ -1077,9 +1219,9 @@ ensure_data_insertable(svn_membuffer_t *
}
else
{
- /* general hit count is low. Keep everything that got hit
- * at all and assign some 50% survival chance to everything
- * else.
+ /* general hit count is low. Keep everything that got
+ * hit at all and assign some 50% survival chance to
+ * everything else.
*/
keep = (entry->hit_count > 0) || (rand() & 1);
}
@@ -1087,15 +1229,16 @@ ensure_data_insertable(svn_membuffer_t *
/* keepers or destroyers? */
if (keep)
{
+ /* Keep ENTRY and move the insertion window.
+ */
move_entry(cache, entry);
}
else
{
- /* Drop the entry from the end of the insertion window, if it
- * has been hit less than the threshold. Otherwise, keep it and
- * move the insertion window one entry further.
+ /* Drop the entry from the end of the insertion window,
+ * because it had been hit less than the threshold.
*/
- drop_size += entry->size;
+ drop_hits += entry->hit_count;
drop_entry(cache, entry);
}
}
@@ -1106,6 +1249,70 @@ ensure_data_insertable(svn_membuffer_t *
* right answer. */
}
+/* This function implements the cache insertion / eviction strategy for L1.
+ *
+ * If necessary, enlarge the insertion window of CACHE->L1 by promoting
+ * entries to L2 until it is at least SIZE bytes long.
+ *
+ * Return TRUE if enough room could be found or made. A FALSE result
+ * indicates that the respective item shall not be added because it is
+ * too large.
+ */
+static svn_boolean_t
+ensure_data_insertable_l1(svn_membuffer_t *cache, apr_size_t size)
+{
+ entry_t *entry;
+
+ /* Guarantees that the while loop will terminate. */
+ if (size > cache->l1.size)
+ return FALSE;
+
+ /* This loop will eventually terminate because every cache entry
+ * would get dropped eventually.
+ */
+ while (1)
+ {
+ /* first offset behind the insertion window
+ */
+ apr_uint64_t end = cache->l1.next == NO_INDEX
+ ? cache->l1.start_offset + cache->l1.size
+ : get_entry(cache, cache->l1.next)->offset;
+
+ /* leave function as soon as the insertion window is large enough
+ */
+ if (end >= size + cache->l1.current_data)
+ return TRUE;
+
+ /* Enlarge the insertion window
+ */
+ if (cache->l1.next == NO_INDEX)
+ {
+ /* We reached the end of the data buffer; restart at the beginning.
+ * Due to the randomized nature of our LFU implementation, very
+ * large data items may require multiple passes. Therefore, SIZE
+ * should be restricted to significantly less than data_size.
+ */
+ cache->l1.current_data = cache->l1.start_offset;
+ cache->l1.next = cache->l1.first;
+ }
+ else
+ {
+ /* Remove the entry from the end of insertion window and promote
+ * it to L2, if it is important enough.
+ */
+ entry = get_entry(cache, cache->l1.next);
+
+ if (ensure_data_insertable_l2(cache, entry, cache->l1.next))
+ promote_entry(cache, entry);
+ else
+ drop_entry(cache, entry);
+ }
+ }
+
+ /* This will never be reached. But if it was, "can't insert" was the
+ * right answer. */
+}
+
/* Mimic apr_pcalloc in APR_POOL_DEBUG mode, i.e. handle failed allocations
* (e.g. OOM) properly: Allocate at least SIZE bytes from POOL and zero
* the content of the allocated memory if ZERO has been set. Return NULL
@@ -1158,7 +1365,7 @@ svn_cache__membuffer_cache_create(svn_me
segment_count = MAX_SEGMENT_COUNT;
if (segment_count * MIN_SEGMENT_SIZE > total_size)
segment_count = total_size / MIN_SEGMENT_SIZE;
-
+
/* The segment count must be a power of two. Round it down as necessary.
*/
while ((segment_count & (segment_count-1)) != 0)
@@ -1225,13 +1432,13 @@ svn_cache__membuffer_cache_create(svn_me
*/
data_size = ALIGN_VALUE(total_size - directory_size + 1) - ITEM_ALIGNMENT;
- /* For cache sizes > 4TB, individual cache segments will be larger
- * than 16GB allowing for >4GB entries. But caching chunks larger
- * than 4GB is simply not supported.
+ /* For cache sizes > 16TB, individual cache segments will be larger
+ * than 32GB allowing for >4GB entries. But caching chunks larger
+ * than 4GB are simply not supported.
*/
- max_entry_size = data_size / 4 > MAX_ITEM_SIZE
+ max_entry_size = data_size / 8 > MAX_ITEM_SIZE
? MAX_ITEM_SIZE
- : data_size / 4;
+ : data_size / 8;
/* to keep the entries small, we use 32 bit indexes only
* -> we need to ensure that no more then 4G entries exist.
@@ -1259,13 +1466,25 @@ svn_cache__membuffer_cache_create(svn_me
hence "unused" */
c[seg].group_initialized = apr_pcalloc(pool, group_init_size);
- c[seg].first = NO_INDEX;
- c[seg].last = NO_INDEX;
- c[seg].next = NO_INDEX;
+ /* Allocate 1/4th of the data buffer to L1
+ */
+ c[seg].l1.first = NO_INDEX;
+ c[seg].l1.last = NO_INDEX;
+ c[seg].l1.next = NO_INDEX;
+ c[seg].l1.start_offset = 0;
+ c[seg].l1.size = ALIGN_VALUE(data_size / 4);
+ c[seg].l1.current_data = 0;
+
+ /* The remaining 3/4th will be used as L2
+ */
+ c[seg].l2.first = NO_INDEX;
+ c[seg].l2.last = NO_INDEX;
+ c[seg].l2.next = NO_INDEX;
+ c[seg].l2.start_offset = c[seg].l1.size;
+ c[seg].l2.size = data_size - c[seg].l1.size;
+ c[seg].l2.current_data = c[seg].l2.start_offset;
- c[seg].data_size = data_size;
c[seg].data = secure_aligned_alloc(pool, (apr_size_t)data_size, FALSE);
- c[seg].current_data = 0;
c[seg].data_used = 0;
c[seg].max_entry_size = max_entry_size;
@@ -1282,7 +1501,7 @@ svn_cache__membuffer_cache_create(svn_me
{
/* We are OOM. There is no need to proceed with "half a cache".
*/
- return svn_error_wrap_apr(APR_ENOMEM, _("OOM"));
+ return svn_error_wrap_apr(APR_ENOMEM, "OOM");
}
#if APR_HAS_THREADS
@@ -1397,7 +1616,7 @@ membuffer_cache_set_internal(svn_membuff
*/
if ( buffer != NULL
&& cache->max_entry_size >= size
- && ensure_data_insertable(cache, size))
+ && ensure_data_insertable_l1(cache, size))
{
/* Remove old data for this key, if that exists.
* Get an unused entry for the key and and initialize it with
@@ -1405,7 +1624,7 @@ membuffer_cache_set_internal(svn_membuff
*/
entry = find_entry(cache, group_index, to_find, TRUE);
entry->size = size;
- entry->offset = cache->current_data;
+ entry->offset = cache->l1.current_data;
#ifdef SVN_DEBUG_CACHE_MEMBUFFER
@@ -1758,13 +1977,13 @@ membuffer_cache_set_partial_internal(svn
*/
drop_entry(cache, entry);
if ( (cache->max_entry_size >= size)
- && ensure_data_insertable(cache, size))
+ && ensure_data_insertable_l1(cache, size))
{
/* Write the new entry.
*/
entry = find_entry(cache, group_index, to_find, TRUE);
entry->size = size;
- entry->offset = cache->current_data;
+ entry->offset = cache->l1.current_data;
if (size)
memcpy(cache->data + entry->offset, data, size);
@@ -1829,6 +2048,22 @@ membuffer_cache_set_partial(svn_membuffe
* svn_cache__t instance.
*/
+/* Stores the combined key value for the given key. It will be used by
+ * combine_key() to short-circuit expensive hash calculations.
+ */
+typedef struct last_access_key_t
+{
+ /* result of key combining */
+ entry_key_t combined_key;
+
+ /* length of the key (or APR_HASH_KEY_STRING if not used) */
+ apr_size_t key_len;
+
+ /* the original key. Only KEY_LEN bytes are valid. We use uint32 for
+ * better compatibility with pseudo-md5 functions. */
+ apr_uint32_t key[64];
+} last_access_key_t;
+
/* Internal cache structure (used in svn_cache__t.cache_internal) basically
* holding the additional parameters needed to call the respective membuffer
* functions.
@@ -1876,6 +2111,11 @@ typedef struct svn_membuffer_cache_t
*/
int alloc_counter;
+ /* cache for the last key used.
+ * Will be NULL for caches with short fix-sized keys.
+ */
+ last_access_key_t *last_access;
+
/* if enabled, this will serialize the access to this instance.
*/
svn_mutex__t *mutex;
@@ -1893,46 +2133,127 @@ typedef struct svn_membuffer_cache_t
*/
#define ALLOCATIONS_PER_POOL_CLEAR 10
-
/* Basically calculate a hash value for KEY of length KEY_LEN, combine it
* with the CACHE->PREFIX and write the result in CACHE->COMBINED_KEY.
+ * This could replace combine_key() entirely but we actually use it only
+ * when the quick path failed.
*/
static void
-combine_key(svn_membuffer_cache_t *cache,
- const void *key,
- apr_ssize_t key_len)
+combine_long_key(svn_membuffer_cache_t *cache,
+ const void *key,
+ apr_ssize_t key_len)
{
+ assert(cache->last_access);
+
+ /* handle variable-length keys */
if (key_len == APR_HASH_KEY_STRING)
key_len = strlen((const char *) key);
- if (key_len < 16)
+ /* same key as the last time? -> short-circuit */
+ if ( key_len == cache->last_access->key_len
+ && memcmp(key, cache->last_access->key, key_len) == 0)
{
- apr_uint32_t data[4] = { 0 };
- memcpy(data, key, key_len);
+ memcpy(cache->combined_key, cache->last_access->combined_key,
+ sizeof(cache->combined_key));
+ }
+ else if (key_len >= 64)
+ {
+ /* relatively long key. Use the generic, slow hash code for it */
+ apr_md5((unsigned char*)cache->combined_key, key, key_len);
+ cache->combined_key[0] ^= cache->prefix[0];
+ cache->combined_key[1] ^= cache->prefix[1];
- svn__pseudo_md5_15((apr_uint32_t *)cache->combined_key, data);
+ /* is the key short enough to cache the result? */
+ if (key_len <= sizeof(cache->last_access->key))
+ {
+ memcpy(cache->last_access->combined_key, cache->combined_key,
+ sizeof(cache->combined_key));
+ cache->last_access->key_len = key_len;
+ memcpy(cache->last_access->key, key, key_len);
+ }
}
- else if (key_len < 32)
+ else
{
- apr_uint32_t data[8] = { 0 };
- memcpy(data, key, key_len);
+ /* shorter keys use efficient hash code and *do* cache the results */
+ cache->last_access->key_len = key_len;
+ if (key_len < 16)
+ {
+ memset(cache->last_access->key, 0, 16);
+ memcpy(cache->last_access->key, key, key_len);
- svn__pseudo_md5_31((apr_uint32_t *)cache->combined_key, data);
+ svn__pseudo_md5_15((apr_uint32_t *)cache->combined_key,
+ cache->last_access->key);
+ }
+ else if (key_len < 32)
+ {
+ memset(cache->last_access->key, 0, 32);
+ memcpy(cache->last_access->key, key, key_len);
+
+ svn__pseudo_md5_31((apr_uint32_t *)cache->combined_key,
+ cache->last_access->key);
+ }
+ else
+ {
+ memset(cache->last_access->key, 0, 64);
+ memcpy(cache->last_access->key, key, key_len);
+
+ svn__pseudo_md5_63((apr_uint32_t *)cache->combined_key,
+ cache->last_access->key);
+ }
+
+ cache->combined_key[0] ^= cache->prefix[0];
+ cache->combined_key[1] ^= cache->prefix[1];
+
+ memcpy(cache->last_access->combined_key, cache->combined_key,
+ sizeof(cache->combined_key));
}
- else if (key_len < 64)
+}
+
+/* Basically calculate a hash value for KEY of length KEY_LEN, combine it
+ * with the CACHE->PREFIX and write the result in CACHE->COMBINED_KEY.
+ */
+static void
+combine_key(svn_membuffer_cache_t *cache,
+ const void *key,
+ apr_ssize_t key_len)
+{
+ /* copy of *key, padded with 0 */
+ apr_uint64_t data[2];
+
+ /* short, fixed-size keys are the most common case */
+ if (key_len == 16)
+ {
+ data[0] = ((const apr_uint64_t *)key)[0];
+ data[1] = ((const apr_uint64_t *)key)[1];
+ }
+ else if (key_len == 8)
+ {
+ data[0] = ((const apr_uint64_t *)key)[0];
+ data[1] = 0;
+ }
+ else if (key_len != APR_HASH_KEY_STRING && key_len < 16)
{
- apr_uint32_t data[16] = { 0 };
+ data[0] = 0;
+ data[1] = 0;
memcpy(data, key, key_len);
-
- svn__pseudo_md5_63((apr_uint32_t *)cache->combined_key, data);
}
else
{
- apr_md5((unsigned char*)cache->combined_key, key, key_len);
+ /* longer or variably sized keys */
+ combine_long_key(cache, key, key_len);
+ return;
}
- cache->combined_key[0] ^= cache->prefix[0];
- cache->combined_key[1] ^= cache->prefix[1];
+ /* scramble key DATA. All of this must be reversible to prevent key
+ * collisions. So, we limit ourselves to xor and permutations. */
+ data[1] = (data[1] << 27) | (data[1] >> 37);
+ data[1] ^= data[0] & 0xffff;
+ data[0] ^= data[1] & 0xffffffffffff0000ull;
+ data[0] = (data[0] << 43) | (data[0] >> 21);
+
+ /* combine with this cache's namespace */
+ cache->combined_key[0] = data[0] ^ cache->prefix[0];
+ cache->combined_key[1] = data[1] ^ cache->prefix[1];
}
/* Implement svn_cache__vtable_t.get (not thread-safe)
@@ -2112,9 +2433,9 @@ 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->data_size += segment->l1.size + segment->l2.size;
info->used_size += segment->data_used;
- info->total_size += segment->data_size +
+ info->total_size += segment->l1.size + segment->l2.size +
segment->group_count * GROUP_SIZE * sizeof(entry_t);
info->used_entries += segment->used_entries;
@@ -2347,6 +2668,18 @@ svn_cache__create_membuffer_cache(svn_ca
pool));
memcpy(cache->prefix, checksum->digest, sizeof(cache->prefix));
+ /* fix-length keys of 16 bytes or under don't need a buffer because we
+ * can use a very fast key combining algorithm. */
+ if ((klen == APR_HASH_KEY_STRING) || klen > sizeof(entry_key_t))
+ {
+ cache->last_access = apr_pcalloc(pool, sizeof(*cache->last_access));
+ cache->last_access->key_len = APR_HASH_KEY_STRING;
+ }
+ else
+ {
+ cache->last_access = NULL;
+ }
+
#ifdef SVN_DEBUG_CACHE_MEMBUFFER
/* Initialize cache debugging support.
@@ -2362,6 +2695,7 @@ svn_cache__create_membuffer_cache(svn_ca
wrapper->cache_internal = cache;
wrapper->error_handler = 0;
wrapper->error_baton = 0;
+ wrapper->pretend_empty = !!getenv("SVN_X_DOES_NOT_MARK_THE_SPOT");
*cache_p = wrapper;
return SVN_NO_ERROR;
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cache-memcache.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cache-memcache.c Fri May 10 14:58:47 2013
@@ -407,6 +407,7 @@ svn_cache__create_memcache(svn_cache__t
wrapper->cache_internal = cache;
wrapper->error_handler = 0;
wrapper->error_baton = 0;
+ wrapper->pretend_empty = !!getenv("SVN_X_DOES_NOT_MARK_THE_SPOT");
*cache_p = wrapper;
return SVN_NO_ERROR;
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cache.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cache.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cache.c Fri May 10 14:58:47 2013
@@ -75,6 +75,10 @@ svn_cache__get(void **value_p,
/* In case any errors happen and are quelched, make sure we start
out with FOUND set to false. */
*found = FALSE;
+#ifdef SVN_DEBUG
+ if (cache->pretend_empty)
+ return SVN_NO_ERROR;
+#endif
cache->reads++;
err = handle_error(cache,
@@ -114,6 +118,12 @@ svn_cache__iter(svn_boolean_t *completed
void *user_baton,
apr_pool_t *scratch_pool)
{
+#ifdef SVN_DEBUG
+ if (cache->pretend_empty)
+ /* Pretend CACHE is empty. */
+ return SVN_NO_ERROR;
+#endif
+
return (cache->vtable->iter)(completed,
cache->cache_internal,
user_cb,
@@ -135,6 +145,10 @@ svn_cache__get_partial(void **value,
/* In case any errors happen and are quelched, make sure we start
out with FOUND set to false. */
*found = FALSE;
+#ifdef SVN_DEBUG
+ if (cache->pretend_empty)
+ return SVN_NO_ERROR;
+#endif
cache->reads++;
err = handle_error(cache,
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cache.h?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cache.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cache.h Fri May 10 14:58:47 2013
@@ -99,6 +99,10 @@ struct svn_cache__t {
/* Total number of function calls that returned an error. */
apr_uint64_t failures;
+
+ /* Cause all getters to act as though the cache contains no data.
+ (Currently this never becomes set except in maintainer builds.) */
+ svn_boolean_t pretend_empty;
};
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c Fri May 10 14:58:47 2013
@@ -46,6 +46,7 @@
#include "svn_ctype.h"
#include "svn_dso.h"
#include "svn_dirent_uri.h"
+#include "svn_hash.h"
#include "svn_path.h"
#include "svn_pools.h"
#include "svn_error.h"
@@ -147,7 +148,9 @@ svn_cmdline_init(const char *progname, F
_set_error_mode(_OUT_TO_STDERR);
/* In _DEBUG mode: Redirect all debug output (E.g. assert() to stderr.
- (Ignored in releas builds) */
+ (Ignored in release builds) */
+ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
@@ -855,7 +858,7 @@ svn_cmdline__apply_config_options(apr_ha
APR_ARRAY_IDX(config_options, i,
svn_cmdline__config_argument_t *);
- cfg = apr_hash_get(config, arg->file, APR_HASH_KEY_STRING);
+ cfg = svn_hash_gets(config, arg->file);
if (cfg)
{
@@ -1051,7 +1054,7 @@ svn_cmdline__be_interactive(svn_boolean_
return (isatty(STDIN_FILENO) != 0);
#endif
}
- else if (force_interactive)
+ else if (force_interactive)
return TRUE;
return !non_interactive;
@@ -1081,8 +1084,7 @@ find_editor_binary(const char **editor,
/* If not found then fall back on the config file. */
if (! e)
{
- cfg = config ? apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG,
- APR_HASH_KEY_STRING) : NULL;
+ cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG) : NULL;
svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
}
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/compat.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/compat.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/compat.c Fri May 10 14:58:47 2013
@@ -24,6 +24,7 @@
#include <apr_pools.h>
#include <apr_strings.h>
+#include "svn_hash.h"
#include "svn_types.h"
#include "svn_error.h"
#include "svn_compat.h"
@@ -75,12 +76,9 @@ svn_compat_log_revprops_clear(apr_hash_t
{
if (revprops)
{
- apr_hash_set(revprops, SVN_PROP_REVISION_AUTHOR,
- APR_HASH_KEY_STRING, NULL);
- apr_hash_set(revprops, SVN_PROP_REVISION_DATE,
- APR_HASH_KEY_STRING, NULL);
- apr_hash_set(revprops, SVN_PROP_REVISION_LOG,
- APR_HASH_KEY_STRING, NULL);
+ svn_hash_sets(revprops, SVN_PROP_REVISION_AUTHOR, NULL);
+ svn_hash_sets(revprops, SVN_PROP_REVISION_DATE, NULL);
+ svn_hash_sets(revprops, SVN_PROP_REVISION_LOG, NULL);
}
}
@@ -105,14 +103,11 @@ svn_compat_log_revprops_out(const char *
*author = *date = *message = NULL;
if (revprops)
{
- if ((author_s = apr_hash_get(revprops, SVN_PROP_REVISION_AUTHOR,
- APR_HASH_KEY_STRING)))
+ if ((author_s = svn_hash_gets(revprops, SVN_PROP_REVISION_AUTHOR)))
*author = author_s->data;
- if ((date_s = apr_hash_get(revprops, SVN_PROP_REVISION_DATE,
- APR_HASH_KEY_STRING)))
+ if ((date_s = svn_hash_gets(revprops, SVN_PROP_REVISION_DATE)))
*date = date_s->data;
- if ((message_s = apr_hash_get(revprops, SVN_PROP_REVISION_LOG,
- APR_HASH_KEY_STRING)))
+ if ((message_s = svn_hash_gets(revprops, SVN_PROP_REVISION_LOG)))
*message = message_s->data;
}
}
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/config.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/config.c Fri May 10 14:58:47 2013
@@ -29,6 +29,7 @@
#include <apr_general.h>
#include <apr_lib.h>
+#include "svn_hash.h"
#include "svn_error.h"
#include "svn_pools.h"
#include "config_impl.h"
@@ -46,9 +47,6 @@ struct cfg_section_t
/* The section name. */
const char *name;
- /* The section name, converted into a hash key. */
- const char *hash_key;
-
/* Table of cfg_option_t's. */
apr_hash_t *options;
};
@@ -79,9 +77,10 @@ struct cfg_option_t
svn_error_t *
-svn_config_create(svn_config_t **cfgp,
- svn_boolean_t section_names_case_sensitive,
- apr_pool_t *result_pool)
+svn_config_create2(svn_config_t **cfgp,
+ svn_boolean_t section_names_case_sensitive,
+ svn_boolean_t option_names_case_sensitive,
+ apr_pool_t *result_pool)
{
svn_config_t *cfg = apr_palloc(result_pool, sizeof(*cfg));
@@ -92,21 +91,26 @@ svn_config_create(svn_config_t **cfgp,
cfg->tmp_key = svn_stringbuf_create_empty(result_pool);
cfg->tmp_value = svn_stringbuf_create_empty(result_pool);
cfg->section_names_case_sensitive = section_names_case_sensitive;
+ cfg->option_names_case_sensitive = option_names_case_sensitive;
*cfgp = cfg;
return SVN_NO_ERROR;
}
svn_error_t *
-svn_config_read2(svn_config_t **cfgp, const char *file,
+svn_config_read3(svn_config_t **cfgp, const char *file,
svn_boolean_t must_exist,
svn_boolean_t section_names_case_sensitive,
- apr_pool_t *pool)
+ svn_boolean_t option_names_case_sensitive,
+ apr_pool_t *result_pool)
{
svn_config_t *cfg;
svn_error_t *err;
- SVN_ERR(svn_config_create(&cfg, section_names_case_sensitive, pool));
+ SVN_ERR(svn_config_create2(&cfg,
+ section_names_case_sensitive,
+ option_names_case_sensitive,
+ result_pool));
/* Yes, this is platform-specific code in Subversion, but there's no
practical way to migrate it into APR, as it's simultaneously
@@ -116,10 +120,10 @@ svn_config_read2(svn_config_t **cfgp, co
#ifdef WIN32
if (0 == strncmp(file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN))
err = svn_config__parse_registry(cfg, file + SVN_REGISTRY_PREFIX_LEN,
- must_exist, pool);
+ must_exist, result_pool);
else
#endif /* WIN32 */
- err = svn_config__parse_file(cfg, file, must_exist, pool);
+ err = svn_config__parse_file(cfg, file, must_exist, result_pool);
if (err != SVN_NO_ERROR)
return err;
@@ -132,13 +136,17 @@ svn_config_read2(svn_config_t **cfgp, co
svn_error_t *
svn_config_parse(svn_config_t **cfgp, svn_stream_t *stream,
svn_boolean_t section_names_case_sensitive,
+ svn_boolean_t option_names_case_sensitive,
apr_pool_t *result_pool)
{
svn_config_t *cfg;
svn_error_t *err;
apr_pool_t *scratch_pool = svn_pool_create(result_pool);
- err = svn_config_create(&cfg, section_names_case_sensitive, result_pool);
+ err = svn_config_create2(&cfg,
+ section_names_case_sensitive,
+ option_names_case_sensitive,
+ result_pool);
if (err == SVN_NO_ERROR)
err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
@@ -180,7 +188,8 @@ read_all(svn_config_t **cfgp,
#ifdef WIN32
if (sys_registry_path)
{
- SVN_ERR(svn_config_read2(cfgp, sys_registry_path, FALSE, FALSE, pool));
+ SVN_ERR(svn_config_read3(cfgp, sys_registry_path, FALSE, FALSE, FALSE,
+ pool));
red_config = TRUE;
}
#endif /* WIN32 */
@@ -191,7 +200,8 @@ read_all(svn_config_t **cfgp,
SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE));
else
{
- SVN_ERR(svn_config_read2(cfgp, sys_file_path, FALSE, FALSE, pool));
+ SVN_ERR(svn_config_read3(cfgp, sys_file_path,
+ FALSE, FALSE, FALSE, pool));
red_config = TRUE;
}
}
@@ -205,8 +215,8 @@ read_all(svn_config_t **cfgp,
SVN_ERR(svn_config_merge(*cfgp, usr_registry_path, FALSE));
else
{
- SVN_ERR(svn_config_read2(cfgp, usr_registry_path,
- FALSE, FALSE, pool));
+ SVN_ERR(svn_config_read3(cfgp, usr_registry_path,
+ FALSE, FALSE, FALSE, pool));
red_config = TRUE;
}
}
@@ -218,13 +228,14 @@ read_all(svn_config_t **cfgp,
SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE));
else
{
- SVN_ERR(svn_config_read2(cfgp, usr_file_path, FALSE, FALSE, pool));
+ SVN_ERR(svn_config_read3(cfgp, usr_file_path,
+ FALSE, FALSE, FALSE, pool));
red_config = TRUE;
}
}
if (! red_config)
- SVN_ERR(svn_config_create(cfgp, FALSE, pool));
+ SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
return SVN_NO_ERROR;
}
@@ -354,7 +365,10 @@ svn_config_merge(svn_config_t *cfg, cons
### We could use a tmp subpool for this, since merge_cfg is going
to be tossed afterwards. Premature optimization, though? */
svn_config_t *merge_cfg;
- SVN_ERR(svn_config_read2(&merge_cfg, file, must_exist, FALSE, cfg->pool));
+ SVN_ERR(svn_config_read3(&merge_cfg, file, must_exist,
+ cfg->section_names_case_sensitive,
+ cfg->option_names_case_sensitive,
+ cfg->pool));
/* Now copy the new options into the original table. */
for_each_option(merge_cfg, cfg, merge_cfg->pool, merge_callback);
@@ -429,7 +443,8 @@ find_option(svn_config_t *cfg, const cha
/* Canonicalize the option key */
svn_stringbuf_set(cfg->tmp_key, option);
- make_hash_key(cfg->tmp_key->data);
+ if (! cfg->option_names_case_sensitive)
+ make_hash_key(cfg->tmp_key->data);
opt = apr_hash_get(sec->options, cfg->tmp_key->data,
cfg->tmp_key->len);
@@ -463,19 +478,29 @@ make_string_from_option(const char **val
/* Expand the option value if necessary. */
if (!opt->expanded)
{
- apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
+ /* before attempting to expand an option, check for the placeholder.
+ * If none is there, there is no point in calling expand_option_value.
+ */
+ if (opt->value && strchr(opt->value, '%'))
+ {
+ apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
- expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
- opt->expanded = TRUE;
+ expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
+ opt->expanded = TRUE;
- if (!x_pool)
+ if (!x_pool)
+ {
+ /* Grab the fully expanded value from tmp_pool before its
+ disappearing act. */
+ if (opt->x_value)
+ opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
+ strlen(opt->x_value));
+ svn_pool_destroy(tmp_pool);
+ }
+ }
+ else
{
- /* Grab the fully expanded value from tmp_pool before its
- disappearing act. */
- if (opt->x_value)
- opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
- strlen(opt->x_value));
- svn_pool_destroy(tmp_pool);
+ opt->expanded = TRUE;
}
}
@@ -575,41 +600,45 @@ expand_option_value(svn_config_t *cfg, c
*opt_x_valuep = NULL;
}
-static void
+static cfg_section_t *
svn_config_addsection(svn_config_t *cfg,
- const char *section,
- cfg_section_t **sec)
-{
+ const char *section)
+{
cfg_section_t *s;
+ const char *hash_key;
s = apr_palloc(cfg->pool, sizeof(cfg_section_t));
s->name = apr_pstrdup(cfg->pool, section);
if(cfg->section_names_case_sensitive)
- s->hash_key = s->name;
+ hash_key = s->name;
else
- s->hash_key = make_hash_key(apr_pstrdup(cfg->pool, section));
+ hash_key = make_hash_key(apr_pstrdup(cfg->pool, section));
s->options = apr_hash_make(cfg->pool);
- apr_hash_set(cfg->sections, s->hash_key, APR_HASH_KEY_STRING, s);
-
- *sec = s;
+ svn_hash_sets(cfg->sections, hash_key, s);
+
+ return s;
}
static void
svn_config_create_option(cfg_option_t **opt,
const char *option,
const char *value,
+ svn_boolean_t option_names_case_sensitive,
apr_pool_t *pool)
{
cfg_option_t *o;
o = apr_palloc(pool, sizeof(cfg_option_t));
o->name = apr_pstrdup(pool, option);
- o->hash_key = make_hash_key(apr_pstrdup(pool, option));
+ if(option_names_case_sensitive)
+ o->hash_key = o->name;
+ else
+ o->hash_key = make_hash_key(apr_pstrdup(pool, option));
o->value = apr_pstrdup(pool, value);
o->x_value = NULL;
o->expanded = FALSE;
-
+
*opt = o;
}
@@ -669,15 +698,17 @@ svn_config_set(svn_config_t *cfg,
}
/* Create a new option */
- svn_config_create_option(&opt, option, value, cfg->pool);
+ svn_config_create_option(&opt, option, value,
+ cfg->option_names_case_sensitive,
+ cfg->pool);
if (sec == NULL)
{
/* Even the section doesn't exist. Create it. */
- svn_config_addsection(cfg, section, &sec);
+ sec = svn_config_addsection(cfg, section);
}
- apr_hash_set(sec->options, opt->hash_key, APR_HASH_KEY_STRING, opt);
+ svn_hash_sets(sec->options, opt->hash_key, opt);
}
@@ -1004,7 +1035,7 @@ const char *svn_config_find_group(svn_co
gb.key = key;
gb.match = NULL;
gb.pool = pool;
- svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool);
+ (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool);
return gb.match;
}
@@ -1035,10 +1066,11 @@ svn_config_dup(svn_config_t **cfgp,
apr_hash_index_t *optidx;
*cfgp = 0;
- SVN_ERR(svn_config_create(cfgp, FALSE, pool));
+ SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
(*cfgp)->x_values = src->x_values;
(*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive;
+ (*cfgp)->option_names_case_sensitive = src->option_names_case_sensitive;
for (sectidx = apr_hash_first(pool, src->sections);
sectidx != NULL;
@@ -1053,7 +1085,7 @@ svn_config_dup(svn_config_t **cfgp,
apr_hash_this(sectidx, §key, §keyLength, §val);
srcsect = sectval;
- svn_config_addsection(*cfgp, srcsect->name, &destsec);
+ destsec = svn_config_addsection(*cfgp, srcsect->name);
for (optidx = apr_hash_first(pool, srcsect->options);
optidx != NULL;
@@ -1068,7 +1100,9 @@ svn_config_dup(svn_config_t **cfgp,
apr_hash_this(optidx, &optkey, &optkeyLength, &optval);
srcopt = optval;
- svn_config_create_option(&destopt, srcopt->name, srcopt->value, pool);
+ svn_config_create_option(&destopt, srcopt->name, srcopt->value,
+ (*cfgp)->option_names_case_sensitive,
+ pool);
destopt->value = apr_pstrdup(pool, srcopt->value);
destopt->x_value = apr_pstrdup(pool, srcopt->x_value);
@@ -1078,7 +1112,7 @@ svn_config_dup(svn_config_t **cfgp,
optkeyLength, destopt);
}
}
-
+
return SVN_NO_ERROR;
}
@@ -1105,7 +1139,7 @@ svn_config_copy_config(apr_hash_t **cfg_
SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool));
- apr_hash_set(*cfg_hash,
+ apr_hash_set(*cfg_hash,
apr_pstrdup(pool, (const char*)ckey),
ckeyLength, destconfig);
}
@@ -1170,6 +1204,6 @@ svn_config_has_section(svn_config_t *cfg
if (! cfg->section_names_case_sensitive)
make_hash_key(cfg->tmp_key->data);
- sec = apr_hash_get(cfg->sections, cfg->tmp_key->data, APR_HASH_KEY_STRING);
+ sec = svn_hash_gets(cfg->sections, cfg->tmp_key->data);
return sec != NULL;
}
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/config_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/config_auth.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/config_auth.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/config_auth.c Fri May 10 14:58:47 2013
@@ -26,13 +26,15 @@
#include "svn_dirent_uri.h"
#include "svn_hash.h"
#include "svn_io.h"
-
+#include "svn_pools.h"
#include "config_impl.h"
#include "auth.h"
#include "svn_private_config.h"
+#include "private/svn_auth_private.h"
+
/* Helper for svn_config_{read|write}_auth_data. Return a path to a
file within ~/.subversion/auth/ that holds CRED_KIND credentials
within REALMSTRING. If no path is available *PATH will be set to
@@ -128,8 +130,8 @@ svn_config_write_auth_data(apr_hash_t *h
/* Add the realmstring to the hash, so programs (or users) can
verify exactly which set of credentials this file holds. */
- apr_hash_set(hash, SVN_CONFIG_REALMSTRING_KEY, APR_HASH_KEY_STRING,
- svn_string_create(realmstring, pool));
+ svn_hash_sets(hash, SVN_CONFIG_REALMSTRING_KEY,
+ svn_string_create(realmstring, pool));
SVN_ERR_W(svn_io_file_open(&authfile, auth_path,
(APR_WRITE | APR_CREATE | APR_TRUNCATE
@@ -146,7 +148,130 @@ svn_config_write_auth_data(apr_hash_t *h
/* To be nice, remove the realmstring from the hash again, just in
case the caller wants their hash unchanged. */
- apr_hash_set(hash, SVN_CONFIG_REALMSTRING_KEY, APR_HASH_KEY_STRING, NULL);
+ svn_hash_sets(hash, SVN_CONFIG_REALMSTRING_KEY, NULL);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_config_walk_auth_data(const char *config_dir,
+ svn_config_auth_walk_func_t walk_func,
+ void *walk_baton,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ apr_pool_t *iterpool;
+ svn_boolean_t finished = FALSE;
+ const char *cred_kinds[] =
+ {
+ SVN_AUTH_CRED_SIMPLE,
+ SVN_AUTH_CRED_USERNAME,
+ SVN_AUTH_CRED_SSL_CLIENT_CERT,
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+ SVN_AUTH_CRED_SSL_SERVER_TRUST,
+ NULL
+ };
+
+ if (! config_dir)
+ {
+ /* Can't locate the cache to clear */
+ return SVN_NO_ERROR;
+ }
+
+ iterpool = svn_pool_create(scratch_pool);
+ for (i = 0; cred_kinds[i]; i++)
+ {
+ const char *item_path;
+ const char *dir_path;
+ apr_hash_t *nodes;
+ svn_error_t *err;
+ apr_pool_t *itempool;
+ apr_hash_index_t *hi;
+
+ svn_pool_clear(iterpool);
+
+ if (finished)
+ break;
+
+ SVN_ERR(svn_auth__file_path(&item_path, cred_kinds[i], "!", config_dir,
+ iterpool));
+
+ dir_path = svn_dirent_dirname(item_path, iterpool);
+
+ err = svn_io_get_dirents3(&nodes, dir_path, TRUE, iterpool, iterpool);
+ if (err)
+ {
+ if (!APR_STATUS_IS_ENOENT(err->apr_err)
+ && !SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
+ return svn_error_trace(err);
+
+ svn_error_clear(err);
+ continue;
+ }
+
+ itempool = svn_pool_create(iterpool);
+ for (hi = apr_hash_first(iterpool, nodes); hi; hi = apr_hash_next(hi))
+ {
+ svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
+ svn_stream_t *stream;
+ apr_hash_t *creds_hash;
+ const svn_string_t *realm;
+ svn_boolean_t delete_file = FALSE;
+
+ if (finished)
+ break;
+
+ if (dirent->kind != svn_node_file)
+ continue;
+
+ svn_pool_clear(itempool);
+
+ item_path = svn_dirent_join(dir_path, svn__apr_hash_index_key(hi),
+ itempool);
+
+ err = svn_stream_open_readonly(&stream, item_path,
+ itempool, itempool);
+ if (err)
+ {
+ /* Ignore this file. There are no credentials in it anyway */
+ svn_error_clear(err);
+ continue;
+ }
+
+ creds_hash = apr_hash_make(itempool);
+ err = svn_hash_read2(creds_hash, stream,
+ SVN_HASH_TERMINATOR, itempool);
+ err = svn_error_compose_create(err, svn_stream_close(stream));
+ if (err)
+ {
+ /* Ignore this file. There are no credentials in it anyway */
+ svn_error_clear(err);
+ continue;
+ }
+
+ realm = svn_hash_gets(creds_hash, SVN_CONFIG_REALMSTRING_KEY);
+ if (! realm)
+ continue; /* Not an auth file */
+
+ err = walk_func(&delete_file, walk_baton, cred_kinds[i],
+ realm->data, creds_hash, itempool);
+ if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+ {
+ svn_error_clear(err);
+ err = SVN_NO_ERROR;
+ finished = TRUE;
+ }
+ SVN_ERR(err);
+
+ if (delete_file)
+ {
+ /* Delete the file on disk */
+ SVN_ERR(svn_io_remove_file2(item_path, TRUE, itempool));
+ }
+ }
+ }
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/config_file.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/config_file.c Fri May 10 14:58:47 2013
@@ -417,7 +417,7 @@ svn_config__parse_file(svn_config_t *cfg
err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
- if (err != SVN_NO_ERROR)
+ if (err != SVN_NO_ERROR)
{
/* Add the filename to the error stack. */
err = svn_error_createf(err->apr_err, err,
@@ -1155,6 +1155,16 @@ svn_config_ensure(const char *config_dir
"### ra_local (the file:// scheme). The value represents the number" NL
"### of MB used by the cache." NL
"# memory-cache-size = 16" NL
+ "### Set diff-ignore-content-type to 'yes' to cause 'svn diff' to" NL
+ "### attempt to show differences of all modified files regardless" NL
+ "### of their MIME content type. By default, Subversion will only" NL
+ "### attempt to show differences for files believed to have human-" NL
+ "### readable (non-binary) content. This option is especially" NL
+ "### useful when Subversion is configured (via the 'diff-cmd'" NL
+ "### option) to employ an external differencing tool which is able" NL
+ "### to show meaningful differences for binary file formats. [New" NL
+ "### in 1.9]" NL
+ "# diff-ignore-content-type = no" NL
"" NL
"### Section for configuring automatic properties." NL
"[auto-props]" NL
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/config_impl.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/config_impl.h?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/config_impl.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/config_impl.h Fri May 10 14:58:47 2013
@@ -67,6 +67,9 @@ struct svn_config_t
/* Specifies whether section names are populated case sensitively. */
svn_boolean_t section_names_case_sensitive;
+
+ /* Specifies whether option names are populated case sensitively. */
+ svn_boolean_t option_names_case_sensitive;
};
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/config_win.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/config_win.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/config_win.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/config_win.c Fri May 10 14:58:47 2013
@@ -215,18 +215,17 @@ svn_config__parse_registry(svn_config_t
for (index = 0; ; ++index)
{
DWORD section_len = (DWORD)section->blocksize;
- FILETIME last_write_time;
HKEY sub_hkey;
err = RegEnumKeyEx(hkey, index, section->data, §ion_len,
- NULL, NULL, NULL, &last_write_time);
+ NULL, NULL, NULL, NULL);
if (err == ERROR_NO_MORE_ITEMS)
break;
if (err == ERROR_MORE_DATA)
{
svn_stringbuf_ensure(section, section_len);
err = RegEnumKeyEx(hkey, index, section->data, §ion_len,
- NULL, NULL, NULL, &last_write_time);
+ NULL, NULL, NULL, NULL);
}
if (err != ERROR_SUCCESS)
{
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/debug.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/debug.c?rev=1481041&r1=1481040&r2=1481041&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/debug.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/debug.c Fri May 10 14:58:47 2013
@@ -32,6 +32,9 @@
#include "svn_types.h"
#include "svn_string.h"
+#ifndef SVN_DBG__PROTOTYPES
+#define SVN_DBG__PROTOTYPES
+#endif
#include "private/svn_debug.h"