You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gb...@apache.org on 2013/09/26 15:47:26 UTC
svn commit: r1526487 [8/10] - in
/subversion/branches/invoke-diff-cmd-feature: ./ build/ac-macros/
build/generator/ build/generator/templates/ contrib/client-side/emacs/
notes/ subversion/bindings/javahl/native/
subversion/bindings/javahl/src/org/apach...
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_local/split_url.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_local/split_url.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_local/split_url.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_local/split_url.c Thu Sep 26 13:47:21 2013
@@ -39,6 +39,7 @@ svn_ra_local__split_URL(svn_repos_t **re
const char *repos_dirent;
const char *repos_root_dirent;
svn_stringbuf_t *urlbuf;
+ apr_size_t root_end;
SVN_ERR(svn_uri_get_dirent_from_file_url(&repos_dirent, URL, pool));
@@ -65,10 +66,17 @@ svn_ra_local__split_URL(svn_repos_t **re
"/",
svn_dirent_skip_ancestor(repos_root_dirent, repos_dirent),
(const char *)NULL); */
- *fs_path = &repos_dirent[strlen(repos_root_dirent)];
-
- if (**fs_path == '\0')
+ root_end = strlen(repos_root_dirent);
+ if (! repos_dirent[root_end])
*fs_path = "/";
+ else if (repos_dirent[root_end] == '/')
+ *fs_path = &repos_dirent[root_end];
+ else
+ {
+ /* On Windows "C:/" is the parent directory of "C:/dir" */
+ *fs_path = &repos_dirent[root_end-1];
+ SVN_ERR_ASSERT((*fs_path)[0] == '/');
+ }
/* Remove the path components after the root dirent from the original URL,
to get a URL to the repository root.
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/commit.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/commit.c Thu Sep 26 13:47:21 2013
@@ -1933,7 +1933,18 @@ add_file(const char *path,
if (handler->sline.code != 404)
{
- return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL,
+ if (handler->sline.code != 200)
+ {
+ svn_error_t *err;
+
+ err = svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location);
+
+ SVN_ERR(err);
+ }
+
+ return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
_("File '%s' already exists"), path);
}
}
@@ -2168,8 +2179,8 @@ close_file(void *file_baton,
{
proppatch_context_t *proppatch;
- proppatch = apr_pcalloc(ctx->pool, sizeof(*proppatch));
- proppatch->pool = ctx->pool;
+ proppatch = apr_pcalloc(scratch_pool, sizeof(*proppatch));
+ proppatch->pool = scratch_pool;
proppatch->relpath = ctx->relpath;
proppatch->path = ctx->url;
proppatch->commit = ctx->commit;
@@ -2177,7 +2188,7 @@ close_file(void *file_baton,
proppatch->removed_props = ctx->removed_props;
proppatch->base_revision = ctx->base_revision;
- SVN_ERR(proppatch_resource(proppatch, ctx->commit, ctx->pool));
+ SVN_ERR(proppatch_resource(proppatch, ctx->commit, scratch_pool));
}
return SVN_NO_ERROR;
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/log.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/log.c Thu Sep 26 13:47:21 2013
@@ -76,6 +76,7 @@ typedef struct log_context_t {
svn_boolean_t changed_paths;
svn_boolean_t strict_node_history;
svn_boolean_t include_merged_revisions;
+ svn_move_behavior_t move_behavior;
const apr_array_header_t *revprops;
int nest_level; /* used to track mergeinfo nesting levels */
int count; /* only incremented when nest_level == 0 */
@@ -451,6 +452,14 @@ create_log_body(serf_bucket_t **body_bkt
alloc);
}
+ if (log_ctx->move_behavior != svn_move_behavior_no_moves)
+ {
+ svn_ra_serf__add_tag_buckets(buckets,
+ "S:move-behavior",
+ apr_ltoa(pool, log_ctx->move_behavior),
+ alloc);
+ }
+
if (log_ctx->revprops)
{
int i;
@@ -507,6 +516,7 @@ svn_ra_serf__get_log(svn_ra_session_t *r
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton,
@@ -532,6 +542,7 @@ svn_ra_serf__get_log(svn_ra_session_t *r
log_ctx->changed_paths = discover_changed_paths;
log_ctx->strict_node_history = strict_node_history;
log_ctx->include_merged_revisions = include_merged_revisions;
+ log_ctx->move_behavior = move_behavior;
log_ctx->revprops = revprops;
log_ctx->nest_level = 0;
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/ra_serf.h?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/ra_serf.h Thu Sep 26 13:47:21 2013
@@ -429,6 +429,10 @@ typedef struct svn_ra_serf__handler_t {
enabled. */
svn_boolean_t custom_accept_encoding;
+ /* If TRUE then default DAV: capabilities request headers is not configured
+ for request. */
+ svn_boolean_t no_dav_headers;
+
/* Has the request/response been completed? */
svn_boolean_t done;
@@ -1494,6 +1498,7 @@ svn_ra_serf__get_log(svn_ra_session_t *s
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton,
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/update.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/update.c Thu Sep 26 13:47:21 2013
@@ -1574,6 +1574,7 @@ fetch_file(report_context_t *ctx, report
handler->session = ctx->sess;
handler->custom_accept_encoding = TRUE;
+ handler->no_dav_headers = TRUE;
handler->header_delegate = headers_fetch;
handler->header_delegate_baton = fetch_ctx;
@@ -3705,6 +3706,7 @@ svn_ra_serf__get_file(svn_ra_session_t *
handler->session = session;
handler->custom_accept_encoding = TRUE;
+ handler->no_dav_headers = TRUE;
handler->header_delegate = headers_fetch;
handler->header_delegate_baton = stream_ctx;
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/util.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_serf/util.c Thu Sep 26 13:47:21 2013
@@ -705,6 +705,9 @@ apr_status_t svn_ra_serf__handle_client_
*
* If CONTENT_TYPE is not-NULL, it will be sent as the Content-Type header.
*
+ * If DAV_HEADERS is non-zero, it will add standard DAV capabilites headers
+ * to request.
+ *
* REQUEST_POOL should live for the duration of the request. Serf will
* construct this and provide it to the request_setup callback, so we
* should just use that one.
@@ -717,6 +720,7 @@ setup_serf_req(serf_request_t *request,
const char *method, const char *url,
serf_bucket_t *body_bkt, const char *content_type,
const char *accept_encoding,
+ svn_boolean_t dav_headers,
apr_pool_t *request_pool,
apr_pool_t *scratch_pool)
{
@@ -783,12 +787,15 @@ setup_serf_req(serf_request_t *request,
serf_bucket_headers_setn(*hdrs_bkt, "Accept-Encoding", accept_encoding);
}
- /* These headers need to be sent with every request; see issue #3255
- ("mod_dav_svn does not pass client capabilities to start-commit
- hooks") for why. */
- serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_DEPTH);
- serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_MERGEINFO);
- serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_LOG_REVPROPS);
+ /* These headers need to be sent with every request except GET; see
+ issue #3255 ("mod_dav_svn does not pass client capabilities to
+ start-commit hooks") for why. */
+ if (dav_headers)
+ {
+ serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_DEPTH);
+ serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_MERGEINFO);
+ serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_LOG_REVPROPS);
+ }
return SVN_NO_ERROR;
}
@@ -2241,7 +2248,8 @@ setup_request(serf_request_t *request,
SVN_ERR(setup_serf_req(request, req_bkt, &headers_bkt,
handler->session, handler->method, handler->path,
body_bkt, handler->body_type, accept_encoding,
- request_pool, scratch_pool));
+ !handler->no_dav_headers, request_pool,
+ scratch_pool));
if (handler->header_delegate)
{
@@ -2251,7 +2259,7 @@ setup_request(serf_request_t *request,
request_pool));
}
- return APR_SUCCESS;
+ return SVN_NO_ERROR;
}
/* Implements the serf_request_setup_t interface (which sets up both a
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/client.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/client.c Thu Sep 26 13:47:21 2013
@@ -1487,6 +1487,7 @@ perform_ra_svn_log(svn_error_t **outer_e
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton,
@@ -1536,11 +1537,13 @@ perform_ra_svn_log(svn_error_t **outer_e
else
want_custom_revprops = TRUE;
}
- SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!))"));
+ SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!)n)",
+ (apr_uint64_t) move_behavior));
}
else
{
- SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!w())", "all-revprops"));
+ SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!w()n)", "all-revprops",
+ (apr_uint64_t) move_behavior));
want_author = TRUE;
want_date = TRUE;
@@ -1712,6 +1715,7 @@ ra_svn_log(svn_ra_session_t *session,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton, apr_pool_t *pool)
@@ -1726,7 +1730,7 @@ ra_svn_log(svn_ra_session_t *session,
discover_changed_paths,
strict_node_history,
include_merged_revisions,
- revprops,
+ move_behavior, revprops,
receiver, receiver_baton,
pool));
return svn_error_trace(
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/deprecated.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/protocol
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/protocol?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_ra_svn/protocol Thu Sep 26 13:47:21 2013
@@ -382,11 +382,13 @@ second place for auth-request point as n
[ end-rev:number ] changed-paths:bool strict-node:bool
? limit:number
? include-merged-revisions:bool
- all-revprops | revprops ( revprop:string ... ) )
+ all-revprops | revprops ( revprop:string ... )
+ ? move-behavior:number )
Before sending response, server sends log entries, ending with "done".
If a client does not want to specify a limit, it should send 0 as the
limit parameter. rev-props excludes author, date, and log; they are
sent separately for backwards-compatibility.
+ Move-behavior is encoded like enum svn_move_behavior_t.
log-entry: ( ( change:changed-path-entry ... ) rev:number
[ author:string ] [ date:string ] [ message:string ]
? has-children:bool invalid-revnum:bool
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/commit.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/commit.c Thu Sep 26 13:47:21 2013
@@ -1198,20 +1198,6 @@ move_cb(void *baton,
}
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- struct ev2_baton *eb = baton;
-
- SVN_ERR(svn_editor_rotate(eb->inner, relpaths, revisions));
- return SVN_NO_ERROR;
-}
-
-
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
@@ -1333,7 +1319,6 @@ svn_repos__get_commit_ev2(svn_editor_t *
delete_cb,
copy_cb,
move_cb,
- rotate_cb,
complete_cb,
abort_cb
};
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/deprecated.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/deprecated.c Thu Sep 26 13:47:21 2013
@@ -472,6 +472,30 @@ svn_repos_fs_get_locks(apr_hash_t **lock
/*** From logs.c ***/
svn_error_t *
+svn_repos_get_logs4(svn_repos_t *repos,
+ const apr_array_header_t *paths,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ int limit,
+ svn_boolean_t discover_changed_paths,
+ svn_boolean_t strict_node_history,
+ svn_boolean_t include_merged_revisions,
+ const apr_array_header_t *revprops,
+ svn_repos_authz_func_t authz_read_func,
+ void *authz_read_baton,
+ svn_log_entry_receiver_t receiver,
+ void *receiver_baton,
+ apr_pool_t *pool)
+{
+ return svn_repos_get_logs5(repos, paths, start, end, limit,
+ discover_changed_paths, strict_node_history,
+ include_merged_revisions,
+ svn_move_behavior_no_moves, revprops,
+ authz_read_func, authz_read_baton,
+ receiver, receiver_baton, pool);
+}
+
+svn_error_t *
svn_repos_get_logs3(svn_repos_t *repos,
const apr_array_header_t *paths,
svn_revnum_t start,
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c Thu Sep 26 13:47:21 2013
@@ -38,6 +38,7 @@
#include "private/svn_mergeinfo_private.h"
#include "private/svn_fs_private.h"
+#include "private/svn_cache.h"
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
@@ -130,6 +131,13 @@ struct edit_baton
/* reusable buffer for writing file contents */
char buffer[SVN__STREAM_CHUNK_SIZE];
apr_size_t bufsize;
+
+ /* map nodeID -> node kind. May be NULL.
+ The key is the string representation of the node ID given in
+ directory entries. If we find an entry in this cache, the
+ respective node has already been verified as readable and being
+ of the type stored as value in the cache. */
+ svn_cache__t *verified_dirents_cache;
};
struct dir_baton
@@ -960,6 +968,7 @@ get_dump_editor(const svn_delta_editor_t
svn_revnum_t oldest_dumped_rev,
svn_boolean_t use_deltas,
svn_boolean_t verify,
+ svn_cache__t *verified_dirents_cache,
apr_pool_t *pool)
{
/* Allocate an edit baton to be stored in every directory baton.
@@ -984,6 +993,7 @@ get_dump_editor(const svn_delta_editor_t
eb->verify = verify;
eb->found_old_reference = found_old_reference;
eb->found_old_mergeinfo = found_old_mergeinfo;
+ eb->verified_dirents_cache = verified_dirents_cache;
/* Set up the editor. */
dump_editor->open_root = open_root;
@@ -1180,7 +1190,8 @@ svn_repos_dump_fs3(svn_repos_t *repos,
"", stream, &found_old_reference,
&found_old_mergeinfo, NULL,
notify_func, notify_baton,
- start_rev, use_deltas_for_rev, FALSE, subpool));
+ start_rev, use_deltas_for_rev, FALSE,
+ NULL, subpool));
/* Drive the editor in one way or another. */
SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
@@ -1292,9 +1303,42 @@ verify_directory_entry(void *baton, cons
{
struct dir_baton *db = baton;
svn_fs_dirent_t *dirent = (svn_fs_dirent_t *)val;
- char *path = svn_relpath_join(db->path, (const char *)key, pool);
+ char *path;
apr_hash_t *dirents;
svn_filesize_t len;
+ svn_string_t *unparsed_id;
+
+ /* most directory entries will be unchanged from previous revs.
+ We should find those in the cache and they must match the
+ type defined in the DIRENT. */
+ if (db->edit_baton->verified_dirents_cache)
+ {
+ svn_node_kind_t kind;
+ svn_boolean_t found;
+ unparsed_id = svn_fs_unparse_id(dirent->id, pool);
+
+ SVN_ERR(svn_cache__get((void **)&kind, &found,
+ db->edit_baton->verified_dirents_cache,
+ unparsed_id->data, pool));
+
+ if (found)
+ {
+ if (kind == dirent->kind)
+ return SVN_NO_ERROR;
+ else
+ {
+ path = svn_relpath_join(db->path, (const char *)key, pool);
+
+ return
+ svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Unexpected node kind %d for '%s'. "
+ "Expected kind was %d."),
+ dirent->kind, path, kind);
+ }
+ }
+ }
+
+ path = svn_relpath_join(db->path, (const char *)key, pool);
/* since we can't access the directory entries directly by their ID,
we need to navigate from the FS_ROOT to them (relatively expensive
@@ -1316,6 +1360,11 @@ verify_directory_entry(void *baton, cons
dirent->kind, path);
}
+ /* remember ID, kind pair */
+ if (db->edit_baton->verified_dirents_cache)
+ SVN_ERR(svn_cache__set(db->edit_baton->verified_dirents_cache,
+ unparsed_id->data, &dirent->kind, pool));
+
return SVN_NO_ERROR;
}
@@ -1359,6 +1408,7 @@ verify_one_revision(svn_fs_t *fs,
svn_revnum_t start_rev,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_cache__t *verified_dirents_cache,
apr_pool_t *scratch_pool)
{
const svn_delta_editor_t *dump_editor;
@@ -1377,6 +1427,7 @@ verify_one_revision(svn_fs_t *fs,
notify_func, notify_baton,
start_rev,
FALSE, TRUE, /* use_deltas, verify */
+ verified_dirents_cache,
scratch_pool));
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
dump_editor, dump_edit_baton,
@@ -1424,6 +1475,30 @@ verify_fs2_notify_func(svn_revnum_t revi
notify_baton->notify, pool);
}
+/* cache entry (de-)serialization support for svn_node_kind_t. */
+static svn_error_t *
+serialize_node_kind(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ *data_len = sizeof(svn_node_kind_t);
+ *data = in;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+deserialize_node_kind(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ *(svn_node_kind_t *)out = *(svn_node_kind_t *)data;
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_repos_verify_fs3(svn_repos_t *repos,
svn_revnum_t start_rev,
@@ -1444,6 +1519,7 @@ svn_repos_verify_fs3(svn_repos_t *repos,
struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
svn_error_t *err;
svn_boolean_t found_corruption = FALSE;
+ svn_cache__t *verified_dirents_cache = NULL;
/* Determine the current youngest revision of the filesystem. */
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1505,13 +1581,26 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_error_clear(err);
}
+ if (svn_cache__get_global_membuffer_cache())
+ SVN_ERR(svn_cache__create_membuffer_cache
+ (&verified_dirents_cache,
+ svn_cache__get_global_membuffer_cache(),
+ serialize_node_kind,
+ deserialize_node_kind,
+ APR_HASH_KEY_STRING,
+ svn_uuid_generate(pool),
+ SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ FALSE,
+ pool));
+
for (rev = start_rev; rev <= end_rev; rev++)
{
svn_pool_clear(iterpool);
/* Wrapper function to catch the possible errors. */
- err = verify_one_revision(fs, rev, notify_func, notify_baton, start_rev,
- cancel_func, cancel_baton, iterpool);
+ err = verify_one_revision(fs, rev, notify_func, notify_baton,
+ start_rev, cancel_func, cancel_baton,
+ verified_dirents_cache, iterpool);
if (err)
{
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/log.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/log.c Thu Sep 26 13:47:21 2013
@@ -69,7 +69,8 @@ svn_repos_check_revision_access(svn_repo
/* Fetch the changes associated with REVISION. */
SVN_ERR(svn_fs_revision_root(&rev_root, fs, revision, pool));
- SVN_ERR(svn_fs_paths_changed2(&changes, rev_root, pool));
+ SVN_ERR(svn_fs_paths_changed3(&changes, rev_root,
+ svn_move_behavior_explicit_moves, pool));
/* No changed paths? We're done. */
if (apr_hash_count(changes) == 0)
@@ -105,6 +106,8 @@ svn_repos_check_revision_access(svn_repo
{
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
{
const char *copyfrom_path;
svn_revnum_t copyfrom_rev;
@@ -163,7 +166,8 @@ svn_repos_check_revision_access(svn_repo
*
* To prevent changes from being processed over and over again, the
* changed paths for ROOT may be passed in PREFETCHED_CHANGES. If the
- * latter is NULL, we will request the list inside this function.
+ * latter is NULL, we will request the list inside this function using
+ * the specified MOVE_BEHAVIOR.
*
* If optional AUTHZ_READ_FUNC is non-NULL, then use it (with
* AUTHZ_READ_BATON and FS) to check whether each changed-path (and
@@ -184,6 +188,7 @@ detect_changed(apr_hash_t **changed,
svn_fs_root_t *root,
svn_fs_t *fs,
apr_hash_t *prefetched_changes,
+ svn_move_behavior_t move_behavior,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
apr_pool_t *pool)
@@ -196,7 +201,7 @@ detect_changed(apr_hash_t **changed,
*changed = svn_hash__make(pool);
if (changes == NULL)
- SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
+ SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
if (apr_hash_count(changes) == 0)
/* No paths changed in this revision? Uh, sure, I guess the
@@ -255,6 +260,14 @@ detect_changed(apr_hash_t **changed,
action = 'D';
break;
+ case svn_fs_path_change_move:
+ action = 'V';
+ break;
+
+ case svn_fs_path_change_movereplace:
+ action = 'E';
+ break;
+
case svn_fs_path_change_modify:
default:
action = 'M';
@@ -306,7 +319,8 @@ detect_changed(apr_hash_t **changed,
}
- if ((action == 'A') || (action == 'R'))
+ if ( (action == 'A') || (action == 'R')
+ || (action == 'V') || (action == 'E'))
{
const char *copyfrom_path = change->copyfrom_path;
svn_revnum_t copyfrom_rev = change->copyfrom_rev;
@@ -563,7 +577,9 @@ next_history_rev(const apr_array_header_
catalogs describing how mergeinfo values on paths (which are the
keys of those catalogs) were changed in REV. If *PREFETCHED_CAHNGES
already contains the changed paths for REV, use that. Otherwise,
- request that data and return it in *PREFETCHED_CHANGES. */
+ request that data and return it in *PREFETCHED_CHANGES.
+ MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+ layer which changes to report as moves instead of additions. */
/* ### TODO: This would make a *great*, useful public function,
### svn_repos_fs_mergeinfo_changed()! -- cmpilato */
static svn_error_t *
@@ -572,6 +588,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
apr_hash_t **prefetched_changes,
svn_fs_t *fs,
svn_revnum_t rev,
+ svn_move_behavior_t move_behavior,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -592,7 +609,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
narrow down our search. */
SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
if (*prefetched_changes == NULL)
- SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
+ SVN_ERR(svn_fs_paths_changed3(prefetched_changes, root, move_behavior,
+ scratch_pool));
/* No changed paths? We're done. */
if (apr_hash_count(*prefetched_changes) == 0)
@@ -638,6 +656,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
was. If not, there's no previous location to examine. */
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
{
const char *copyfrom_path;
svn_revnum_t copyfrom_rev;
@@ -782,7 +802,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
*ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
If *PREFETCHED_CAHNGES already contains the changed paths for
REV, use that. Otherwise, request that data and return it in
- *PREFETCHED_CHANGES.
+ *PREFETCHED_CHANGES. MOVE_BEHAVIOR tells the FS layer which
+ changes to report as moves instead of additions.
Use POOL for all allocations. */
static svn_error_t *
get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
@@ -791,6 +812,7 @@ get_combined_mergeinfo_changes(svn_merge
svn_fs_t *fs,
const apr_array_header_t *paths,
svn_revnum_t rev,
+ svn_move_behavior_t move_behavior,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -820,7 +842,8 @@ get_combined_mergeinfo_changes(svn_merge
err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
&added_mergeinfo_catalog,
prefetched_changes,
- fs, rev, scratch_pool, scratch_pool);
+ fs, rev, move_behavior,
+ scratch_pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
@@ -1025,6 +1048,7 @@ fill_log_entry(svn_log_entry_t *log_entr
svn_fs_t *fs,
apr_hash_t *prefetched_changes,
svn_boolean_t discover_changed_paths,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
@@ -1043,7 +1067,7 @@ fill_log_entry(svn_log_entry_t *log_entr
SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool));
patherr = detect_changed(&changed_paths,
- newroot, fs, prefetched_changes,
+ newroot, fs, prefetched_changes, move_behavior,
authz_read_func, authz_read_baton,
pool);
@@ -1160,9 +1184,9 @@ fill_log_entry(svn_log_entry_t *log_entr
only the revision properties named by the (const char *) array elements
(i.e. retrieve none if the array is empty).
- LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, and
- NESTED_MERGES are as per the arguments of the same name to DO_LOGS. If
- HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
+ LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, MOVE_BEHAVIOR,
+ and NESTED_MERGES are as per the arguments of the same name to DO_LOGS.
+ If HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
already represented in LOG_TARGET_HISTORY_AS_MERGEINFO, then don't send
the log message for REV. If SUBTRACTIVE_MERGE is true, then REV was
reverse merged.
@@ -1180,6 +1204,7 @@ send_log(svn_revnum_t rev,
svn_boolean_t discover_changed_paths,
svn_boolean_t subtractive_merge,
svn_boolean_t handling_merged_revision,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t has_children,
svn_log_entry_receiver_t receiver,
@@ -1195,8 +1220,8 @@ send_log(svn_revnum_t rev,
log_entry = svn_log_entry_create(pool);
SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes,
discover_changed_paths || handling_merged_revision,
- revprops, authz_read_func, authz_read_baton,
- pool));
+ move_behavior, revprops,
+ authz_read_func, authz_read_baton, pool));
log_entry->has_children = has_children;
log_entry->subtractive_merge = subtractive_merge;
@@ -1663,6 +1688,7 @@ do_logs(svn_fs_t *fs,
svn_boolean_t handling_merged_revisions,
svn_boolean_t subtractive_merge,
svn_boolean_t ignore_missing_locations,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t descending_order,
svn_log_entry_receiver_t receiver,
@@ -1712,6 +1738,7 @@ handle_merged_revisions(svn_revnum_t rev
svn_mergeinfo_t deleted_mergeinfo,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton,
@@ -1754,7 +1781,7 @@ handle_merged_revisions(svn_revnum_t rev
pl_range->range.start, pl_range->range.end, 0,
discover_changed_paths, strict_node_history,
TRUE, pl_range->reverse_merge, TRUE, TRUE,
- revprops, TRUE, receiver, receiver_baton,
+ move_behavior, revprops, TRUE, receiver, receiver_baton,
authz_read_func, authz_read_baton, iterpool));
}
svn_pool_destroy(iterpool);
@@ -1888,6 +1915,9 @@ store_search(svn_mergeinfo_t processed,
If IGNORE_MISSING_LOCATIONS is set, don't treat requests for bogus
repository locations as fatal -- just ignore them.
+ MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+ layer which changes to report as moves instead of additions.
+
If LOG_TARGET_HISTORY_AS_MERGEINFO is not NULL then it contains mergeinfo
representing the history of PATHS between HIST_START and HIST_END.
@@ -1925,6 +1955,7 @@ do_logs(svn_fs_t *fs,
svn_boolean_t subtractive_merge,
svn_boolean_t handling_merged_revisions,
svn_boolean_t ignore_missing_locations,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t descending_order,
svn_log_entry_receiver_t receiver,
@@ -2019,8 +2050,8 @@ do_logs(svn_fs_t *fs,
&deleted_mergeinfo,
&changes,
fs, cur_paths,
- current, iterpool,
- iterpool));
+ current, move_behavior,
+ iterpool, iterpool));
has_children = (apr_hash_count(added_mergeinfo) > 0
|| apr_hash_count(deleted_mergeinfo) > 0);
}
@@ -2034,7 +2065,7 @@ do_logs(svn_fs_t *fs,
log_target_history_as_mergeinfo, nested_merges,
discover_changed_paths,
subtractive_merge, handling_merged_revisions,
- revprops, has_children,
+ move_behavior, revprops, has_children,
receiver, receiver_baton,
authz_read_func, authz_read_baton, iterpool));
@@ -2057,6 +2088,7 @@ do_logs(svn_fs_t *fs,
added_mergeinfo, deleted_mergeinfo,
discover_changed_paths,
strict_node_history,
+ move_behavior,
revprops,
receiver, receiver_baton,
authz_read_func,
@@ -2138,7 +2170,8 @@ do_logs(svn_fs_t *fs,
SVN_ERR(send_log(current, fs, NULL,
log_target_history_as_mergeinfo, nested_merges,
discover_changed_paths, subtractive_merge,
- handling_merged_revisions, revprops, has_children,
+ handling_merged_revisions, move_behavior,
+ revprops, has_children,
receiver, receiver_baton, authz_read_func,
authz_read_baton, iterpool));
if (has_children)
@@ -2156,7 +2189,8 @@ do_logs(svn_fs_t *fs,
added_mergeinfo,
deleted_mergeinfo,
discover_changed_paths,
- strict_node_history, revprops,
+ strict_node_history,
+ move_behavior, revprops,
receiver, receiver_baton,
authz_read_func,
authz_read_baton,
@@ -2258,7 +2292,7 @@ get_paths_history_as_mergeinfo(svn_merge
}
svn_error_t *
-svn_repos_get_logs4(svn_repos_t *repos,
+svn_repos_get_logs5(svn_repos_t *repos,
const apr_array_header_t *paths,
svn_revnum_t start,
svn_revnum_t end,
@@ -2266,6 +2300,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
@@ -2374,7 +2409,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
rev = start + i;
SVN_ERR(send_log(rev, fs, NULL, NULL, NULL,
discover_changed_paths, FALSE,
- FALSE, revprops, FALSE, receiver,
+ FALSE, move_behavior, revprops, FALSE, receiver,
receiver_baton, authz_read_func,
authz_read_baton, iterpool));
}
@@ -2402,7 +2437,8 @@ svn_repos_get_logs4(svn_repos_t *repos,
return do_logs(repos->fs, paths, paths_history_mergeinfo, NULL, NULL, start, end,
limit, discover_changed_paths, strict_node_history,
- include_merged_revisions, FALSE, FALSE, FALSE, revprops,
+ include_merged_revisions, FALSE, FALSE, FALSE,
+ move_behavior, revprops,
descending_order, receiver, receiver_baton,
authz_read_func, authz_read_baton, pool);
}
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/reporter.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/reporter.c Thu Sep 26 13:47:21 2013
@@ -499,7 +499,7 @@ get_revision_info(report_baton_t *b,
info->author = author ? svn_string_dup(author, b->pool) : NULL;
/* Cache it */
- apr_hash_set(b->revision_infos, &info->rev, sizeof(rev), info);
+ apr_hash_set(b->revision_infos, &info->rev, sizeof(info->rev), info);
}
*revision_info = info;
@@ -1143,6 +1143,8 @@ delta_dirs(report_baton_t *b, svn_revnum
apr_hash_t *s_entries = NULL, *t_entries;
apr_hash_index_t *hi;
apr_pool_t *subpool;
+ apr_array_header_t *t_ordered_entries = NULL;
+ int i;
/* Compare the property lists. If we're starting empty, pass a NULL
source path so that we add all the properties.
@@ -1275,9 +1277,12 @@ delta_dirs(report_baton_t *b, svn_revnum
}
/* Loop over the dirents in the target. */
- for (hi = apr_hash_first(pool, t_entries); hi; hi = apr_hash_next(hi))
+ SVN_ERR(svn_fs_dir_optimal_order(&t_ordered_entries, b->t_root,
+ t_entries, pool));
+ for (i = 0; i < t_ordered_entries->nelts; ++i)
{
- const svn_fs_dirent_t *t_entry = svn__apr_hash_index_val(hi);
+ const svn_fs_dirent_t *t_entry
+ = APR_ARRAY_IDX(t_ordered_entries, i, svn_fs_dirent_t *);
const svn_fs_dirent_t *s_entry;
const char *s_fullpath, *t_fullpath, *e_fullpath;
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache-membuffer.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache-membuffer.c Thu Sep 26 13:47:21 2013
@@ -51,7 +51,8 @@
* 2. A directory of cache entries. This is organized similar to CPU
* data caches: for every possible key, there is exactly one group
* of entries that may contain the header info for an item with
- * that given key. The result is a GROUP_SIZE-way associative cache.
+ * that given key. The result is a GROUP_SIZE+-way associative cache
+ * whose associativity can be dynamically increased.
*
* Only the start address of these two data parts are given as a native
* pointer. All other references are expressed as offsets to these pointers.
@@ -97,6 +98,10 @@
* about 50% of the content survives every 50% of the cache being re-written
* with new entries. For details on the fine-tuning involved, see the
* comments in ensure_data_insertable_l2().
+ *
+ * Due to the randomized mapping of keys to entry groups, some groups may
+ * overflow. In that case, there are spare groups that can be chained to
+ * 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
@@ -111,13 +116,6 @@
* on their hash key.
*/
-/* A 16-way associative cache seems to be a good compromise between
- * performance (worst-case lookups) and efficiency-loss due to collisions.
- *
- * This value may be changed to any positive integer.
- */
-#define GROUP_SIZE 16
-
/* For more efficient copy operations, let's align all data items properly.
* Must be a power of 2.
*/
@@ -298,17 +296,18 @@ static svn_error_t* assert_equal_tags(co
#define DEBUG_CACHE_MEMBUFFER_TAG tag,
-#define DEBUG_CACHE_MEMBUFFER_INIT_TAG \
- entry_tag_t _tag; \
- entry_tag_t *tag = &_tag; \
- SVN_ERR(store_key_part(tag, \
- cache->prefix, \
- cache->prefix_tail, \
- key, \
- cache->key_len == APR_HASH_KEY_STRING \
- ? strlen((const char *) key) \
- : cache->key_len, \
- cache->pool));
+#define DEBUG_CACHE_MEMBUFFER_INIT_TAG \
+ entry_tag_t _tag; \
+ entry_tag_t *tag = &_tag; \
+ if (key) \
+ SVN_ERR(store_key_part(tag, \
+ cache->prefix, \
+ cache->prefix_tail, \
+ key, \
+ cache->key_len == APR_HASH_KEY_STRING \
+ ? strlen((const char *) key) \
+ : cache->key_len, \
+ cache->pool));
#else
@@ -336,10 +335,11 @@ typedef struct entry_t
*/
apr_uint64_t offset;
- /* Size of the serialized item data. May be 0.
+ /* Size of the serialized item data. May be 0. The MAX_ITEM_SIZE macro
+ * above ensures that there will be no overflows.
* Only valid for used entries.
*/
- apr_size_t size;
+ apr_uint32_t size;
/* Number of (read) hits for this entry. Will be reset upon write.
* Only valid for used entries.
@@ -372,15 +372,60 @@ typedef struct entry_t
#endif
} entry_t;
-/* We group dictionary entries to make this GROUP-SIZE-way associative.
+/* Group header struct.
*/
-typedef struct entry_group_t
+typedef struct group_header_t
{
/* number of entries used [0 .. USED-1] */
apr_uint32_t used;
+ /* next group in the chain or NO_INDEX for the last.
+ * For recycleable unused spare groups, this points to the next
+ * unused spare group */
+ apr_uint32_t next;
+
+ /* previously group in the chain or NO_INDEX for the first */
+ apr_uint32_t previous;
+
+ /* 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
+ * not cross memory page boundaries. Since we already access the cache
+ * randomly, having two page table lookups instead of one is bad.
+ */
+#define GROUP_BLOCK_SIZE 512
+
+/* A ~10-way associative cache seems to be a good compromise between
+ * performance (worst-case lookups) and efficiency-loss due to collisions.
+ *
+ * This value may be changed to any positive integer.
+ */
+#define GROUP_SIZE \
+ ((GROUP_BLOCK_SIZE - sizeof(group_header_t)) / sizeof(entry_t))
+
+/* Maximum number of groups in a chain, i.e. a cache index group can hold
+ * up to GROUP_SIZE * MAX_GROUP_CHAIN_LENGTH entries.
+ */
+#define MAX_GROUP_CHAIN_LENGTH 8
+
+/* We group dictionary entries to make this GROUP-SIZE-way associative.
+ */
+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];
+
/* the actual entries */
entry_t entries[GROUP_SIZE];
+
} entry_group_t;
/* Per-cache level header structure. Instances of this are members of
@@ -432,7 +477,8 @@ struct svn_membuffer_t
and that all segments must / will report the same values here. */
apr_uint32_t segment_count;
- /* The dictionary, GROUP_SIZE * group_count entries long. Never NULL.
+ /* The dictionary, GROUP_SIZE * (group_count + spare_group_count)
+ * entries long. Never NULL.
*/
entry_group_t *directory;
@@ -445,6 +491,20 @@ struct svn_membuffer_t
*/
apr_uint32_t group_count;
+ /* Total number of spare groups.
+ */
+ apr_uint32_t spare_group_count;
+
+ /* First recycleable spare group.
+ */
+ apr_uint32_t first_spare_group;
+
+ /* Maximum number of spare groups ever used. I.e. group index
+ * group_count + max_spare_used is the first unused spare group
+ * if first_spare_group is NO_INDEX.
+ */
+ apr_uint32_t max_spare_used;
+
/* Pointer to the data buffer, data_size bytes long. Never NULL.
*/
unsigned char *data;
@@ -645,6 +705,132 @@ do {
SVN_ERR(unlock_cache(cache, (expr))); \
} while (0)
+/* Returns 0 if the entry group identified by GROUP_INDEX in CACHE has not
+ * been initialized, yet. In that case, this group can not data. Otherwise,
+ * a non-zero value is returned.
+ */
+static APR_INLINE unsigned char
+is_group_initialized(svn_membuffer_t *cache, apr_uint32_t group_index)
+{
+ unsigned char flags
+ = cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)];
+ unsigned char bit_mask
+ = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
+
+ return flags & bit_mask;
+}
+
+/* Initializes the section of the directory in CACHE that contains
+ * the entry group identified by GROUP_INDEX. */
+static void
+initialize_group(svn_membuffer_t *cache, apr_uint32_t group_index)
+{
+ unsigned char bit_mask;
+ apr_uint32_t i;
+
+ /* range of groups to initialize due to GROUP_INIT_GRANULARITY */
+ apr_uint32_t first_index =
+ (group_index / GROUP_INIT_GRANULARITY) * GROUP_INIT_GRANULARITY;
+ apr_uint32_t last_index = first_index + GROUP_INIT_GRANULARITY;
+ if (last_index > cache->group_count)
+ last_index = cache->group_count;
+
+ for (i = first_index; i < last_index; ++i)
+ {
+ group_header_t *header = &cache->directory[i].header;
+ header->used = 0;
+ header->chain_length = 1;
+ header->next = NO_INDEX;
+ header->previous = NO_INDEX;
+ }
+
+ /* set the "initialized" bit for these groups */
+ bit_mask
+ = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
+ cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)]
+ |= bit_mask;
+}
+
+/* Return the next available spare group from CACHE and mark it as used.
+ * May return NULL.
+ */
+static entry_group_t *
+allocate_spare_group(svn_membuffer_t *cache)
+{
+ entry_group_t *group = NULL;
+
+ /* is there some ready-to-use group? */
+ if (cache->first_spare_group != NO_INDEX)
+ {
+ group = &cache->directory[cache->first_spare_group];
+ cache->first_spare_group = group->header.next;
+ }
+
+ /* any so far untouched spares available? */
+ else if (cache->max_spare_used < cache->spare_group_count)
+ {
+ apr_uint32_t group_index = cache->group_count + cache->max_spare_used;
+ ++cache->max_spare_used;
+
+ if (!is_group_initialized(cache, group_index))
+ initialize_group(cache, group_index);
+
+ group = &cache->directory[group_index];
+ }
+
+ /* spare groups must be empty */
+ assert(!group || !group->header.used);
+ return group;
+}
+
+/* Mark previously allocated spare group GROUP in CACHE as "unused".
+ */
+static void
+free_spare_group(svn_membuffer_t *cache,
+ entry_group_t *group)
+{
+ assert(group->header.used == 0);
+ assert(group->header.previous != NO_INDEX);
+ assert(group - cache->directory >= cache->group_count);
+
+ /* unchain */
+ cache->directory[group->header.previous].header.next = NO_INDEX;
+ group->header.chain_length = 0;
+ group->header.previous = NO_INDEX;
+
+ /* add to chain of spares */
+ group->header.next = cache->first_spare_group;
+ cache->first_spare_group = group - cache->directory;
+}
+
+/* Follow the group chain from GROUP in CACHE to its end and return the last
+ * group. May return GROUP.
+ */
+static entry_group_t *
+last_group_in_chain(svn_membuffer_t *cache,
+ entry_group_t *group)
+{
+ while (group->header.next != NO_INDEX)
+ group = &cache->directory[group->header.next];
+
+ return group;
+}
+
+/* Return the CHAIN_INDEX-th element in the group chain starting from group
+ * START_GROUP_INDEX in CACHE.
+ */
+static entry_group_t *
+get_group(svn_membuffer_t *cache,
+ apr_uint32_t start_group_index,
+ apr_uint32_t chain_index)
+{
+ entry_group_t *group = &cache->directory[start_group_index];
+ for (; chain_index; --chain_index)
+ group = &cache->directory[group->header.next];
+
+ return group;
+}
+
/* Resolve a dictionary entry reference, i.e. return the entry
* for the given IDX.
*/
@@ -766,13 +952,13 @@ drop_entry(svn_membuffer_t *cache, entry
*/
apr_uint32_t idx = get_index(cache, entry);
apr_uint32_t group_index = idx / GROUP_SIZE;
- entry_group_t *group = &cache->directory[group_index];
- apr_uint32_t last_in_group = group_index * GROUP_SIZE + group->used - 1;
- cache_level_t *level = get_cache_level(cache, entry);
+ entry_group_t *last_group
+ = last_group_in_chain(cache, &cache->directory[group_index]);
+ apr_uint32_t last_in_group
+ = (last_group - cache->directory) * GROUP_SIZE
+ + last_group->header.used - 1;
- /* Only valid to be called for used entries.
- */
- assert(idx <= last_in_group);
+ cache_level_t *level = get_cache_level(cache, entry);
/* update global cache usage counters
*/
@@ -806,16 +992,16 @@ drop_entry(svn_membuffer_t *cache, entry
/* unlink it from the chain of used entries
*/
unchain_entry(cache, level, entry, idx);
-
+
/* Move last entry into hole (if the removed one is not the last used).
* We need to do this since all used entries are at the beginning of
* the group's entries array.
*/
- if (idx < last_in_group)
+ if (idx != last_in_group)
{
/* copy the last used entry to the removed entry's index
*/
- *entry = group->entries[group->used-1];
+ *entry = last_group->entries[last_group->header.used-1];
/* this ENTRY may belong to a different cache level than the entry
* we have just removed */
@@ -839,7 +1025,12 @@ drop_entry(svn_membuffer_t *cache, entry
/* Update the number of used entries.
*/
- group->used--;
+ last_group->header.used--;
+
+ /* Release the last group in the chain if it is a spare group
+ */
+ if (!last_group->header.used && last_group->header.previous != NO_INDEX)
+ free_spare_group(cache, last_group);
}
/* Insert ENTRY into the chain of used dictionary entries. The entry's
@@ -860,7 +1051,7 @@ insert_entry(svn_membuffer_t *cache, ent
* It must also be the first unused entry in the group.
*/
assert(entry->offset == level->current_data);
- assert(idx == group_index * GROUP_SIZE + group->used);
+ assert(idx == group_index * GROUP_SIZE + group->header.used);
level->current_data = ALIGN_VALUE(entry->offset + entry->size);
/* update usage counters
@@ -868,7 +1059,7 @@ insert_entry(svn_membuffer_t *cache, ent
cache->used_entries++;
cache->data_used += entry->size;
entry->hit_count = 0;
- group->used++;
+ group->header.used++;
/* update entry chain
*/
@@ -910,46 +1101,6 @@ let_entry_age(svn_membuffer_t *cache, en
entry->hit_count -= hits_removed;
}
-/* Returns 0 if the entry group identified by GROUP_INDEX in CACHE has not
- * been initialized, yet. In that case, this group can not data. Otherwise,
- * a non-zero value is returned.
- */
-static APR_INLINE unsigned char
-is_group_initialized(svn_membuffer_t *cache, apr_uint32_t group_index)
-{
- unsigned char flags
- = cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)];
- unsigned char bit_mask
- = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
-
- return flags & bit_mask;
-}
-
-/* Initializes the section of the directory in CACHE that contains
- * the entry group identified by GROUP_INDEX. */
-static void
-initialize_group(svn_membuffer_t *cache, apr_uint32_t group_index)
-{
- unsigned char bit_mask;
- apr_uint32_t i;
-
- /* range of groups to initialize due to GROUP_INIT_GRANULARITY */
- apr_uint32_t first_index =
- (group_index / GROUP_INIT_GRANULARITY) * GROUP_INIT_GRANULARITY;
- apr_uint32_t last_index = first_index + GROUP_INIT_GRANULARITY;
- if (last_index > cache->group_count)
- last_index = cache->group_count;
-
- for (i = first_index; i < last_index; ++i)
- cache->directory[i].used = 0;
-
- /* set the "initialized" bit for these groups */
- bit_mask
- = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
- cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)]
- |= bit_mask;
-}
-
/* Given the GROUP_INDEX that shall contain an entry with the hash key
* TO_FIND, find that entry in the specified group.
*
@@ -995,45 +1146,98 @@ find_entry(svn_membuffer_t *cache,
/* try to find the matching entry
*/
- for (i = 0; i < group->used; ++i)
- if ( to_find[0] == group->entries[i].key[0]
- && to_find[1] == group->entries[i].key[1])
- {
- /* found it
- */
- entry = &group->entries[i];
- if (find_empty)
- drop_entry(cache, entry);
- else
- return entry;
- }
+ 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])
+ {
+ /* found it
+ */
+ entry = &group->entries[i];
+ if (!find_empty)
+ return entry;
+
+ /* need to empty that entry */
+ drop_entry(cache, entry);
+ if (group->header.used == GROUP_SIZE)
+ group = last_group_in_chain(cache, group);
+ else if (group->header.chain_length == 0)
+ group = last_group_in_chain(cache,
+ &cache->directory[group_index]);
+
+ break;
+ }
+
+ /* end of chain? */
+ if (group->header.next == NO_INDEX)
+ break;
+
+ /* only full groups may chain */
+ assert(group->header.used == GROUP_SIZE);
+ group = &cache->directory[group->header.next];
+ }
/* None found. Are we looking for a free entry?
*/
if (find_empty)
{
- /* if there is no empty entry, delete the oldest entry
+ /* There is no empty entry in the chain, try chaining a spare group.
*/
- if (group->used == GROUP_SIZE)
+ if ( group->header.used == GROUP_SIZE
+ && group->header.chain_length < MAX_GROUP_CHAIN_LENGTH)
+ {
+ entry_group_t *new_group = allocate_spare_group(cache);
+ if (new_group)
+ {
+ /* chain groups
+ */
+ new_group->header.chain_length = group->header.chain_length + 1;
+ new_group->header.previous = group - cache->directory;
+ new_group->header.next = NO_INDEX;
+ group->header.next = new_group - cache->directory;
+ group = new_group;
+ }
+ }
+
+ /* if GROUP is still filled, we need to remove a random entry */
+ if (group->header.used == GROUP_SIZE)
{
/* every entry gets the same chance of being removed.
- * Otherwise, we free the first entry, fill it and remove it
- * again on the next occasion without considering the other
- * entries in this group. Also, apply priorities strictly.
+ * Otherwise, we free the first entry, fill it and
+ * remove it again on the next occasion without considering
+ * the other entries in this group.
+ *
+ * We hit only one random group instead of processing all
+ * groups in the chain.
*/
- entry = &group->entries[rand() % GROUP_SIZE];
- for (i = 1; i < GROUP_SIZE; ++i)
- if ( (entry->priority > group->entries[i].priority)
- || ( entry->priority == group->entries[i].priority
- && entry->hit_count > group->entries[i].hit_count))
- entry = &group->entries[i];
+ cache_level_t *entry_level;
+ int to_remove = rand() % (GROUP_SIZE * group->header.chain_length);
+ entry_group_t *to_shrink
+ = get_group(cache, group_index, to_remove / GROUP_SIZE);
+
+ entry = &to_shrink->entries[to_remove % GROUP_SIZE];
+ entry_level = get_cache_level(cache, entry);
+ for (i = 0; i < GROUP_SIZE; ++i)
+ {
+ /* keep L1 entries whenever possible */
+
+ cache_level_t *level
+ = get_cache_level(cache, &to_shrink->entries[i]);
+ if ( (level != entry_level && entry_level == &cache->l1)
+ || (entry->hit_count > to_shrink->entries[i].hit_count))
+ {
+ entry_level = level;
+ entry = &to_shrink->entries[i];
+ }
+ }
/* for the entries that don't have been removed,
* reduce their hit counts to put them at a relative
* disadvantage the next time.
*/
for (i = 0; i < GROUP_SIZE; ++i)
- if (entry != &group->entries[i])
+ if (entry != &to_shrink->entries[i])
let_entry_age(cache, entry);
drop_entry(cache, entry);
@@ -1041,7 +1245,7 @@ find_entry(svn_membuffer_t *cache,
/* initialize entry for the new key
*/
- entry = &group->entries[group->used];
+ entry = &group->entries[group->header.used];
entry->key[0] = to_find[0];
entry->key[1] = to_find[1];
}
@@ -1097,6 +1301,7 @@ promote_entry(svn_membuffer_t *cache, en
apr_uint32_t idx = get_index(cache, entry);
apr_size_t size = ALIGN_VALUE(entry->size);
assert(get_cache_level(cache, entry) == &cache->l1);
+ assert(idx == cache->l1.next);
/* copy item from the current location in L1 to the start of L2's
* insertion window */
@@ -1127,8 +1332,7 @@ promote_entry(svn_membuffer_t *cache, en
*/
static svn_boolean_t
ensure_data_insertable_l2(svn_membuffer_t *cache,
- entry_t *to_fit_in,
- apr_uint32_t idx)
+ entry_t *to_fit_in)
{
entry_t *entry;
apr_uint64_t average_hit_value;
@@ -1147,9 +1351,6 @@ ensure_data_insertable_l2(svn_membuffer_
/* accumulated "worth" of items dropped so far */
apr_size_t drop_hits = 0;
- /* verify parameters */
- assert(idx == get_index(cache, to_fit_in));
-
/* This loop will eventually terminate because every cache entry
* would get dropped eventually:
* - hit counts become 0 after the got kept for 32 full scans
@@ -1221,16 +1422,6 @@ ensure_data_insertable_l2(svn_membuffer_
{
keep = TRUE;
}
- else if (cache->l2.next / GROUP_SIZE == idx / GROUP_SIZE)
- {
- /* Special case: we cannot drop entries that are in the same
- * group as TO_FIT_IN because that might the latter to become
- * invalidated it it happens to be the highest used entry in
- * the group. So, we must keep ENTRY unconditionally.
- * (this is a very rare condition)
- */
- keep = TRUE;
- }
else if ( entry->priority < SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY
&& to_fit_in->priority > entry->priority)
{
@@ -1308,8 +1499,6 @@ ensure_data_insertable_l2(svn_membuffer_
static svn_boolean_t
ensure_data_insertable_l1(svn_membuffer_t *cache, apr_size_t size)
{
- entry_t *entry;
-
/* Guarantees that the while loop will terminate. */
if (size > cache->l1.size)
return FALSE;
@@ -1321,9 +1510,11 @@ ensure_data_insertable_l1(svn_membuffer_
{
/* first offset behind the insertion window
*/
+ apr_uint32_t entry_index = cache->l1.next;
+ entry_t *entry = get_entry(cache, entry_index);
apr_uint64_t end = cache->l1.next == NO_INDEX
? cache->l1.start_offset + cache->l1.size
- : get_entry(cache, cache->l1.next)->offset;
+ : entry->offset;
/* leave function as soon as the insertion window is large enough
*/
@@ -1347,12 +1538,16 @@ ensure_data_insertable_l1(svn_membuffer_
/* Remove the entry from the end of insertion window and promote
* it to L2, if it is important enough.
*/
- entry = get_entry(cache, cache->l1.next);
+ svn_boolean_t keep = ensure_data_insertable_l2(cache, entry);
- if (ensure_data_insertable_l2(cache, entry, cache->l1.next))
- promote_entry(cache, entry);
- else
- drop_entry(cache, entry);
+ /* We might have touched the group that contains ENTRY. Recheck. */
+ if (entry_index == cache->l1.next)
+ {
+ if (keep)
+ promote_entry(cache, entry);
+ else
+ drop_entry(cache, entry);
+ }
}
}
@@ -1395,6 +1590,8 @@ svn_cache__membuffer_cache_create(svn_me
apr_uint32_t seg;
apr_uint32_t group_count;
+ apr_uint32_t main_group_count;
+ apr_uint32_t spare_group_count;
apr_uint32_t group_init_size;
apr_uint64_t data_size;
apr_uint64_t max_entry_size;
@@ -1469,8 +1666,8 @@ svn_cache__membuffer_cache_create(svn_me
*/
if (directory_size > total_size - sizeof(entry_group_t))
directory_size = total_size - sizeof(entry_group_t);
- if (directory_size < sizeof(entry_group_t))
- directory_size = sizeof(entry_group_t);
+ if (directory_size < 2 * sizeof(entry_group_t))
+ directory_size = 2 * sizeof(entry_group_t);
/* limit the data size to what we can address.
* Note that this cannot overflow since all values are of size_t.
@@ -1498,6 +1695,11 @@ svn_cache__membuffer_cache_create(svn_me
? (APR_UINT32_MAX / GROUP_SIZE) - 1
: (apr_uint32_t)(directory_size / sizeof(entry_group_t));
+ /* set some of the index directory aside as over-flow (spare) buffers */
+ spare_group_count = MAX(group_count / 4, 1);
+ main_group_count = group_count - spare_group_count;
+ assert(spare_group_count > 0 && main_group_count > 0);
+
group_init_size = 1 + group_count / (8 * GROUP_INIT_GRANULARITY);
for (seg = 0; seg < segment_count; ++seg)
{
@@ -1505,7 +1707,11 @@ svn_cache__membuffer_cache_create(svn_me
*/
c[seg].segment_count = (apr_uint32_t)segment_count;
- c[seg].group_count = group_count;
+ c[seg].group_count = main_group_count;
+ c[seg].spare_group_count = spare_group_count;
+ c[seg].first_spare_group = NO_INDEX;
+ c[seg].max_spare_used = 0;
+
c[seg].directory = apr_pcalloc(pool,
group_count * sizeof(entry_group_t));
@@ -1870,7 +2076,24 @@ membuffer_cache_has_key_internal(svn_mem
entry_key_t to_find,
svn_boolean_t *found)
{
- *found = find_entry(cache, group_index, to_find, FALSE) != NULL;
+ entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
+ if (entry)
+ {
+ /* This is often happen in "block read" where most data is already
+ in L2 and only a few previously evicted items are added to L1
+ again. While items in L1 are well protected for a while, L2
+ items may get evicted soon. Thus, mark all them as "hit" to give
+ them a higher chance for survival. */
+ entry->hit_count++;
+ cache->hit_count++;
+ cache->total_hits++;
+
+ *found = TRUE;
+ }
+ else
+ {
+ *found = FALSE;
+ }
return SVN_NO_ERROR;
}
@@ -1888,6 +2111,8 @@ membuffer_cache_has_key(svn_membuffer_t
/* find the entry group that will hold the key.
*/
apr_uint32_t group_index = get_group_index(&cache, key);
+ cache->total_reads++;
+
WITH_READ_LOCK(cache,
membuffer_cache_has_key_internal(cache,
group_index,
@@ -2573,8 +2798,10 @@ svn_membuffer_get_segment_info(svn_membu
if (include_histogram)
for (i = 0; i < segment->group_count; ++i)
{
+ entry_group_t *chain_end
+ = last_group_in_chain(segment, &segment->directory[i]);
apr_size_t use
- = MIN(segment->directory[i].used,
+ = MIN(chain_end->header.used,
sizeof(info->histogram) / sizeof(info->histogram[0]) - 1);
info->histogram[use]++;
}
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache_config.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cache_config.c Thu Sep 26 13:47:21 2013
@@ -118,7 +118,7 @@ svn_cache__get_global_membuffer_cache(vo
err = svn_cache__membuffer_cache_create(
&new_cache,
(apr_size_t)cache_size,
- (apr_size_t)(cache_size / 10),
+ (apr_size_t)(cache_size / 5),
0,
! svn_cache_config_get()->single_threaded,
FALSE,
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cmdline.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/cmdline.c Thu Sep 26 13:47:21 2013
@@ -357,7 +357,7 @@ svn_cmdline_fputs(const char *string, FI
{
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(apr_get_os_error()))
+ if (SVN__APR_STATUS_IS_EPIPE(apr_get_os_error()))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
else
return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
@@ -380,7 +380,7 @@ svn_cmdline_fflush(FILE *stream)
{
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(apr_get_os_error()))
+ if (SVN__APR_STATUS_IS_EPIPE(apr_get_os_error()))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
else
return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/compress.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/dirent_uri.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/dirent_uri.c Thu Sep 26 13:47:21 2013
@@ -1862,6 +1862,9 @@ svn_uri_is_canonical(const char *uri, ap
#endif /* SVN_USE_DOS_PATHS */
/* Now validate the rest of the URI. */
+ seg = ptr;
+ while (*ptr && (*ptr != '/'))
+ ptr++;
while(1)
{
apr_size_t seglen = ptr - seg;
@@ -1880,9 +1883,8 @@ svn_uri_is_canonical(const char *uri, ap
if (*ptr == '/')
ptr++;
- seg = ptr;
-
+ seg = ptr;
while (*ptr && (*ptr != '/'))
ptr++;
}
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c Thu Sep 26 13:47:21 2013
@@ -3067,7 +3067,7 @@ svn_io_create_custom_diff_cmd(const char
svn_stringbuf_appendcstr(token, token_list[i]);
len = 0;
- while ( (found = strstr(com->data, token->data) &&
+ while ( (found = strstr(com->data, token->data)) &&
(strlen(found) > len) )
{
len = strlen(found);
@@ -3570,7 +3570,7 @@ do_io_file_wrapper_cleanup(apr_file_t *f
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(status))
+ if (SVN__APR_STATUS_IS_EPIPE(status))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
if (name)
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/packed_data.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/prefix_string.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/utf8proc.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/utf8proc/utf8proc.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/utf8proc/utf8proc.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/utf8proc/utf8proc_data.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/old-and-busted.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/old-and-busted.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/old-and-busted.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/old-and-busted.c Thu Sep 26 13:47:21 2013
@@ -811,11 +811,15 @@ atts_to_entry(svn_wc_entry_t **new_entry
### not used by loggy; no need to set MODIFY_FLAGS */
entry->url = extract_string(atts, ENTRIES_ATTR_URL, pool);
+ if (entry->url)
+ entry->url = svn_uri_canonicalize(entry->url, pool);
/* Set up repository root. Make sure it is a prefix of url.
### not used by loggy; no need to set MODIFY_FLAGS */
entry->repos = extract_string(atts, ENTRIES_ATTR_REPOS, pool);
+ if (entry->repos)
+ entry->repos = svn_uri_canonicalize(entry->repos, pool);
if (entry->url && entry->repos
&& !svn_uri__is_ancestor(entry->repos, entry->url))
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/update_editor.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/update_editor.c Thu Sep 26 13:47:21 2013
@@ -3010,18 +3010,55 @@ absent_node(const char *path,
kind = svn_node_unknown;
}
- if (status == svn_wc__db_status_normal
- && kind == svn_node_dir)
+ if (status == svn_wc__db_status_normal)
{
- /* We found an obstructing working copy!
+ svn_boolean_t wcroot;
+ /* We found an obstructing working copy or a file external! */
- We can do two things now:
- 1) notify the user, record a skip, etc.
- 2) Just record the absent node in BASE in the parent
- working copy.
+ SVN_ERR(svn_wc__db_is_wcroot(&wcroot, eb->db, local_abspath,
+ scratch_pool));
- As option 2 happens to be exactly what we do anyway, lets do that.
- */
+ if (wcroot)
+ {
+ /*
+ We have an obstructing working copy; possibly a directory external
+
+ We can do two things now:
+ 1) notify the user, record a skip, etc.
+ 2) Just record the absent node in BASE in the parent
+ working copy.
+
+ As option 2 happens to be exactly what we do anyway, fall through.
+ */
+ }
+ else
+ {
+ /* The server asks us to replace a file external
+ (Existing BASE node; not reported by the working copy crawler or
+ there would have been a delete_entry() call.
+
+ There is no way we can store this state in the working copy as
+ the BASE layer is already filled.
+
+ We could error out, but that is not helping anybody; the user is not
+ even seeing with what the file external would be replaced, so let's
+ report a skip and continue the update.
+ */
+
+ if (eb->notify_func)
+ {
+ svn_wc_notify_t *notify;
+ notify = svn_wc_create_notify(
+ local_abspath,
+ svn_wc_notify_update_skip_obstruction,
+ scratch_pool);
+
+ eb->notify_func(eb->notify_baton, notify, scratch_pool);
+ }
+
+ svn_pool_destroy(scratch_pool);
+ return SVN_NO_ERROR;
+ }
}
else if (status == svn_wc__db_status_not_present
|| status == svn_wc__db_status_server_excluded
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_update_move.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_update_move.c Thu Sep 26 13:47:21 2013
@@ -1297,15 +1297,6 @@ tc_editor_move(void *baton,
}
static svn_error_t *
-tc_editor_rotate(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
-static svn_error_t *
tc_editor_complete(void *baton,
apr_pool_t *scratch_pool)
{
@@ -1331,7 +1322,6 @@ static const svn_editor_cb_many_t editor
tc_editor_delete,
tc_editor_copy,
tc_editor_move,
- tc_editor_rotate,
tc_editor_complete,
tc_editor_abort
};
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/merge.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/merge.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/merge.c Thu Sep 26 13:47:21 2013
@@ -115,6 +115,7 @@ static svn_error_t *
do_resources(const dav_svn_repos *repos,
svn_fs_root_t *root,
svn_revnum_t revision,
+ svn_move_behavior_t move_behavior,
ap_filter_t *output,
apr_bucket_brigade *bb,
apr_pool_t *pool)
@@ -129,7 +130,7 @@ do_resources(const dav_svn_repos *repos,
and deleted things. Also, note that deleted things don't merit
responses of their own -- they are considered modifications to
their parent. */
- SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
+ SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
{
@@ -155,6 +156,8 @@ do_resources(const dav_svn_repos *repos,
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
send_self = TRUE;
send_parent = TRUE;
break;
@@ -360,7 +363,10 @@ dav_svn__merge_response(ap_filter_t *out
### we can pass back the new version URL */
/* and go make me proud, boy! */
- serr = do_resources(repos, root, new_rev, output, bb, pool);
+ serr = do_resources(repos, root, new_rev,
+ /* report changes with no further interpretation */
+ svn_move_behavior_explicit_moves,
+ output, bb, pool);
if (serr != NULL)
{
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/mod_dav_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/mod_dav_svn.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/mod_dav_svn.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/mod_dav_svn.c Thu Sep 26 13:47:21 2013
@@ -217,6 +217,7 @@ create_dir_config(apr_pool_t *p, char *d
conf->bulk_updates = CONF_BULKUPD_ON;
conf->v2_protocol = CONF_FLAG_ON;
conf->hooks_env = NULL;
+ conf->txdelta_cache = CONF_FLAG_ON;
return conf;
}
@@ -1207,7 +1208,7 @@ static const command_rec cmds[] =
ACCESS_CONF|RSRC_CONF,
"speeds up data access to older revisions by caching "
"delta information if sufficient in-memory cache is "
- "available (default is Off)."),
+ "available (default is On)."),
/* per directory/location */
AP_INIT_FLAG("SVNCacheFullTexts", SVNCacheFullTexts_cmd, NULL,
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/reports/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/reports/log.c?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/reports/log.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/mod_dav_svn/reports/log.c Thu Sep 26 13:47:21 2013
@@ -301,6 +301,9 @@ dav_svn__log_report(const dav_resource *
svn_boolean_t discover_changed_paths = FALSE; /* off by default */
svn_boolean_t strict_node_history = FALSE; /* off by default */
svn_boolean_t include_merged_revisions = FALSE; /* off by default */
+ svn_move_behavior_t move_behavior = svn_move_behavior_no_moves;
+ /* no moves by default */
+
apr_array_header_t *revprops = apr_array_make(resource->pool, 3,
sizeof(const char *));
apr_array_header_t *paths
@@ -395,6 +398,24 @@ dav_svn__log_report(const dav_resource *
resource->pool);
APR_ARRAY_PUSH(paths, const char *) = target;
}
+ else if (strcmp(child->name, "move-behavior") == 0)
+ {
+ int move_behavior_param;
+ serr = svn_cstring_atoi(&move_behavior_param,
+ dav_xml_get_cdata(child, resource->pool, 1));
+ if (serr)
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Malformed CDATA in element "
+ "\"move-behavior\"", resource->pool);
+
+ if ( move_behavior_param < 0
+ || move_behavior_param > svn_move_behavior_auto_moves)
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Invalid CDATA in element "
+ "\"move-behavior\"", resource->pool);
+
+ move_behavior = (svn_move_behavior_t) move_behavior_param;
+ }
/* else unknown element; skip it */
}
@@ -424,7 +445,7 @@ dav_svn__log_report(const dav_resource *
flag in our log_receiver_baton structure). */
/* Send zero or more log items. */
- serr = svn_repos_get_logs4(repos->repos,
+ serr = svn_repos_get_logs5(repos->repos,
paths,
start,
end,
@@ -432,6 +453,7 @@ dav_svn__log_report(const dav_resource *
discover_changed_paths,
strict_node_history,
include_merged_revisions,
+ move_behavior,
revprops,
dav_svn__authz_read_func(&arb),
&arb,
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h?rev=1526487&r1=1526486&r2=1526487&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h Thu Sep 26 13:47:21 2013
@@ -225,6 +225,7 @@ typedef struct svn_cl__opt_state_t
(not converted to UTF-8) */
svn_boolean_t parents; /* create intermediate directories */
svn_boolean_t use_merge_history; /* use/display extra merge information */
+ svn_boolean_t auto_moves; /* interpret unique DEL/ADD pairs as moves */
svn_cl__accept_t accept_which; /* how to handle conflicts */
svn_cl__show_revs_t show_revs; /* mergeinfo flavor */
svn_depth_t set_depth; /* new sticky ambient depth value */