You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/06/23 14:55:47 UTC
svn commit: r1687045 [11/31] - in
/subversion/branches/svn-mergeinfo-normalizer: ./ build/ build/ac-macros/
build/generator/ build/generator/templates/ doc/
subversion/bindings/javahl/ subversion/bindings/javahl/native/
subversion/bindings/javahl/nativ...
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/dump.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/dump.c Tue Jun 23 12:55:43 2015
@@ -2334,7 +2334,7 @@ verify_one_revision(svn_fs_t *fs,
}
/* Baton type used for forwarding notifications from FS API to REPOS API. */
-struct verify_fs2_notify_func_baton_t
+struct verify_fs_notify_func_baton_t
{
/* notification function to call (must not be NULL) */
svn_repos_notify_func_t notify_func;
@@ -2348,11 +2348,11 @@ struct verify_fs2_notify_func_baton_t
/* Forward the notification to BATON. */
static void
-verify_fs2_notify_func(svn_revnum_t revision,
+verify_fs_notify_func(svn_revnum_t revision,
void *baton,
apr_pool_t *pool)
{
- struct verify_fs2_notify_func_baton_t *notify_baton = baton;
+ struct verify_fs_notify_func_baton_t *notify_baton = baton;
notify_baton->notify->revision = revision;
notify_baton->notify_func(notify_baton->notify_baton,
@@ -2378,9 +2378,10 @@ svn_repos_verify_fs3(svn_repos_t *repos,
apr_pool_t *iterpool = svn_pool_create(pool);
svn_repos_notify_t *notify;
svn_fs_progress_notify_func_t verify_notify = NULL;
- struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
+ struct verify_fs_notify_func_baton_t *verify_notify_baton = NULL;
svn_error_t *err;
- svn_boolean_t found_corruption = FALSE;
+ svn_boolean_t failed_metadata = FALSE;
+ svn_revnum_t failed_revisions = 0;
/* Determine the current youngest revision of the filesystem. */
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -2409,7 +2410,7 @@ svn_repos_verify_fs3(svn_repos_t *repos,
{
notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end, pool);
- verify_notify = verify_fs2_notify_func;
+ verify_notify = verify_fs_notify_func;
verify_notify_baton = apr_palloc(pool, sizeof(*verify_notify_baton));
verify_notify_baton->notify_func = notify_func;
verify_notify_baton->notify_baton = notify_baton;
@@ -2423,34 +2424,26 @@ svn_repos_verify_fs3(svn_repos_t *repos,
verify_notify, verify_notify_baton,
cancel_func, cancel_baton, pool);
- if (err)
+ if (err && err->apr_err == SVN_ERR_CANCELLED)
+ {
+ return svn_error_trace(err);
+ }
+ else if (err)
{
- if (err->apr_err == SVN_ERR_CANCELLED)
- return svn_error_trace(err);
-
- found_corruption = TRUE;
notify_verification_error(SVN_INVALID_REVNUM, err, notify_func,
notify_baton, iterpool);
- /* If we already reported the error, reset it. */
- if (notify_func)
+ if (!keep_going)
+ {
+ /* Return the error, the caller doesn't want us to continue. */
+ return svn_error_trace(err);
+ }
+ else
{
+ /* Clear the error and keep going. */
+ failed_metadata = TRUE;
svn_error_clear(err);
- err = NULL;
}
-
- /* If we abort the verification now, combine yet unreported error
- info with the generic one we return. */
- if (!keep_going)
- /* ### Jump to "We're done" and so send the final notification,
- for consistency? */
- return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, err,
- _("Repository '%s' failed to verify"),
- svn_dirent_local_style(svn_repos_path(repos,
- pool),
- pool));
-
- svn_error_clear(err);
}
if (!metadata_only)
@@ -2464,24 +2457,30 @@ svn_repos_verify_fs3(svn_repos_t *repos,
cancel_func, cancel_baton,
iterpool);
- if (err)
+ if (err && err->apr_err == SVN_ERR_CANCELLED)
+ {
+ return svn_error_trace(err);
+ }
+ else if (err)
{
- if (err->apr_err == SVN_ERR_CANCELLED)
- return svn_error_trace(err);
-
- found_corruption = TRUE;
notify_verification_error(rev, err, notify_func, notify_baton,
iterpool);
- svn_error_clear(err);
- if (keep_going)
- continue;
+ if (!keep_going)
+ {
+ /* Return the error, the caller doesn't want us to continue. */
+ return svn_error_trace(err);
+ }
else
- break;
+ {
+ /* Clear the error and keep going. */
+ ++failed_revisions;
+ svn_error_clear(err);
+ }
}
-
- if (notify_func)
+ else if (notify_func)
{
+ /* Tell the caller that we're done with this revision. */
notify->revision = rev;
notify_func(notify_baton, notify, iterpool);
}
@@ -2496,12 +2495,40 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_pool_destroy(iterpool);
- if (found_corruption)
- return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
- _("Repository '%s' failed to verify"),
- svn_dirent_local_style(svn_repos_path(repos,
- pool),
- pool));
+ /* Summarize the results. */
+ if (failed_metadata || 0 != failed_revisions)
+ {
+ const char *const repos_path =
+ svn_dirent_local_style(svn_repos_path(repos, pool), pool);
+
+ if (0 == failed_revisions)
+ {
+ return svn_error_createf(
+ SVN_ERR_REPOS_VERIFY_FAILED, NULL,
+ _("Metadata verification failed on repository '%s'"),
+ repos_path);
+ }
+ else
+ {
+ const char* format_string;
+
+ if (failed_metadata)
+ format_string = apr_psprintf(
+ pool, _("Verification of metadata and"
+ " %%%s out of %%%s revisions"
+ " failed on repository '%%s'"),
+ SVN_REVNUM_T_FMT, SVN_REVNUM_T_FMT);
+ else
+ format_string = apr_psprintf(
+ pool, _("Verification of %%%s out of %%%s revisions"
+ " failed on repository '%%s'"),
+ SVN_REVNUM_T_FMT, SVN_REVNUM_T_FMT);
+
+ return svn_error_createf(
+ SVN_ERR_REPOS_VERIFY_FAILED, NULL, format_string,
+ failed_revisions, end_rev - start_rev + 1, repos_path);
+ }
+ }
return SVN_NO_ERROR;
}
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/replay.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/replay.c Tue Jun 23 12:55:43 2015
@@ -555,10 +555,6 @@ path_driver_cb_func(void **dir_baton,
return svn_error_create(SVN_ERR_FS_ALREADY_EXISTS, NULL,
_("Root directory already exists."));
- /* A NULL parent_baton will cause a segfault. It should never be
- NULL for non-root paths. */
- SVN_ERR_ASSERT(parent_baton);
-
/* Was this node copied? */
SVN_ERR(fill_copyfrom(©from_root, ©from_path, ©from_rev,
&src_readable, root, change,
@@ -971,6 +967,11 @@ svn_repos_replay2(svn_fs_root_t *root,
const char *repos_root = "";
void *unlock_baton;
+ /* If we were not given a low water mark, assume that everything is there,
+ all the way back to revision 0. */
+ if (! SVN_IS_VALID_REVNUM(low_water_mark))
+ low_water_mark = 0;
+
/* Special-case r0, which we know is an empty revision; if we don't
special-case it we might end up trying to compare it to "r-1". */
if (svn_fs_is_revision_root(root)
@@ -1493,7 +1494,7 @@ svn_repos__replay_ev2(svn_fs_root_t *roo
svn_error_t *err = SVN_NO_ERROR;
int i;
- SVN_ERR_ASSERT(!svn_dirent_is_absolute(base_repos_relpath));
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(base_repos_relpath));
/* Special-case r0, which we know is an empty revision; if we don't
special-case it we might end up trying to compare it to "r-1". */
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/reporter.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/reporter.c Tue Jun 23 12:55:43 2015
@@ -1282,7 +1282,7 @@ delta_dirs(report_baton_t *b, svn_revnum
/* Loop over the dirents in the target. */
SVN_ERR(svn_fs_dir_optimal_order(&t_ordered_entries, b->t_root,
- t_entries, subpool));
+ t_entries, subpool, iterpool));
for (i = 0; i < t_ordered_entries->nelts; ++i)
{
const svn_fs_dirent_t *t_entry
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/repos.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/repos.c Tue Jun 23 12:55:43 2015
@@ -1635,9 +1635,10 @@ svn_repos_fs(svn_repos_t *repos)
}
const char *
-svn_repos_fs_type(svn_repos_t *repos, apr_pool_t *pool)
+svn_repos_fs_type(svn_repos_t *repos,
+ apr_pool_t *result_pool)
{
- return apr_pstrdup(pool, repos->fs_type);
+ return apr_pstrdup(result_pool, repos->fs_type);
}
/* For historical reasons, for the Berkeley DB backend, this code uses
@@ -1957,7 +1958,7 @@ svn_repos_hotcopy3(const char *src_path,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
svn_fs_hotcopy_notify_t fs_notify_func;
struct fs_hotcopy_notify_baton_t fs_notify_baton;
@@ -1968,8 +1969,8 @@ svn_repos_hotcopy3(const char *src_path,
svn_repos_t *dst_repos;
svn_error_t *err;
- SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, pool));
- SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, pool));
+ SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, scratch_pool));
+ SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, scratch_pool));
if (strcmp(src_abspath, dst_abspath) == 0)
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Hotcopy source and destination are equal"));
@@ -1979,7 +1980,7 @@ svn_repos_hotcopy3(const char *src_path,
FALSE, FALSE,
FALSE, /* don't try to open the db yet. */
NULL,
- pool, pool));
+ scratch_pool, scratch_pool));
/* If we are going to clean logs, then get an exclusive lock on
db-logs.lock, to ensure that no one else will work with logs.
@@ -1987,7 +1988,7 @@ svn_repos_hotcopy3(const char *src_path,
If we are just copying, then get a shared lock to ensure that
no one else will clean logs while we copying them */
- SVN_ERR(lock_db_logs_file(src_repos, clean_logs, pool));
+ SVN_ERR(lock_db_logs_file(src_repos, clean_logs, scratch_pool));
/* Copy the repository to a new path, with exception of
specially handled directories */
@@ -2001,16 +2002,16 @@ svn_repos_hotcopy3(const char *src_path,
0,
hotcopy_structure,
&hotcopy_context,
- pool));
+ scratch_pool));
/* Prepare dst_repos object so that we may create locks,
so that we may open repository */
- dst_repos = create_svn_repos_t(dst_abspath, pool);
+ dst_repos = create_svn_repos_t(dst_abspath, scratch_pool);
dst_repos->fs_type = src_repos->fs_type;
dst_repos->format = src_repos->format;
- err = create_locks(dst_repos, pool);
+ err = create_locks(dst_repos, scratch_pool);
if (err)
{
if (incremental && err->apr_err == SVN_ERR_DIR_NOT_EMPTY)
@@ -2019,7 +2020,8 @@ svn_repos_hotcopy3(const char *src_path,
return svn_error_trace(err);
}
- err = svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT, pool);
+ err = svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT,
+ scratch_pool);
if (err)
{
if (incremental && APR_STATUS_IS_EEXIST(err->apr_err))
@@ -2030,7 +2032,7 @@ svn_repos_hotcopy3(const char *src_path,
/* Exclusively lock the new repository.
No one should be accessing it at the moment */
- SVN_ERR(lock_repos(dst_repos, TRUE, FALSE, pool));
+ SVN_ERR(lock_repos(dst_repos, TRUE, FALSE, scratch_pool));
fs_notify_func = notify_func ? fs_hotcopy_notify : NULL;
fs_notify_baton.notify_func = notify_func;
@@ -2039,12 +2041,12 @@ svn_repos_hotcopy3(const char *src_path,
SVN_ERR(svn_fs_hotcopy3(src_repos->db_path, dst_repos->db_path,
clean_logs, incremental,
fs_notify_func, &fs_notify_baton,
- cancel_func, cancel_baton, pool));
+ cancel_func, cancel_baton, scratch_pool));
/* Destination repository is ready. Stamp it with a format number. */
return svn_io_write_version_file
- (svn_dirent_join(dst_repos->path, SVN_REPOS__FORMAT, pool),
- dst_repos->format, pool);
+ (svn_dirent_join(dst_repos->path, SVN_REPOS__FORMAT, scratch_pool),
+ dst_repos->format, scratch_pool);
}
/* Return the library version number. */
@@ -2065,7 +2067,6 @@ svn_repos_stat(svn_dirent_t **dirent,
svn_node_kind_t kind;
svn_dirent_t *ent;
const char *datestring;
- apr_hash_t *prophash;
SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
@@ -2081,9 +2082,7 @@ svn_repos_stat(svn_dirent_t **dirent,
if (kind == svn_node_file)
SVN_ERR(svn_fs_file_length(&(ent->size), root, path, pool));
- SVN_ERR(svn_fs_node_proplist(&prophash, root, path, pool));
- if (apr_hash_count(prophash) > 0)
- ent->has_props = TRUE;
+ SVN_ERR(svn_fs_node_has_props(&ent->has_props, root, path, pool));
SVN_ERR(svn_repos_get_committed_info(&(ent->created_rev),
&datestring,
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/rev_hunt.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_repos/rev_hunt.c Tue Jun 23 12:55:43 2015
@@ -310,9 +310,8 @@ svn_repos_deleted_rev(svn_fs_t *fs,
svn_revnum_t *deleted,
apr_pool_t *pool)
{
- apr_pool_t *subpool;
- svn_fs_root_t *start_root, *root, *copy_root;
- const char *copy_path;
+ apr_pool_t *iterpool;
+ svn_fs_root_t *start_root, *root;
svn_revnum_t mid_rev;
svn_node_kind_t kind;
svn_fs_node_relation_t node_relation;
@@ -379,6 +378,8 @@ svn_repos_deleted_rev(svn_fs_t *fs,
root, path, pool));
if (node_relation != svn_fs_node_unrelated)
{
+ svn_fs_root_t *copy_root;
+ const char *copy_path;
SVN_ERR(svn_fs_closest_copy(©_root, ©_path, root,
path, pool));
if (!copy_root ||
@@ -432,15 +433,15 @@ svn_repos_deleted_rev(svn_fs_t *fs,
*/
mid_rev = (start + end) / 2;
- subpool = svn_pool_create(pool);
+ iterpool = svn_pool_create(pool);
while (1)
{
- svn_pool_clear(subpool);
+ svn_pool_clear(iterpool);
/* Get revision root and node id for mid_rev at that revision. */
- SVN_ERR(svn_fs_revision_root(&root, fs, mid_rev, subpool));
- SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
+ SVN_ERR(svn_fs_revision_root(&root, fs, mid_rev, iterpool));
+ SVN_ERR(svn_fs_check_path(&kind, root, path, iterpool));
if (kind == svn_node_none)
{
/* Case D: Look lower in the range. */
@@ -449,13 +450,15 @@ svn_repos_deleted_rev(svn_fs_t *fs,
}
else
{
+ svn_fs_root_t *copy_root;
+ const char *copy_path;
/* Determine the relationship between the start node
and the current node. */
SVN_ERR(svn_fs_node_relation(&node_relation, start_root, path,
- root, path, pool));
+ root, path, iterpool));
if (node_relation != svn_fs_node_unrelated)
- SVN_ERR(svn_fs_closest_copy(©_root, ©_path, root,
- path, subpool));
+ SVN_ERR(svn_fs_closest_copy(©_root, ©_path, root,
+ path, iterpool));
if (node_relation == svn_fs_node_unrelated ||
(copy_root &&
(svn_fs_revision_root_revision(copy_root) > start)))
@@ -479,7 +482,7 @@ svn_repos_deleted_rev(svn_fs_t *fs,
}
}
- svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -666,8 +669,7 @@ svn_repos_trace_node_locations(svn_fs_t
/* First - let's sort the array of the revisions from the greatest revision
* downward, so it will be easier to search on. */
location_revisions = apr_array_copy(pool, location_revisions_orig);
- qsort(location_revisions->elts, location_revisions->nelts,
- sizeof(*revision_ptr), svn_sort_compare_revisions);
+ svn_sort__array(location_revisions, svn_sort_compare_revisions);
revision_ptr = (svn_revnum_t *)location_revisions->elts;
revision_ptr_end = revision_ptr + location_revisions->nelts;
@@ -835,27 +837,32 @@ svn_repos_node_location_segments(svn_rep
{
svn_fs_t *fs = svn_repos_fs(repos);
svn_stringbuf_t *current_path;
- svn_revnum_t youngest_rev = SVN_INVALID_REVNUM, current_rev;
+ svn_revnum_t youngest_rev, current_rev;
apr_pool_t *subpool;
+ SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
+
/* No PEG_REVISION? We'll use HEAD. */
if (! SVN_IS_VALID_REVNUM(peg_revision))
- {
- SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
- peg_revision = youngest_rev;
- }
+ peg_revision = youngest_rev;
- /* No START_REV? We'll use HEAD (which we may have already fetched). */
+ if (peg_revision > youngest_rev)
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"), peg_revision);
+
+ /* No START_REV? We'll use peg rev. */
if (! SVN_IS_VALID_REVNUM(start_rev))
- {
- if (SVN_IS_VALID_REVNUM(youngest_rev))
- start_rev = youngest_rev;
- else
- SVN_ERR(svn_fs_youngest_rev(&start_rev, fs, pool));
- }
+ start_rev = peg_revision;
+ else if (start_rev > peg_revision)
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"), start_rev);
/* No END_REV? We'll use 0. */
- end_rev = SVN_IS_VALID_REVNUM(end_rev) ? end_rev : 0;
+ if (! SVN_IS_VALID_REVNUM(end_rev))
+ end_rev = 0;
+ else if (end_rev > start_rev)
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"), end_rev);
/* Are the revision properly ordered? They better be -- the API
demands it. */
@@ -1329,6 +1336,7 @@ struct send_baton
apr_hash_t *last_props;
const char *last_path;
svn_fs_root_t *last_root;
+ svn_boolean_t include_merged_revisions;
};
/* Send PATH_REV to HANDLER and HANDLER_BATON, using information provided by
@@ -1366,15 +1374,32 @@ send_path_revision(struct path_revision
SVN_ERR(svn_prop_diffs(&prop_diffs, props, sb->last_props,
sb->iterpool));
- /* Check if the contents *may* have changed. (Allow false positives,
- for now, as the blame implementation currently depends on them.) */
- /* Special case: In the first revision, we always provide a delta. */
- if (sb->last_root)
- SVN_ERR(svn_fs_contents_different(&contents_changed, sb->last_root,
- sb->last_path, root, path_rev->path,
- sb->iterpool));
+ /* Check if the contents *may* have changed. */
+ if (! sb->last_root)
+ {
+ /* Special case: In the first revision, we always provide a delta. */
+ contents_changed = TRUE;
+ }
+ else if (sb->include_merged_revisions
+ && strcmp(sb->last_path, path_rev->path))
+ {
+ /* ### This is a HACK!!!
+ * Blame -g, in older clients anyways, relies on getting a notification
+ * whenever the path changes - even if there was no content change.
+ *
+ * TODO: A future release should take an extra parameter and depending
+ * on that either always send a text delta or only send it if there
+ * is a difference. */
+ contents_changed = TRUE;
+ }
else
- contents_changed = TRUE;
+ {
+ /* Did the file contents actually change?
+ * It could e.g. be a property-only change. */
+ SVN_ERR(svn_fs_contents_different(&contents_changed, sb->last_root,
+ sb->last_path, root, path_rev->path,
+ sb->iterpool));
+ }
/* We have all we need, give to the handler. */
SVN_ERR(handler(handler_baton, path_rev->path, path_rev->revnum,
@@ -1443,6 +1468,7 @@ get_file_revs_backwards(svn_repos_t *rep
last_pool = svn_pool_create(scratch_pool);
sb.iterpool = svn_pool_create(scratch_pool);
sb.last_pool = svn_pool_create(scratch_pool);
+ sb.include_merged_revisions = FALSE;
/* We want the first txdelta to be against the empty file. */
sb.last_root = NULL;
@@ -1598,6 +1624,9 @@ svn_repos_get_file_revs2(svn_repos_t *re
/* Create an empty hash table for the first property diff. */
sb.last_props = apr_hash_make(sb.last_pool);
+ /* Inform send_path_revision() whether workarounds / special behavior
+ * may be needed. */
+ sb.include_merged_revisions = include_merged_revisions;
/* Get the revisions we are interested in. */
duplicate_path_revs = apr_hash_make(scratch_pool);
Propchange: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Jun 23 12:55:43 2015
@@ -12,3 +12,4 @@ internal_statements.h
errorcode.inc
libsvn_subr.pc.in
libsvn_subr.pc
+config_keys.inc
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/atomic.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/atomic.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/atomic.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/atomic.c Tue Jun 23 12:55:43 2015
@@ -20,6 +20,7 @@
* ====================================================================
*/
+#include <assert.h>
#include <apr_time.h>
#include "private/svn_atomic.h"
@@ -29,11 +30,20 @@
#define SVN_ATOMIC_INIT_FAILED 2
#define SVN_ATOMIC_INITIALIZED 3
-svn_error_t*
-svn_atomic__init_once(volatile svn_atomic_t *global_status,
- svn_error_t *(*init_func)(void*,apr_pool_t*),
- void *baton,
- apr_pool_t* pool)
+
+/*
+ * This is the actual atomic initialization driver. The caller must
+ * provide either ERR_INIT_FUNC and ERR_P, or STR_INIT_FUNC and
+ * ERRSTR_P, but never both.
+ */
+static void
+init_once(svn_atomic__err_init_func_t err_init_func,
+ svn_error_t **err_p,
+ svn_atomic__str_init_func_t str_init_func,
+ const char **errstr_p,
+ volatile svn_atomic_t *global_status,
+ void *baton,
+ apr_pool_t* pool)
{
/* !! Don't use localizable strings in this function, because these
!! might cause deadlocks. This function can be used to initialize
@@ -42,44 +52,94 @@ svn_atomic__init_once(volatile svn_atomi
/* We have to call init_func exactly once. Because APR
doesn't have statically-initialized mutexes, we implement a poor
man's spinlock using svn_atomic_cas. */
+
+ svn_error_t *err = SVN_NO_ERROR;
+ const char *errstr = NULL;
svn_atomic_t status = svn_atomic_cas(global_status,
SVN_ATOMIC_START_INIT,
SVN_ATOMIC_UNINITIALIZED);
- if (status == SVN_ATOMIC_UNINITIALIZED)
+#ifdef SVN_DEBUG
+ /* Check that the parameters are valid. */
+ assert(!err_init_func != !str_init_func);
+ assert(!err_init_func == !err_p);
+ assert(!str_init_func == !errstr_p);
+#endif /* SVN_DEBUG */
+
+ for (;;)
{
- svn_error_t *err = init_func(baton, pool);
- if (err)
+ switch (status)
{
-#if APR_HAS_THREADS
- /* Tell other threads that the initialization failed. */
- svn_atomic_cas(global_status,
- SVN_ATOMIC_INIT_FAILED,
- SVN_ATOMIC_START_INIT);
-#endif
- return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err,
- "Couldn't perform atomic initialization");
+ case SVN_ATOMIC_UNINITIALIZED:
+ if (err_init_func)
+ err = err_init_func(baton, pool);
+ else
+ errstr = str_init_func(baton);
+ if (err || errstr)
+ {
+ status = svn_atomic_cas(global_status,
+ SVN_ATOMIC_INIT_FAILED,
+ SVN_ATOMIC_START_INIT);
+ }
+ else
+ {
+ status = svn_atomic_cas(global_status,
+ SVN_ATOMIC_INITIALIZED,
+ SVN_ATOMIC_START_INIT);
+ }
+
+ /* Take another spin through the switch to report either
+ failure or success. */
+ continue;
+
+ case SVN_ATOMIC_START_INIT:
+ /* Wait for the init function to complete. */
+ apr_sleep(APR_USEC_PER_SEC / 1000);
+ status = svn_atomic_cas(global_status,
+ SVN_ATOMIC_UNINITIALIZED,
+ SVN_ATOMIC_UNINITIALIZED);
+ continue;
+
+ case SVN_ATOMIC_INIT_FAILED:
+ if (err_init_func)
+ *err_p = svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err,
+ "Couldn't perform atomic initialization");
+ else
+ *errstr_p = errstr;
+ return;
+
+ case SVN_ATOMIC_INITIALIZED:
+ if (err_init_func)
+ *err_p = SVN_NO_ERROR;
+ else
+ *errstr_p = NULL;
+ return;
+
+ default:
+ /* Something went seriously wrong with the atomic operations. */
+ abort();
}
- svn_atomic_cas(global_status,
- SVN_ATOMIC_INITIALIZED,
- SVN_ATOMIC_START_INIT);
- }
-#if APR_HAS_THREADS
- /* Wait for whichever thread is performing initialization to finish. */
- /* XXX FIXME: Should we have a maximum wait here, like we have in
- the Windows file IO spinner? */
- else while (status != SVN_ATOMIC_INITIALIZED)
- {
- if (status == SVN_ATOMIC_INIT_FAILED)
- return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, NULL,
- "Couldn't perform atomic initialization");
-
- apr_sleep(APR_USEC_PER_SEC / 1000);
- status = svn_atomic_cas(global_status,
- SVN_ATOMIC_UNINITIALIZED,
- SVN_ATOMIC_UNINITIALIZED);
}
-#endif /* APR_HAS_THREADS */
+}
+
- return SVN_NO_ERROR;
+svn_error_t *
+svn_atomic__init_once(volatile svn_atomic_t *global_status,
+ svn_atomic__err_init_func_t err_init_func,
+ void *baton,
+ apr_pool_t* pool)
+{
+ svn_error_t *err;
+ init_once(err_init_func, &err, NULL, NULL, global_status, baton, pool);
+ return err;
+}
+
+const char *
+svn_atomic__init_once_no_error(volatile svn_atomic_t *global_status,
+ svn_atomic__str_init_func_t str_init_func,
+ void *baton)
+{
+ const char *errstr;
+ init_once(NULL, NULL, str_init_func, &errstr, global_status, baton, NULL);
+ return errstr;
}
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/auth.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/auth.c Tue Jun 23 12:55:43 2015
@@ -109,10 +109,10 @@ struct svn_auth_baton_t
/* run-time parameters needed by providers. */
apr_hash_t *parameters;
+ apr_hash_t *slave_parameters;
/* run-time credentials cache. */
apr_hash_t *creds_cache;
-
};
/* Abstracted iteration baton */
@@ -125,6 +125,7 @@ struct svn_auth_iterstate_t
const char *realmstring; /* The original realmstring passed in */
const char *cache_key; /* key to use in auth_baton's creds_cache */
svn_auth_baton_t *auth_baton; /* the original auth_baton. */
+ apr_hash_t *parameters;
};
@@ -142,6 +143,7 @@ svn_auth_open(svn_auth_baton_t **auth_ba
ab = apr_pcalloc(pool, sizeof(*ab));
ab->tables = apr_hash_make(pool);
ab->parameters = apr_hash_make(pool);
+ /* ab->slave_parameters = NULL; */
ab->creds_cache = apr_hash_make(pool);
ab->pool = pool;
@@ -170,7 +172,8 @@ svn_auth_open(svn_auth_baton_t **auth_ba
*auth_baton = ab;
}
-
+/* Magic pointer value to allow storing 'NULL' in an apr_hash_t */
+static const void *auth_NULL = NULL;
void
svn_auth_set_parameter(svn_auth_baton_t *auth_baton,
@@ -178,17 +181,35 @@ svn_auth_set_parameter(svn_auth_baton_t
const void *value)
{
if (auth_baton)
- svn_hash_sets(auth_baton->parameters, name, value);
+ {
+ if (auth_baton->slave_parameters)
+ {
+ if (!value)
+ value = &auth_NULL;
+
+ svn_hash_sets(auth_baton->slave_parameters, name, value);
+ }
+ else
+ svn_hash_sets(auth_baton->parameters, name, value);
+ }
}
const void *
svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
const char *name)
{
- if (auth_baton)
- return svn_hash_gets(auth_baton->parameters, name);
- else
+ const void *value;
+ if (!auth_baton)
return NULL;
+ else if (!auth_baton->slave_parameters)
+ return svn_hash_gets(auth_baton->parameters, name);
+
+ value = svn_hash_gets(auth_baton->slave_parameters, name);
+
+ if (value)
+ return (value == &auth_NULL ? NULL : value);
+
+ return svn_hash_gets(auth_baton->parameters, name);
}
@@ -218,6 +239,7 @@ svn_auth_first_credentials(void **creden
svn_boolean_t got_first = FALSE;
svn_auth_iterstate_t *iterstate;
const char *cache_key;
+ apr_hash_t *parameters;
if (! auth_baton)
return svn_error_create(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
@@ -230,6 +252,26 @@ svn_auth_first_credentials(void **creden
_("No provider registered for '%s' credentials"),
cred_kind);
+ if (auth_baton->slave_parameters)
+ {
+ apr_hash_index_t *hi;
+ parameters = apr_hash_copy(pool, auth_baton->parameters);
+
+ for (hi = apr_hash_first(pool, auth_baton->slave_parameters);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *value = apr_hash_this_val(hi);
+
+ if (value == &auth_NULL)
+ value = NULL;
+
+ svn_hash_sets(parameters, apr_hash_this_key(hi), value);
+ }
+ }
+ else
+ parameters = auth_baton->parameters;
+
/* First, see if we have cached creds in the auth_baton. */
cache_key = make_cache_key(cred_kind, realmstring, pool);
creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
@@ -247,7 +289,7 @@ svn_auth_first_credentials(void **creden
svn_auth_provider_object_t *);
SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton,
provider->provider_baton,
- auth_baton->parameters,
+ parameters,
realmstring,
auth_baton->pool));
@@ -274,6 +316,7 @@ svn_auth_first_credentials(void **creden
iterstate->realmstring = apr_pstrdup(pool, realmstring);
iterstate->cache_key = cache_key;
iterstate->auth_baton = auth_baton;
+ iterstate->parameters = parameters;
*state = iterstate;
/* Put the creds in the cache */
@@ -310,7 +353,7 @@ svn_auth_next_credentials(void **credent
{
SVN_ERR(provider->vtable->first_credentials(
&creds, &(state->provider_iter_baton),
- provider->provider_baton, auth_baton->parameters,
+ provider->provider_baton, state->parameters,
state->realmstring, auth_baton->pool));
state->got_first = TRUE;
}
@@ -319,7 +362,7 @@ svn_auth_next_credentials(void **credent
SVN_ERR(provider->vtable->next_credentials(&creds,
state->provider_iter_baton,
provider->provider_baton,
- auth_baton->parameters,
+ state->parameters,
state->realmstring,
auth_baton->pool));
}
@@ -348,19 +391,17 @@ svn_auth_save_credentials(svn_auth_iters
svn_auth_provider_object_t *provider;
svn_boolean_t save_succeeded = FALSE;
const char *no_auth_cache;
- svn_auth_baton_t *auth_baton;
void *creds;
if (! state || state->table->providers->nelts <= state->provider_idx)
return SVN_NO_ERROR;
- auth_baton = state->auth_baton;
creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
if (! creds)
return SVN_NO_ERROR;
/* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
- no_auth_cache = svn_hash_gets(auth_baton->parameters,
+ no_auth_cache = svn_hash_gets(state->parameters,
SVN_AUTH_PARAM_NO_AUTH_CACHE);
if (no_auth_cache)
return SVN_NO_ERROR;
@@ -373,7 +414,7 @@ svn_auth_save_credentials(svn_auth_iters
SVN_ERR(provider->vtable->save_credentials(&save_succeeded,
creds,
provider->provider_baton,
- auth_baton->parameters,
+ state->parameters,
state->realmstring,
pool));
if (save_succeeded)
@@ -389,7 +430,7 @@ svn_auth_save_credentials(svn_auth_iters
if (provider->vtable->save_credentials)
SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds,
provider->provider_baton,
- auth_baton->parameters,
+ state->parameters,
state->realmstring,
pool));
@@ -687,10 +728,12 @@ svn_auth_get_platform_specific_client_pr
}
svn_error_t *
-svn_auth__apply_config_for_server(svn_auth_baton_t *auth_baton,
- apr_hash_t *config,
- const char *server_name,
- apr_pool_t *scratch_pool)
+svn_auth__make_session_auth(svn_auth_baton_t **session_auth_baton,
+ const svn_auth_baton_t *auth_baton,
+ apr_hash_t *config,
+ const char *server_name,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
@@ -702,6 +745,12 @@ svn_auth__apply_config_for_server(svn_au
svn_config_t *servers = NULL;
const char *server_group = NULL;
+ struct svn_auth_baton_t *ab;
+
+ ab = apr_pmemdup(result_pool, auth_baton, sizeof(*ab));
+
+ ab->slave_parameters = apr_hash_make(result_pool);
+
/* The 'store-passwords' and 'store-auth-creds' parameters used to
* live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
* if values for these parameters have already been set by our
@@ -716,12 +765,10 @@ svn_auth__apply_config_for_server(svn_au
* "store-auth-creds = yes" -- they'll get the expected behaviour.
*/
- if (svn_auth_get_parameter(auth_baton,
- SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
+ if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
store_passwords = FALSE;
- if (svn_auth_get_parameter(auth_baton,
- SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
+ if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
store_auth_creds = FALSE;
/* All the svn_auth_set_parameter() calls below this not only affect the
@@ -806,46 +853,30 @@ svn_auth__apply_config_for_server(svn_au
/* Save auth caching parameters in the auth parameter hash. */
if (! store_passwords)
- svn_auth_set_parameter(auth_baton,
- SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
+ svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
- svn_auth_set_parameter(auth_baton,
+ svn_auth_set_parameter(ab,
SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
store_plaintext_passwords);
if (! store_pp)
- svn_auth_set_parameter(auth_baton,
+ svn_auth_set_parameter(ab,
SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
"");
- svn_auth_set_parameter(auth_baton,
+ svn_auth_set_parameter(ab,
SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
store_pp_plaintext);
if (! store_auth_creds)
- svn_auth_set_parameter(auth_baton,
- SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
+ svn_auth_set_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
- /* ### This setting may have huge side-effects when the auth baton is shared
- ### between different ra sessions, as it will change which server settings
- ### will be used for all future auth requests.
- ###
- ### E.g. when you connect using a ssl client cert that is specified in the
- ### config file, you might have it when you first connect... but if you
- ### then connect to another repository, you might not see the same
- ### settings when the SSL connection is built up again later on.
- ###
- ### Most current usages should probably have been keyed on the realm
- ### string instead of this magic flag that changes when multiple repositories
- ### are used.
- ###
- ### This especially affects long living ra sessions, such as those on the
- ### reuse-ra-session branch.
- */
if (server_group)
- svn_auth_set_parameter(auth_baton,
+ svn_auth_set_parameter(ab,
SVN_AUTH_PARAM_SERVER_GROUP,
- apr_pstrdup(auth_baton->pool, server_group));
+ apr_pstrdup(ab->pool, server_group));
+
+ *session_auth_baton = ab;
return SVN_NO_ERROR;
}
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-inprocess.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-inprocess.c Tue Jun 23 12:55:43 2015
@@ -23,8 +23,6 @@
#include <assert.h>
-#include <apr_thread_mutex.h>
-
#include "svn_pools.h"
#include "svn_private_config.h"
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-membuffer.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/cache-membuffer.c Tue Jun 23 12:55:43 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.
@@ -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;
@@ -1883,7 +1937,7 @@ svn_cache__membuffer_clear(svn_membuffer
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;
@@ -1896,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,
@@ -1929,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
@@ -1942,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,
@@ -1952,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);
@@ -1978,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;
@@ -2007,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;
@@ -2015,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
@@ -2026,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++;
}
@@ -2056,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,
@@ -2069,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.
*/
@@ -2112,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
@@ -2140,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
@@ -2154,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
@@ -2162,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;
}
@@ -2174,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
@@ -2186,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,
@@ -2214,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);
@@ -2243,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,
@@ -2274,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,
@@ -2293,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);
@@ -2306,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);
}
}
@@ -2330,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,
@@ -2338,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
@@ -2362,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
@@ -2380,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++;
@@ -2392,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)
{
@@ -2421,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.
*/
@@ -2447,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
@@ -2464,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
@@ -2472,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,
@@ -2498,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.
@@ -2533,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.
@@ -2553,23 +2597,13 @@ typedef struct svn_membuffer_cache_t
/* Temporary buffer containing the hash key for the current access
*/
- entry_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;
+ full_key_t combined_key;
/* 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
@@ -2580,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);
- }
+ aligned_key_len = ALIGN_VALUE(key_len);
- cache->combined_key[0] ^= cache->prefix[0];
- cache->combined_key[1] ^= cache->prefix[1];
-
- memcpy(cache->last_access->combined_key, cache->combined_key,
- sizeof(cache->combined_key));
- }
+ /* 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
@@ -2654,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)
@@ -2721,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
@@ -2758,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 */
@@ -2790,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,
@@ -2836,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,
@@ -2864,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
@@ -2936,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 */
@@ -3129,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
*/
@@ -3144,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/svn-mergeinfo-normalizer/subversion/libsvn_subr/checksum.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/checksum.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_subr/checksum.c Tue Jun 23 12:55:43 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);
}