svn commit: r1931688 - in subversion/branches/better-pristines: . subversion/include/private subversion/libsvn_subr subversion/tests/libsvn_subr tools/lz4

[email protected]
Newsgroups gmane.comp.version-control.subversion.svn
Message-ID <177013017940.4067842.7885969519565330608@svn02-us-east.apache.org>
Author: brane
Date: Tue Feb  3 14:49:38 2026
New Revision: 1931688

Log:
Add an LZ4 compressed stream.

* subversion/include/private/svn_io_private.h
  (svn_stream__lz4_compressed): New; stream constructor prototype.
* subversion/libsvn_subr/stream.c
  (zbaton): Unrelated change: make substrem an svn_stream_t*.
  (lz4_baton,
   read_handler_lz4,
   ensure_write_buffer_lz4,
   write_handler_lz4,
   close_handler_lz4): New LZ4 stream helpers.
  (svn_stream__lz4_compressed): Implement the stream constructor.

* subversion/tests/libsvn_subr/stream-test.c
  (do_test_stream_compressed): Renamed and refactored from
   test_stream_compressed().
  (test_stream_compressed,
   test_stream_compressed_lz4): Test drivers for the above.
  (test_funcs): Register the new test.

* build.conf
  (slz4): New tool, simulates lz4/unlz4.
  (tools/lz4/slz4.c): Implement the lz4/unlz4 simulator.

Added:
   subversion/branches/better-pristines/tools/lz4/
   subversion/branches/better-pristines/tools/lz4/slz4.c   (contents, props changed)
Modified:
   subversion/branches/better-pristines/build.conf
   subversion/branches/better-pristines/subversion/include/private/svn_io_private.h
   subversion/branches/better-pristines/subversion/libsvn_subr/stream.c
   subversion/branches/better-pristines/subversion/tests/libsvn_subr/stream-test.c

Modified: subversion/branches/better-pristines/build.conf
==============================================================================
--- subversion/branches/better-pristines/build.conf	Tue Feb  3 12:45:02 2026	(r1931687)
+++ subversion/branches/better-pristines/build.conf	Tue Feb  3 14:49:38 2026	(r1931688)
@@ -1699,6 +1699,13 @@ sources = diff4.c
 install = tools
 libs = libsvn_diff libsvn_subr apriconv apr
 
+[slz4]
+type = exe
+path = tools/lz4
+sources = slz4.c
+install = tools
+libs = libsvn_subr apriconv apr
+
 [svnbench]
 description = Benchmarking and diagnostics tool for the network layer
 type = exe

Modified: subversion/branches/better-pristines/subversion/include/private/svn_io_private.h
==============================================================================
--- subversion/branches/better-pristines/subversion/include/private/svn_io_private.h	Tue Feb  3 12:45:02 2026	(r1931687)
+++ subversion/branches/better-pristines/subversion/include/private/svn_io_private.h	Tue Feb  3 14:49:38 2026	(r1931688)
@@ -171,6 +171,12 @@ svn_stream__adler32(svn_stream_t *stream
                     svn_boolean_t read_all,
                     apr_pool_t *result_pool);
 
+/* Similar to svn_stream_compressed() but uses LZ4 instead of zlib.
+   See: svn_lz4__compress_create() etc. in svn_subr_private.h.
+*/
+svn_stream_t *
+svn_stream__lz4_compressed(svn_stream_t *stream, apr_pool_t *pool);
+
 #if defined(WIN32)
 
 /* ### Move to something like io.h or subr.h, to avoid making it

Modified: subversion/branches/better-pristines/subversion/libsvn_subr/stream.c
==============================================================================
--- subversion/branches/better-pristines/subversion/libsvn_subr/stream.c	Tue Feb  3 12:45:02 2026	(r1931687)
+++ subversion/branches/better-pristines/subversion/libsvn_subr/stream.c	Tue Feb  3 14:49:38 2026	(r1931688)
@@ -1148,13 +1148,10 @@ svn_stream__aprfile(svn_stream_t *stream
 struct zbaton {
   z_stream *in;                 /* compressed stream for reading */
   z_stream *out;                /* compressed stream for writing */
-  void *substream;              /* The substream */
-  void *read_buffer;            /* buffer   used   for  reading   from
-                                   substream */
-  int read_flush;               /* what flush mode to use while
-                                   reading */
-  apr_pool_t *pool;             /* The pool this baton is allocated
-                                   on */
+  svn_stream_t *substream;      /* The substream */
+  void *read_buffer;            /* buffer used for reading from substream */
+  int read_flush;               /* what flush mode to use while reading */
+  apr_pool_t *pool;             /* The pool this baton is allocated in */
 };
 
 /* zlib alloc function. opaque is the pool we need. */
@@ -1368,6 +1365,139 @@ svn_stream_compressed(svn_stream_t *stre
 
   return zstream;
 }
+
+
+struct lz4_baton {
+  svn_lz4__decompress_ctx_t *dctx; /* Decompression context for reading */
+  svn_lz4__compress_ctx_t *cctx;   /* Compression context for writing */
+  svn_stream_t *substream;
+  svn_stringbuf_t *write_buffer;
+  char *read_buffer;
+  apr_size_t read_pos;
+  apr_size_t read_size;
+  apr_size_t size_hint;
+  apr_pool_t *pool;                /* The pool this baton is allocated in */
+};
+
+/* Read data from the substream and decompress it. */
+static svn_error_t *
+read_handler_lz4(void *baton, char *buffer, apr_size_t *len)
+{
+  struct lz4_baton *const ctx = baton;
+  apr_size_t read_total = 0;
+
+  if (!ctx->dctx)
+    {
+      SVN_ERR(svn_lz4__decompress_create(&ctx->dctx, FALSE, ctx->pool));
+      ctx->read_buffer = apr_palloc(ctx->pool, ZBUFFER_SIZE);
+      ctx->read_pos = ctx->read_size = 0;
+      ctx->size_hint = 1;
+    }
+
+  while (read_total < *len && ctx->size_hint > 0)
+    {
+      apr_size_t input_size;
+      apr_size_t output_size;
+
+      if (ctx->read_pos >= ctx->read_size)
+        {
+          ctx->read_size = ZBUFFER_SIZE;
+          SVN_ERR(svn_stream_read_full(ctx->substream,
+                                       ctx->read_buffer, &ctx->read_size));
+          ctx->read_pos = 0;
+        }
+
+      input_size = ctx->read_size - ctx->read_pos;
+      output_size = *len - read_total;
+      SVN_ERR(svn_lz4__decompress(&ctx->size_hint, ctx->dctx,
+                                  buffer + read_total, &output_size,
+                                  ctx->read_buffer + ctx->read_pos,
+                                  &input_size));
+      ctx->read_pos += input_size;
+
+      read_total += output_size;
+    }
+
+  *len = read_total;
+  return SVN_NO_ERROR;
+}
+
+/* Ensure we have enough space in the write buffer */
+static void
+ensure_write_buffer_lz4(struct lz4_baton *ctx, apr_size_t size)
+{
+  if (!ctx->write_buffer)
+    ctx->write_buffer = svn_stringbuf_create_ensure(size, ctx->pool);
+  else
+    svn_stringbuf_ensure(ctx->write_buffer, size);
+}
+
+/* Compress data and write it to the substream. */
+static svn_error_t *
+write_handler_lz4(void *baton, const char *buffer, apr_size_t *len)
+{
+  struct lz4_baton *const ctx = baton;
+
+  apr_size_t input_size = *len;
+  apr_size_t output_size = 0;
+
+  if (!ctx->cctx)
+    {
+      SVN_ERR(svn_lz4__compress_create(&ctx->cctx, FALSE, ctx->pool));
+      output_size = svn_lz4__header_size_max();
+    }
+
+  output_size += svn_lz4__compress_bound(ctx->cctx, input_size);
+  ensure_write_buffer_lz4(ctx, output_size);
+  SVN_ERR(svn_lz4__compress_update(&output_size, ctx->cctx,
+                                   ctx->write_buffer->data, output_size,
+                                   buffer, input_size));
+  return svn_error_trace(svn_stream_write(ctx->substream,
+                                          ctx->write_buffer->data,
+                                          &output_size));
+}
+
+/* Handle flushing and closing the stream */
+static svn_error_t *
+close_handler_lz4(void *baton)
+{
+  struct lz4_baton *const ctx = baton;
+  apr_size_t output_size;
+
+  /* If we haven't written anything, there's nothing to flush. */
+  if (!ctx->cctx)
+    return SVN_NO_ERROR;
+
+  output_size = svn_lz4__compress_bound(ctx->cctx, 0);
+  ensure_write_buffer_lz4(ctx, output_size);
+  SVN_ERR(svn_lz4__compress_end(&output_size, ctx->cctx,
+                                ctx->write_buffer->data, output_size));
+  return svn_error_trace(svn_stream_write(ctx->substream,
+                                          ctx->write_buffer->data,
+                                          &output_size));
+  return svn_error_trace(svn_stream_close(ctx->substream));
+}
+
+svn_stream_t *
+svn_stream__lz4_compressed(svn_stream_t *stream, apr_pool_t *pool)
+{
+  struct svn_stream_t *zstream;
+  struct lz4_baton *ctx;
+
+  assert(stream != NULL);
+
+  ctx = apr_pcalloc(pool, sizeof(*ctx));
+  ctx->substream = stream;
+  ctx->pool = pool;
+
+  zstream = svn_stream_create(ctx, pool);
+  svn_stream_set_read2(zstream, NULL /* only full read support */,
+                       read_handler_lz4);
+  svn_stream_set_write(zstream, write_handler_lz4);
+  svn_stream_set_close(zstream, close_handler_lz4);
+
+  return zstream;
+}
 
 
 /* Checksummed stream support */

Modified: subversion/branches/better-pristines/subversion/tests/libsvn_subr/stream-test.c
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/libsvn_subr/stream-test.c	Tue Feb  3 12:45:02 2026	(r1931687)
+++ subversion/branches/better-pristines/subversion/tests/libsvn_subr/stream-test.c	Tue Feb  3 14:49:38 2026	(r1931688)
@@ -150,7 +150,8 @@ generate_test_bytes(int num_bytes, apr_p
 
 
 static svn_error_t *
-test_stream_compressed(apr_pool_t *pool)
+do_test_stream_compressed(svn_stream_t *(*ctor)(svn_stream_t *, apr_pool_t *),
+                          apr_pool_t *pool)
 {
 #define NUM_TEST_STRINGS 5
 #define TEST_BUF_SIZE 10
@@ -194,16 +195,12 @@ test_stream_compressed(apr_pool_t *pool)
       inbuf = svn_stringbuf_create_empty(subpool);
       outbuf = svn_stringbuf_create_empty(subpool);
 
-      stream = svn_stream_compressed(svn_stream_from_stringbuf(outbuf,
-                                                               subpool),
-                                     subpool);
+      stream = ctor(svn_stream_from_stringbuf(outbuf, subpool), subpool);
       len = origbuf->len;
       SVN_ERR(svn_stream_write(stream, origbuf->data, &len));
       SVN_ERR(svn_stream_close(stream));
 
-      stream = svn_stream_compressed(svn_stream_from_stringbuf(outbuf,
-                                                               subpool),
-                                     subpool);
+      stream = ctor(svn_stream_from_stringbuf(outbuf, subpool), subpool);
       len = TEST_BUF_SIZE;
       while (len >= TEST_BUF_SIZE)
         {
@@ -231,6 +228,19 @@ test_stream_compressed(apr_pool_t *pool)
 }
 
 static svn_error_t *
+test_stream_compressed(apr_pool_t *pool)
+{
+  return do_test_stream_compressed(svn_stream_compressed, pool);
+}
+
+static svn_error_t *
+test_stream_compressed_lz4(apr_pool_t *pool)
+{
+  return do_test_stream_compressed(svn_stream__lz4_compressed, pool);
+}
+
+
+static svn_error_t *
 test_stream_tee(apr_pool_t *pool)
 {
   svn_stringbuf_t *test_bytes = generate_test_bytes(100, pool);
@@ -1162,7 +1172,9 @@ static struct svn_test_descriptor_t test
     SVN_TEST_PASS2(test_stream_from_string,
                    "test svn_stream_from_string"),
     SVN_TEST_PASS2(test_stream_compressed,
-                   "test compressed streams"),
+                   "test zlib compressed streams"),
+    SVN_TEST_PASS2(test_stream_compressed_lz4,
+                   "test LZ4 compressed streams"),
     SVN_TEST_PASS2(test_stream_tee,
                    "test 'tee' streams"),
     SVN_TEST_PASS2(test_stream_seek_file,

Added: subversion/branches/better-pristines/tools/lz4/slz4.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ subversion/branches/better-pristines/tools/lz4/slz4.c	Tue Feb  3 14:49:38 2026	(r1931688)
@@ -0,0 +1,102 @@
+/* slz4.c -- test driver for LZ4 de/compression
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+
+/*
+ * This compression driver can create create files that can be
+ * read by 'unlz4' and decmpress files created by 'lz4'.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <apr.h>
+
+#include "svn_error.h"
+#include "svn_io.h"
+#include "svn_pools.h"
+#include "private/svn_io_private.h"
+
+
+static void handle_error(svn_error_t *svn_err, int exitcode)
+{
+  if (svn_err)
+    {
+      svn_handle_error2(svn_err, stdout, FALSE, "slz4: ");
+      exit(exitcode);
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+  apr_pool_t *pool;
+  svn_stream_t *istream;
+  svn_stream_t *ostream;
+  int compress = 1;
+
+  if (argc >= 2)
+    {
+      int usage = 0;
+
+      if (0 == strcmp(argv[1], "-d"))
+        compress = 0;
+      else if (0 == strcmp(argv[1], "-c"))
+        compress = 1;
+      else
+        {
+          fprintf(stderr, "error: unknown option: %s\n", argv[1]);
+          usage = 1;
+        }
+      if (argc > 2)
+        {
+          fprintf(stderr, "error: too many arguments\n");
+          usage = 1;
+        }
+
+      if (usage)
+        {
+          fprintf(stderr,
+                  "Usage: %s [-c|-d] <{input} >{output}\n"
+                  "   -c  compress {input} to {output}     [DEFAULT]\n"
+                  "   -d  decompress {output} from {input}\n",
+                  argv[0]);
+          exit(2);
+        }
+    }
+
+  apr_initialize();
+  atexit(apr_terminate);
+
+  pool = svn_pool_create(NULL);
+  handle_error(svn_stream_for_stdin2(&istream, TRUE, pool), 2);
+  handle_error(svn_stream_for_stdout(&ostream, pool), 2);
+
+  if (compress)
+    ostream = svn_stream__lz4_compressed(ostream, pool);
+  else
+    istream = svn_stream__lz4_compressed(istream, pool);
+
+  handle_error(svn_stream_copy3(istream, ostream, NULL, NULL, pool), 1);
+  return 0;
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.