Port r21075 from trunk to the 1.4.x-r21075 backport branch.
The only change between this and the original version committed to trunk
is that the portions that were applied to mod_dav_svn/reports/replay.c on
trunk have been applied to mod_dav_svn/replay.c on the branch, with some
minor tweaks to account for different names of some structures.
git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/1.4.x-r21075@861165 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/subversion/include/svn_ra_svn.h b/subversion/include/svn_ra_svn.h
index 8c5890b..e39fd1f 100644
--- a/subversion/include/svn_ra_svn.h
+++ b/subversion/include/svn_ra_svn.h
@@ -346,7 +346,17 @@
/** Receive edit commands over the network and use them to drive @a editor
* with @a edit_baton. On return, @a *aborted will be set if the edit was
- * aborted.
+ * aborted. The drive can be terminated with a finish-replay command only
+ * if @a for_replay is true.
+ */
+svn_error_t *svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const svn_delta_editor_t *editor,
+ void *edit_baton,
+ svn_boolean_t *aborted,
+ svn_boolean_t for_replay);
+
+/** Like svn_ra_svn_drive_editor2, but with @a for_replay always FALSE.
*/
svn_error_t *svn_ra_svn_drive_editor(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
const svn_delta_editor_t *editor,
diff --git a/subversion/libsvn_ra_dav/replay.c b/subversion/libsvn_ra_dav/replay.c
index dde0458..841f784 100644
--- a/subversion/libsvn_ra_dav/replay.c
+++ b/subversion/libsvn_ra_dav/replay.c
@@ -389,7 +389,7 @@
if (rb->dirs->nelts)
svn_pool_destroy(APR_ARRAY_IDX(rb->dirs, 0, dir_item_t).pool);
- rb->err = rb->editor->close_edit(rb->edit_baton, rb->pool);
+ rb->err = SVN_NO_ERROR;
break;
case ELEM_apply_textdelta:
diff --git a/subversion/libsvn_ra_local/ra_plugin.c b/subversion/libsvn_ra_local/ra_plugin.c
index c27d380..6dbd492 100644
--- a/subversion/libsvn_ra_local/ra_plugin.c
+++ b/subversion/libsvn_ra_local/ra_plugin.c
@@ -1266,8 +1266,6 @@
send_deltas, editor, edit_baton, NULL, NULL,
pool));
- SVN_ERR(editor->close_edit(edit_baton, pool));
-
return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_ra_serf/replay.c b/subversion/libsvn_ra_serf/replay.c
index 6a56905..91b1660 100644
--- a/subversion/libsvn_ra_serf/replay.c
+++ b/subversion/libsvn_ra_serf/replay.c
@@ -406,7 +406,6 @@
if (state == REPORT &&
strcmp(name.name, "editor-report") == 0)
{
- SVN_ERR(ctx->editor->close_edit(ctx->editor_baton, parser->state->pool));
svn_ra_serf__xml_pop_state(parser);
}
else if (state == OPEN_DIR && strcmp(name.name, "open-directory") == 0)
diff --git a/subversion/libsvn_ra_svn/client.c b/subversion/libsvn_ra_svn/client.c
index 4dc734a..75f9c46 100644
--- a/subversion/libsvn_ra_svn/client.c
+++ b/subversion/libsvn_ra_svn/client.c
@@ -1964,8 +1964,8 @@
_("Server doesn't support the replay "
"command")));
- SVN_ERR(svn_ra_svn_drive_editor(sess->conn, pool, editor, edit_baton,
- NULL));
+ SVN_ERR(svn_ra_svn_drive_editor2(sess->conn, pool, editor, edit_baton,
+ NULL, TRUE));
SVN_ERR(svn_ra_svn_read_cmd_response(sess->conn, pool, ""));
diff --git a/subversion/libsvn_ra_svn/editor.c b/subversion/libsvn_ra_svn/editor.c
index b6f2443..1b4cf88 100644
--- a/subversion/libsvn_ra_svn/editor.c
+++ b/subversion/libsvn_ra_svn/editor.c
@@ -67,6 +67,7 @@
apr_hash_t *tokens;
svn_boolean_t *aborted;
apr_pool_t *pool;
+ svn_boolean_t for_replay;
} ra_svn_driver_state_t;
typedef struct {
@@ -704,6 +705,19 @@
return svn_ra_svn_write_cmd_response(conn, pool, "");
}
+static svn_error_t *ra_svn_handle_finish_replay(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ apr_array_header_t *params,
+ void *baton)
+{
+ ra_svn_driver_state_t *ds = baton;
+ if (!ds->for_replay)
+ return svn_error_createf
+ (SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
+ _("Command 'finish-replay' invalid outside of replays"));
+ return SVN_NO_ERROR;
+}
+
static const svn_ra_svn_cmd_entry_t ra_svn_edit_commands[] = {
{ "target-rev", ra_svn_handle_target_rev },
{ "open-root", ra_svn_handle_open_root },
@@ -719,23 +733,41 @@
{ "close-file", ra_svn_handle_close_file },
{ "close-edit", ra_svn_handle_close_edit, TRUE },
{ "abort-edit", ra_svn_handle_abort_edit, TRUE },
+ { "finish-replay", ra_svn_handle_finish_replay, TRUE },
{ NULL }
};
-svn_error_t *svn_ra_svn_drive_editor(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
- const svn_delta_editor_t *editor,
- void *edit_baton,
- svn_boolean_t *aborted)
+svn_error_t *svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const svn_delta_editor_t *editor,
+ void *edit_baton,
+ svn_boolean_t *aborted,
+ svn_boolean_t for_replay)
{
ra_svn_driver_state_t state;
if (svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_EDIT_PIPELINE))
- return svn_ra_svn__drive_editorp(conn, pool, editor, edit_baton, aborted);
+ return svn_ra_svn__drive_editorp(conn, pool, editor, edit_baton, aborted,
+ for_replay);
state.editor = editor;
state.edit_baton = edit_baton;
state.tokens = apr_hash_make(pool);
state.aborted = aborted;
state.pool = pool;
+ state.for_replay = for_replay;
return svn_ra_svn_handle_commands(conn, pool, ra_svn_edit_commands, &state);
}
+
+svn_error_t *svn_ra_svn_drive_editor(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+ const svn_delta_editor_t *editor,
+ void *edit_baton,
+ svn_boolean_t *aborted)
+{
+ return svn_ra_svn_drive_editor2(conn,
+ pool,
+ editor,
+ edit_baton,
+ aborted,
+ FALSE);
+}
diff --git a/subversion/libsvn_ra_svn/editorp.c b/subversion/libsvn_ra_svn/editorp.c
index 5b156fe..2648ba0 100644
--- a/subversion/libsvn_ra_svn/editorp.c
+++ b/subversion/libsvn_ra_svn/editorp.c
@@ -71,6 +71,7 @@
apr_pool_t *pool;
apr_pool_t *file_pool;
int file_refs;
+ svn_boolean_t for_replay;
} ra_svn_driver_state_t;
/* Works for both directories and files; however, the pool handling is
@@ -788,6 +789,21 @@
return svn_ra_svn_write_cmd_response(conn, pool, "");
}
+static svn_error_t *ra_svn_handle_finish_replay(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ apr_array_header_t *params,
+ ra_svn_driver_state_t *ds)
+{
+ if (!ds->for_replay)
+ return svn_error_createf
+ (SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
+ _("Command 'finish-replay' invalid outside of replays"));
+ ds->done = TRUE;
+ if (ds->aborted)
+ *ds->aborted = FALSE;
+ return SVN_NO_ERROR;
+}
+
static const struct {
const char *cmd;
svn_error_t *(*handler)(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
@@ -812,6 +828,7 @@
{ "absent-file", ra_svn_handle_absent_file },
{ "close-edit", ra_svn_handle_close_edit },
{ "abort-edit", ra_svn_handle_abort_edit },
+ { "finish-replay", ra_svn_handle_finish_replay },
{ NULL }
};
@@ -837,7 +854,8 @@
apr_pool_t *pool,
const svn_delta_editor_t *editor,
void *edit_baton,
- svn_boolean_t *aborted)
+ svn_boolean_t *aborted,
+ svn_boolean_t for_replay)
{
ra_svn_driver_state_t state;
apr_pool_t *subpool = svn_pool_create(pool);
@@ -854,6 +872,7 @@
state.pool = pool;
state.file_pool = svn_pool_create(pool);
state.file_refs = 0;
+ state.for_replay = for_replay;
while (!state.done)
{
diff --git a/subversion/libsvn_ra_svn/protocol b/subversion/libsvn_ra_svn/protocol
index dc6880c..ce123f9 100644
--- a/subversion/libsvn_ra_svn/protocol
+++ b/subversion/libsvn_ra_svn/protocol
@@ -461,6 +461,10 @@
params: ( )
response: ( )
+ finish-replay
+ params: ( )
+ Only delivered from server to client, at the end of a replay.
+
3.1.3. Report Command Set
To reduce round-trip delays, report commands do not return responses.
diff --git a/subversion/libsvn_ra_svn/ra_svn.h b/subversion/libsvn_ra_svn/ra_svn.h
index 6ff4991..b3a8d8f 100644
--- a/subversion/libsvn_ra_svn/ra_svn.h
+++ b/subversion/libsvn_ra_svn/ra_svn.h
@@ -81,7 +81,8 @@
apr_pool_t *pool,
const svn_delta_editor_t *editor,
void *edit_baton,
- svn_boolean_t *aborted);
+ svn_boolean_t *aborted,
+ svn_boolean_t for_replay);
/* CRAM-MD5 client implementation. */
svn_error_t *svn_ra_svn__cram_client(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
diff --git a/subversion/mod_dav_svn/replay.c b/subversion/mod_dav_svn/replay.c
index a959417..b195e57 100644
--- a/subversion/mod_dav_svn/replay.c
+++ b/subversion/mod_dav_svn/replay.c
@@ -61,6 +61,16 @@
}
static svn_error_t *
+end_report(dav_svn_edit_baton_t *eb)
+{
+ SVN_ERR(dav_svn__send_xml(eb->bb, eb->output,
+ "</S:editor-report>" DEBUG_CR));
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
maybe_close_textdelta(dav_svn_edit_baton_t *eb)
{
if (eb->sending_textdelta)
@@ -355,11 +365,6 @@
static svn_error_t *close_edit(void *edit_baton,
apr_pool_t *pool)
{
- dav_svn_edit_baton_t *eb = edit_baton;
-
- SVN_ERR(dav_svn__send_xml(eb->bb, eb->output,
- "</S:editor-report>" DEBUG_CR));
-
return SVN_NO_ERROR;
}
@@ -503,7 +508,7 @@
"Problem replaying revision",
resource->pool);
- if ((err = editor->close_edit(edit_baton, resource->pool)))
+ if ((err = end_report(edit_baton)))
return dav_svn_convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
"Problem closing editor drive",
resource->pool);
diff --git a/subversion/svnserve/serve.c b/subversion/svnserve/serve.c
index 0647b13..c99a9cb 100644
--- a/subversion/svnserve/serve.c
+++ b/subversion/svnserve/serve.c
@@ -1976,13 +1976,12 @@
err = svn_repos_replay2(root, b->fs_path->data, low_water_mark,
send_deltas, editor, edit_baton,
authz_check_access_cb_func(b), b, pool);
- if (! err)
- SVN_CMD_ERR(editor->close_edit(edit_baton, pool));
if (err)
svn_error_clear(editor->abort_edit(edit_baton, pool));
SVN_CMD_ERR(err);
+ SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "finish-replay", ""));
SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
return SVN_NO_ERROR;
diff --git a/subversion/svnsync/main.c b/subversion/svnsync/main.c
index 5718676..a75c87e 100644
--- a/subversion/svnsync/main.c
+++ b/subversion/svnsync/main.c
@@ -1075,6 +1075,8 @@
SVN_ERR(svn_ra_replay(from_session, current, 0, TRUE,
cancel_editor, cancel_baton, subpool));
+ SVN_ERR(cancel_editor->close_edit(cancel_baton, subpool));
+
/* Sanity check that we actually committed the revision we meant to. */
if (baton->committed_rev != current)
return svn_error_createf