Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/cache-membuffer.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/cache-membuffer.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/cache-membuffer.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/cache-membuffer.c Sun Jun 14 20:58:10 2015 @@ -28,13 +28,16 @@ #include "svn_pools.h" #include "svn_checksum.h" #include "svn_private_config.h" -#include "cache.h" #include "svn_string.h" #include "svn_sorts.h" /* get the MIN macro */ + #include "private/svn_atomic.h" #include "private/svn_dep_compat.h" #include "private/svn_mutex.h" -#include "private/svn_pseudo_md5.h" +#include "private/svn_string_private.h" + +#include "cache.h" +#include "fnv1a.h" /* * This svn_cache__t implementation actually consists of two parts: @@ -45,8 +48,9 @@ * A membuffer cache consists of two parts: * * 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. + * representation, prefixed by their full cache keys. 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 @@ -78,9 +82,10 @@ * 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. + * the new item (plus its full key), 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, * L2 uses a randomized variant of LFU (see ensure_data_insertable_l2 for @@ -104,11 +109,13 @@ * an already used group to extend it. * * To limit the entry size and management overhead, not the actual item keys - * 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 - * unlikely. + * but only their hashed "fingerprint" will be stored. These are reasonably + * unique to prevent collisions, so we only need to support up to one entry + * per entry key. To guarantee that there are no conflicts, however, we + * store the actual full key immediately in front of the serialized item + * data. That is, the entry offset actually points to the full key and the + * key length stored in the entry acts as an additional offset to find the + * actual item. * * All access to the cached data needs to be serialized. Because we want * to scale well despite that bottleneck, we simply segment the cache into @@ -178,17 +185,34 @@ */ #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. +/* We use this structure to identify cache entries. There cannot be two + * entries with the same entry key. However unlikely, though, two different + * full keys (see full_key_t) may have the same entry key. That is a + * collision and at most one of them can be stored in the cache at any time. */ -typedef apr_uint64_t entry_key_t[2]; +typedef struct entry_key_t +{ + /* 16 byte finger print of the full key. */ + apr_uint64_t fingerprint[2]; -/* The prefix passed to svn_cache__create_membuffer_cache() effectively - * defines the type of all items stored by that cache instance. We'll take - * the last 15 bytes + \0 as plaintext for easy identification by the dev. + /* Length of the full key. This value is aligned to ITEM_ALIGNMENT to + * make sure the subsequent item content is properly aligned. */ + apr_size_t key_len; +} entry_key_t; + +/* A full key, i.e. the combination of the cache's key prefix with some + * dynamic part appended to it. It also contains its ENTRY_KEY. */ -#define PREFIX_TAIL_LEN 16 +typedef struct full_key_t +{ + /* Reduced form identifying the cache entry (if such an entry exists). */ + entry_key_t entry_key; + + /* This contains the full combination. Note that the SIZE element may + * be larger than ENTRY_KEY.KEY_LEN, but only the latter determines the + * valid key size. */ + svn_membuf_t full_key; +} full_key_t; /* Debugging / corruption detection support. * If you define this macro, the getter functions will performed expensive @@ -198,6 +222,12 @@ typedef apr_uint64_t entry_key_t[2]; */ #ifdef SVN_DEBUG_CACHE_MEMBUFFER +/* The prefix passed to svn_cache__create_membuffer_cache() effectively + * defines the type of all items stored by that cache instance. We'll take + * the last 15 bytes + \0 as plaintext for easy identification by the dev. + */ +#define PREFIX_TAIL_LEN 16 + /* This record will be attached to any cache entry. It tracks item data * (content), key and type as hash values and is the baseline against which * the getters will compare their results to detect inconsistencies. @@ -233,22 +263,33 @@ typedef struct entry_tag_t /* Initialize all members of TAG except for the content hash. */ static svn_error_t *store_key_part(entry_tag_t *tag, - entry_key_t prefix_hash, - char *prefix_tail, + const full_key_t *prefix_key, const void *key, apr_size_t key_len, apr_pool_t *pool) { svn_checksum_t *checksum; + const char *prefix = prefix_key->full_key.data; + apr_size_t prefix_len = strlen(prefix); + + if (prefix_len > sizeof(tag->prefix_tail)) + { + prefix += prefix_len - (sizeof(tag->prefix_tail) - 1); + prefix_len = sizeof(tag->prefix_tail) - 1; + } + SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, key, key_len, pool)); - memcpy(tag->prefix_hash, prefix_hash, sizeof(tag->prefix_hash)); + memcpy(tag->prefix_hash, prefix_key->entry_key.fingerprint, + sizeof(tag->prefix_hash)); memcpy(tag->key_hash, checksum->digest, sizeof(tag->key_hash)); - memcpy(tag->prefix_tail, prefix_tail, sizeof(tag->prefix_tail)); + + memset(tag->prefix_tail, 0, sizeof(tag->key_hash)); + memcpy(tag->prefix_tail, prefix, prefix_len + 1); tag->key_len = key_len; @@ -258,7 +299,7 @@ static svn_error_t *store_key_part(entry /* Initialize the content hash member of TAG. */ static svn_error_t* store_content_part(entry_tag_t *tag, - const char *data, + const void *data, apr_size_t size, apr_pool_t *pool) { @@ -305,8 +346,7 @@ static svn_error_t* assert_equal_tags(co entry_tag_t *tag = &_tag; \ if (key) \ SVN_ERR(store_key_part(tag, \ - cache->prefix, \ - cache->info_prefix, \ + &cache->prefix, \ key, \ cache->key_len == APR_HASH_KEY_STRING \ ? strlen((const char *) key) \ @@ -323,23 +363,6 @@ static svn_error_t* assert_equal_tags(co #endif /* SVN_DEBUG_CACHE_MEMBUFFER */ -/* Per svn_cache_t instance initialization helper. - * Copy the last to up PREFIX_TAIL_LEN-1 chars from PREFIX to PREFIX_TAIL. - * If the prefix has been structured by ':', only store the last element - * (which will tell us the type). - */ -static void get_prefix_tail(const char *prefix, char *prefix_tail) -{ - apr_size_t len = strlen(prefix); - apr_size_t to_copy = MIN(len, PREFIX_TAIL_LEN - 1); - const char *last_colon = strrchr(prefix, ':'); - apr_size_t last_element_pos = last_colon ? 0 : last_colon - prefix + 1; - - to_copy = MIN(to_copy, len - last_element_pos); - memset(prefix_tail, 0, PREFIX_TAIL_LEN); - memcpy(prefix_tail, prefix + len - to_copy, to_copy); -} - /* 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 @@ -360,7 +383,7 @@ typedef struct entry_t * above ensures that there will be no overflows. * Only valid for used entries. */ - apr_uint32_t size; + apr_size_t size; /* Number of (read) hits for this entry. Will be reset upon write. * Only valid for used entries. @@ -411,7 +434,7 @@ typedef struct group_header_t /* number of elements in the chain from start to here. * >= 1 for used groups, 0 for unused spare groups */ apr_uint32_t chain_length; - + } group_header_t; /* The size of the group struct should be a power of two make sure it does @@ -439,7 +462,7 @@ typedef struct entry_group_t { /* group globals */ group_header_t header; - + /* padding and also room for future extensions */ char padding[GROUP_BLOCK_SIZE - sizeof(group_header_t) - sizeof(entry_t) * GROUP_SIZE]; @@ -971,11 +994,11 @@ unchain_entry(svn_membuffer_t *cache, { assert(idx == get_index(cache, entry)); - /* update + /* update */ if (level->next == idx) level->next = entry->next; - + /* unlink it from the chain of used entries */ if (entry->previous == NO_INDEX) @@ -1122,17 +1145,19 @@ insert_entry(svn_membuffer_t *cache, ent */ static apr_uint32_t get_group_index(svn_membuffer_t **cache, - entry_key_t key) + const entry_key_t *key) { svn_membuffer_t *segment0 = *cache; + apr_uint64_t key0 = key->fingerprint[0]; + apr_uint64_t key1 = key->fingerprint[1]; /* 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 modulus is a prime larger than the largest * counts. */ - *cache = &segment0[(key[1] % APR_UINT64_C(2809637) + (key[0] / 37)) + *cache = &segment0[(key1 % APR_UINT64_C(2809637) + (key0 / 37)) & (segment0->segment_count - 1)]; - return (key[0] % APR_UINT64_C(5030895599)) % segment0->group_count; + return (key0 % APR_UINT64_C(5030895599)) % segment0->group_count; } /* Reduce the hit count of ENTRY and update the accumulated hit info @@ -1153,6 +1178,17 @@ let_entry_age(svn_membuffer_t *cache, en } } +/* Return whether the keys in LHS and RHS match. + */ +static svn_boolean_t +entry_keys_match(const entry_key_t *lhs, + const entry_key_t *rhs) +{ + return (lhs->fingerprint[0] == rhs->fingerprint[0]) + && (lhs->fingerprint[1] == rhs->fingerprint[1]) + && (lhs->key_len == rhs->key_len); +} + /* Given the GROUP_INDEX that shall contain an entry with the hash key * TO_FIND, find that entry in the specified group. * @@ -1164,11 +1200,15 @@ let_entry_age(svn_membuffer_t *cache, en * new content), an unused entry or a forcibly removed entry (if all * group entries are currently in use). The entries' hash value will be * initialized with TO_FIND. + * + * Note: This function requires the caller to appropriately lock the CACHE. + * For FIND_EMPTY==FALSE, a read lock is required, for FIND_EMPTY==TRUE, + * the write lock must have been acquired. */ static entry_t * find_entry(svn_membuffer_t *cache, apr_uint32_t group_index, - const apr_uint64_t to_find[2], + const full_key_t *to_find, svn_boolean_t find_empty) { entry_group_t *group; @@ -1189,8 +1229,7 @@ find_entry(svn_membuffer_t *cache, entry = &group->entries[0]; /* initialize entry for the new key */ - entry->key[0] = to_find[0]; - entry->key[1] = to_find[1]; + entry->key = to_find->entry_key; } return entry; @@ -1201,14 +1240,28 @@ find_entry(svn_membuffer_t *cache, while (1) { for (i = 0; i < group->header.used; ++i) - if ( to_find[0] == group->entries[i].key[0] - && to_find[1] == group->entries[i].key[1]) + if (entry_keys_match(&group->entries[i].key, &to_find->entry_key)) { - /* found it - */ + /* This is the only entry that _may_ contain the correct data. */ entry = &group->entries[i]; + + /* If we want to preserve it, check that it is actual a match. */ if (!find_empty) - return entry; + { + /* If there is no full key to compare, we are done. */ + if (!entry->key.key_len) + return entry; + + /* Compare the full key. */ + if (memcmp(to_find->full_key.data, + cache->data + entry->offset, + entry->key.key_len) == 0) + return entry; + + /* Key conflict. The entry to find cannot be anywhere else. + * Therefore, it is not cached. */ + return NULL; + } /* need to empty that entry */ drop_entry(cache, entry); @@ -1218,6 +1271,8 @@ find_entry(svn_membuffer_t *cache, group = last_group_in_chain(cache, &cache->directory[group_index]); + /* No entry found (actually, none left to find). */ + entry = NULL; break; } @@ -1300,8 +1355,7 @@ find_entry(svn_membuffer_t *cache, /* initialize entry for the new key */ entry = &group->entries[group->header.used]; - entry->key[0] = to_find[0]; - entry->key[1] = to_find[1]; + entry->key = to_find->entry_key; } return entry; @@ -1375,12 +1429,12 @@ promote_entry(svn_membuffer_t *cache, en } /* 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. */ @@ -1507,7 +1561,7 @@ ensure_data_insertable_l2(svn_membuffer_ * Count the "hit importance" such that we are not sacrificing * too much of the high-hit contents. However, don't count * low-priority hits because higher prio entries will often - * provide the same data but in a further stage of processing. + * provide the same data but in a further stage of processing. */ if (entry->priority > SVN_CACHE__MEMBUFFER_LOW_PRIORITY) drop_hits += entry->hit_count * (apr_uint64_t)entry->priority; @@ -1819,6 +1873,61 @@ svn_cache__membuffer_cache_create(svn_me return SVN_NO_ERROR; } +svn_error_t * +svn_cache__membuffer_clear(svn_membuffer_t *cache) +{ + apr_size_t seg; + apr_size_t segment_count = cache->segment_count; + + /* Length of the group_initialized array in bytes. + See also svn_cache__membuffer_cache_create(). */ + apr_size_t group_init_size + = 1 + (cache->group_count + cache->spare_group_count) + / (8 * GROUP_INIT_GRANULARITY); + + /* Clear segment by segment. This implies that other thread may read + and write to other segments after we cleared them and before the + last segment is done. + + However, that is no different from a write request coming through + right after we cleared all segments because dependencies between + cache entries (recursive lookup / access locks) are not allowed. + */ + for (seg = 0; seg < segment_count; ++seg) + { + /* Unconditionally acquire the write lock. */ + SVN_ERR(force_write_lock_cache(&cache[seg])); + + /* Mark all groups as "not initialized", which implies "empty". */ + cache[seg].first_spare_group = NO_INDEX; + cache[seg].max_spare_used = 0; + + memset(cache[seg].group_initialized, 0, group_init_size); + + /* Unlink L1 contents. */ + cache[seg].l1.first = NO_INDEX; + cache[seg].l1.last = NO_INDEX; + cache[seg].l1.next = NO_INDEX; + cache[seg].l1.current_data = cache[seg].l1.start_offset; + + /* Unlink L2 contents. */ + cache[seg].l2.first = NO_INDEX; + cache[seg].l2.last = NO_INDEX; + cache[seg].l2.next = NO_INDEX; + cache[seg].l2.current_data = cache[seg].l2.start_offset; + + /* Reset content counters. */ + cache[seg].data_used = 0; + cache[seg].used_entries = 0; + + /* Segment may be used again. */ + SVN_ERR(unlock_cache(&cache[seg], SVN_NO_ERROR)); + } + + /* done here */ + 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. * @@ -1828,7 +1937,7 @@ svn_cache__membuffer_cache_create(svn_me static svn_error_t * entry_exists_internal(svn_membuffer_t *cache, apr_uint32_t group_index, - entry_key_t to_find, + const full_key_t *to_find, svn_boolean_t *found) { *found = find_entry(cache, group_index, to_find, FALSE) != NULL; @@ -1841,7 +1950,7 @@ entry_exists_internal(svn_membuffer_t *c static svn_error_t * entry_exists(svn_membuffer_t *cache, apr_uint32_t group_index, - entry_key_t to_find, + const full_key_t *to_find, svn_boolean_t *found) { WITH_READ_LOCK(cache, @@ -1874,9 +1983,9 @@ select_level(svn_membuffer_t *cache, && priority > SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY) { /* Large but important items go into L2. */ - entry_t dummy_entry = { { 0 } }; + entry_t dummy_entry = { { { 0 } } }; dummy_entry.priority = priority; - dummy_entry.size = (apr_uint32_t) size; + dummy_entry.size = size; return ensure_data_insertable_l2(cache, &dummy_entry) ? &cache->l2 @@ -1887,9 +1996,9 @@ select_level(svn_membuffer_t *cache, return NULL; } -/* Try to insert the serialized item given in BUFFER with SIZE into - * the group GROUP_INDEX of CACHE and uniquely identify it by hash - * value TO_FIND. +/* Try to insert the serialized item given in BUFFER with ITEM_SIZE + * into the group GROUP_INDEX of CACHE and uniquely identify it by + * hash value TO_FIND. * * However, there is no guarantee that it will actually be put into * the cache. If there is already some data associated with TO_FIND, @@ -1897,19 +2006,20 @@ select_level(svn_membuffer_t *cache, * be inserted. * * Note: This function requires the caller to serialization access. - * Don't call it directly, call membuffer_cache_get_partial instead. + * Don't call it directly, call membuffer_cache_set instead. */ static svn_error_t * membuffer_cache_set_internal(svn_membuffer_t *cache, - entry_key_t to_find, + const full_key_t *to_find, apr_uint32_t group_index, char *buffer, - apr_size_t size, + apr_size_t item_size, apr_uint32_t priority, DEBUG_CACHE_MEMBUFFER_TAG_ARG apr_pool_t *scratch_pool) { cache_level_t *level; + apr_size_t size = item_size + to_find->entry_key.key_len; /* first, look for a previous entry for the given key */ entry_t *entry = find_entry(cache, group_index, to_find, FALSE); @@ -1923,20 +2033,24 @@ membuffer_cache_set_internal(svn_membuff * negative value. */ cache->data_used += (apr_uint64_t)size - entry->size; - entry->size = (apr_uint32_t) size; + entry->size = size; entry->priority = priority; #ifdef SVN_DEBUG_CACHE_MEMBUFFER /* Remember original content, type and key (hashes) */ - SVN_ERR(store_content_part(tag, buffer, size, scratch_pool)); + SVN_ERR(store_content_part(tag, buffer, item_size, scratch_pool)); memcpy(&entry->tag, tag, sizeof(*tag)); #endif - if (size) - memcpy(cache->data + entry->offset, buffer, size); + if (entry->key.key_len) + memcpy(cache->data + entry->offset, to_find->full_key.data, + entry->key.key_len); + if (item_size) + memcpy(cache->data + entry->offset + entry->key.key_len, buffer, + item_size); cache->total_writes++; return SVN_NO_ERROR; @@ -1952,7 +2066,7 @@ membuffer_cache_set_internal(svn_membuff * the serialized item's (future) position within data buffer. */ entry = find_entry(cache, group_index, to_find, TRUE); - entry->size = (apr_uint32_t) size; + entry->size = size; entry->offset = level->current_data; entry->priority = priority; @@ -1960,7 +2074,7 @@ membuffer_cache_set_internal(svn_membuff /* Remember original content, type and key (hashes) */ - SVN_ERR(store_content_part(tag, buffer, size, scratch_pool)); + SVN_ERR(store_content_part(tag, buffer, item_size, scratch_pool)); memcpy(&entry->tag, tag, sizeof(*tag)); #endif @@ -1971,8 +2085,12 @@ membuffer_cache_set_internal(svn_membuff /* Copy the serialized item data into the cache. */ - if (size) - memcpy(cache->data + entry->offset, buffer, size); + if (entry->key.key_len) + memcpy(cache->data + entry->offset, to_find->full_key.data, + entry->key.key_len); + if (item_size) + memcpy(cache->data + entry->offset + entry->key.key_len, buffer, + item_size); cache->total_writes++; } @@ -2001,7 +2119,7 @@ membuffer_cache_set_internal(svn_membuff */ static svn_error_t * membuffer_cache_set(svn_membuffer_t *cache, - entry_key_t key, + const full_key_t *key, void *item, svn_cache__serialize_func_t serializer, apr_uint32_t priority, @@ -2014,7 +2132,7 @@ membuffer_cache_set(svn_membuffer_t *cac /* find the entry group that will hold the key. */ - group_index = get_group_index(&cache, key); + group_index = get_group_index(&cache, &key->entry_key); /* Serialize data data. */ @@ -2057,12 +2175,12 @@ increment_hit_counters(svn_membuffer_t * * be done in POOL. * * Note: This function requires the caller to serialization access. - * Don't call it directly, call membuffer_cache_get_partial instead. + * Don't call it directly, call membuffer_cache_get instead. */ static svn_error_t * membuffer_cache_get_internal(svn_membuffer_t *cache, apr_uint32_t group_index, - entry_key_t to_find, + const full_key_t *to_find, char **buffer, apr_size_t *item_size, DEBUG_CACHE_MEMBUFFER_TAG_ARG @@ -2085,9 +2203,9 @@ membuffer_cache_get_internal(svn_membuff return SVN_NO_ERROR; } - size = ALIGN_VALUE(entry->size); + size = ALIGN_VALUE(entry->size) - entry->key.key_len; *buffer = ALIGN_POINTER(apr_palloc(result_pool, size + ITEM_ALIGNMENT-1)); - memcpy(*buffer, (const char*)cache->data + entry->offset, size); + memcpy(*buffer, cache->data + entry->offset + entry->key.key_len, size); #ifdef SVN_DEBUG_CACHE_MEMBUFFER @@ -2099,7 +2217,8 @@ 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 - entry->key.key_len, + result_pool)); SVN_ERR(assert_equal_tags(&entry->tag, tag)); #endif @@ -2107,7 +2226,7 @@ membuffer_cache_get_internal(svn_membuff /* update hit statistics */ increment_hit_counters(cache, entry); - *item_size = entry->size; + *item_size = entry->size - entry->key.key_len; return SVN_NO_ERROR; } @@ -2119,7 +2238,7 @@ membuffer_cache_get_internal(svn_membuff */ static svn_error_t * membuffer_cache_get(svn_membuffer_t *cache, - entry_key_t key, + const full_key_t *key, void **item, svn_cache__deserialize_func_t deserializer, DEBUG_CACHE_MEMBUFFER_TAG_ARG @@ -2131,7 +2250,7 @@ membuffer_cache_get(svn_membuffer_t *cac /* find the entry group that will hold the key. */ - group_index = get_group_index(&cache, key); + group_index = get_group_index(&cache, &key->entry_key); WITH_READ_LOCK(cache, membuffer_cache_get_internal(cache, group_index, @@ -2159,7 +2278,7 @@ membuffer_cache_get(svn_membuffer_t *cac static svn_error_t * membuffer_cache_has_key_internal(svn_membuffer_t *cache, apr_uint32_t group_index, - entry_key_t to_find, + const full_key_t *to_find, svn_boolean_t *found) { entry_t *entry = find_entry(cache, group_index, to_find, FALSE); @@ -2188,12 +2307,12 @@ membuffer_cache_has_key_internal(svn_mem */ static svn_error_t * membuffer_cache_has_key(svn_membuffer_t *cache, - entry_key_t key, + const full_key_t *key, svn_boolean_t *found) { /* find the entry group that will hold the key. */ - apr_uint32_t group_index = get_group_index(&cache, key); + apr_uint32_t group_index = get_group_index(&cache, &key->entry_key); cache->total_reads++; WITH_READ_LOCK(cache, @@ -2219,7 +2338,7 @@ membuffer_cache_has_key(svn_membuffer_t static svn_error_t * membuffer_cache_get_partial_internal(svn_membuffer_t *cache, apr_uint32_t group_index, - entry_key_t to_find, + const full_key_t *to_find, void **item, svn_boolean_t *found, svn_cache__partial_getter_func_t deserializer, @@ -2238,6 +2357,8 @@ membuffer_cache_get_partial_internal(svn } else { + const void *item_data = cache->data + entry->offset + entry->key.key_len; + apr_size_t item_size = entry->size - entry->key.key_len; *found = TRUE; increment_hit_counters(cache, entry); @@ -2251,19 +2372,12 @@ membuffer_cache_get_partial_internal(svn /* Compare original content, type and key (hashes) */ - SVN_ERR(store_content_part(tag, - (const char*)cache->data + entry->offset, - entry->size, - result_pool)); + SVN_ERR(store_content_part(tag, item_data, item_size, result_pool)); SVN_ERR(assert_equal_tags(&entry->tag, tag)); #endif - return deserializer(item, - (const char*)cache->data + entry->offset, - entry->size, - baton, - result_pool); + return deserializer(item, item_data, item_size, baton, result_pool); } } @@ -2275,7 +2389,7 @@ membuffer_cache_get_partial_internal(svn */ static svn_error_t * membuffer_cache_get_partial(svn_membuffer_t *cache, - entry_key_t key, + const full_key_t *key, void **item, svn_boolean_t *found, svn_cache__partial_getter_func_t deserializer, @@ -2283,7 +2397,7 @@ membuffer_cache_get_partial(svn_membuffe DEBUG_CACHE_MEMBUFFER_TAG_ARG apr_pool_t *result_pool) { - apr_uint32_t group_index = get_group_index(&cache, key); + apr_uint32_t group_index = get_group_index(&cache, &key->entry_key); WITH_READ_LOCK(cache, membuffer_cache_get_partial_internal @@ -2307,7 +2421,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, - entry_key_t to_find, + const full_key_t *to_find, svn_cache__partial_setter_func_t func, void *baton, DEBUG_CACHE_MEMBUFFER_TAG_ARG @@ -2325,9 +2439,10 @@ membuffer_cache_set_partial_internal(svn svn_error_t *err; /* access the serialized cache item */ - char *data = (char*)cache->data + entry->offset; - char *orig_data = data; - apr_size_t size = entry->size; + apr_size_t key_len = entry->key.key_len; + void *item_data = cache->data + entry->offset + key_len; + void *orig_data = item_data; + apr_size_t item_size = entry->size - key_len; increment_hit_counters(cache, entry); cache->total_writes++; @@ -2337,19 +2452,19 @@ membuffer_cache_set_partial_internal(svn /* Check for overlapping entries. */ SVN_ERR_ASSERT(entry->next == NO_INDEX || - entry->offset + size + entry->offset + entry->size <= get_entry(cache, entry->next)->offset); /* Compare original content, type and key (hashes) */ - SVN_ERR(store_content_part(tag, data, size, scratch_pool)); + SVN_ERR(store_content_part(tag, item_data, item_size, scratch_pool)); SVN_ERR(assert_equal_tags(&entry->tag, tag)); #endif /* modify it, preferably in-situ. */ - err = func((void **)&data, &size, baton, scratch_pool); + err = func(&item_data, &item_size, baton, scratch_pool); if (err) { @@ -2366,21 +2481,26 @@ membuffer_cache_set_partial_internal(svn /* if the modification caused a re-allocation, we need to remove * the old entry and to copy the new data back into cache. */ - if (data != orig_data) + if (item_data != orig_data) { /* Remove the old entry and try to make space for the new one. */ drop_entry(cache, entry); - if ( (cache->max_entry_size >= size) - && ensure_data_insertable_l1(cache, size)) + if ( (cache->max_entry_size >= item_size + key_len) + && ensure_data_insertable_l1(cache, item_size + key_len)) { /* Write the new entry. */ entry = find_entry(cache, group_index, to_find, TRUE); - entry->size = (apr_uint32_t) size; + entry->size = item_size + key_len; entry->offset = cache->l1.current_data; - if (size) - memcpy(cache->data + entry->offset, data, size); + + if (key_len) + memcpy(cache->data + entry->offset, + to_find->full_key.data, key_len); + if (item_size) + memcpy(cache->data + entry->offset + key_len, item_data, + item_size); /* Link the entry properly. */ @@ -2392,7 +2512,7 @@ membuffer_cache_set_partial_internal(svn /* Remember original content, type and key (hashes) */ - SVN_ERR(store_content_part(tag, data, size, scratch_pool)); + SVN_ERR(store_content_part(tag, item_data, item_size, scratch_pool)); memcpy(&entry->tag, tag, sizeof(*tag)); #endif @@ -2409,7 +2529,7 @@ membuffer_cache_set_partial_internal(svn */ static svn_error_t * membuffer_cache_set_partial(svn_membuffer_t *cache, - entry_key_t key, + const full_key_t *key, svn_cache__partial_setter_func_t func, void *baton, DEBUG_CACHE_MEMBUFFER_TAG_ARG @@ -2417,7 +2537,7 @@ membuffer_cache_set_partial(svn_membuffe { /* cache item lookup */ - apr_uint32_t group_index = get_group_index(&cache, key); + apr_uint32_t group_index = get_group_index(&cache, &key->entry_key); WITH_WRITE_LOCK(cache, membuffer_cache_set_partial_internal (cache, group_index, key, func, baton, @@ -2443,22 +2563,6 @@ 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_ssize_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. @@ -2478,15 +2582,10 @@ typedef struct svn_membuffer_cache_t svn_cache__deserialize_func_t deserializer; /* Prepend this byte sequence to any key passed to us. - * This makes (very likely) our keys different from all keys used - * by other svn_membuffer_cache_t instances. + * This makes our keys different from all keys used by svn_membuffer_cache_t + * instances that we don't want to share cached data with. */ - entry_key_t prefix; - - /* The tail of the prefix string. It is being used as a developer-visible - * ID for this cache instance. - */ - char info_prefix[PREFIX_TAIL_LEN]; + full_key_t prefix; /* length of the keys that will be passed to us through the * svn_cache_t interface. May be APR_HASH_KEY_STRING. @@ -2495,26 +2594,16 @@ typedef struct svn_membuffer_cache_t /* priority class for all items written through this interface */ apr_uint32_t priority; - + /* Temporary buffer containing the hash key for the current access */ - entry_key_t combined_key; + full_key_t combined_key; - /* 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; } svn_membuffer_cache_t; -/* After an estimated ALLOCATIONS_PER_POOL_CLEAR allocations, we should - * clear the svn_membuffer_cache_t.pool to keep memory consumption in check. - */ -#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 @@ -2525,70 +2614,35 @@ combine_long_key(svn_membuffer_cache_t * const void *key, apr_ssize_t key_len) { - assert(cache->last_access); + apr_uint32_t *digest_buffer; + char *key_copy; + apr_size_t prefix_len = cache->prefix.entry_key.key_len; + apr_size_t aligned_key_len; /* handle variable-length keys */ if (key_len == APR_HASH_KEY_STRING) key_len = strlen((const char *) key); - /* 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) - { - 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]; - - /* 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 - { - /* 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_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]; + aligned_key_len = ALIGN_VALUE(key_len); - memcpy(cache->last_access->combined_key, cache->combined_key, - sizeof(cache->combined_key)); - } + /* Combine keys. */ + svn_membuf__ensure(&cache->combined_key.full_key, + aligned_key_len + prefix_len); + + key_copy = (char *)cache->combined_key.full_key.data + prefix_len; + cache->combined_key.entry_key.key_len = aligned_key_len + prefix_len; + memcpy(key_copy, key, key_len); + memset(key_copy + key_len, 0, aligned_key_len - key_len); + + /* Hash key into 16 bytes. */ + digest_buffer = (apr_uint32_t *)cache->combined_key.entry_key.fingerprint; + svn__fnv1a_32x4_raw(digest_buffer, key, key_len); + + /* Combine with prefix. */ + cache->combined_key.entry_key.fingerprint[0] + ^= cache->prefix.entry_key.fingerprint[0]; + cache->combined_key.entry_key.fingerprint[1] + ^= cache->prefix.entry_key.fingerprint[1]; } /* Basically calculate a hash value for KEY of length KEY_LEN, combine it @@ -2599,42 +2653,47 @@ 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) + if (key_len != APR_HASH_KEY_STRING && key_len <= 16) { + const apr_size_t prefix_len = cache->prefix.entry_key.key_len; + + /* Copy of *key, padded with 0. + * We put it just behind the prefix already copied into the COMBINED_KEY. + * The buffer space has been allocated when the cache was created. */ + apr_uint64_t *data = (void *)((char *)cache->combined_key.full_key.data + + prefix_len); + assert(prefix_len <= cache->combined_key.full_key.size - 16); + cache->combined_key.entry_key.key_len = prefix_len + 16; + data[0] = 0; data[1] = 0; memcpy(data, key, key_len); + + /* Scramble key DATA to spread the key space more evenly across the + * cache segments and entry buckets. All of this shall be reversible + * to prevent key collisions. So, we limit ourselves to xor and + * permutations. + * + * As long as we compare the full combined key, the additional + * fingerprint collisions introduced by a non-reversible scramble + * would simply reduce the cache effectiveness. + */ + data[1] = (data[1] << 27) | (data[1] >> 37); + data[1] ^= data[0] & 0xffff; + data[0] ^= data[1] & APR_UINT64_C(0xffffffffffff0000); + + /* combine with this cache's namespace */ + cache->combined_key.entry_key.fingerprint[0] + = data[0] ^ cache->prefix.entry_key.fingerprint[0]; + cache->combined_key.entry_key.fingerprint[1] + = data[1] ^ cache->prefix.entry_key.fingerprint[1]; } else { /* longer or variably sized keys */ combine_long_key(cache, key, key_len); - return; } - - /* 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] & APR_UINT64_C(0xffffffffffff0000); - - /* 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) @@ -2666,7 +2725,7 @@ svn_membuffer_cache_get(void **value_p, /* Look the item up. */ SVN_ERR(membuffer_cache_get(cache->membuffer, - cache->combined_key, + &cache->combined_key, value_p, cache->deserializer, DEBUG_CACHE_MEMBUFFER_TAG @@ -2703,7 +2762,7 @@ svn_membuffer_cache_has_key(svn_boolean_ /* Look the item up. */ SVN_ERR(membuffer_cache_has_key(cache->membuffer, - cache->combined_key, + &cache->combined_key, found)); /* return result */ @@ -2735,7 +2794,7 @@ svn_membuffer_cache_set(void *cache_void * that the item will actually be cached afterwards. */ return membuffer_cache_set(cache->membuffer, - cache->combined_key, + &cache->combined_key, value, cache->serializer, cache->priority, @@ -2781,7 +2840,7 @@ svn_membuffer_cache_get_partial(void **v combine_key(cache, key, cache->key_len); SVN_ERR(membuffer_cache_get_partial(cache->membuffer, - cache->combined_key, + &cache->combined_key, value_p, found, func, @@ -2809,7 +2868,7 @@ svn_membuffer_cache_set_partial(void *ca { combine_key(cache, key, cache->key_len); SVN_ERR(membuffer_cache_set_partial(cache->membuffer, - cache->combined_key, + &cache->combined_key, func, baton, DEBUG_CACHE_MEMBUFFER_TAG @@ -2881,7 +2940,7 @@ svn_membuffer_cache_get_info(void *cache /* cache front-end specific data */ - info->id = apr_pstrdup(result_pool, cache->info_prefix); + info->id = apr_pstrdup(result_pool, cache->prefix.full_key.data); /* collect info from shared cache back-end */ @@ -3074,11 +3133,12 @@ svn_cache__create_membuffer_cache(svn_ca apr_pool_t *scratch_pool) { svn_checksum_t *checksum; + apr_size_t prefix_len, prefix_orig_len; /* allocate the cache header structures */ svn_cache__t *wrapper = apr_pcalloc(result_pool, sizeof(*wrapper)); - svn_membuffer_cache_t *cache = apr_palloc(result_pool, sizeof(*cache)); + svn_membuffer_cache_t *cache = apr_pcalloc(result_pool, sizeof(*cache)); /* initialize our internal cache header */ @@ -3089,33 +3149,38 @@ svn_cache__create_membuffer_cache(svn_ca cache->deserializer = deserializer ? deserializer : deserialize_svn_stringbuf; - get_prefix_tail(prefix, cache->info_prefix); cache->priority = priority; cache->key_len = klen; SVN_ERR(svn_mutex__init(&cache->mutex, thread_safe, result_pool)); - /* for performance reasons, we don't actually store the full prefix but a - * hash value of it - */ + /* Copy the prefix into the prefix full key. Align it to ITEM_ALIGMENT. + * Don't forget to include the terminating NUL. */ + prefix_orig_len = strlen(prefix) + 1; + prefix_len = ALIGN_VALUE(prefix_orig_len); + + svn_membuf__create(&cache->prefix.full_key, prefix_len, result_pool); + memcpy((char *)cache->prefix.full_key.data, prefix, prefix_orig_len); + memset((char *)cache->prefix.full_key.data + prefix_orig_len, 0, + prefix_len - prefix_orig_len); + + /* Construct the folded prefix key. */ SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, prefix, strlen(prefix), scratch_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(result_pool, sizeof(*cache->last_access)); - cache->last_access->key_len = APR_HASH_KEY_STRING; - } - else - { - cache->last_access = NULL; - } + memcpy(cache->prefix.entry_key.fingerprint, checksum->digest, + sizeof(cache->prefix.entry_key.fingerprint)); + cache->prefix.entry_key.key_len = prefix_len; + + /* Initialize the combined key. Pre-allocate some extra room in the full + * key such that we probably don't need to re-alloc. */ + cache->combined_key.entry_key = cache->prefix.entry_key; + svn_membuf__create(&cache->combined_key.full_key, prefix_len + 200, + result_pool); + memcpy(cache->combined_key.full_key.data, cache->prefix.full_key.data, + prefix_len); /* initialize the generic cache wrapper */
Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/cache.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/cache.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/cache.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/cache.c Sun Jun 14 20:58:10 2015 @@ -102,6 +102,11 @@ svn_cache__has_key(svn_boolean_t *found, apr_pool_t *scratch_pool) { *found = FALSE; +#ifdef SVN_DEBUG + if (cache->pretend_empty) + return SVN_NO_ERROR; +#endif + return handle_error(cache, (cache->vtable->has_key)(found, cache->cache_internal, Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/checksum.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/checksum.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/checksum.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/checksum.c Sun Jun 14 20:58:10 2015 @@ -80,6 +80,14 @@ static const apr_size_t digest_sizes[] = sizeof(apr_uint32_t) }; +/* Checksum type prefixes used in serialized checksums. */ +static const char *ckind_str[] = { + "$md5 $", + "$sha1$", + "$fnv1$", + "$fnvm$", +}; + /* Returns the digest size of it's argument. */ #define DIGESTSIZE(k) \ (((k) < svn_checksum_md5 || (k) > svn_checksum_fnv1a_32x4) ? 0 : digest_sizes[k]) @@ -317,13 +325,10 @@ svn_checksum_serialize(const svn_checksu apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - const char *ckind_str; - SVN_ERR_ASSERT_NO_RETURN(checksum->kind >= svn_checksum_md5 || checksum->kind <= svn_checksum_fnv1a_32x4); - ckind_str = (checksum->kind == svn_checksum_md5 ? "$md5 $" : "$sha1$"); return apr_pstrcat(result_pool, - ckind_str, + ckind_str[checksum->kind], svn_checksum_to_cstring(checksum, scratch_pool), SVN_VA_NULL); } @@ -335,18 +340,29 @@ svn_checksum_deserialize(const svn_check apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - svn_checksum_kind_t ckind; + svn_checksum_kind_t kind; svn_checksum_t *parsed_checksum; - /* "$md5 $..." or "$sha1$..." */ - SVN_ERR_ASSERT(strlen(data) > 6); + /* All prefixes have the same length. */ + apr_size_t prefix_len = strlen(ckind_str[0]); - ckind = (data[1] == 'm' ? svn_checksum_md5 : svn_checksum_sha1); - SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, ckind, - data + 6, result_pool)); - *checksum = parsed_checksum; + /* "$md5 $...", "$sha1$..." or ... */ + if (strlen(data) <= prefix_len) + return svn_error_createf(SVN_ERR_BAD_CHECKSUM_PARSE, NULL, + _("Invalid prefix in checksum '%s'"), + data); + + for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind) + if (strncmp(ckind_str[kind], data, prefix_len) == 0) + { + SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, kind, + data + prefix_len, result_pool)); + *checksum = parsed_checksum; + return SVN_NO_ERROR; + } - return SVN_NO_ERROR; + return svn_error_createf(SVN_ERR_BAD_CHECKSUM_KIND, NULL, + "Unknown checksum kind in '%s'", data); } Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/cmdline.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/cmdline.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/cmdline.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/cmdline.c Sun Jun 14 20:58:10 2015 @@ -538,19 +538,20 @@ trust_server_cert_non_interactive(svn_au apr_pool_t *pool) { struct trust_server_cert_non_interactive_baton *b = baton; + apr_uint32_t non_ignored_failures; *cred_p = NULL; - if (failures == 0 || - (b->trust_server_cert_unknown_ca && - (failures & SVN_AUTH_SSL_UNKNOWNCA)) || - (b->trust_server_cert_cn_mismatch && - (failures & SVN_AUTH_SSL_CNMISMATCH)) || - (b->trust_server_cert_expired && - (failures & SVN_AUTH_SSL_EXPIRED)) || - (b->trust_server_cert_not_yet_valid && - (failures & SVN_AUTH_SSL_NOTYETVALID)) || - (b->trust_server_cert_other_failure && - (failures & SVN_AUTH_SSL_OTHER))) + /* Mask away bits we are instructed to ignore. */ + non_ignored_failures = failures & ~( + (b->trust_server_cert_unknown_ca ? SVN_AUTH_SSL_UNKNOWNCA : 0) + | (b->trust_server_cert_cn_mismatch ? SVN_AUTH_SSL_CNMISMATCH : 0) + | (b->trust_server_cert_expired ? SVN_AUTH_SSL_EXPIRED : 0) + | (b->trust_server_cert_not_yet_valid ? SVN_AUTH_SSL_NOTYETVALID : 0) + | (b->trust_server_cert_other_failure ? SVN_AUTH_SSL_OTHER : 0) + ); + + /* If no failures remain, accept the certificate. */ + if (non_ignored_failures == 0) { *cred_p = apr_pcalloc(pool, sizeof(**cred_p)); (*cred_p)->may_save = FALSE; @@ -810,9 +811,124 @@ svn_cmdline__print_xml_prop(svn_stringbu return; } +/* Return the most similar string to NEEDLE in HAYSTACK, which contains + * HAYSTACK_LEN elements. Return NULL if no string is sufficiently similar. + */ +/* See svn_cl__similarity_check() for a more general solution. */ +static const char * +most_similar(const char *needle_cstr, + const char **haystack, + apr_size_t haystack_len, + apr_pool_t *scratch_pool) +{ + const char *max_similar; + apr_size_t max_score = 0; + apr_size_t i; + svn_membuf_t membuf; + svn_string_t *needle_str = svn_string_create(needle_cstr, scratch_pool); + + svn_membuf__create(&membuf, 64, scratch_pool); + + for (i = 0; i < haystack_len; i++) + { + apr_size_t score; + svn_string_t *hay = svn_string_create(haystack[i], scratch_pool); + + score = svn_string__similarity(needle_str, hay, &membuf, NULL); + + /* If you update this factor, consider updating + * svn_cl__similarity_check(). */ + if (score >= (2 * SVN_STRING__SIM_RANGE_MAX + 1) / 3 + && score > max_score) + { + max_score = score; + max_similar = haystack[i]; + } + } + + if (max_score) + return max_similar; + else + return NULL; +} + +/* Verify that NEEDLE is in HAYSTACK, which contains HAYSTACK_LEN elements. */ +static svn_error_t * +string_in_array(const char *needle, + const char **haystack, + apr_size_t haystack_len, + apr_pool_t *scratch_pool) +{ + const char *next_of_kin; + apr_size_t i; + for (i = 0; i < haystack_len; i++) + { + if (!strcmp(needle, haystack[i])) + return SVN_NO_ERROR; + } + + /* Error. */ + next_of_kin = most_similar(needle, haystack, haystack_len, scratch_pool); + if (next_of_kin) + return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Ignoring unknown value '%s'; " + "did you mean '%s'?"), + needle, next_of_kin); + else + return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Ignoring unknown value '%s'"), + needle); +} + +#include "config_keys.inc" + +/* Validate the FILE, SECTION, and OPTION components of CONFIG_OPTION are + * known. Return an error if not. (An unknown value may be either a typo + * or added in a newer minor version of Subversion.) */ +static svn_error_t * +validate_config_option(svn_cmdline__config_argument_t *config_option, + apr_pool_t *scratch_pool) +{ + svn_boolean_t arbitrary_keys = FALSE; + + /* TODO: some day, we could also verify that OPTION is valid for SECTION; + i.e., forbid invalid combinations such as config:auth:diff-extensions. */ + +#define ARRAYLEN(x) ( sizeof((x)) / sizeof((x)[0]) ) + + SVN_ERR(string_in_array(config_option->file, svn__valid_config_files, + ARRAYLEN(svn__valid_config_files), + scratch_pool)); + SVN_ERR(string_in_array(config_option->section, svn__valid_config_sections, + ARRAYLEN(svn__valid_config_sections), + scratch_pool)); + + /* Don't validate option names for sections such as servers[group], + * config[tunnels], and config[auto-props] that permit arbitrary options. */ + { + int i; + + for (i = 0; i < ARRAYLEN(svn__empty_config_sections); i++) + { + if (!strcmp(config_option->section, svn__empty_config_sections[i])) + arbitrary_keys = TRUE; + } + } + + if (! arbitrary_keys) + SVN_ERR(string_in_array(config_option->option, svn__valid_config_options, + ARRAYLEN(svn__valid_config_options), + scratch_pool)); + +#undef ARRAYLEN + + return SVN_NO_ERROR; +} + svn_error_t * svn_cmdline__parse_config_option(apr_array_header_t *config_options, const char *opt_arg, + const char *prefix, apr_pool_t *pool) { svn_cmdline__config_argument_t *config_option; @@ -826,6 +942,8 @@ svn_cmdline__parse_config_option(apr_arr if ((equals_sign = strchr(second_colon + 1, '=')) && (equals_sign != second_colon + 1)) { + svn_error_t *warning; + config_option = apr_pcalloc(pool, sizeof(*config_option)); config_option->file = apr_pstrndup(pool, opt_arg, first_colon - opt_arg); @@ -834,6 +952,13 @@ svn_cmdline__parse_config_option(apr_arr config_option->option = apr_pstrndup(pool, second_colon + 1, equals_sign - second_colon - 1); + warning = validate_config_option(config_option, pool); + if (warning) + { + svn_handle_warning2(stderr, warning, prefix); + svn_error_clear(warning); + } + if (! (strchr(config_option->option, ':'))) { config_option->value = apr_pstrndup(pool, equals_sign + 1, @@ -1200,12 +1325,12 @@ svn_cmdline__edit_string_externally(svn_ apr_file_t *tmp_file; const char *tmpfile_name; const char *tmpfile_native; - const char *tmpfile_apr, *base_dir_apr; + const char *base_dir_apr; svn_string_t *translated_contents; - apr_status_t apr_err, apr_err2; + apr_status_t apr_err; apr_size_t written; apr_finfo_t finfo_before, finfo_after; - svn_error_t *err = SVN_NO_ERROR, *err2; + svn_error_t *err = SVN_NO_ERROR; char *old_cwd; int sys_err; svn_boolean_t remove_file = TRUE; @@ -1288,49 +1413,36 @@ svn_cmdline__edit_string_externally(svn_ the file we just created!! ***/ /* Dump initial CONTENTS to TMP_FILE. */ - apr_err = apr_file_write_full(tmp_file, translated_contents->data, - translated_contents->len, &written); + err = svn_io_file_write_full(tmp_file, translated_contents->data, + translated_contents->len, &written, + pool); - apr_err2 = apr_file_close(tmp_file); - if (! apr_err) - apr_err = apr_err2; + err = svn_error_compose_create(err, svn_io_file_close(tmp_file, pool)); /* Make sure the whole CONTENTS were written, else return an error. */ - if (apr_err) - { - err = svn_error_wrap_apr(apr_err, _("Can't write to '%s'"), - tmpfile_name); - goto cleanup; - } - - err = svn_path_cstring_from_utf8(&tmpfile_apr, tmpfile_name, pool); if (err) goto cleanup; /* Get information about the temporary file before the user has been allowed to edit its contents. */ - apr_err = apr_stat(&finfo_before, tmpfile_apr, - APR_FINFO_MTIME, pool); - if (apr_err) - { - err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name); - goto cleanup; - } + err = svn_io_stat(&finfo_before, tmpfile_name, APR_FINFO_MTIME, pool); + if (err) + goto cleanup; /* Backdate the file a little bit in case the editor is very fast and doesn't change the size. (Use two seconds, since some filesystems have coarse granularity.) It's OK if this call fails, so we don't check its return value.*/ - apr_file_mtime_set(tmpfile_apr, finfo_before.mtime - 2000, pool); + err = svn_io_set_file_affected_time(finfo_before.mtime + - apr_time_from_sec(2), + tmpfile_name, pool); + svn_error_clear(err); /* Stat it again to get the mtime we actually set. */ - apr_err = apr_stat(&finfo_before, tmpfile_apr, - APR_FINFO_MTIME | APR_FINFO_SIZE, pool); - if (apr_err) - { - err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name); - goto cleanup; - } + err = svn_io_stat(&finfo_before, tmpfile_name, + APR_FINFO_MTIME | APR_FINFO_SIZE, pool); + if (err) + goto cleanup; /* Prepare the editor command line. */ err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool); @@ -1358,13 +1470,10 @@ svn_cmdline__edit_string_externally(svn_ } /* Get information about the temporary file after the assumed editing. */ - apr_err = apr_stat(&finfo_after, tmpfile_apr, - APR_FINFO_MTIME | APR_FINFO_SIZE, pool); - if (apr_err) - { - err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name); - goto cleanup; - } + err = svn_io_stat(&finfo_after, tmpfile_name, + APR_FINFO_MTIME | APR_FINFO_SIZE, pool); + if (err) + goto cleanup; /* If the file looks changed... */ if ((finfo_before.mtime != finfo_after.mtime) || @@ -1402,13 +1511,9 @@ svn_cmdline__edit_string_externally(svn_ if (remove_file) { /* Remove the file from disk. */ - err2 = svn_io_remove_file2(tmpfile_name, FALSE, pool); - - /* Only report remove error if there was no previous error. */ - if (! err && err2) - err = err2; - else - svn_error_clear(err2); + err = svn_error_compose_create( + err, + svn_io_remove_file2(tmpfile_name, FALSE, pool)); } cleanup2: @@ -1424,3 +1529,50 @@ svn_cmdline__edit_string_externally(svn_ return svn_error_trace(err); } + +svn_error_t * +svn_cmdline__parse_trust_options( + svn_boolean_t *trust_server_cert_unknown_ca, + svn_boolean_t *trust_server_cert_cn_mismatch, + svn_boolean_t *trust_server_cert_expired, + svn_boolean_t *trust_server_cert_not_yet_valid, + svn_boolean_t *trust_server_cert_other_failure, + const char *opt_arg, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *failures; + int i; + + *trust_server_cert_unknown_ca = FALSE; + *trust_server_cert_cn_mismatch = FALSE; + *trust_server_cert_expired = FALSE; + *trust_server_cert_not_yet_valid = FALSE; + *trust_server_cert_other_failure = FALSE; + + failures = svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, scratch_pool); + + for (i = 0; i < failures->nelts; i++) + { + const char *value = APR_ARRAY_IDX(failures, i, const char *); + if (!strcmp(value, "unknown-ca")) + *trust_server_cert_unknown_ca = TRUE; + else if (!strcmp(value, "cn-mismatch")) + *trust_server_cert_cn_mismatch = TRUE; + else if (!strcmp(value, "expired")) + *trust_server_cert_expired = TRUE; + else if (!strcmp(value, "not-yet-valid")) + *trust_server_cert_not_yet_valid = TRUE; + else if (!strcmp(value, "other")) + *trust_server_cert_other_failure = TRUE; + else + return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Unknown value '%s' for %s.\n" + "Supported values: %s"), + value, + "--trust-server-cert-failures", + "unknown-ca, cn-mismatch, expired, " + "not-yet-valid, other"); + } + + return SVN_NO_ERROR; +} Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/compress.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/compress.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/compress.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/compress.c Sun Jun 14 20:58:10 2015 @@ -220,7 +220,7 @@ zlib_decode(const unsigned char *in, apr } svn_error_t * -svn__compress(svn_stringbuf_t *in, +svn__compress(const void *data, apr_size_t len, svn_stringbuf_t *out, int compression_method) { @@ -230,13 +230,13 @@ svn__compress(svn_stringbuf_t *in, _("Unsupported compression method %d"), compression_method); - return zlib_encode(in->data, in->len, out, compression_method); + return zlib_encode(data, len, out, compression_method); } svn_error_t * -svn__decompress(svn_stringbuf_t *in, +svn__decompress(const void *data, apr_size_t len, svn_stringbuf_t *out, apr_size_t limit) { - return zlib_decode((const unsigned char*)in->data, in->len, out, limit); + return zlib_decode(data, len, out, limit); } Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/config.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/config.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/config.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/config.c Sun Jun 14 20:58:10 2015 @@ -741,7 +741,7 @@ svn_config_set(svn_config_t *cfg, cfg_option_t *opt; /* Ignore write attempts to r/o configurations. - * + * * Since we should never try to modify r/o data, trigger an assertion * in debug mode. */ Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/config_file.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/config_file.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/config_file.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/config_file.c Sun Jun 14 20:58:10 2015 @@ -940,7 +940,6 @@ svn_config_ensure(const char *config_dir "### HTTP operation." NL "### http-chunked-requests Whether to use chunked transfer" NL "### encoding for HTTP requests body." NL - "### neon-debug-mask Debug mask for Neon HTTP library" NL "### ssl-authority-files List of files, each of a trusted CA" NL "### ssl-trust-default-ca Trust the system 'default' CAs" NL @@ -1033,7 +1032,6 @@ svn_config_ensure(const char *config_dir "### Most users will not need to explicitly set the http-library" NL "### option, but valid values for the option include:" NL "### 'serf': Serf-based module (Subversion 1.5 - present)" NL - "### 'neon': Neon-based module (Subversion 1.0 - 1.7)" NL "### Availability of these modules may depend on your specific" NL "### Subversion distribution." NL "###" NL @@ -1058,7 +1056,6 @@ svn_config_ensure(const char *config_dir "# http-proxy-username = blah" NL "# http-proxy-password = doubleblah" NL "# http-timeout = 60" NL - "# neon-debug-mask = 130" NL #ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE "# store-plaintext-passwords = no" NL #endif @@ -1099,7 +1096,6 @@ svn_config_ensure(const char *config_dir "# http-proxy-password = defaultpassword" NL "# http-compression = no" NL "# No http-timeout, so just use the builtin default." NL - "# No neon-debug-mask, so neon debugging is disabled." NL "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem" NL "#" NL "# Password / passphrase caching parameters:" NL Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/config_win.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/config_win.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/config_win.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/config_win.c Sun Jun 14 20:58:10 2015 @@ -197,14 +197,19 @@ svn_config__parse_registry(svn_config_t &hkey); if (err != ERROR_SUCCESS) { - const int is_enoent = APR_STATUS_IS_ENOENT(APR_FROM_OS_ERROR(err)); + apr_status_t apr_err = APR_FROM_OS_ERROR(err); + svn_boolean_t is_enoent = APR_STATUS_IS_ENOENT(apr_err) + || (err == ERROR_INVALID_HANDLE); + if (!is_enoent) - return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, + return svn_error_createf(SVN_ERR_BAD_FILENAME, + svn_error_wrap_apr(apr_err, NULL), _("Can't open registry key '%s'"), svn_dirent_local_style(file, pool)); - else if (must_exist && is_enoent) - return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, - _("Can't find registry key '%s'"), + else if (must_exist) + return svn_error_createf(SVN_ERR_BAD_FILENAME, + NULL, + _("Can't open registry key '%s'"), svn_dirent_local_style(file, pool)); else return SVN_NO_ERROR; Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/dirent_uri.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/dirent_uri.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/dirent_uri.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/dirent_uri.c Sun Jun 14 20:58:10 2015 @@ -1295,9 +1295,9 @@ svn_relpath_split(const char **dirpath, } const char * -svn_relpath_limit(const char *relpath, - int max_components, - apr_pool_t *result_pool) +svn_relpath_prefix(const char *relpath, + int max_components, + apr_pool_t *result_pool) { const char *end; assert(relpath_is_canonical(relpath)); @@ -1738,8 +1738,8 @@ relpath_is_canonical(const char *relpath if (ptr[len-1] == '/' || (ptr[len-1] == '.' && ptr[len-2] == '/')) return FALSE; - /* '.' are rare. So, search for them globally. There will often be no - * more than one hit. Also note that we already checked for invalid + /* '.' are rare. So, search for them globally. There will often be no + * more than one hit. Also note that we already checked for invalid * starts and endings, i.e. we only need to check for "/./" */ for (dot_pos = memchr(ptr, '.', len); Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/dso.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/dso.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/dso.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/dso.c Sun Jun 14 20:58:10 2015 @@ -19,7 +19,6 @@ * ==================================================================== */ -#include <apr_thread_mutex.h> #include <apr_hash.h> #include "svn_hash.h" @@ -29,6 +28,7 @@ #include "private/svn_mutex.h" #include "private/svn_atomic.h" +#include "private/svn_subr_private.h" /* A mutex to protect our global pool and cache. */ static svn_mutex__t *dso_mutex = NULL; @@ -50,12 +50,10 @@ static volatile svn_atomic_t atomic_init there. */ #define NOT_THERE ((void *) ¬_there_sentinel) -svn_error_t * -svn_dso_initialize2(void) +static svn_error_t * +atomic_init_func(void *baton, + apr_pool_t *pool) { - if (dso_pool) - return SVN_NO_ERROR; - dso_pool = svn_pool_create(NULL); SVN_ERR(svn_mutex__init(&dso_mutex, TRUE, dso_pool)); @@ -64,11 +62,12 @@ svn_dso_initialize2(void) return SVN_NO_ERROR; } -static svn_error_t * -atomic_init_func(void *baton, - apr_pool_t *pool) +svn_error_t * +svn_dso_initialize2(void) { - SVN_ERR(svn_dso_initialize2()); + SVN_ERR(svn_atomic__init_once(&atomic_init_status, atomic_init_func, + NULL, NULL)); + return SVN_NO_ERROR; } @@ -118,11 +117,17 @@ svn_dso_load_internal(apr_dso_handle_t * svn_error_t * svn_dso_load(apr_dso_handle_t **dso, const char *fname) { - SVN_ERR(svn_atomic__init_once(&atomic_init_status, atomic_init_func, - NULL, NULL)); + SVN_ERR(svn_dso_initialize2()); SVN_MUTEX__WITH_LOCK(dso_mutex, svn_dso_load_internal(dso, fname)); return SVN_NO_ERROR; } + +apr_pool_t * +svn_dso__pool(void) +{ + return dso_pool; +} + #endif /* APR_HAS_DSO */ Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/error.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/error.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/error.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/error.c Sun Jun 14 20:58:10 2015 @@ -28,6 +28,10 @@ #include <apr_pools.h> #include <apr_strings.h> +#if defined(SVN_DEBUG) && APR_HAS_THREADS +#include <apr_thread_proc.h> +#endif + #include <zlib.h> #ifndef SVN_ERR__TRACING @@ -38,12 +42,57 @@ #include "svn_pools.h" #include "svn_utf.h" +#include "private/svn_error_private.h" +#include "svn_private_config.h" + +#if defined(SVN_DEBUG) && APR_HAS_THREADS +#include "private/svn_atomic.h" +#include "pools.h" +#endif + + #ifdef SVN_DEBUG -/* XXX FIXME: These should be protected by a thread mutex. - svn_error__locate and make_error_internal should cooperate - in locking and unlocking it. */ +# if APR_HAS_THREADS +static apr_threadkey_t *error_file_key = NULL; +static apr_threadkey_t *error_line_key = NULL; + +/* No-op destructor for apr_threadkey_private_create(). */ +static void null_threadkey_dtor(void *stuff) {} + +/* Implements svn_atomic__str_init_func_t. + Callback used by svn_error__locate to initialize the thread-local + error location storage. This function will never return an + error string. */ +static const char * +locate_init_once(void *ignored_baton) +{ + /* Strictly speaking, this is a memory leak, since we're creating an + unmanaged, top-level pool and never destroying it. We do this + because this pool controls the lifetime of the thread-local + storage for error locations, and that storage must always be + available. */ + apr_pool_t *threadkey_pool = svn_pool__create_unmanaged(TRUE); + apr_status_t status; + + status = apr_threadkey_private_create(&error_file_key, + null_threadkey_dtor, + threadkey_pool); + if (status == APR_SUCCESS) + status = apr_threadkey_private_create(&error_line_key, + null_threadkey_dtor, + threadkey_pool); + + /* If anything went wrong with the creation of the thread-local + storage, we'll revert to the old, thread-agnostic behaviour */ + if (status != APR_SUCCESS) + error_file_key = error_line_key = NULL; + + return NULL; +} +# endif /* APR_HAS_THREADS */ -/* XXX TODO: Define mutex here #if APR_HAS_THREADS */ +/* These location variables will be used in no-threads mode or if + thread-local storage is not available. */ static const char * volatile error_file = NULL; static long volatile error_line = -1; @@ -51,9 +100,6 @@ static long volatile error_line = -1; static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>"; #endif /* SVN_DEBUG */ -#include "svn_private_config.h" -#include "private/svn_error_private.h" - /* * Undefine the helpers for creating errors. @@ -67,6 +113,7 @@ static const char SVN_FILE_LINE_UNDEFINE #undef svn_error_create #undef svn_error_createf #undef svn_error_quick_wrap +#undef svn_error_quick_wrapf #undef svn_error_wrap_apr /* Note: Although this is a "__" function, it was historically in the @@ -75,11 +122,25 @@ static const char SVN_FILE_LINE_UNDEFINE void svn_error__locate(const char *file, long line) { -#if defined(SVN_DEBUG) - /* XXX TODO: Lock mutex here */ +#ifdef SVN_DEBUG +# if APR_HAS_THREADS + static volatile svn_atomic_t init_status = 0; + svn_atomic__init_once_no_error(&init_status, locate_init_once, NULL); + + if (error_file_key && error_line_key) + { + apr_status_t status; + status = apr_threadkey_private_set((char*)file, error_file_key); + if (status == APR_SUCCESS) + status = apr_threadkey_private_set((void*)line, error_line_key); + if (status == APR_SUCCESS) + return; + } +# endif /* APR_HAS_THREADS */ + error_file = file; error_line = line; -#endif +#endif /* SVN_DEBUG */ } @@ -102,6 +163,9 @@ make_error_internal(apr_status_t apr_err { apr_pool_t *pool; svn_error_t *new_error; +#ifdef SVN_DEBUG + apr_status_t status = APR_ENOTIMPL; +#endif /* Reuse the child's pool, or create our own. */ if (child) @@ -120,16 +184,34 @@ make_error_internal(apr_status_t apr_err new_error->apr_err = apr_err; new_error->child = child; new_error->pool = pool; -#if defined(SVN_DEBUG) - new_error->file = error_file; - new_error->line = error_line; - /* XXX TODO: Unlock mutex here */ + +#ifdef SVN_DEBUG +#if APR_HAS_THREADS + if (error_file_key && error_line_key) + { + void *item; + status = apr_threadkey_private_get(&item, error_file_key); + if (status == APR_SUCCESS) + { + new_error->file = item; + status = apr_threadkey_private_get(&item, error_line_key); + if (status == APR_SUCCESS) + new_error->line = (long)item; + } + } +# endif /* APR_HAS_THREADS */ + + if (status != APR_SUCCESS) + { + new_error->file = error_file; + new_error->line = error_line; + } if (! child) apr_pool_cleanup_register(pool, new_error, err_abort, apr_pool_cleanup_null); -#endif +#endif /* SVN_DEBUG */ return new_error; } @@ -224,6 +306,26 @@ svn_error_quick_wrap(svn_error_t *child, new_msg); } +svn_error_t * +svn_error_quick_wrapf(svn_error_t *child, + const char *fmt, + ...) +{ + svn_error_t *err; + va_list ap; + + if (child == SVN_NO_ERROR) + return SVN_NO_ERROR; + + err = make_error_internal(child->apr_err, child); + + va_start(ap, fmt); + err->message = apr_pvsprintf(err->pool, fmt, ap); + va_end(ap); + + return err; +} + /* Messages in tracing errors all point to this static string. */ static const char error_tracing_link[] = "traced call"; @@ -557,10 +659,6 @@ svn_handle_error2(svn_error_t *err, apr_array_header_t *empties; svn_error_t *tmp_err; - /* ### The rest of this file carefully avoids using svn_pool_*(), - preferring apr_pool_*() instead. I can't remember why -- it may - be an artifact of r843793, or it may be for some deeper reason -- - but I'm playing it safe and using apr_pool_*() here too. */ subpool = svn_pool_create(err->pool); empties = apr_array_make(subpool, 0, sizeof(apr_status_t)); Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.c Sun Jun 14 20:58:10 2015 @@ -34,7 +34,7 @@ */ /* FNV-1 32 bit constants taken from - * http://www.isthe.com/chongo/tech/comp/fnv/ + * http://www.isthe.com/chongo/tech/comp/fnv/ */ #define FNV1_PRIME_32 0x01000193 #define FNV1_BASE_32 2166136261U @@ -47,7 +47,7 @@ fnv1a_32(apr_uint32_t hash, const void * { const unsigned char *data = input; const unsigned char *end = data + len; - + for (; data != end; ++data) { hash ^= *data; @@ -132,6 +132,25 @@ svn__fnv1a_32x4(const void *input, apr_s len - processed); } +void +svn__fnv1a_32x4_raw(apr_uint32_t hashes[4], + const void *input, + apr_size_t len) +{ + apr_size_t processed; + + apr_size_t i; + for (i = 0; i < SCALING; ++i) + hashes[i] = FNV1_BASE_32; + + /* Process full 16 byte chunks. */ + processed = fnv1a_32x4(hashes, input, len); + + /* Fold the remainder (if any) into the first hash. */ + hashes[0] = fnv1a_32(hashes[0], (const char *)input + processed, + len - processed); +} + struct svn_fnv1a_32__context_t { apr_uint32_t hash; @@ -142,7 +161,7 @@ svn_fnv1a_32__context_create(apr_pool_t { svn_fnv1a_32__context_t *context = apr_palloc(pool, sizeof(*context)); context->hash = FNV1_BASE_32; - + return context; } @@ -203,7 +222,7 @@ svn_fnv1a_32x4__update(svn_fnv1a_32x4__c memcpy(context->buffer + context->buffered, data, to_copy); data = (const char *)data + to_copy; len -= to_copy; - + fnv1a_32x4(context->hashes, context->buffer, SCALING); context->buffered = 0; } Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.h URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.h?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.h (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/fnv1a.h Sun Jun 14 20:58:10 2015 @@ -76,6 +76,14 @@ svn_fnv1a_32x4__update(svn_fnv1a_32x4__c apr_uint32_t svn_fnv1a_32x4__finalize(svn_fnv1a_32x4__context_t *context); +/* Set HASHES to the 4 partial hash sums produced by the modified FVN-1a + * over INPUT of LEN bytes. + */ +void +svn__fnv1a_32x4_raw(apr_uint32_t hashes[4], + const void *input, + apr_size_t len); + #ifdef __cplusplus } #endif /* __cplusplus */ Modified: subversion/branches/fsx-1.10/subversion/libsvn_subr/gpg_agent.c URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_subr/gpg_agent.c?rev=1685464&r1=1685463&r2=1685464&view=diff ============================================================================== --- subversion/branches/fsx-1.10/subversion/libsvn_subr/gpg_agent.c (original) +++ subversion/branches/fsx-1.10/subversion/libsvn_subr/gpg_agent.c Sun Jun 14 20:58:10 2015 @@ -209,7 +209,7 @@ find_running_gpg_agent(int *new_sd, apr_ /* This implements the method of finding the socket as described in * the gpg-agent man page under the --use-standard-socket option. - * The manage page misleadingly says the standard socket is + * The manage page misleadingly says the standard socket is * "named 'S.gpg-agent' located in the home directory." The standard * socket path is actually in the .gnupg directory in the home directory, * i.e. ~/.gnupg/S.gpg-agent */ @@ -219,7 +219,7 @@ find_running_gpg_agent(int *new_sd, apr_ apr_array_header_t *socket_details; /* For reference GPG_AGENT_INFO consists of 3 : separated fields. - * The path to the socket, the pid of the gpg-agent process and + * The path to the socket, the pid of the gpg-agent process and * finally the version of the protocol the agent talks. */ socket_details = svn_cstring_split(gpg_agent_info, ":", TRUE, pool);
