You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by vm...@apache.org on 2012/12/23 19:34:20 UTC
svn commit: r1425508 [9/17] - in /subversion/branches/javahl-ra: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/hudson/
notes/ notes/api-errata/1.8/ notes/obliterate/ notes/tree-conflicts/
subversion/ subversion/bindings/s...
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/cache-membuffer.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/cache-membuffer.c Sun Dec 23 18:34:14 2012
@@ -33,11 +33,12 @@
#include "svn_string.h"
#include "private/svn_dep_compat.h"
#include "private/svn_mutex.h"
+#include "private/svn_pseudo_md5.h"
/*
* This svn_cache__t implementation actually consists of two parts:
* a shared (per-process) singleton membuffer cache instance and shallow
- * svn_cache__t frontend instances that each use different key spaces.
+ * svn_cache__t front-end instances that each use different key spaces.
* For data management, they all forward to the singleton membuffer cache.
*
* A membuffer cache consists of two parts:
@@ -65,7 +66,7 @@
*
* 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 accomodate the new
+ * 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.
@@ -79,7 +80,7 @@
* get evicted, it is moved to the begin of that window and the window is
* moved.
*
- * Moreover, the entry's hits get halfed to make that entry more likely to
+ * Moreover, the entry's hits get halved to make that entry more likely to
* be removed the next time the sliding insertion / removal window comes by.
* As a result, frequently used entries are likely not to be dropped until
* they get not used for a while. Also, even a cache thrashing situation
@@ -100,33 +101,46 @@
* on their hash key.
*/
-/* A 4-way associative cache seems to be the best compromise between
+/* A 16-way associative cache seems to be a good compromise between
* performance (worst-case lookups) and efficiency-loss due to collisions.
*
* This value may be changed to any positive integer.
*/
-#define GROUP_SIZE 4
-
-/* We use MD5 for digest size and speed (SHA1 is >2x slower, for instance).
- */
-#define KEY_SIZE APR_MD5_DIGESTSIZE
+#define GROUP_SIZE 16
/* For more efficient copy operations, let'a align all data items properly.
* Must be a power of 2.
*/
#define ITEM_ALIGNMENT 16
-/* Don't create cache segments smaller than this value unless the total
- * cache size itself is smaller.
+/* 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
+
+/* The minimum segment size we will allow for multi-segmented caches
+ */
+#define MIN_SEGMENT_SIZE 0x10000ull
+
+/* The maximum number of segments allowed. Larger numbers reduce the size
+ * of each segment, in turn reducing the max size of a cachable item.
+ * Also, each segment gets its own lock object. The actual number supported
+ * by the OS may therefore be lower and svn_cache__membuffer_cache_create
+ * may return an error.
*/
-#define MIN_SEGMENT_SIZE 0x2000000ull
+#define MAX_SEGMENT_COUNT 0x10000
+
+/* 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
/* 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
* vector that is likely to fit into the CPU caches even for fairly large
- * caches. For instance, the default of 32 means 8x32 groups per byte, i.e.
- * 8 flags/byte x 32 groups/flag x 4 entries/group x 40 index bytes/entry
- * x 16 cache bytes/index byte = 1kB init vector / 640MB cache.
+ * membuffer caches. For instance, the default of 32 means 8x32 groups per
+ * byte, i.e. 8 flags/byte x 32 groups/flag x 8 entries/group x 40 index
+ * bytes/entry x 8 cache bytes/index byte = 1kB init vector / 640MB cache.
*/
#define GROUP_INIT_GRANULARITY 32
@@ -134,10 +148,6 @@
*/
#define NO_INDEX APR_UINT32_MAX
-/* Invalid buffer offset reference value. Equivalent to APR_UINT32_T(-1)
- */
-#define NO_OFFSET APR_UINT64_MAX
-
/* To save space in our group structure, we only use 32 bit size values
* and, therefore, limit the size of each entry to just below 4GB.
* Supporting larger items is not a good idea as the data transfer
@@ -145,6 +155,12 @@
*/
#define MAX_ITEM_SIZE ((apr_uint32_t)(0 - ITEM_ALIGNMENT))
+/* A 16 byte key type. We use that to identify cache entries.
+ * The notation as just two integer values will cause many compilers
+ * to create better code.
+ */
+typedef apr_uint64_t entry_key_t[2];
+
/* Debugging / corruption detection support.
* If you define this macro, the getter functions will performed expensive
* checks on the item data, requested keys and entry types. If there is
@@ -205,7 +221,7 @@ static void get_prefix_tail(const char *
/* Initialize all members of TAG except for the content hash.
*/
static svn_error_t *store_key_part(entry_tag_t *tag,
- unsigned char *prefix_hash,
+ entry_key_t prefix_hash,
char *prefix_tail,
const void *key,
apr_size_t key_len,
@@ -270,11 +286,12 @@ static svn_error_t* assert_equal_tags(co
#define DEBUG_CACHE_MEMBUFFER_TAG_ARG entry_tag_t *tag,
-#define DEBUG_CACHE_MEMBUFFER_TAG &tag,
+#define DEBUG_CACHE_MEMBUFFER_TAG tag,
#define DEBUG_CACHE_MEMBUFFER_INIT_TAG \
- entry_tag_t tag; \
- SVN_ERR(store_key_part(&tag, \
+ entry_tag_t _tag; \
+ entry_tag_t *tag = &_tag; \
+ SVN_ERR(store_key_part(tag, \
cache->prefix, \
cache->prefix_tail, \
key, \
@@ -296,17 +313,15 @@ 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. An entry is unused if and only if its OFFSET
- * member is NO_OFFSET.
+ * list of used entries.
*/
typedef struct entry_t
{
/* Identifying the data item. Only valid for used entries.
*/
- unsigned char key [KEY_SIZE];
+ entry_key_t key;
- /* If NO_OFFSET, the entry is not in used. Otherwise, it is the offset
- * of the cached item's serialized data within the data buffer.
+ /* The offset of the cached item's serialized data within the data buffer.
*/
apr_uint64_t offset;
@@ -344,7 +359,14 @@ typedef struct entry_t
/* We group dictionary entries to make this GROUP-SIZE-way assicative.
*/
-typedef entry_t entry_group_t[GROUP_SIZE];
+typedef struct entry_group_t
+{
+ /* number of entries used [0 .. USED-1] */
+ apr_size_t used;
+
+ /* the actual entries */
+ entry_t entries[GROUP_SIZE];
+} entry_group_t;
/* The cache header structure.
*/
@@ -444,6 +466,12 @@ struct svn_membuffer_t
* thread-safe.
*/
apr_thread_rwlock_t *lock;
+
+ /* If set, write access will wait until they get exclusive access.
+ * Otherwise, they will become no-ops if the segment is currently
+ * read-locked.
+ */
+ svn_boolean_t allow_blocking_writes;
#endif
};
@@ -471,18 +499,48 @@ read_lock_cache(svn_membuffer_t *cache)
return SVN_NO_ERROR;
}
-/* If locking is supported for CACHE, aquire a write lock for it.
+/* If locking is supported for CACHE, acquire a write lock for it.
*/
static svn_error_t *
-write_lock_cache(svn_membuffer_t *cache)
+write_lock_cache(svn_membuffer_t *cache, svn_boolean_t *success)
{
#if APR_HAS_THREADS
if (cache->lock)
- {
- apr_status_t status = apr_thread_rwlock_wrlock(cache->lock);
- if (status)
- return svn_error_wrap_apr(status, _("Can't write-lock cache mutex"));
- }
+ {
+ apr_status_t status;
+ if (cache->allow_blocking_writes)
+ {
+ status = apr_thread_rwlock_wrlock(cache->lock);
+ }
+ else
+ {
+ status = apr_thread_rwlock_trywrlock(cache->lock);
+ if (SVN_LOCK_IS_BUSY(status))
+ {
+ *success = FALSE;
+ status = APR_SUCCESS;
+ }
+ }
+
+ if (status)
+ return svn_error_wrap_apr(status,
+ _("Can't write-lock cache mutex"));
+ }
+#endif
+ return SVN_NO_ERROR;
+}
+
+/* If locking is supported for CACHE, acquire an unconditional write lock
+ * for it.
+ */
+static svn_error_t *
+force_write_lock_cache(svn_membuffer_t *cache)
+{
+#if APR_HAS_THREADS
+ apr_status_t status = apr_thread_rwlock_wrlock(cache->lock);
+ if (status)
+ return svn_error_wrap_apr(status,
+ _("Can't write-lock cache mutex"));
#endif
return SVN_NO_ERROR;
}
@@ -508,7 +566,7 @@ unlock_cache(svn_membuffer_t *cache, svn
}
/* If supported, guard the execution of EXPR with a read lock to cache.
- * Macro has been modelled after SVN_MUTEX__WITH_LOCK.
+ * Macro has been modeled after SVN_MUTEX__WITH_LOCK.
*/
#define WITH_READ_LOCK(cache, expr) \
do { \
@@ -517,12 +575,29 @@ do {
} while (0)
/* If supported, guard the execution of EXPR with a write lock to cache.
- * Macro has been modelled after SVN_MUTEX__WITH_LOCK.
- */
-#define WITH_WRITE_LOCK(cache, expr) \
-do { \
- SVN_ERR(write_lock_cache(cache)); \
- SVN_ERR(unlock_cache(cache, (expr))); \
+ * Macro has been modeled after SVN_MUTEX__WITH_LOCK.
+ *
+ * The write lock process is complicated if we don't allow to wait for
+ * the lock: If we didn't get the lock, we may still need to remove an
+ * existing entry for the given key because that content is now stale.
+ * Once we discovered such an entry, we unconditionally do a blocking
+ * wait for the write lock. In case no old content could be found, a
+ * failing lock attempt is simply a no-op and we exit the macro.
+ */
+#define WITH_WRITE_LOCK(cache, expr) \
+do { \
+ svn_boolean_t got_lock = TRUE; \
+ SVN_ERR(write_lock_cache(cache, &got_lock)); \
+ if (!got_lock) \
+ { \
+ svn_boolean_t exists; \
+ SVN_ERR(entry_exists(cache, group_index, key, &exists)); \
+ if (exists) \
+ SVN_ERR(force_write_lock_cache(cache)); \
+ else \
+ break; \
+ } \
+ SVN_ERR(unlock_cache(cache, (expr))); \
} while (0)
/* Resolve a dictionary entry reference, i.e. return the entry
@@ -531,7 +606,7 @@ do {
static APR_INLINE entry_t *
get_entry(svn_membuffer_t *cache, apr_uint32_t idx)
{
- return &cache->directory[idx / GROUP_SIZE][idx % GROUP_SIZE];
+ return &cache->directory[idx / GROUP_SIZE].entries[idx % GROUP_SIZE];
}
/* Get the entry references for the given ENTRY.
@@ -539,7 +614,11 @@ get_entry(svn_membuffer_t *cache, apr_ui
static APR_INLINE apr_uint32_t
get_index(svn_membuffer_t *cache, entry_t *entry)
{
- return (apr_uint32_t)(entry - (entry_t *)cache->directory);
+ apr_uint32_t group_index
+ = ((char *)entry - (char *)cache->directory) / sizeof(entry_group_t);
+
+ return group_index * GROUP_SIZE
+ + (apr_uint32_t)(entry - cache->directory[group_index].entries);
}
/* Remove the used ENTRY from the CACHE, i.e. make it "unused".
@@ -548,11 +627,16 @@ get_index(svn_membuffer_t *cache, entry_
static void
drop_entry(svn_membuffer_t *cache, entry_t *entry)
{
+ /* the group that ENTRY belongs to plus a number of useful index values
+ */
apr_uint32_t idx = get_index(cache, entry);
+ apr_uint32_t group_index = idx / GROUP_SIZE;
+ entry_group_t *group = &cache->directory[group_index];
+ apr_uint32_t last_in_group = group_index * GROUP_SIZE + group->used - 1;
/* Only valid to be called for used entries.
*/
- assert(entry->offset != NO_OFFSET);
+ assert(idx <= last_in_group);
/* update global cache usage counters
*/
@@ -574,7 +658,7 @@ drop_entry(svn_membuffer_t *cache, entry
/* remove the first entry -> insertion may start at pos 0, now */
cache->current_data = 0;
}
- else
+ else
{
/* insertion may start right behind the previous entry */
entry_t *previous = get_entry(cache, entry->previous);
@@ -595,9 +679,35 @@ drop_entry(svn_membuffer_t *cache, entry
else
get_entry(cache, entry->next)->previous = entry->previous;
- /* Mark the entry as unused.
+ /* 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.
*/
- entry->offset = NO_OFFSET;
+ if (idx < last_in_group)
+ {
+ /* copy the last used entry to the removed entry's index
+ */
+ *entry = group->entries[group->used-1];
+
+ /* update foreign links to new index
+ */
+ if (last_in_group == cache->next)
+ cache->next = idx;
+
+ if (entry->previous == NO_INDEX)
+ cache->first = idx;
+ else
+ get_entry(cache, entry->previous)->next = idx;
+
+ if (entry->next == NO_INDEX)
+ cache->last = idx;
+ else
+ get_entry(cache, entry->next)->previous = idx;
+ }
+
+ /* Update the number of used entries.
+ */
+ group->used--;
}
/* Insert ENTRY into the chain of used dictionary entries. The entry's
@@ -607,21 +717,28 @@ drop_entry(svn_membuffer_t *cache, entry
static void
insert_entry(svn_membuffer_t *cache, entry_t *entry)
{
+ /* the group that ENTRY belongs to plus a number of useful index values
+ */
apr_uint32_t idx = get_index(cache, entry);
+ apr_uint32_t group_index = idx / GROUP_SIZE;
+ entry_group_t *group = &cache->directory[group_index];
entry_t *next = cache->next == NO_INDEX
? NULL
: get_entry(cache, cache->next);
/* 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(idx == group_index * GROUP_SIZE + group->used);
cache->current_data = ALIGN_VALUE(entry->offset + entry->size);
- /* update global cache usage counters
+ /* update usage counters
*/
cache->used_entries++;
cache->data_used += entry->size;
entry->hit_count = 0;
+ group->used++;
/* update entry chain
*/
@@ -656,6 +773,11 @@ insert_entry(svn_membuffer_t *cache, ent
else
cache->first = idx;
}
+
+ /* The current insertion position must never point outside our
+ * data buffer.
+ */
+ assert(cache->current_data <= cache->data_size);
}
/* Map a KEY of 16 bytes to the CACHE and group that shall contain the
@@ -663,22 +785,13 @@ insert_entry(svn_membuffer_t *cache, ent
*/
static apr_uint32_t
get_group_index(svn_membuffer_t **cache,
- const apr_uint32_t *key)
+ entry_key_t key)
{
- 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).
- */
- 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;
+ 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;
}
/* Reduce the hit count of ENTRY and update the accumunated hit info
@@ -714,7 +827,7 @@ static void
initialize_group(svn_membuffer_t *cache, apr_uint32_t group_index)
{
unsigned char bit_mask;
- apr_uint32_t i, j;
+ apr_uint32_t i;
/* range of groups to initialize due to GROUP_INIT_GRANULARITY */
apr_uint32_t first_index =
@@ -724,8 +837,7 @@ initialize_group(svn_membuffer_t *cache,
last_index = cache->group_count;
for (i = first_index; i < last_index; ++i)
- for (j = 0; j < GROUP_SIZE; j++)
- cache->directory[i][j].offset = NO_OFFSET;
+ cache->directory[i].used = 0;
/* set the "initialized" bit for these groups */
bit_mask
@@ -749,16 +861,16 @@ initialize_group(svn_membuffer_t *cache,
static entry_t *
find_entry(svn_membuffer_t *cache,
apr_uint32_t group_index,
- const unsigned char *to_find,
+ const apr_uint64_t to_find[2],
svn_boolean_t find_empty)
{
- entry_t *group;
+ entry_group_t *group;
entry_t *entry = NULL;
- int i;
+ apr_size_t i;
/* get the group that *must* contain the entry
*/
- group = &cache->directory[group_index][0];
+ group = &cache->directory[group_index];
/* If the entry group has not been initialized, yet, there is no data.
*/
@@ -767,10 +879,11 @@ find_entry(svn_membuffer_t *cache,
if (find_empty)
{
initialize_group(cache, group_index);
- entry = group;
+ entry = &group->entries[0];
/* initialize entry for the new key */
- memcpy(entry->key, to_find, KEY_SIZE);
+ entry->key[0] = to_find[0];
+ entry->key[1] = to_find[1];
}
return entry;
@@ -778,54 +891,53 @@ find_entry(svn_membuffer_t *cache,
/* try to find the matching entry
*/
- for (i = 0; i < GROUP_SIZE; ++i)
- if (group[i].offset != NO_OFFSET &&
- !memcmp(to_find, group[i].key, KEY_SIZE))
+ for (i = 0; i < group->used; ++i)
+ if ( to_find[0] == group->entries[i].key[0]
+ && to_find[1] == group->entries[i].key[1])
{
/* found it
*/
- entry = &group[i];
+ entry = &group->entries[i];
if (find_empty)
drop_entry(cache, entry);
-
- return entry;
+ else
+ return entry;
}
/* None found. Are we looking for a free entry?
*/
if (find_empty)
{
- /* look for an empty entry and return that ...
- */
- for (i = 0; i < GROUP_SIZE; ++i)
- if (group[i].offset == NO_OFFSET)
- {
- entry = &group[i];
- break;
- }
-
- /* ... or, if none is empty, delete the oldest entry
+ /* if there is no empty entry, delete the oldest entry
*/
- if (entry == NULL)
+ if (group->used == GROUP_SIZE)
{
- entry = &group[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
+ * the other entries in this group.
+ */
+ entry = &group->entries[rand() % GROUP_SIZE];
for (i = 1; i < GROUP_SIZE; ++i)
- if (entry->hit_count > group[i].hit_count)
- entry = &group[i];
+ if (entry->hit_count > group->entries[i].hit_count)
+ entry = &group->entries[i];
/* for the entries that don't have been removed,
* reduce their hitcounts to put them at a relative
* disadvantage the next time.
*/
for (i = 0; i < GROUP_SIZE; ++i)
- if (entry != &group[i])
+ if (entry != &group->entries[i])
let_entry_age(cache, entry);
drop_entry(cache, entry);
}
- /* initialize entry for the new key */
- memcpy(entry->key, to_find, KEY_SIZE);
+ /* initialize entry for the new key
+ */
+ entry = &group->entries[group->used];
+ entry->key[0] = to_find[0];
+ entry->key[1] = to_find[1];
}
return entry;
@@ -863,6 +975,11 @@ move_entry(svn_membuffer_t *cache, entry
*/
cache->current_data = entry->offset + size;
cache->next = entry->next;
+
+ /* The current insertion position must never point outside our
+ * data buffer.
+ */
+ assert(cache->current_data <= cache->data_size);
}
/* If necessary, enlarge the insertion window until it is at least
@@ -904,7 +1021,7 @@ ensure_data_insertable(svn_membuffer_t *
/* leave function as soon as the insertion window is large enough
*/
- if (end - cache->current_data >= size)
+ if (end >= size + cache->current_data)
return TRUE;
/* Don't be too eager to cache data. Smaller items will fit into
@@ -946,22 +1063,38 @@ ensure_data_insertable(svn_membuffer_t *
}
else
{
- /* 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;
+ svn_boolean_t keep;
- /* 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.
- */
- if (entry->hit_count >= threshold)
+ 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.
+ */
+ average_hit_value = cache->hit_count / cache->used_entries;
+ threshold = (average_hit_value+1) * (rand() % 4096) / 2048;
+
+ keep = entry->hit_count >= threshold;
+ }
+ 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);
+ }
+
+ /* keepers or destroyers? */
+ if (keep)
{
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_size += entry->size;
drop_entry(cache, entry);
}
@@ -995,56 +1128,82 @@ static void* secure_aligned_alloc(apr_po
return memory;
}
-/* Create a new membuffer cache instance. If the TOTAL_SIZE of the
- * memory i too small to accomodate the DICTIONARY_SIZE, the latte
- * will be resized automatically. Also, a minumum size is assured
- * for the DICTIONARY_SIZE. THREAD_SAFE may be FALSE, if there will
- * be no concurrent acccess to the CACHE returned.
- *
- * All allocations, in particular the data buffer and dictionary will
- * be made from POOL.
- */
svn_error_t *
svn_cache__membuffer_cache_create(svn_membuffer_t **cache,
apr_size_t total_size,
apr_size_t directory_size,
+ apr_size_t segment_count,
svn_boolean_t thread_safe,
+ svn_boolean_t allow_blocking_writes,
apr_pool_t *pool)
{
svn_membuffer_t *c;
- apr_uint32_t segment_count_shift = 0;
- apr_uint32_t segment_count = 1;
-
apr_uint32_t seg;
apr_uint32_t group_count;
apr_uint32_t group_init_size;
apr_uint64_t data_size;
apr_uint64_t max_entry_size;
- /* Determine a reasonable number of cache segments. Segmentation is
- * only useful for multi-threaded / multi-core servers as it reduces
- * lock contention on these systems.
- *
- * But on these systems, we can assume that ample memory has been
- * allocated to this cache. Smaller caches should not be segmented
- * as this severely limites the maximum size of cachable items.
- *
- * Segments should not be smaller than 32MB and max. cachable item
- * size should grow as fast as segmentation.
+ /* Limit the total size (only relevant if we can address > 4GB)
*/
- while (((2 * MIN_SEGMENT_SIZE) << (2 * segment_count_shift)) < total_size)
- ++segment_count_shift;
+#if APR_SIZEOF_VOIDP > 4
+ if (total_size > MAX_SEGMENT_SIZE * MAX_SEGMENT_COUNT)
+ total_size = MAX_SEGMENT_SIZE * MAX_SEGMENT_COUNT;
+#endif
- segment_count = 1 << segment_count_shift;
+ /* Limit the segment count
+ */
+ if (segment_count > MAX_SEGMENT_COUNT)
+ 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)
+ segment_count &= segment_count-1;
+
+ /* if the caller hasn't provided a reasonable segment count or the above
+ * limitations set it to 0, derive one from the absolute cache size
+ */
+ if (segment_count < 1)
+ {
+ /* Determine a reasonable number of cache segments. Segmentation is
+ * only useful for multi-threaded / multi-core servers as it reduces
+ * lock contention on these systems.
+ *
+ * But on these systems, we can assume that ample memory has been
+ * allocated to this cache. Smaller caches should not be segmented
+ * as this severely limits the maximum size of cachable items.
+ *
+ * Segments should not be smaller than 32MB and max. cachable item
+ * size should grow as fast as segmentation.
+ */
+
+ apr_uint32_t segment_count_shift = 0;
+ while (((2 * DEFAULT_MIN_SEGMENT_SIZE) << (2 * segment_count_shift))
+ < total_size)
+ ++segment_count_shift;
+
+ segment_count = 1 << segment_count_shift;
+ }
+
+ /* If we have an extremely large cache (>512 GB), the default segment
+ * size may exceed the amount allocatable as one chunk. In that case,
+ * increase segmentation until we are under the threshold.
+ */
+ while ( total_size / segment_count > MAX_SEGMENT_SIZE
+ && segment_count < MAX_SEGMENT_COUNT)
+ segment_count *= 2;
/* allocate cache as an array of segments / cache objects */
c = apr_palloc(pool, segment_count * sizeof(*c));
/* Split total cache size into segments of equal size
*/
- total_size >>= segment_count_shift;
- directory_size >>= segment_count_shift;
+ total_size /= segment_count;
+ directory_size /= segment_count;
/* prevent pathological conditions: ensure a certain minimum cache size
*/
@@ -1061,8 +1220,10 @@ svn_cache__membuffer_cache_create(svn_me
/* limit the data size to what we can address.
* Note that this cannot overflow since all values are of size_t.
+ * Also, make it a multiple of the item placement granularity to
+ * prevent subtle overflows.
*/
- data_size = total_size - directory_size;
+ 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
@@ -1137,6 +1298,10 @@ svn_cache__membuffer_cache_create(svn_me
if (status)
return svn_error_wrap_apr(status, _("Can't create cache mutex"));
}
+
+ /* Select the behavior of write operations.
+ */
+ c[seg].allow_blocking_writes = allow_blocking_writes;
#endif
}
@@ -1146,6 +1311,40 @@ svn_cache__membuffer_cache_create(svn_me
return SVN_NO_ERROR;
}
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND and set *FOUND accordingly.
+ *
+ * Note: This function requires the caller to serialize access.
+ * Don't call it directly, call entry_exists instead.
+ */
+static svn_error_t *
+entry_exists_internal(svn_membuffer_t *cache,
+ apr_uint32_t group_index,
+ entry_key_t to_find,
+ svn_boolean_t *found)
+{
+ *found = find_entry(cache, group_index, to_find, FALSE) != NULL;
+ return SVN_NO_ERROR;
+}
+
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND and set *FOUND accordingly.
+ */
+static svn_error_t *
+entry_exists(svn_membuffer_t *cache,
+ apr_uint32_t group_index,
+ entry_key_t to_find,
+ svn_boolean_t *found)
+{
+ WITH_READ_LOCK(cache,
+ entry_exists_internal(cache,
+ group_index,
+ to_find,
+ found));
+
+ return SVN_NO_ERROR;
+}
+
/* Try to insert the serialized item given in BUFFER with SIZE into
* the group GROUP_INDEX of CACHE and uniquely identify it by hash
@@ -1161,13 +1360,39 @@ svn_cache__membuffer_cache_create(svn_me
*/
static svn_error_t *
membuffer_cache_set_internal(svn_membuffer_t *cache,
- const unsigned char *to_find,
+ entry_key_t to_find,
apr_uint32_t group_index,
char *buffer,
apr_size_t size,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
apr_pool_t *scratch_pool)
{
+ /* first, look for a previous entry for the given key */
+ entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
+
+ /* if there is an old version of that entry and the new data fits into
+ * the old spot, just re-use that space. */
+ if (buffer && entry && entry->size >= size)
+ {
+ cache->data_used += size - entry->size;
+ entry->size = size;
+
+#ifdef SVN_DEBUG_CACHE_MEMBUFFER
+
+ /* Remember original content, type and key (hashes)
+ */
+ SVN_ERR(store_content_part(tag, buffer, size, scratch_pool));
+ memcpy(&entry->tag, tag, sizeof(*tag));
+
+#endif
+
+ if (size)
+ memcpy(cache->data + entry->offset, buffer, size);
+
+ cache->total_writes++;
+ return SVN_NO_ERROR;
+ }
+
/* if necessary, enlarge the insertion window.
*/
if ( buffer != NULL
@@ -1176,9 +1401,9 @@ membuffer_cache_set_internal(svn_membuff
{
/* Remove old data for this key, if that exists.
* Get an unused entry for the key and and initialize it with
- * the serialized item's (future) posion within data buffer.
+ * the serialized item's (future) position within data buffer.
*/
- entry_t *entry = find_entry(cache, group_index, to_find, TRUE);
+ entry = find_entry(cache, group_index, to_find, TRUE);
entry->size = size;
entry->offset = cache->current_data;
@@ -1191,22 +1416,25 @@ membuffer_cache_set_internal(svn_membuff
#endif
+ /* Link the entry properly.
+ */
+ insert_entry(cache, entry);
+
/* Copy the serialized item data into the cache.
*/
if (size)
memcpy(cache->data + entry->offset, buffer, size);
- /* Link the entry properly.
- */
- insert_entry(cache, entry);
cache->total_writes++;
}
else
{
/* if there is already an entry for this key, drop it.
*/
- find_entry(cache, group_index, to_find, TRUE);
+ if (entry)
+ drop_entry(cache, entry);
}
+
return SVN_NO_ERROR;
}
@@ -1221,7 +1449,7 @@ membuffer_cache_set_internal(svn_membuff
*/
static svn_error_t *
membuffer_cache_set(svn_membuffer_t *cache,
- const void *key,
+ entry_key_t key,
void *item,
svn_cache__serialize_func_t serializer,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1265,7 +1493,7 @@ membuffer_cache_set(svn_membuffer_t *cac
static svn_error_t *
membuffer_cache_get_internal(svn_membuffer_t *cache,
apr_uint32_t group_index,
- const unsigned char *to_find,
+ entry_key_t to_find,
char **buffer,
apr_size_t *item_size,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1302,7 +1530,7 @@ membuffer_cache_get_internal(svn_membuff
/* Compare original content, type and key (hashes)
*/
- SVN_ERR(store_content_part(tag, buffer, entry->size, result_pool));
+ SVN_ERR(store_content_part(tag, *buffer, entry->size, result_pool));
SVN_ERR(assert_equal_tags(&entry->tag, tag));
#endif
@@ -1325,7 +1553,7 @@ membuffer_cache_get_internal(svn_membuff
*/
static svn_error_t *
membuffer_cache_get(svn_membuffer_t *cache,
- const void *key,
+ entry_key_t key,
void **item,
svn_cache__deserialize_func_t deserializer,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1372,7 +1600,7 @@ membuffer_cache_get(svn_membuffer_t *cac
static svn_error_t *
membuffer_cache_get_partial_internal(svn_membuffer_t *cache,
apr_uint32_t group_index,
- const unsigned char *to_find,
+ entry_key_t to_find,
void **item,
svn_boolean_t *found,
svn_cache__partial_getter_func_t deserializer,
@@ -1431,7 +1659,7 @@ membuffer_cache_get_partial_internal(svn
*/
static svn_error_t *
membuffer_cache_get_partial(svn_membuffer_t *cache,
- const void *key,
+ entry_key_t key,
void **item,
svn_boolean_t *found,
svn_cache__partial_getter_func_t deserializer,
@@ -1463,7 +1691,7 @@ membuffer_cache_get_partial(svn_membuffe
static svn_error_t *
membuffer_cache_set_partial_internal(svn_membuffer_t *cache,
apr_uint32_t group_index,
- const unsigned char *to_find,
+ entry_key_t to_find,
svn_cache__partial_setter_func_t func,
void *baton,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1504,7 +1732,7 @@ membuffer_cache_set_partial_internal(svn
#endif
- /* modify it, preferrably in-situ.
+ /* modify it, preferably in-situ.
*/
err = func((void **)&data, &size, baton, scratch_pool);
@@ -1525,7 +1753,7 @@ membuffer_cache_set_partial_internal(svn
{
/* Remove the old entry and try to make space for the new one.
*/
- drop_entry(cache, entry);
+ entry = find_entry(cache, group_index, to_find, TRUE);
if ( (cache->max_entry_size >= size)
&& ensure_data_insertable(cache, size))
{
@@ -1539,17 +1767,17 @@ membuffer_cache_set_partial_internal(svn
/* Link the entry properly.
*/
insert_entry(cache, entry);
+ }
+ }
#ifdef SVN_DEBUG_CACHE_MEMBUFFER
- /* Remember original content, type and key (hashes)
- */
- SVN_ERR(store_content_part(tag, data, size, scratch_pool));
- memcpy(&entry->tag, tag, sizeof(*tag));
+ /* Remember original content, type and key (hashes)
+ */
+ SVN_ERR(store_content_part(tag, data, size, scratch_pool));
+ memcpy(&entry->tag, tag, sizeof(*tag));
#endif
- }
- }
}
}
@@ -1563,7 +1791,7 @@ membuffer_cache_set_partial_internal(svn
*/
static svn_error_t *
membuffer_cache_set_partial(svn_membuffer_t *cache,
- const void *key,
+ entry_key_t key,
svn_cache__partial_setter_func_t func,
void *baton,
DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1575,7 +1803,7 @@ membuffer_cache_set_partial(svn_membuffe
WITH_WRITE_LOCK(cache,
membuffer_cache_set_partial_internal
(cache, group_index, key, func, baton,
- DEBUG_CACHE_MEMBUFFER_TAG_ARG
+ DEBUG_CACHE_MEMBUFFER_TAG
scratch_pool));
/* done here -> unlock the cache
@@ -1619,7 +1847,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.
*/
- apr_uint64_t prefix [APR_MD5_DIGESTSIZE / sizeof(apr_uint64_t)];
+ entry_key_t prefix;
/* A copy of the unmodified prefix. It is being used as a user-visible
* ID for this cache instance.
@@ -1633,7 +1861,7 @@ typedef struct svn_membuffer_cache_t
/* Temporary buffer containing the hash key for the current access
*/
- apr_uint64_t combined_key [APR_MD5_DIGESTSIZE / sizeof(apr_uint64_t)];
+ entry_key_t combined_key;
/* a pool for temporary allocations during get() and set()
*/
@@ -1673,7 +1901,31 @@ combine_key(svn_membuffer_cache_t *cache
if (key_len == APR_HASH_KEY_STRING)
key_len = strlen((const char *) key);
- apr_md5((unsigned char*)cache->combined_key, key, key_len);
+ if (key_len < 16)
+ {
+ apr_uint32_t data[4] = { 0 };
+ memcpy(data, key, key_len);
+
+ svn__pseudo_md5_15((apr_uint32_t *)cache->combined_key, data);
+ }
+ else if (key_len < 32)
+ {
+ apr_uint32_t data[8] = { 0 };
+ memcpy(data, key, key_len);
+
+ svn__pseudo_md5_31((apr_uint32_t *)cache->combined_key, data);
+ }
+ else if (key_len < 64)
+ {
+ apr_uint32_t data[16] = { 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);
+ }
cache->combined_key[0] ^= cache->prefix[0];
cache->combined_key[1] ^= cache->prefix[1];
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/cache-memcache.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/cache-memcache.c Sun Dec 23 18:34:14 2012
@@ -470,7 +470,8 @@ add_memcache_server(const char *name,
0, /* min connections */
5, /* soft max connections */
10, /* hard max connections */
- 50, /* connection time to live (secs) */
+ /* time to live (in microseconds) */
+ apr_time_from_sec(50),
&server);
if (apr_err != APR_SUCCESS)
{
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/cache_config.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/cache_config.c Sun Dec 23 18:34:14 2012
@@ -52,7 +52,7 @@ static svn_cache_config_t cache_settings
* has little impact on performance and a more modest
* value (< 100) may be more suitable.
*/
-#ifdef APR_HAS_THREADS
+#if APR_HAS_THREADS
FALSE /* assume multi-threaded operation.
* Because this simply activates proper synchronization
* between threads, it is a safe default.
@@ -118,8 +118,10 @@ svn_cache__get_global_membuffer_cache(vo
err = svn_cache__membuffer_cache_create(
&new_cache,
(apr_size_t)cache_size,
- (apr_size_t)(cache_size / 16),
+ (apr_size_t)(cache_size / 10),
+ 0,
! svn_cache_config_get()->single_threaded,
+ FALSE,
pool);
/* Some error occured. Most likely it's an OOM error but we don't
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/cmdline.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/cmdline.c Sun Dec 23 18:34:14 2012
@@ -526,6 +526,13 @@ svn_cmdline_create_auth_baton(svn_auth_b
if (non_interactive == FALSE)
{
+ svn_boolean_t ssl_client_cert_file_prompt;
+
+ SVN_ERR(svn_config_get_bool(cfg, &ssl_client_cert_file_prompt,
+ SVN_CONFIG_SECTION_AUTH,
+ SVN_CONFIG_OPTION_SSL_CLIENT_CERT_FILE_PROMPT,
+ FALSE));
+
/* Two basic prompt providers: username/password, and just username. */
svn_auth_get_simple_prompt_provider(&provider,
svn_cmdline_auth_simple_prompt,
@@ -539,19 +546,23 @@ svn_cmdline_create_auth_baton(svn_auth_b
2, /* retry limit */ pool);
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
- /* Three ssl prompt providers, for server-certs, client-certs,
- and client-cert-passphrases. */
+ /* SSL prompt providers: server-certs and client-cert-passphrases. */
svn_auth_get_ssl_server_trust_prompt_provider
(&provider, svn_cmdline_auth_ssl_server_trust_prompt, pb, pool);
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
- svn_auth_get_ssl_client_cert_prompt_provider
- (&provider, svn_cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
- APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
-
svn_auth_get_ssl_client_cert_pw_prompt_provider
(&provider, svn_cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool);
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
+
+ /* If configuration allows, add a provider for client-cert path
+ prompting, too. */
+ if (ssl_client_cert_file_prompt)
+ {
+ svn_auth_get_ssl_client_cert_prompt_provider
+ (&provider, svn_cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
+ }
}
else if (trust_server_cert)
{
@@ -631,6 +642,7 @@ void
svn_cmdline__print_xml_prop(svn_stringbuf_t **outstr,
const char* propname,
svn_string_t *propval,
+ svn_boolean_t inherited_prop,
apr_pool_t *pool)
{
const char *xml_safe;
@@ -654,16 +666,22 @@ svn_cmdline__print_xml_prop(svn_stringbu
}
if (encoding)
- svn_xml_make_open_tag(outstr, pool, svn_xml_protect_pcdata,
- "property", "name", propname,
- "encoding", encoding, NULL);
+ svn_xml_make_open_tag(
+ outstr, pool, svn_xml_protect_pcdata,
+ inherited_prop ? "inherited_property" : "property",
+ "name", propname,
+ "encoding", encoding, NULL);
else
- svn_xml_make_open_tag(outstr, pool, svn_xml_protect_pcdata,
- "property", "name", propname, NULL);
+ svn_xml_make_open_tag(
+ outstr, pool, svn_xml_protect_pcdata,
+ inherited_prop ? "inherited_property" : "property",
+ "name", propname, NULL);
svn_stringbuf_appendcstr(*outstr, xml_safe);
- svn_xml_make_close_tag(outstr, pool, "property");
+ svn_xml_make_close_tag(
+ outstr, pool,
+ inherited_prop ? "inherited_property" : "property");
return;
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/config.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/config.c Sun Dec 23 18:34:14 2012
@@ -555,6 +555,43 @@ expand_option_value(svn_config_t *cfg, c
*opt_x_valuep = NULL;
}
+static void
+svn_config_addsection(svn_config_t *cfg,
+ const char *section,
+ cfg_section_t **sec)
+{
+ cfg_section_t *s;
+
+ 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;
+ else
+ s->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;
+}
+
+static void
+svn_config_create_option(cfg_option_t **opt,
+ const char *option,
+ const char *value,
+ 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));
+
+ o->value = apr_pstrdup(pool, value);
+ o->x_value = NULL;
+ o->expanded = FALSE;
+
+ *opt = o;
+}
void
@@ -612,25 +649,12 @@ svn_config_set(svn_config_t *cfg,
}
/* Create a new option */
- opt = apr_palloc(cfg->pool, sizeof(*opt));
- opt->name = apr_pstrdup(cfg->pool, option);
- opt->hash_key = make_hash_key(apr_pstrdup(cfg->pool, option));
-
- opt->value = apr_pstrdup(cfg->pool, value);
- opt->x_value = NULL;
- opt->expanded = FALSE;
+ svn_config_create_option(&opt, option, value, cfg->pool);
if (sec == NULL)
{
/* Even the section doesn't exist. Create it. */
- sec = apr_palloc(cfg->pool, sizeof(*sec));
- sec->name = apr_pstrdup(cfg->pool, section);
- if(cfg->section_names_case_sensitive)
- sec->hash_key = sec->name;
- else
- sec->hash_key = make_hash_key(apr_pstrdup(cfg->pool, section));
- sec->options = apr_hash_make(cfg->pool);
- apr_hash_set(cfg->sections, sec->hash_key, APR_HASH_KEY_STRING, sec);
+ svn_config_addsection(cfg, section, &sec);
}
apr_hash_set(sec->options, opt->hash_key, APR_HASH_KEY_STRING, opt);
@@ -951,6 +975,94 @@ svn_config_get_server_setting(svn_config
return retval;
}
+
+svn_error_t *
+svn_config_dup(svn_config_t **cfgp,
+ svn_config_t *src,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *sectidx;
+ apr_hash_index_t *optidx;
+
+ *cfgp = 0;
+ SVN_ERR(svn_config_create(cfgp, FALSE, pool));
+
+ (*cfgp)->x_values = src->x_values;
+ (*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive;
+
+ for (sectidx = apr_hash_first(pool, src->sections);
+ sectidx != NULL;
+ sectidx = apr_hash_next(sectidx))
+ {
+ const void *sectkey;
+ void *sectval;
+ apr_ssize_t sectkeyLength;
+ cfg_section_t * srcsect;
+ cfg_section_t * destsec;
+
+ apr_hash_this(sectidx, §key, §keyLength, §val);
+ srcsect = sectval;
+
+ svn_config_addsection(*cfgp, srcsect->name, &destsec);
+
+ for (optidx = apr_hash_first(pool, srcsect->options);
+ optidx != NULL;
+ optidx = apr_hash_next(optidx))
+ {
+ const void *optkey;
+ void *optval;
+ apr_ssize_t optkeyLength;
+ cfg_option_t *srcopt;
+ cfg_option_t *destopt;
+
+ apr_hash_this(optidx, &optkey, &optkeyLength, &optval);
+ srcopt = optval;
+
+ svn_config_create_option(&destopt, srcopt->name, srcopt->value, pool);
+
+ destopt->value = apr_pstrdup(pool, srcopt->value);
+ destopt->x_value = apr_pstrdup(pool, srcopt->x_value);
+ destopt->expanded = srcopt->expanded;
+ apr_hash_set(destsec->options,
+ apr_pstrdup(pool, (const char*)optkey),
+ optkeyLength, destopt);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_config_copy_config(apr_hash_t **cfg_hash,
+ apr_hash_t *src_hash,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *cidx;
+
+ *cfg_hash = apr_hash_make(pool);
+ for (cidx = apr_hash_first(pool, src_hash);
+ cidx != NULL;
+ cidx = apr_hash_next(cidx))
+ {
+ const void *ckey;
+ void *cval;
+ apr_ssize_t ckeyLength;
+ svn_config_t * srcconfig;
+ svn_config_t * destconfig;
+
+ apr_hash_this(cidx, &ckey, &ckeyLength, &cval);
+ srcconfig = cval;
+
+ SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool));
+
+ apr_hash_set(*cfg_hash,
+ apr_pstrdup(pool, (const char*)ckey),
+ ckeyLength, destconfig);
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t*
svn_config_get_server_setting_int(svn_config_t *cfg,
const char *server_group,
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/config_file.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/config_file.c Sun Dec 23 18:34:14 2012
@@ -1034,6 +1034,13 @@ svn_config_ensure(const char *config_dir
"# kwallet-svn-application-name-with-pid = yes" NL
#endif
"###" NL
+ "### Set ssl-client-cert-file-prompt to 'yes' to cause the client" NL
+ "### to prompt for a path to a client cert file when the server" NL
+ "### requests a client cert but no client cert file is found in the" NL
+ "### expected place (see the 'ssl-client-cert-file' option in the" NL
+ "### 'servers' configuration file). Defaults to 'no'." NL
+ "# ssl-client-cert-file-prompt = no" NL
+ "###" NL
"### The rest of the [auth] section in this file has been deprecated."
NL
"### Both 'store-passwords' and 'store-auth-creds' can now be" NL
@@ -1153,7 +1160,12 @@ svn_config_ensure(const char *config_dir
"# *.png = svn:mime-type=image/png" NL
"# *.jpg = svn:mime-type=image/jpeg" NL
"# Makefile = svn:eol-style=native" NL
- "" NL;
+ "" NL
+ "### Section for configuring working copies." NL
+ "[working-copy]" NL
+ "### Set to true to enable exclusive SQLite locking. Some clients" NL
+ "### may not support exclusive locking." NL
+ "# exclusive-locking = false" NL;
err = svn_io_file_open(&f, path,
(APR_WRITE | APR_CREATE | APR_EXCL),
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/deprecated.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/deprecated.c Sun Dec 23 18:34:14 2012
@@ -36,6 +36,7 @@
#include "svn_path.h"
#include "svn_opt.h"
#include "svn_cmdline.h"
+#include "svn_version.h"
#include "svn_pools.h"
#include "svn_dso.h"
#include "svn_mergeinfo.h"
@@ -604,8 +605,11 @@ svn_opt_print_help(apr_getopt_t *os,
}
}
else if (print_version) /* just --version */
- SVN_ERR(svn_opt__print_version_info(pgm_name, version_footer,
- quiet, FALSE, pool));
+ {
+ SVN_ERR(svn_opt__print_version_info(pgm_name, version_footer,
+ svn_version_extended(FALSE, pool),
+ quiet, FALSE, pool));
+ }
else if (os && !targets->nelts) /* `-h', `--help', or `help' */
svn_opt_print_generic_help(header,
cmd_table,
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/eol.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/eol.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/eol.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/eol.c Sun Dec 23 18:34:14 2012
@@ -32,18 +32,6 @@
/* Machine-word-sized masks used in svn_eol__find_eol_start.
*/
-#if APR_SIZEOF_VOIDP == 8
-# define LOWER_7BITS_SET 0x7f7f7f7f7f7f7f7f
-# define BIT_7_SET 0x8080808080808080
-# define R_MASK 0x0a0a0a0a0a0a0a0a
-# define N_MASK 0x0d0d0d0d0d0d0d0d
-#else
-# define LOWER_7BITS_SET 0x7f7f7f7f
-# define BIT_7_SET 0x80808080
-# define R_MASK 0x0a0a0a0a
-# define N_MASK 0x0d0d0d0d
-#endif
-
char *
svn_eol__find_eol_start(char *buf, apr_size_t len)
{
@@ -69,19 +57,19 @@ svn_eol__find_eol_start(char *buf, apr_s
/* This is a variant of the well-known strlen test: */
apr_uintptr_t chunk = *(const apr_uintptr_t *)buf;
- /* A byte in R_TEST is \0, iff it was \r in *BUF.
- * Similarly, N_TEST is an indicator for \n. */
- apr_uintptr_t r_test = chunk ^ R_MASK;
- apr_uintptr_t n_test = chunk ^ N_MASK;
-
- /* A byte in R_TEST can by < 0x80, iff it has been \0 before
- * (i.e. \r in *BUF). Dito for N_TEST. */
- r_test |= (r_test & LOWER_7BITS_SET) + LOWER_7BITS_SET;
- n_test |= (n_test & LOWER_7BITS_SET) + LOWER_7BITS_SET;
+ /* A byte in SVN__R_TEST is \0, iff it was \r in *BUF.
+ * Similarly, SVN__N_TEST is an indicator for \n. */
+ apr_uintptr_t r_test = chunk ^ SVN__R_MASK;
+ apr_uintptr_t n_test = chunk ^ SVN__N_MASK;
+
+ /* A byte in SVN__R_TEST can by < 0x80, iff it has been \0 before
+ * (i.e. \r in *BUF). Dito for SVN__N_TEST. */
+ r_test |= (r_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
+ n_test |= (n_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
/* Check whether at least one of the words contains a byte <0x80
* (if one is detected, there was a \r or \n in CHUNK). */
- if ((r_test & n_test & BIT_7_SET) != BIT_7_SET)
+ if ((r_test & n_test & SVN__BIT_7_SET) != SVN__BIT_7_SET)
break;
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/error.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/error.c Sun Dec 23 18:34:14 2012
@@ -196,9 +196,14 @@ svn_error_wrap_apr(apr_status_t status,
va_start(ap, fmt);
msg = apr_pvsprintf(err->pool, fmt, ap);
va_end(ap);
- err->message = apr_psprintf(err->pool, "%s%s%s", msg,
- (msg_apr) ? ": " : "",
- (msg_apr) ? msg_apr : "");
+ if (msg_apr)
+ {
+ err->message = apr_pstrcat(err->pool, msg, ": ", msg_apr, NULL);
+ }
+ else
+ {
+ err->message = msg;
+ }
}
return err;
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/gpg_agent.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/gpg_agent.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/gpg_agent.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/gpg_agent.c Sun Dec 23 18:34:14 2012
@@ -107,10 +107,10 @@ static svn_boolean_t
receive_from_gpg_agent(int sd, char *buf, size_t n)
{
int i = 0;
- int recvd;
+ size_t recvd;
char c;
- /* Clear existing buffer concent before reading response. */
+ /* Clear existing buffer content before reading response. */
if (n > 0)
*buf = '\0';
@@ -326,7 +326,6 @@ password_get_gpg_agent(svn_boolean_t *do
display = getenv("DISPLAY");
if (display != NULL)
{
- request = apr_psprintf(pool, "OPTION display=%s\n", display);
if (!send_option(sd, buffer, BUFFER_SIZE, "display", display, pool))
{
close(sd);
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/io.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/io.c Sun Dec 23 18:34:14 2012
@@ -2058,8 +2058,12 @@ svn_io_file_lock2(const char *lock_file,
if (locktype == APR_FLOCK_EXCLUSIVE)
flags |= APR_WRITE;
+ /* locktype is never read after this block, so we don't need to bother
+ setting it. If that were to ever change, uncomment the following
+ block.
if (nonblocking)
locktype |= APR_FLOCK_NONBLOCK;
+ */
SVN_ERR(svn_io_file_open(&lockfile_handle, lock_file, flags,
APR_OS_DEFAULT,
@@ -3427,30 +3431,60 @@ svn_error_t *
svn_io_read_length_line(apr_file_t *file, char *buf, apr_size_t *limit,
apr_pool_t *pool)
{
+ /* variables */
+ apr_size_t total_read = 0;
+ svn_boolean_t eof = FALSE;
const char *name;
svn_error_t *err;
- apr_size_t i;
- char c;
+ apr_size_t buf_size = *limit;
- for (i = 0; i < *limit; i++)
+ while (buf_size > 0)
{
- SVN_ERR(svn_io_file_getc(&c, file, pool));
- /* Note: this error could be APR_EOF, which
- is totally fine. The caller should be aware of
- this. */
+ /* read a fair chunk of data at once. But don't get too ambitious
+ * as that would result in too much waste. Also make sure we can
+ * put a NUL after the last byte read.
+ */
+ apr_size_t to_read = buf_size < 129 ? buf_size - 1 : 128;
+ apr_size_t bytes_read = 0;
+ char *eol;
+
+ /* read data block (or just a part of it) */
+ SVN_ERR(svn_io_file_read_full2(file, buf, to_read,
+ &bytes_read, &eof, pool));
+
+ /* look or a newline char */
+ buf[bytes_read] = 0;
+ eol = strchr(buf, '\n');
+ if (eol)
+ {
+ apr_off_t offset = (eol + 1 - buf) - (apr_off_t)bytes_read;
+
+ *eol = 0;
+ *limit = total_read + (eol - buf);
+
+ /* correct the file pointer:
+ * appear as though we just had read the newline char
+ */
+ SVN_ERR(svn_io_file_seek(file, APR_CUR, &offset, pool));
- if (c == '\n')
- {
- buf[i] = '\0';
- *limit = i;
return SVN_NO_ERROR;
}
- else
+ else if (eof)
{
- buf[i] = c;
+ /* no EOL found but we hit the end of the file.
+ * Generate a nice EOF error object and return it.
+ */
+ char dummy;
+ SVN_ERR(svn_io_file_getc(&dummy, file, pool));
}
+
+ /* next data chunk */
+ buf_size -= bytes_read;
+ buf += bytes_read;
+ total_read += bytes_read;
}
+ /* buffer limit has been exceeded without finding the EOL */
err = svn_io_file_name_get(&name, file, pool);
if (err)
name = NULL;
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/log.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/log.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/log.c Sun Dec 23 18:34:14 2012
@@ -380,3 +380,17 @@ svn_log__replay(const char *path, svn_re
log_path = "/";
return apr_psprintf(pool, "replay %s r%ld", log_path, rev);
}
+
+const char *
+svn_log__get_inherited_props(const char *path,
+ svn_revnum_t rev,
+ apr_pool_t *pool)
+{
+ const char *log_path;
+
+ if (path && path[0] != '\0')
+ log_path = svn_path_uri_encode(path, pool);
+ else
+ log_path = "/";
+ return apr_psprintf(pool, "get-inherited-props %s r%ld", log_path, rev);
+}
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/mergeinfo.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/mergeinfo.c Sun Dec 23 18:34:14 2012
@@ -35,6 +35,7 @@
#include "private/svn_fspath.h"
#include "private/svn_mergeinfo_private.h"
#include "private/svn_string_private.h"
+#include "private/svn_subr_private.h"
#include "svn_private_config.h"
#include "svn_hash.h"
#include "private/svn_dep_compat.h"
@@ -616,6 +617,7 @@ parse_revision_line(const char **input,
apr_pool_t *scratch_pool)
{
const char *pathname = "";
+ apr_ssize_t klen;
svn_rangelist_t *existing_rangelist;
svn_rangelist_t *rangelist = apr_array_make(scratch_pool, 1,
sizeof(svn_merge_range_t *));
@@ -700,14 +702,14 @@ parse_revision_line(const char **input,
leading slash, e.g. "trunk:4033\n/trunk:4039-4995". In the event
we encounter this we merge the rangelists together under a single
absolute path key. */
- existing_rangelist = apr_hash_get(hash, pathname, APR_HASH_KEY_STRING);
+ klen = strlen(pathname);
+ existing_rangelist = apr_hash_get(hash, pathname, klen);
if (existing_rangelist)
SVN_ERR(svn_rangelist_merge2(rangelist, existing_rangelist,
scratch_pool, scratch_pool));
- apr_hash_set(hash, apr_pstrdup(apr_hash_pool_get(hash), pathname),
- APR_HASH_KEY_STRING,
- svn_rangelist_dup(rangelist, apr_hash_pool_get(hash)));
+ apr_hash_set(hash, apr_pstrmemdup(apr_hash_pool_get(hash), pathname, klen),
+ klen, svn_rangelist_dup(rangelist, apr_hash_pool_get(hash)));
return SVN_NO_ERROR;
}
@@ -736,7 +738,7 @@ svn_mergeinfo_parse(svn_mergeinfo_t *mer
{
svn_error_t *err;
- *mergeinfo = apr_hash_make(pool);
+ *mergeinfo = svn_hash__make(pool);
err = parse_top(&input, input + strlen(input), *mergeinfo, pool);
/* Always return SVN_ERR_MERGEINFO_PARSE_ERROR as the topmost error. */
@@ -1559,29 +1561,28 @@ mergeinfo_hash_diff_cb(const void *key,
{
/* Record any deltas (additions or deletions). */
svn_rangelist_t *deleted_rangelist, *added_rangelist;
- from_rangelist = apr_hash_get(cb->from, path, APR_HASH_KEY_STRING);
- to_rangelist = apr_hash_get(cb->to, path, APR_HASH_KEY_STRING);
+ from_rangelist = apr_hash_get(cb->from, path, klen);
+ to_rangelist = apr_hash_get(cb->to, path, klen);
SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
from_rangelist, to_rangelist,
cb->consider_inheritance, cb->pool));
if (cb->deleted && deleted_rangelist->nelts > 0)
- apr_hash_set(cb->deleted, apr_pstrdup(cb->pool, path),
- APR_HASH_KEY_STRING, deleted_rangelist);
+ apr_hash_set(cb->deleted, apr_pstrmemdup(cb->pool, path, klen),
+ klen, deleted_rangelist);
if (cb->added && added_rangelist->nelts > 0)
- apr_hash_set(cb->added, apr_pstrdup(cb->pool, path),
- APR_HASH_KEY_STRING, added_rangelist);
+ apr_hash_set(cb->added, apr_pstrmemdup(cb->pool, path, klen),
+ klen, added_rangelist);
}
else if ((status == svn_hash_diff_key_a) && cb->deleted)
{
- from_rangelist = apr_hash_get(cb->from, path, APR_HASH_KEY_STRING);
- apr_hash_set(cb->deleted, apr_pstrdup(cb->pool, path),
- APR_HASH_KEY_STRING,
+ from_rangelist = apr_hash_get(cb->from, path, klen);
+ apr_hash_set(cb->deleted, apr_pstrmemdup(cb->pool, path, klen), klen,
svn_rangelist_dup(from_rangelist, cb->pool));
}
else if ((status == svn_hash_diff_key_b) && cb->added)
{
- to_rangelist = apr_hash_get(cb->to, path, APR_HASH_KEY_STRING);
- apr_hash_set(cb->added, apr_pstrdup(cb->pool, path), APR_HASH_KEY_STRING,
+ to_rangelist = apr_hash_get(cb->to, path, klen);
+ apr_hash_set(cb->added, apr_pstrmemdup(cb->pool, path, klen), klen,
svn_rangelist_dup(to_rangelist, cb->pool));
}
return SVN_NO_ERROR;
@@ -1618,17 +1619,17 @@ svn_mergeinfo_diff2(svn_mergeinfo_t *del
if (from && to == NULL)
{
*deleted = svn_mergeinfo_dup(from, result_pool);
- *added = apr_hash_make(result_pool);
+ *added = svn_hash__make(result_pool);
}
else if (from == NULL && to)
{
- *deleted = apr_hash_make(result_pool);
+ *deleted = svn_hash__make(result_pool);
*added = svn_mergeinfo_dup(to, result_pool);
}
else
{
- *deleted = apr_hash_make(result_pool);
- *added = apr_hash_make(result_pool);
+ *deleted = svn_hash__make(result_pool);
+ *added = svn_hash__make(result_pool);
if (from && to)
{
@@ -1648,17 +1649,77 @@ svn_mergeinfo__equals(svn_boolean_t *is_
svn_boolean_t consider_inheritance,
apr_pool_t *pool)
{
- if (apr_hash_count(info1) == apr_hash_count(info2))
+ apr_hash_index_t *hi;
+
+ *is_equal = FALSE;
+
+ /* special cases: at least one side has no merge info */
+ if (info1 == NULL && info2 == NULL)
{
- svn_mergeinfo_t deleted, added;
- SVN_ERR(svn_mergeinfo_diff2(&deleted, &added, info1, info2,
- consider_inheritance, pool, pool));
- *is_equal = apr_hash_count(deleted) == 0 && apr_hash_count(added) == 0;
+ *is_equal = TRUE;
+ return SVN_NO_ERROR;
}
- else
+
+ if (info1 == NULL || info2 == NULL)
+ return SVN_NO_ERROR;
+
+ /* trivial case: different number of paths -> unequal */
+ if (apr_hash_count(info1) != apr_hash_count(info2))
+ return SVN_NO_ERROR;
+
+ /* compare range lists for all paths */
+ for (hi = apr_hash_first(pool, info1); hi; hi = apr_hash_next(hi))
{
- *is_equal = FALSE;
+ const char *key;
+ apr_ssize_t key_length;
+ svn_rangelist_t *lhs, *rhs;
+ int i;
+ svn_rangelist_t *deleted, *added;
+
+ /* get both path lists */
+ apr_hash_this(hi, (const void**)&key, &key_length, (void **)&lhs);
+ rhs = apr_hash_get(info2, key, key_length);
+
+ /* missing on one side? */
+ if (rhs == NULL)
+ return SVN_NO_ERROR;
+
+ /* quick compare: the range lists will often be a perfect match */
+ if (lhs->nelts == rhs->nelts)
+ {
+ for (i = 0; i < lhs->nelts; ++i)
+ {
+ svn_merge_range_t *lrange
+ = APR_ARRAY_IDX(lhs, i, svn_merge_range_t *);
+ svn_merge_range_t *rrange
+ = APR_ARRAY_IDX(rhs, i, svn_merge_range_t *);
+
+ /* range mismatch? -> needs detailed comparison */
+ if ( lrange->start != rrange->start
+ || lrange->end != rrange->end)
+ break;
+
+ /* inheritance mismatch? -> merge info differs */
+ if ( consider_inheritance
+ && lrange->inheritable != rrange->inheritable)
+ return SVN_NO_ERROR;
+ }
+
+ /* all ranges found to match -> next path */
+ if (i == lhs->nelts)
+ continue;
+ }
+
+ /* range lists differ but there are many ways to sort and aggregate
+ revisions into ranges. Do a full diff on them. */
+ SVN_ERR(svn_rangelist_diff(&deleted, &added, lhs, rhs,
+ consider_inheritance, pool));
+ if (deleted->nelts || added->nelts)
+ return SVN_NO_ERROR;
}
+
+ /* no mismatch found */
+ *is_equal = TRUE;
return SVN_NO_ERROR;
}
@@ -1668,62 +1729,37 @@ svn_mergeinfo_merge2(svn_mergeinfo_t mer
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_array_header_t *sorted1, *sorted2;
- int i, j;
+ apr_hash_index_t *hi;
apr_pool_t *iterpool;
if (!apr_hash_count(changes))
return SVN_NO_ERROR;
- sorted1 = svn_sort__hash(mergeinfo, svn_sort_compare_items_as_paths,
- scratch_pool);
- sorted2 = svn_sort__hash(changes, svn_sort_compare_items_as_paths,
- scratch_pool);
-
- i = 0;
- j = 0;
iterpool = svn_pool_create(scratch_pool);
- while (i < sorted1->nelts && j < sorted2->nelts)
+ for (hi = apr_hash_first(scratch_pool, changes); hi; hi = apr_hash_next(hi))
{
- svn_sort__item_t elt1, elt2;
- int res;
-
- svn_pool_clear(iterpool);
-
- elt1 = APR_ARRAY_IDX(sorted1, i, svn_sort__item_t);
- elt2 = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
- res = svn_sort_compare_items_as_paths(&elt1, &elt2);
-
- if (res == 0)
- {
- svn_rangelist_t *rl1, *rl2;
-
- rl1 = elt1.value;
- rl2 = elt2.value;
-
- SVN_ERR(svn_rangelist_merge2(rl1, rl2, result_pool, iterpool));
- apr_hash_set(mergeinfo, elt1.key, elt1.klen, rl1);
- i++;
- j++;
- }
- else if (res < 0)
- {
- i++;
+ const char *key;
+ apr_ssize_t klen;
+ svn_rangelist_t *to_insert;
+ svn_rangelist_t *target;
+
+ /* get ranges to insert and the target ranges list of that insertion */
+ apr_hash_this(hi, (const void**)&key, &klen, (void*)&to_insert);
+ target = apr_hash_get(mergeinfo, key, klen);
+
+ /* if range list exists, just expand on it.
+ * Otherwise, add new hash entry. */
+ if (target)
+ {
+ SVN_ERR(svn_rangelist_merge2(target, to_insert, result_pool,
+ iterpool));
+ apr_pool_clear(iterpool);
}
else
- {
- apr_hash_set(mergeinfo, elt2.key, elt2.klen, elt2.value);
- j++;
- }
+ apr_hash_set(mergeinfo, key, klen, to_insert);
}
- svn_pool_destroy(iterpool);
- /* Copy back any remaining elements from the second hash. */
- for (; j < sorted2->nelts; j++)
- {
- svn_sort__item_t elt = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
- apr_hash_set(mergeinfo, elt.key, elt.klen, elt.value);
- }
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -1970,7 +2006,7 @@ svn_mergeinfo_catalog_dup(svn_mergeinfo_
svn_mergeinfo_t
svn_mergeinfo_dup(svn_mergeinfo_t mergeinfo, apr_pool_t *pool)
{
- svn_mergeinfo_t new_mergeinfo = apr_hash_make(pool);
+ svn_mergeinfo_t new_mergeinfo = svn_hash__make(pool);
apr_hash_index_t *hi;
for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
@@ -2161,36 +2197,6 @@ svn_mergeinfo__add_prefix_to_catalog(svn
}
svn_error_t *
-svn_mergeinfo__relpaths_to_urls(apr_hash_t **out_mergeinfo,
- svn_mergeinfo_t mergeinfo,
- const char *repos_root_url,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- *out_mergeinfo = NULL;
- if (mergeinfo)
- {
- apr_hash_index_t *hi;
- apr_hash_t *full_path_mergeinfo = apr_hash_make(result_pool);
-
- for (hi = apr_hash_first(scratch_pool, mergeinfo);
- hi; hi = apr_hash_next(hi))
- {
- const char *key = svn__apr_hash_index_key(hi);
- void *val = svn__apr_hash_index_val(hi);
-
- apr_hash_set(full_path_mergeinfo,
- svn_path_url_add_component2(repos_root_url, key + 1,
- result_pool),
- APR_HASH_KEY_STRING, val);
- }
- *out_mergeinfo = full_path_mergeinfo;
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_mergeinfo__add_suffix_to_mergeinfo(svn_mergeinfo_t *out_mergeinfo,
svn_mergeinfo_t mergeinfo,
const char *suffix_relpath,
@@ -2224,13 +2230,18 @@ svn_rangelist_dup(const svn_rangelist_t
{
svn_rangelist_t *new_rl = apr_array_make(pool, rangelist->nelts,
sizeof(svn_merge_range_t *));
+
+ /* allocate target range buffer with a single operation */
+ svn_merge_range_t *copy = apr_palloc(pool, sizeof(*copy) * rangelist->nelts);
int i;
+ /* fill it iteratively and link it into the range list */
for (i = 0; i < rangelist->nelts; i++)
{
- APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) =
- svn_merge_range_dup(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
- pool);
+ memcpy(copy + i,
+ APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
+ sizeof(*copy));
+ APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) = copy + i;
}
return new_rl;
@@ -2318,38 +2329,6 @@ svn_mergeinfo__catalog_to_formatted_stri
}
svn_error_t *
-svn_mergeinfo__to_formatted_string(svn_string_t **output,
- svn_mergeinfo_t mergeinfo,
- const char *prefix,
- apr_pool_t *pool)
-{
- svn_stringbuf_t *output_buf = NULL;
-
- if (mergeinfo && apr_hash_count(mergeinfo))
- {
- SVN_ERR(mergeinfo_to_stringbuf(&output_buf, mergeinfo,
- prefix ? prefix : "", pool));
- svn_stringbuf_appendcstr(output_buf, "\n");
- }
-#if SVN_DEBUG
- else if (!mergeinfo)
- {
- output_buf = svn_stringbuf_create(prefix ? prefix : "", pool);
- svn_stringbuf_appendcstr(output_buf, _("NULL mergeinfo\n"));
- }
- else if (apr_hash_count(mergeinfo) == 0)
- {
- output_buf = svn_stringbuf_create(prefix ? prefix : "", pool);
- svn_stringbuf_appendcstr(output_buf, _("empty mergeinfo\n"));
- }
-#endif
-
- *output = output_buf ? svn_stringbuf__morph_into_string(output_buf)
- : svn_string_create_empty(pool);
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_mergeinfo__get_range_endpoints(svn_revnum_t *youngest_rev,
svn_revnum_t *oldest_rev,
svn_mergeinfo_t mergeinfo,
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/nls.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/nls.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/nls.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/nls.c Sun Dec 23 18:34:14 2012
@@ -121,10 +121,12 @@ svn_nls_init(void)
#else /* ! WIN32 */
bindtextdomain(PACKAGE_NAME, SVN_LOCALE_DIR);
}
+#endif /* WIN32 */
+
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
#endif /* HAVE_BIND_TEXTDOMAIN_CODESET */
-#endif /* WIN32 */
+
#endif /* ENABLE_NLS */
return err;
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/opt.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/opt.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/opt.c Sun Dec 23 18:34:14 2012
@@ -49,7 +49,6 @@
#include "private/svn_opt_private.h"
#include "opt.h"
-#include "sysinfo.h"
#include "svn_private_config.h"
@@ -1102,9 +1101,11 @@ svn_opt__arg_canonicalize_path(const cha
return SVN_NO_ERROR;
}
+
svn_error_t *
svn_opt__print_version_info(const char *pgm_name,
const char *footer,
+ const svn_version_extended_t *info,
svn_boolean_t quiet,
svn_boolean_t verbose,
apr_pool_t *pool)
@@ -1114,16 +1115,11 @@ svn_opt__print_version_info(const char *
SVN_ERR(svn_cmdline_printf(pool, _("%s, version %s\n"
" compiled %s, %s on %s\n\n"),
- pgm_name, SVN_VERSION, __DATE__, __TIME__,
- SVN_BUILD_HOST));
- SVN_ERR(svn_cmdline_fputs(
- _("Copyright (C) 2012 The Apache Software Foundation.\n"
- "This software consists of contributions made by many "
- "people; see the NOTICE\n"
- "file for more information.\n"
- "Subversion is open source software, see "
- "http://subversion.apache.org/\n\n"),
- stdout, pool));
+ pgm_name, SVN_VERSION,
+ svn_version_ext_build_date(info),
+ svn_version_ext_build_time(info),
+ svn_version_ext_build_host(info)));
+ SVN_ERR(svn_cmdline_printf(pool, "%s\n", svn_version_ext_copyright(info)));
if (footer)
{
@@ -1132,30 +1128,66 @@ svn_opt__print_version_info(const char *
if (verbose)
{
- const char *const host = svn_sysinfo__canonical_host(pool);
- const char *const relname = svn_sysinfo__release_name(pool);
- const char *const dlibs = svn_sysinfo__loaded_libs(pool);
+ const apr_array_header_t *libs;
SVN_ERR(svn_cmdline_fputs(_("System information:\n\n"), stdout, pool));
- if (relname)
- SVN_ERR(svn_cmdline_printf(pool, _("* running on %s\n"
- " - %s\n"),
- host, relname));
- else
- SVN_ERR(svn_cmdline_printf(pool, _("* running on %s\n"), host));
+ SVN_ERR(svn_cmdline_printf(pool, _("* running on %s\n"),
+ svn_version_ext_runtime_host(info)));
+ if (svn_version_ext_runtime_osname(info))
+ {
+ SVN_ERR(svn_cmdline_printf(pool, _(" - %s\n"),
+ svn_version_ext_runtime_osname(info)));
+ }
- if (dlibs)
+ libs = svn_version_ext_linked_libs(info);
+ if (libs && libs->nelts)
{
+ const svn_version_ext_linked_lib_t *lib;
+ int i;
+
+ SVN_ERR(svn_cmdline_fputs(_("* linked dependencies:\n"),
+ stdout, pool));
+ for (i = 0; i < libs->nelts; ++i)
+ {
+ lib = &APR_ARRAY_IDX(libs, i, svn_version_ext_linked_lib_t);
+ if (lib->runtime_version)
+ SVN_ERR(svn_cmdline_printf(pool,
+ " - %s %s (compiled with %s)\n",
+ lib->name,
+ lib->runtime_version,
+ lib->compiled_version));
+ else
+ SVN_ERR(svn_cmdline_printf(pool,
+ " - %s %s (static)\n",
+ lib->name,
+ lib->compiled_version));
+ }
+ }
+
+ libs = svn_version_ext_loaded_libs(info);
+ if (libs && libs->nelts)
+ {
+ const svn_version_ext_loaded_lib_t *lib;
+ int i;
+
SVN_ERR(svn_cmdline_fputs(_("* loaded shared libraries:\n"),
stdout, pool));
- SVN_ERR(svn_cmdline_fputs(dlibs, stdout, pool));
+ for (i = 0; i < libs->nelts; ++i)
+ {
+ lib = &APR_ARRAY_IDX(libs, i, svn_version_ext_loaded_lib_t);
+ if (lib->version)
+ SVN_ERR(svn_cmdline_printf(pool,
+ " - %s (%s)\n",
+ lib->name, lib->version));
+ else
+ SVN_ERR(svn_cmdline_printf(pool, " - %s\n", lib->name));
+ }
}
}
return SVN_NO_ERROR;
}
-
svn_error_t *
svn_opt_print_help4(apr_getopt_t *os,
const char *pgm_name,
@@ -1187,8 +1219,11 @@ svn_opt_print_help4(apr_getopt_t *os,
}
}
else if (print_version) /* just --version */
- SVN_ERR(svn_opt__print_version_info(pgm_name, version_footer,
- quiet, verbose, pool));
+ {
+ SVN_ERR(svn_opt__print_version_info(pgm_name, version_footer,
+ svn_version_extended(verbose, pool),
+ quiet, verbose, pool));
+ }
else if (os && !targets->nelts) /* `-h', `--help', or `help' */
svn_opt_print_generic_help2(header,
cmd_table,
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/opt.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/opt.h?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/opt.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/opt.h Sun Dec 23 18:34:14 2012
@@ -24,15 +24,17 @@
#ifndef SVN_LIBSVN_SUBR_OPT_H
#define SVN_LIBSVN_SUBR_OPT_H
+#include "svn_version.h"
#include "svn_opt.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-/* Print version info for PGM_NAME. If QUIET is true, print in
- * brief. Else if QUIET is not true, print the version more
- * verbosely, and if FOOTER is non-null, print it following the
+
+/* Print version version info for PGM_NAME to the console. If QUIET is
+ * true, print in brief. Else if QUIET is not true, print the version
+ * more verbosely, and if FOOTER is non-null, print it following the
* version information. If VERBOSE is true, print running system info.
*
* Use POOL for temporary allocations.
@@ -40,6 +42,7 @@ extern "C" {
svn_error_t *
svn_opt__print_version_info(const char *pgm_name,
const char *footer,
+ const svn_version_extended_t *info,
svn_boolean_t quiet,
svn_boolean_t verbose,
apr_pool_t *pool);
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/path.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/path.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/path.c Sun Dec 23 18:34:14 2012
@@ -1100,7 +1100,7 @@ svn_path_get_absolute(const char **pabso
}
-
+#if !defined(WIN32) && !defined(DARWIN)
/** Get APR's internal path encoding. */
static svn_error_t *
get_path_encoding(svn_boolean_t *path_is_utf8, apr_pool_t *pool)
@@ -1119,6 +1119,7 @@ get_path_encoding(svn_boolean_t *path_is
*path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8);
return SVN_NO_ERROR;
}
+#endif
svn_error_t *
Modified: subversion/branches/javahl-ra/subversion/libsvn_subr/simple_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_subr/simple_providers.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_subr/simple_providers.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_subr/simple_providers.c Sun Dec 23 18:34:14 2012
@@ -475,6 +475,10 @@ svn_auth__simple_creds_cache_set(svn_boo
/* Save credentials to disk. */
err = svn_config_write_auth_data(creds_hash, SVN_AUTH_CRED_SIMPLE,
realmstring, config_dir, pool);
+ if (err)
+ *saved = FALSE;
+
+ /* ### return error? */
svn_error_clear(err);
return SVN_NO_ERROR;