diff options
Diffstat (limited to 'subversion/mod_dav_svn/reports/log.c')
-rw-r--r-- | subversion/mod_dav_svn/reports/log.c | 120 |
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; } |