Author: ivan
Date: Fri Jun 12 11:09:45 2015
New Revision: 1685063

URL: http://svn.apache.org/r1685063
Log:
Optimize svndiff parser a bit: do not parse delta window header on every
chunk written to svndiff parser write handler.

While this change may look like micro-optimization, in reality parsing delta
window header consume significant time of 'svnbench null-export' execution
over http: data received from network/base64 parser in small chunks. This
makes parsing one delta window header 1000 times until all delta window
received.

* subversion/libsvn_delta/svndiff.c
  (decode_baton): Add fields to hold length and five integer fields of 
   parsed delta window header.
  (write_handler): Reduce scope of local variables. Store parsed delta window
   header fields and length in DECODE_BATON and used on later invocations.
   Reset WINDOW_HEADER_LEN to zero once delta window is processed.
  (svn_txdelta_parse_svndiff): Initialize WINDOW_HEADER_LEN to zero.

Modified:
    subversion/trunk/subversion/libsvn_delta/svndiff.c

Modified: subversion/trunk/subversion/libsvn_delta/svndiff.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/svndiff.c?rev=1685063&r1=1685062&r2=1685063&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/trunk/subversion/libsvn_delta/svndiff.c Fri Jun 12 11:09:45 2015
@@ -342,6 +342,17 @@ struct decode_baton
 
   /* svndiff version in use by delta.  */
   unsigned char version;
+
+  /* Length of parsed delta window header. 0 if window is not parsed yet. */
+  apr_size_t window_header_len;
+
+  /* Five integer fields of parsed delta window header. Valid only if
+     WINDOW_HEADER_LEN > 0 */
+  svn_filesize_t  sview_offset;
+  apr_size_t sview_len;
+  apr_size_t tview_len;
+  apr_size_t inslen;
+  apr_size_t newlen;
 };
 
 
@@ -572,8 +583,6 @@ write_handler(void *baton,
 {
   struct decode_baton *db = (struct decode_baton *) baton;
   const unsigned char *p, *end;
-  svn_filesize_t sview_offset;
-  apr_size_t sview_len, tview_len, inslen, newlen;
   apr_size_t buflen = *len;
 
   /* Chew up four bytes at the beginning for the header.  */
@@ -617,69 +626,94 @@ write_handler(void *baton,
       p = (const unsigned char *) db->buffer->data;
       end = (const unsigned char *) db->buffer->data + db->buffer->len;
 
-      p = decode_file_offset(&sview_offset, p, end);
-      if (p == NULL)
-        break;
-
-      p = decode_size(&sview_len, p, end);
-      if (p == NULL)
-        break;
-
-      p = decode_size(&tview_len, p, end);
-      if (p == NULL)
-        break;
-
-      p = decode_size(&inslen, p, end);
-      if (p == NULL)
-        break;
-
-      p = decode_size(&newlen, p, end);
-      if (p == NULL)
-        break;
-
-      if (tview_len > SVN_DELTA_WINDOW_SIZE ||
-          sview_len > SVN_DELTA_WINDOW_SIZE ||
-          /* for svndiff1, newlen includes the original length */
-          newlen > SVN_DELTA_WINDOW_SIZE + SVN__MAX_ENCODED_UINT_LEN ||
-          inslen > MAX_INSTRUCTION_SECTION_LEN)
-        return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
-                                _("Svndiff contains a too-large window"));
-
-      /* Check for integer overflow.  */
-      if (sview_offset < 0 || inslen + newlen < inslen
-          || sview_len + tview_len < sview_len
-          || (apr_size_t)sview_offset + sview_len < (apr_size_t)sview_offset)
-        return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
-                                _("Svndiff contains corrupt window header"));
-
-      /* Check for source windows which slide backwards.  */
-      if (sview_len > 0
-          && (sview_offset < db->last_sview_offset
+      if (db->window_header_len == 0)
+        {
+          svn_filesize_t sview_offset;
+          apr_size_t sview_len, tview_len, inslen, newlen;
+          const unsigned char *hdr_start = p;
+
+          p = decode_file_offset(&sview_offset, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&sview_len, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&tview_len, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&inslen, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&newlen, p, end);
+          if (p == NULL)
+              break;
+
+          if (tview_len > SVN_DELTA_WINDOW_SIZE ||
+              sview_len > SVN_DELTA_WINDOW_SIZE ||
+              /* for svndiff1, newlen includes the original length */
+              newlen > SVN_DELTA_WINDOW_SIZE + SVN__MAX_ENCODED_UINT_LEN ||
+              inslen > MAX_INSTRUCTION_SECTION_LEN)
+            return svn_error_create(
+                     SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
+                     _("Svndiff contains a too-large window"));
+
+          /* Check for integer overflow.  */
+          if (sview_offset < 0 || inslen + newlen < inslen
+              || sview_len + tview_len < sview_len
+              || (apr_size_t)sview_offset + sview_len < 
(apr_size_t)sview_offset)
+            return svn_error_create(
+                      SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
+                      _("Svndiff contains corrupt window header"));
+
+          /* Check for source windows which slide backwards.  */
+          if (sview_len > 0
+              && (sview_offset < db->last_sview_offset
               || (sview_offset + sview_len
                   < db->last_sview_offset + db->last_sview_len)))
-        return svn_error_create
-          (SVN_ERR_SVNDIFF_BACKWARD_VIEW, NULL,
-           _("Svndiff has backwards-sliding source views"));
+            return svn_error_create(
+                     SVN_ERR_SVNDIFF_BACKWARD_VIEW, NULL,
+                     _("Svndiff has backwards-sliding source views"));
+
+          /* Remember parsed window header. */
+          db->window_header_len = p - hdr_start;
+          db->sview_offset = sview_offset;
+          db->sview_len = sview_len;
+          db->tview_len = tview_len;
+          db->inslen = inslen;
+          db->newlen = newlen;
+        }
+      else
+        {
+          /* Skip already parsed window header. */
+          p += db->window_header_len;
+        }
 
       /* Wait for more data if we don't have enough bytes for the
          whole window.  */
-      if ((apr_size_t) (end - p) < inslen + newlen)
+      if ((apr_size_t) (end - p) < db->inslen + db->newlen)
         return SVN_NO_ERROR;
 
       /* Decode the window and send it off. */
-      SVN_ERR(decode_window(&window, sview_offset, sview_len, tview_len,
-                            inslen, newlen, p, db->subpool,
-                            db->version));
+      SVN_ERR(decode_window(&window, db->sview_offset, db->sview_len,
+                            db->tview_len, db->inslen, db->newlen, p,
+                            db->subpool, db->version));
       SVN_ERR(db->consumer_func(&window, db->consumer_baton));
 
-      p += inslen + newlen;
+      p += db->inslen + db->newlen;
 
       /* Remove processed data from the buffer.  */
       svn_stringbuf_remove(db->buffer, 0, db->buffer->len - (end - p));
 
+      /* Reset window header length. */
+      db->window_header_len = 0;
+
       /* Remember the offset and length of the source view for next time.  */
-      db->last_sview_offset = sview_offset;
-      db->last_sview_len = sview_len;
+      db->last_sview_offset = db->sview_offset;
+      db->last_sview_len = db->sview_len;
 
       /* Clear subpool. */
       svn_pool_clear(db->subpool);
@@ -747,6 +781,7 @@ svn_txdelta_parse_svndiff(svn_txdelta_wi
       db->last_sview_len = 0;
       db->header_bytes = 0;
       db->error_on_early_close = error_on_early_close;
+      db->window_header_len = 0;
       stream = svn_stream_create(db, pool);
 
       svn_stream_set_write(stream, write_handler);


Reply via email to