Author: cmpilato
Date: Fri Nov 30 21:54:35 2012
New Revision: 1415864
URL: http://svn.apache.org/viewvc?rev=1415864&view=rev
Log:
Implement in ra_serf "send-all" mode support for update-style REPORTs
and their responses. (Currently disabled by compile-time conditionals.)
(This one goes out to Ivan Zhakov.)
* subversion/libsvn_ra_serf/update.c
(report_state_e): New state 'TXDELTA'.
(report_info_t): Add 'svndiff_decoder' and 'base64_decoder' members.
(report_context_t): Add 'send_all_mode' flag.
(fetch_file): Don't populate the report_info_t's 'url' member here;
we'll do that in start_report() instead.
(start_report): Notice the "send-all" attribute on the
<update-report> tag, and set the 'send_all_mode' flag accordingly.
Only expect to fetch file contents for added files when not
in "send-all" mode. Handle the <txdelta> tag in "send-all" mode,
pushing a new TXDELTA state and cranking up the svndiff window
handling stuff.
(end_report): When closing opened and added files, calculate the
report_info_t's 'url' field, and handle "send-all" mode where
applicable. Handle the </txdelta> tag by closing up the
base64-decoding stream.
(cdata_report): Handle CDATA for <txdelta> blocks.
(make_update_reporter): Add (disabled) support for asking the server
to use "send-all" mode for update REPORT responses. Also, drop
the <text-deltas> element into the REPORT request when we don't
wish to get real text-deltas.
Modified:
subversion/trunk/subversion/libsvn_ra_serf/update.c
Modified: subversion/trunk/subversion/libsvn_ra_serf/update.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/update.c?rev=1415864&r1=1415863&r2=1415864&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/update.c Fri Nov 30 21:54:35 2012
@@ -74,7 +74,8 @@ typedef enum report_state_e {
ABSENT_FILE,
PROP,
IGNORE_PROP_NAME,
- NEED_PROP_NAME
+ NEED_PROP_NAME,
+ TXDELTA
} report_state_e;
@@ -228,6 +229,8 @@ typedef struct report_info_t
const char *final_sha1_checksum;
svn_txdelta_window_handler_t textdelta;
void *textdelta_baton;
+ svn_stream_t *svndiff_decoder;
+ svn_stream_t *base64_decoder;
/* Checksum for close_file */
const char *final_checksum;
@@ -318,6 +321,9 @@ struct report_context_t {
/* Do we want the server to send copyfrom args or not? */
svn_boolean_t send_copyfrom_args;
+ /* Is the server sending everything in one response? */
+ svn_boolean_t send_all_mode;
+
/* Is the server including properties inline for newly added
files/dirs? */
svn_boolean_t add_props_included;
@@ -1448,17 +1454,6 @@ fetch_file(report_context_t *ctx, report
/* What connection should we go on? */
conn = get_best_connection(ctx);
- /* go fetch info->name from DAV:checked-in */
- info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
- info->base_rev, "DAV:", "checked-in");
-
- if (!info->url)
- {
- return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("The REPORT or PROPFIND response did not "
- "include the requested checked-in value"));
- }
-
/* If needed, create the PROPFIND to retrieve the file's properties. */
info->propfind_handler = NULL;
if (info->fetch_props)
@@ -1625,9 +1620,15 @@ start_report(svn_ra_serf__xml_parser_t *
if (state == NONE && strcmp(name.name, "update-report") == 0)
{
- const char *val = svn_xml_get_attr_value("inline-props", attrs);
+ const char *val;
+
+ val = svn_xml_get_attr_value("inline-props", attrs);
if (val && (strcmp(val, "true") == 0))
ctx->add_props_included = TRUE;
+
+ val = svn_xml_get_attr_value("send-all", attrs);
+ if (val && (strcmp(val, "true") == 0))
+ ctx->send_all_mode = TRUE;
}
else if (state == NONE && strcmp(name.name, "target-revision") == 0)
{
@@ -1830,7 +1831,11 @@ start_report(svn_ra_serf__xml_parser_t *
info = push_state(parser, ctx, ADD_FILE);
info->base_rev = SVN_INVALID_REVNUM;
- info->fetch_file = TRUE;
+
+ /* If the server isn't in "send-all" mode, we should expect to
+ fetch contents for added files. */
+ if (! ctx->send_all_mode)
+ info->fetch_file = TRUE;
/* If the server isn't included properties for added items,
we'll need to fetch them ourselves. */
@@ -2070,7 +2075,31 @@ start_report(svn_ra_serf__xml_parser_t *
addition to <fetch-file>s and such) when *not* in
"send-all" mode. As a client, we're smart enough to know
that's wrong, so we'll just ignore these tags. */
- ;
+ if (ctx->send_all_mode)
+ {
+ const svn_delta_editor_t *update_editor = ctx->update_editor;
+
+ info = push_state(parser, ctx, TXDELTA);
+
+ if (! info->file_baton)
+ {
+ SVN_ERR(open_updated_file(info, FALSE, info->pool));
+ }
+
+ info->base_checksum = svn_xml_get_attr_value("base-checksum",
+ attrs);
+ SVN_ERR(update_editor->apply_textdelta(info->file_baton,
+ info->base_checksum,
+ info->editor_pool,
+ &info->textdelta,
+ &info->textdelta_baton));
+ info->svndiff_decoder = svn_txdelta_parse_svndiff(
+ info->textdelta,
+ info->textdelta_baton,
+ TRUE, info->pool);
+ info->base64_decoder = svn_base64_decode(info->svndiff_decoder,
+ info->pool);
+ }
}
else
{
@@ -2264,13 +2293,89 @@ end_report(svn_ra_serf__xml_parser_t *pa
info->delta_base = value ? value->data : NULL;
}
- SVN_ERR(fetch_file(ctx, info));
+ /* go fetch info->name from DAV:checked-in */
+ info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+ info->base_rev, "DAV:",
"checked-in");
+ if (!info->url)
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("The REPORT or PROPFIND response did not "
+ "include the requested checked-in value"));
+ }
+
+ /* If the server is in "send-all" mode, we might have opened the
+ file when we started seeing content for it. If we didn't get
+ any content for it, we still need to open the file. But in
+ any case, we can then immediately close it. */
+ if (ctx->send_all_mode)
+ {
+ if (! info->file_baton)
+ {
+ SVN_ERR(open_updated_file(info, FALSE, info->pool));
+ }
+ SVN_ERR(close_updated_file(info, info->pool));
+ info->dir->ref_count--;
+ }
+ /* Otherwise, if the server is *not* in "send-all" mode, we
+ should be at a point where we can queue up any auxiliary
+ content-fetching requests. */
+ else
+ {
+ SVN_ERR(fetch_file(ctx, info));
+ }
+
svn_ra_serf__xml_pop_state(parser);
}
else if (state == ADD_FILE && strcmp(name.name, "add-file") == 0)
{
- /* We should have everything we need to fetch the file. */
- SVN_ERR(fetch_file(ctx, parser->state->private));
+ report_info_t *info = parser->state->private;
+
+ /* go fetch info->name from DAV:checked-in */
+ info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+ info->base_rev, "DAV:",
"checked-in");
+ if (!info->url)
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("The REPORT or PROPFIND response did not "
+ "include the requested checked-in value"));
+ }
+
+ /* If the server is in "send-all" mode, we might have opened the
+ file when we started seeing content for it. If we didn't get
+ any content for it, we still need to open the file. But in
+ any case, we can then immediately close it. */
+ if (ctx->send_all_mode)
+ {
+ if (! info->file_baton)
+ {
+ SVN_ERR(open_updated_file(info, FALSE, info->pool));
+ }
+ SVN_ERR(close_updated_file(info, info->pool));
+ info->dir->ref_count--;
+ }
+ /* Otherwise, if the server is *not* in "send-all" mode, we
+ should be at a point where we can queue up any auxiliary
+ content-fetching requests. */
+ else
+ {
+ SVN_ERR(fetch_file(ctx, info));
+ }
+
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ else if (state == TXDELTA && strcmp(name.name, "txdelta") == 0)
+ {
+ report_info_t *info = parser->state->private;
+
+ /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+ <fetch-file>s and such) when *not* in "send-all" mode. As a
+ client, we're smart enough to know that's wrong, so when not
+ in "receiving-all" mode, we'll ignore these tags. */
+ if (ctx->send_all_mode)
+ {
+ SVN_ERR(svn_stream_close(info->base64_decoder));
+ }
+
svn_ra_serf__xml_pop_state(parser);
}
else if (state == PROP)
@@ -2397,6 +2502,27 @@ cdata_report(svn_ra_serf__xml_parser_t *
svn_stringbuf_appendbytes(info->prop_value, data, len);
}
+ else if (parser->state->current_state == TXDELTA)
+ {
+ /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+ <fetch-file>s and such) when *not* in "send-all" mode. As a
+ client, we're smart enough to know that's wrong, so when not
+ in "receiving-all" mode, we'll ignore these tags. */
+ if (ctx->send_all_mode)
+ {
+ apr_size_t nlen = len;
+ report_info_t *info = parser->state->private;
+
+ SVN_ERR(svn_stream_write(info->base64_decoder, data, &nlen));
+ if (nlen != len)
+ {
+ /* Short write without associated error? "Can't happen." */
+ return svn_error_createf(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
+ _("Error writing to '%s': unexpected
EOF"),
+ info->name);
+ }
+ }
+ }
return SVN_NO_ERROR;
}
@@ -3035,9 +3161,19 @@ make_update_reporter(svn_ra_session_t *r
svn_io_file_del_on_pool_cleanup,
report->pool, scratch_pool));
+#ifdef SVN_RA_SERF__UPDATES_SEND_ALL
+ svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "S:update-report",
+ "xmlns:S", SVN_XML_NAMESPACE, "send-all", "true",
+ NULL);
+#else
svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "S:update-report",
"xmlns:S", SVN_XML_NAMESPACE,
NULL);
+ /* Subversion 1.8+ servers can be told to send properties for newly
+ added items inline even when doing a skelta response. */
+ make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+#endif
+
make_simple_xml_tag(&buf, "S:src-path", report->source, scratch_pool);
@@ -3076,9 +3212,18 @@ make_update_reporter(svn_ra_session_t *r
make_simple_xml_tag(&buf, "S:recursive", "no", scratch_pool);
}
- /* Subversion 1.8+ servers can be told to send properties for newly
- added items inline even when doing a skelta response. */
- make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+ /* When in 'send-all' mode, mod_dav_svn will assume that it should
+ calculate and transmit real text-deltas (instead of empty windows
+ that merely indicate "text is changed") unless it finds this
+ element. When not in 'send-all' mode, mod_dav_svn will never
+ send text-deltas at all.
+
+ NOTE: Do NOT count on servers actually obeying this, as some exist
+ which obey send-all, but do not check for this directive at all! */
+ if (! text_deltas)
+ {
+ make_simple_xml_tag(&buf, "S:text-deltas", "no", scratch_pool);
+ }
make_simple_xml_tag(&buf, "S:depth", svn_depth_to_word(depth), scratch_pool);