Author: kotkov
Date: Thu Jul 27 08:53:51 2017
New Revision: 1803140

URL: http://svn.apache.org/viewvc?rev=1803140&view=rev
Log:
Add new svn_txdelta_to_svndiff_stream() API.

This API turns a given svn_txdelta_stream_t delta stream into a readable
svn_stream_t containing svndiff.  It would be required to make ra_serf
stream svndiff deltas without creating temporary files.

* subversion/include/svn_delta.h
  (svn_txdelta_to_svndiff_stream): Declare new function.

* subversion/libsvn_delta/svndiff.c
  (svndiff_stream_baton_t): New.
  (svndiff_stream_write_fn): New, writes svndiff to a temporary buffer.
  (svndiff_stream_read_fn): New, passes the buffered data to the caller and
   refills the internal buffer if necessary.
  (svn_txdelta_to_svndiff_stream): Implement this new function.  Set up
   pull- and push-streams.  Install the read and write stream handlers, and
   return the pull stream to the caller.

* subversion/tests/libsvn_delta/random-test.c
  (do_random_txdelta_to_svndiff_stream_test): Core of the new test, similar
   to do_random_test().
  (random_txdelta_to_svndiff_stream_test): Run new test.
  (test_funcs): Add new test.

Modified:
    subversion/trunk/subversion/include/svn_delta.h
    subversion/trunk/subversion/libsvn_delta/svndiff.c
    subversion/trunk/subversion/tests/libsvn_delta/random-test.c

Modified: subversion/trunk/subversion/include/svn_delta.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_delta.h?rev=1803140&r1=1803139&r2=1803140&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_delta.h (original)
+++ subversion/trunk/subversion/include/svn_delta.h Thu Jul 27 08:53:51 2017
@@ -546,6 +546,20 @@ svn_txdelta_to_svndiff(svn_stream_t *out
                        svn_txdelta_window_handler_t *handler,
                        void **handler_baton);
 
+/** Return a readable generic stream which will produce svndiff-encoded
+ * text delta from the delta stream @a txstream.  @a svndiff_version and
+ * @a compression_level are same as in svn_txdelta_to_svndiff3().
+ *
+ * Allocate the stream in @a pool.
+ *
+ * @since New in 1.10.
+ */
+svn_stream_t *
+svn_txdelta_to_svndiff_stream(svn_txdelta_stream_t *txstream,
+                              int svndiff_version,
+                              int compression_level,
+                              apr_pool_t *pool);
+
 /** Return a writable generic stream which will parse svndiff-format
  * data into a text delta, invoking @a handler with @a handler_baton
  * whenever a new window is ready.

Modified: subversion/trunk/subversion/libsvn_delta/svndiff.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/svndiff.c?rev=1803140&r1=1803139&r2=1803140&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/trunk/subversion/libsvn_delta/svndiff.c Thu Jul 27 08:53:51 2017
@@ -993,3 +993,95 @@ svn_txdelta__read_raw_window_len(apr_siz
   return SVN_NO_ERROR;
 }
 
+typedef struct svndiff_stream_baton_t
+{
+  apr_pool_t *scratch_pool;
+  svn_txdelta_stream_t *txstream;
+  svn_txdelta_window_handler_t handler;
+  void *handler_baton;
+  svn_stringbuf_t *window_buffer;
+  apr_size_t read_pos;
+  svn_boolean_t hit_eof;
+} svndiff_stream_baton_t;
+
+static svn_error_t *
+svndiff_stream_write_fn(void *baton, const char *data, apr_size_t *len)
+{
+  svndiff_stream_baton_t *b = baton;
+
+  svn_stringbuf_appendbytes(b->window_buffer, data, *len);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+svndiff_stream_read_fn(void *baton, char *buffer, apr_size_t *len)
+{
+  svndiff_stream_baton_t *b = baton;
+  apr_size_t left = *len;
+  apr_size_t read = 0;
+
+  while (left && !b->hit_eof)
+    {
+      apr_size_t chunk_size;
+
+      if (b->read_pos == b->window_buffer->len)
+        {
+          svn_txdelta_window_t *window;
+
+          svn_pool_clear(b->scratch_pool);
+          svn_stringbuf_setempty(b->window_buffer);
+          SVN_ERR(svn_txdelta_next_window(&window, b->txstream,
+                                          b->scratch_pool));
+          SVN_ERR(b->handler(window, b->handler_baton));
+          b->read_pos = 0;
+
+          if (!window)
+            b->hit_eof = TRUE;
+        }
+
+      if (left > b->window_buffer->len - b->read_pos)
+        chunk_size = b->window_buffer->len - b->read_pos;
+      else
+        chunk_size = left;
+
+      memcpy(buffer, b->window_buffer->data + b->read_pos, chunk_size);
+      b->read_pos += chunk_size;
+      buffer += chunk_size;
+      read += chunk_size;
+      left -= chunk_size;
+    }
+
+  *len = read;
+  return SVN_NO_ERROR;
+}
+
+svn_stream_t *
+svn_txdelta_to_svndiff_stream(svn_txdelta_stream_t *txstream,
+                              int svndiff_version,
+                              int compression_level,
+                              apr_pool_t *pool)
+{
+  svndiff_stream_baton_t *baton;
+  svn_stream_t *push_stream;
+  svn_stream_t *pull_stream;
+
+  baton = apr_pcalloc(pool, sizeof(*baton));
+  baton->scratch_pool = svn_pool_create(pool);
+  baton->txstream = txstream;
+  baton->window_buffer = svn_stringbuf_create_empty(pool);
+  baton->hit_eof = FALSE;
+  baton->read_pos = 0;
+
+  push_stream = svn_stream_create(baton, pool);
+  svn_stream_set_write(push_stream, svndiff_stream_write_fn);
+
+  svn_txdelta_to_svndiff3(&baton->handler, &baton->handler_baton,
+                          push_stream, svndiff_version,
+                          compression_level, pool);
+
+  pull_stream = svn_stream_create(baton, pool);
+  svn_stream_set_read2(pull_stream, NULL, svndiff_stream_read_fn);
+
+  return pull_stream;
+}

Modified: subversion/trunk/subversion/tests/libsvn_delta/random-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_delta/random-test.c?rev=1803140&r1=1803139&r2=1803140&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_delta/random-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_delta/random-test.c Thu Jul 27 
08:53:51 2017
@@ -515,6 +515,96 @@ random_combine_test(apr_pool_t *pool)
 }
 
 
+/* (Note: *LAST_SEED is an output parameter.) */
+static svn_error_t *
+do_random_txdelta_to_svndiff_stream_test(apr_pool_t *pool,
+                                         apr_uint32_t *last_seed)
+{
+  apr_uint32_t seed;
+  apr_uint32_t maxlen;
+  apr_size_t bytes_range;
+  int i;
+  int iterations;
+  int dump_files;
+  int print_windows;
+  const char *random_bytes;
+  apr_pool_t *iterpool;
+
+  /* Initialize parameters and print out the seed in case we dump core
+     or something. */
+  init_params(&seed, &maxlen, &iterations, &dump_files, &print_windows,
+              &random_bytes, &bytes_range, pool);
+
+  iterpool = svn_pool_create(pool);
+  for (i = 0; i < iterations; i++)
+    {
+      apr_uint32_t subseed_base;
+      apr_file_t *source;
+      apr_file_t *target;
+      apr_file_t *source_copy;
+      apr_file_t *new_target;
+      svn_txdelta_stream_t *txstream;
+      svn_stream_t *delta_stream;
+      svn_txdelta_window_handler_t handler;
+      void *handler_baton;
+      svn_stream_t *push_stream;
+
+      svn_pool_clear(iterpool);
+
+      /* Generate source and target for the delta and its application. */
+      *last_seed = seed;
+      subseed_base = svn_test_rand(&seed);
+      source = generate_random_file(maxlen, subseed_base, &seed,
+                                    random_bytes, bytes_range,
+                                    dump_files, iterpool);
+      target = generate_random_file(maxlen, subseed_base, &seed,
+                                    random_bytes, bytes_range,
+                                    dump_files, iterpool);
+      source_copy = copy_tempfile(source, iterpool);
+      new_target = open_tempfile(NULL, iterpool);
+
+      /* Create a txdelta stream that turns the source into target;
+         turn it into a generic readable svn_stream_t. */
+      svn_txdelta2(&txstream,
+                   svn_stream_from_aprfile2(source, TRUE, iterpool),
+                   svn_stream_from_aprfile2(target, TRUE, iterpool),
+                   FALSE, iterpool);
+      delta_stream = svn_txdelta_to_svndiff_stream(txstream, i % 3, i % 10,
+                                                   iterpool);
+
+      /* Apply it to a copy of the source file to see if we get the
+         same target back. */
+      svn_txdelta_apply(svn_stream_from_aprfile2(source_copy, TRUE, iterpool),
+                        svn_stream_from_aprfile2(new_target, TRUE, iterpool),
+                        NULL, NULL, iterpool, &handler, &handler_baton);
+      push_stream = svn_txdelta_parse_svndiff(handler, handler_baton, TRUE,
+                                              iterpool);
+      SVN_ERR(svn_stream_copy3(delta_stream, push_stream, NULL, NULL,
+                               iterpool));
+
+      SVN_ERR(compare_files(target, new_target, dump_files));
+
+      apr_file_close(source);
+      apr_file_close(target);
+      apr_file_close(source_copy);
+      apr_file_close(new_target);
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements svn_test_driver_t. */
+static svn_error_t *
+random_txdelta_to_svndiff_stream_test(apr_pool_t *pool)
+{
+  apr_uint32_t seed;
+  svn_error_t *err = do_random_txdelta_to_svndiff_stream_test(pool, &seed);
+  if (err)
+    fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+  return err;
+}
+
 /* Change to 1 to enable the unit test for the delta combiner's range index: */
 #if 0
 #include "range-index-test.h"
@@ -533,6 +623,8 @@ static struct svn_test_descriptor_t test
                    "random delta test"),
     SVN_TEST_PASS2(random_combine_test,
                    "random combine delta test"),
+    SVN_TEST_PASS2(random_txdelta_to_svndiff_stream_test,
+                   "random txdelta to svndiff stream test"),
 #ifdef SVN_RANGE_INDEX_TEST_H
     SVN_TEST_PASS2(random_range_index_test,
                    "random range index test"),


Reply via email to