summaryrefslogtreecommitdiff
path: root/subversion/mod_dav_svn/reports/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/mod_dav_svn/reports/log.c')
-rw-r--r--subversion/mod_dav_svn/reports/log.c120
1 files changed, 80 insertions, 40 deletions
diff --git a/subversion/mod_dav_svn/reports/log.c b/subversion/mod_dav_svn/reports/log.c
index acd33ed..76a47c8 100644
--- a/subversion/mod_dav_svn/reports/log.c
+++ b/subversion/mod_dav_svn/reports/log.c
@@ -50,7 +50,7 @@ struct log_receiver_baton
apr_bucket_brigade *bb;
/* where to deliver the output */
- ap_filter_t *output;
+ dav_svn__output *output;
/* Whether we've written the <S:log-report> header. Allows for lazy
writes to support mod_dav-based error handling. */
@@ -65,6 +65,10 @@ struct log_receiver_baton
/* whether the client can handle encoded binary property values */
svn_boolean_t encode_binary_props;
+
+ /* Helper variables to force early bucket brigade flushes */
+ int result_count;
+ int next_forced_flush;
};
@@ -87,6 +91,43 @@ maybe_send_header(struct log_receiver_baton *lrb)
return SVN_NO_ERROR;
}
+/* Utility for log_receiver opening a new XML element in LRB's brigade
+ for LOG_ITEM and return the element's name in *ELEMENT. Use POOL for
+ temporary allocations.
+
+ Call this function for items that may have a copy-from */
+static svn_error_t *
+start_path_with_copy_from(const char **element,
+ struct log_receiver_baton *lrb,
+ svn_log_changed_path2_t *log_item,
+ apr_pool_t *pool)
+{
+ switch (log_item->action)
+ {
+ case 'A': *element = "S:added-path";
+ break;
+ case 'R': *element = "S:replaced-path";
+ break;
+ default: /* Caller, you did wrong! */
+ SVN_ERR_MALFUNCTION();
+ }
+
+ if (log_item->copyfrom_path
+ && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
+ SVN_ERR(dav_svn__brigade_printf
+ (lrb->bb, lrb->output,
+ "<%s copyfrom-path=\"%s\" copyfrom-rev=\"%ld\"",
+ *element,
+ apr_xml_quote_string(pool,
+ log_item->copyfrom_path,
+ 1), /* escape quotes */
+ log_item->copyfrom_rev));
+ else
+ SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output, "<%s", *element));
+
+ return SVN_NO_ERROR;
+}
+
/* This implements `svn_log_entry_receiver_t'.
BATON is a `struct log_receiver_baton *'. */
@@ -203,39 +244,9 @@ log_receiver(void *baton,
switch (log_item->action)
{
case 'A':
- if (log_item->copyfrom_path
- && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
- SVN_ERR(dav_svn__brigade_printf
- (lrb->bb, lrb->output,
- "<S:added-path copyfrom-path=\"%s\""
- " copyfrom-rev=\"%ld\"",
- apr_xml_quote_string(iterpool,
- log_item->copyfrom_path,
- 1), /* escape quotes */
- log_item->copyfrom_rev));
- else
- SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
- "<S:added-path"));
-
- close_element = "S:added-path";
- break;
-
case 'R':
- if (log_item->copyfrom_path
- && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
- SVN_ERR(dav_svn__brigade_printf
- (lrb->bb, lrb->output,
- "<S:replaced-path copyfrom-path=\"%s\""
- " copyfrom-rev=\"%ld\"",
- apr_xml_quote_string(iterpool,
- log_item->copyfrom_path,
- 1), /* escape quotes */
- log_item->copyfrom_rev));
- else
- SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
- "<S:replaced-path"));
-
- close_element = "S:replaced-path";
+ SVN_ERR(start_path_with_copy_from(&close_element, lrb,
+ log_item, iterpool));
break;
case 'D':
@@ -275,6 +286,33 @@ log_receiver(void *baton,
SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
"</S:log-item>" DEBUG_CR));
+ /* In general APR will flush the brigade every 8000 bytes through the filter
+ stack, but log items may not be generated that fast, especially in
+ combination with authz and busy servers. We now explictly flush after
+ log-item 4, 16, 64 and 256 to produce a few results fast.
+
+ This introduces 4 full flushes of our brigade and the installed output
+ filters at growing intervals and then falls back to the standard
+ buffering of 8000 bytes + whatever buffers are added in output filters. */
+ lrb->result_count++;
+ if (lrb->result_count == lrb->next_forced_flush)
+ {
+ apr_bucket *bkt;
+
+ /* Compared to using ap_filter_flush(), which we use in other place
+ this adds a flush frame before flushing the brigade, to make output
+ filters perform a flush as well */
+
+ /* No brigade empty check. We want output filters to flush anyway */
+ bkt = apr_bucket_flush_create(
+ dav_svn__output_get_bucket_alloc(lrb->output));
+ APR_BRIGADE_INSERT_TAIL(lrb->bb, bkt);
+ SVN_ERR(dav_svn__output_pass_brigade(lrb->output, lrb->bb));
+
+ if (lrb->result_count < 256)
+ lrb->next_forced_flush = lrb->next_forced_flush * 4;
+ }
+
return SVN_NO_ERROR;
}
@@ -282,7 +320,7 @@ log_receiver(void *baton,
dav_error *
dav_svn__log_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
@@ -301,6 +339,7 @@ dav_svn__log_report(const dav_resource *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 */
+
apr_array_header_t *revprops = apr_array_make(resource->pool, 3,
sizeof(const char *));
apr_array_header_t *paths
@@ -313,12 +352,10 @@ dav_svn__log_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
/* If this is still FALSE after the loop, we haven't seen either of
@@ -415,12 +452,15 @@ dav_svn__log_report(const dav_resource *resource,
/* Build log receiver baton */
lrb.bb = apr_brigade_create(resource->pool, /* not the subpool! */
- output->c->bucket_alloc);
+ dav_svn__output_get_bucket_alloc(output));
lrb.output = output;
lrb.needs_header = TRUE;
lrb.stack_depth = 0;
/* lrb.requested_custom_revprops set above */
+ lrb.result_count = 0;
+ lrb.next_forced_flush = 4;
+
/* Our svn_log_entry_receiver_t sends the <S:log-report> header in
a lazy fashion. Before writing the first log message, it assures
that the header has already been sent (checking the needs_header
@@ -443,7 +483,7 @@ dav_svn__log_report(const dav_resource *resource,
resource->pool);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}