Limit the max input stream size by adding segment compression
(e.g. 4M segment size), it will benefits:
 - more friendly to block diff (and more details about this);
 - it can also be used for parallel compression in the same file.

Signed-off-by: Li Guifu <bluce....@aliyun.com>
---
 include/erofs/config.h |  1 +
 lib/compress.c         | 11 +++++++++++
 lib/config.c           |  1 +
 3 files changed, 13 insertions(+)

diff --git a/include/erofs/config.h b/include/erofs/config.h
index 2f09749..9125c1e 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -36,6 +36,7 @@ struct erofs_configure {
        char *c_src_path;
        char *c_compr_alg_master;
        int c_compr_level_master;
+       unsigned int c_compr_seg_size;  /* max segment compress size */
        int c_force_inodeversion;
        /* < 0, xattr disabled and INT_MAX, always use inline xattrs */
        int c_inline_xattr_tolerance;
diff --git a/lib/compress.c b/lib/compress.c
index 6cc68ed..8fdbfb2 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -32,6 +32,8 @@ struct z_erofs_vle_compress_ctx {
 
        erofs_blk_t blkaddr;    /* pointing to the next blkaddr */
        u16 clusterofs;
+       unsigned int comprlimits;
+       unsigned int comr_seg_size;
 };
 
 #define Z_EROFS_LEGACY_MAP_HEADER_SIZE \
@@ -158,6 +160,12 @@ static int vle_compress_one(struct erofs_inode *inode,
        while (len) {
                bool raw;
 
+               if (ctx->comprlimits >= ctx->comr_seg_size ||
+                       ctx->comprlimits + EROFS_BLKSIZ >= ctx->comr_seg_size) {
+                       ctx->comprlimits = 0;
+                       goto nocompression;
+               }
+
                if (len <= EROFS_BLKSIZ) {
                        if (final)
                                goto nocompression;
@@ -202,6 +210,7 @@ nocompression:
 
                ++ctx->blkaddr;
                len -= count;
+               ctx->comprlimits += count;
 
                if (!final && ctx->head >= EROFS_CONFIG_COMPR_MAX_SZ) {
                        const unsigned int qh_aligned =
@@ -422,6 +431,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode)
        ctx.head = ctx.tail = 0;
        ctx.clusterofs = 0;
        remaining = inode->i_size;
+       ctx.comprlimits = 0;
+       ctx.comr_seg_size = cfg.c_compr_seg_size;
 
        while (remaining) {
                const u64 readcount = min_t(u64, remaining,
diff --git a/lib/config.c b/lib/config.c
index da0c260..1c39403 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -23,6 +23,7 @@ void erofs_init_configure(void)
        cfg.c_force_inodeversion = 0;
        cfg.c_inline_xattr_tolerance = 2;
        cfg.c_unix_timestamp = -1;
+       cfg.c_compr_seg_size = 1024U * EROFS_BLKSIZ;
 }
 
 void erofs_show_config(void)
-- 
2.17.1

Reply via email to