Author: gstein
Date: Sat Jun 18 03:37:34 2011
New Revision: 1137120

URL: http://svn.apache.org/viewvc?rev=1137120&view=rev
Log:
Continued work on the XML parser pausing and processing. In particular,
this revision enables reading from the "spill" file, and injects that
content into the XML parser.

* subversion/libsvn_ra_serf/util.c:
  (get_buffer): new function to return an allocated buffer, or to recycle
    a previous buffer from the parser context.
  (return_buffer): returns a buffer back to the parser context.
  (write_to_pending): use the new get_buffer() helper
  (svn_ra_serf__process_pending): expand commentary. use the new
    get_buffer() and return_buffer() helpers. add processing of the spill
    file.

Modified:
    subversion/trunk/subversion/libsvn_ra_serf/util.c

Modified: subversion/trunk/subversion/libsvn_ra_serf/util.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/util.c?rev=1137120&r1=1137119&r2=1137120&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/util.c Sat Jun 18 03:37:34 2011
@@ -1215,6 +1215,32 @@ add_done_item(svn_ra_serf__xml_parser_t 
 }
 
 
+/* Get a buffer from the parsing context. It will come from the free list,
+   or allocated as necessary.  */
+static struct pending_buffer_t *
+get_buffer(svn_ra_serf__xml_parser_t *parser)
+{
+  struct pending_buffer_t *pb;
+
+  if (parser->pending->avail == NULL)
+    return apr_palloc(parser->pool, sizeof(*pb));
+
+  pb = parser->pending->avail;
+  parser->pending->avail = pb->next;
+  return pb;
+}
+
+
+/* Return PB to the list of available buffers in PARSER.  */
+static void
+return_buffer(svn_ra_serf__xml_parser_t *parser,
+              struct pending_buffer_t *pb)
+{
+  pb->next = parser->pending->avail;
+  parser->pending->avail = pb;
+}
+
+
 static svn_error_t *
 write_to_pending(svn_ra_serf__xml_parser_t *ctx,
                  const char *data,
@@ -1255,17 +1281,9 @@ write_to_pending(svn_ra_serf__xml_parser
     }
 
   /* We're still within bounds of holding the pending information in
-     memory. Get a buffer (already available, or alloc it), copy the data
-     there, and link it into our pending data.  */
-  if (ctx->pending->avail != NULL)
-    {
-      pb = ctx->pending->avail;
-      ctx->pending->avail = pb->next;
-    }
-  else
-    {
-      pb = apr_palloc(ctx->pool, sizeof(*pb));
-    }
+     memory. Get a buffer, copy the data there, and link it into our
+     pending data.  */
+  pb = get_buffer(ctx);
   /* NOTE: *pb is uninitialized. All fields must be stored.  */
 
   pb->size = len;
@@ -1325,27 +1343,38 @@ svn_error_t *
 svn_ra_serf__process_pending(svn_ra_serf__xml_parser_t *parser,
                              apr_pool_t *scratch_pool)
 {
+  struct pending_buffer_t *pb;
+  svn_error_t *err;
+  apr_off_t output_unused;
+
   /* Fast path exit: already paused, or nothing to do.  */
   if (parser->paused || parser->pending == NULL)
     return SVN_NO_ERROR;
 
+  /* ### it is possible that the XML parsing of the pending content is
+     ### so slow, and that we don't return to reading the connection
+     ### fast enough... that the server will disconnect us. right now,
+     ### that is highly improbably, but is noted for future's sake.
+     ### should that ever happen, the loops in this function can simply
+     ### terminate after N seconds.  */
+
   /* Empty out memory buffers until we run out, or we get paused again.  */
   while (parser->pending->head != NULL)
     {
-      struct pending_buffer_t *pb = parser->pending->head;
-      svn_error_t *err;
-
+      /* Pull the HEAD buffer out of the list.  */
+      pb = parser->pending->head;
       if (parser->pending->tail == pb)
         parser->pending->head = parser->pending->tail = NULL;
       else
         parser->pending->head = pb->next;
+
+      /* We're using less memory now. If we haven't hit the spill file,
+         then we may be able to keep using memory.  */
       parser->pending->memory_size -= pb->size;
 
       err = inject_to_parser(parser, pb->data, pb->size, NULL);
 
-      /* Return the block to the "available" list.  */
-      pb->next = parser->pending->avail;
-      parser->pending->avail = pb;
+      return_buffer(parser, pb);
 
       if (err)
         return svn_error_return(err);
@@ -1360,9 +1389,43 @@ svn_ra_serf__process_pending(svn_ra_serf
   if (parser->pending->spill == NULL)
     return SVN_NO_ERROR;
 
-  /* ### read the spill file...  */
+  /* Seek once to where we left off reading.  */
+  output_unused = parser->pending->spill_start;  /* ### stupid API  */
+  SVN_ERR(svn_io_file_seek(parser->pending->spill,
+                           APR_SET, &output_unused,
+                           scratch_pool));
+
+  /* We need a buffer for reading out of the file. One of these will always
+     exist by the time we start reading from the spill file.  */
+  pb = get_buffer(parser);
+
+  /* Keep reading until we hit EOF, or get paused again.  */
+  while (TRUE)
+    {
+      apr_size_t len = sizeof(pb->data);
+      apr_status_t status;
+
+      /* Read some data and remember where we left off.  */
+      status = apr_file_read(parser->pending->spill, pb->data, &len);
+      if (status && !APR_STATUS_IS_EOF(status))
+        {
+          err = svn_error_wrap_apr(status, NULL);
+          break;
+        }
+      parser->pending->spill_start += len;
 
-  return SVN_NO_ERROR;
+      err = inject_to_parser(parser, pb->data, len, NULL);
+      if (err)
+        break;
+
+      /* If there is no more content (for now), or the callbacks paused
+         the parsing, then we're done.  */
+      if (APR_STATUS_IS_EOF(status) || parser->paused)
+        break;
+    }
+
+  return_buffer(parser, pb);
+  return svn_error_return(err);  /* may be SVN_NO_ERROR  */
 }
 
 


Reply via email to