Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w3dFv-001PNg-0H for pgsql-hackers@arkaria.postgresql.org; Fri, 20 Mar 2026 17:03:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w3dFt-007S3E-25 for pgsql-hackers@arkaria.postgresql.org; Fri, 20 Mar 2026 17:03:26 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w3dFt-007S34-0k for pgsql-hackers@lists.postgresql.org; Fri, 20 Mar 2026 17:03:25 +0000 Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w3dFr-00000000CRV-3fcD for pgsql-hackers@lists.postgresql.org; Fri, 20 Mar 2026 17:03:24 +0000 Received: by mail-ej1-x62d.google.com with SMTP id a640c23a62f3a-b9793fa5371so285967466b.2 for ; Fri, 20 Mar 2026 10:03:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1774026202; cv=none; d=google.com; s=arc-20240605; b=lPGP5X89ryRQ/WXPW5abANCLY3ST1yoJ3UvDllJUNnMZi7ZiHalwwBAmLY+T3jPtRP ZPHAb2CuxFFwWBYeCZz2JSrR2TGLAZMiStn0ztK/iDm8oDkEZ/BHZzIJPK75hNysyb9t KW4sRQvBHvP9bC5MQsHmhjepBNNhnBadNWXBURRYUvP8aehUba922uv+nOFRi4Qroa4E vI7s5MSIKnHvyd2LucUXnN1KkoaE9zlb+uU0RpLuJ85SUcVIwpzrP3tYq3RXh6uBpCBU YZV6c6JTZih44iag2gQV7HdqoOCVhI0PD19epFz4420XausZtLTBRn3NXmFUGgl8zlPt L4kA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=wqyV5bnob1EDeD3MLOkag73dzR4W/9B3ZPx/+wVh2uQ=; fh=nwNxTtLLPTU0ewfLM7SSbrjMajMl+wwnFkCY/fi90vE=; b=dlF2PnLKNiZNnxlmDDkiJsNa3AuWmEiTVLMugKS//r4syLh0Nl1jGHUnFRe5o6QG1e DRltGXR7/t+Y9NKfOCb0UHgk1Cc68zYzTV0ByvWWSJWKz3wQZ4nuuhTgOpoqy+MwCA6p pYmz4k7uQdGSU47Dh4rPU08FMhqh88NV6834H9AUKG8GgNgRbFYwsXuOvQxmskrsz6yB LEWw1zR2h2FYtWJjhKl9P4VhEBuv6d3SoHzBQ+ikczdfzNpUOuyi3ecjMtkfmxRmEKBr NONBEtS2p5zWHcUtnxJ4tsxig4JwOjBDEvkXwFr7WPntNJEvfOkfqgIgytJ6dmWHg2EZ 3sAw==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1774026202; x=1774631002; darn=lists.postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=wqyV5bnob1EDeD3MLOkag73dzR4W/9B3ZPx/+wVh2uQ=; b=JsKm45mPH9Qs9OIunoEQoTSysu0Hhes8gsRtJ3Iw4u0I/whhO1EkMxlgmk/RM+x49F uhryfpWoa/zlwm0b0UD32pFcdjAvW9tdDEKgNF2xZjKpeHfBMTiy1ZK46kpNAtoTQKK/ nYpynBkshmPYgwLLyNEWN0PVvKe6DMpgSFUQhmPZdhEwltlNvQXVyUnAHL+0Vu+9MWyH ZG0a7pZEYLY7bzvPw43eUUNgcxtx+traQ2JCZX5aqH0Y0+f8XFrXZbg+MyLOOqeHSJXy sWaNZGqDztYhPZA0XCYBevywuJQG9JmwNKiTpjbIuYHGxgfcrDz+MQDRRzlHrojN7WVS 4kYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774026202; x=1774631002; h=to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wqyV5bnob1EDeD3MLOkag73dzR4W/9B3ZPx/+wVh2uQ=; b=maN5fbZKp7tWYAgRu6xDNYGJ5eHoZ32coUSJvmD28qPV/Ub/82uOJF7HNqdmyUTJgy HvSt35sVCI+94f1FzaqAhl0e4xBUVpKe8hNWdKf5X4not7BrLPXhKKOn4fnLVmF53K+1 Jm0Z6goQ25ZW1OrlMfoF2kenQr+kTbKt+hrUwk2Gwam8iWJFZsgIv2h5IMPwnWqCGZQI VHmUv064WaRAu0GBj/4APk1dO2prvhsVJfz6ToBKOt8c+gBtMVr78ED1nEyakk2pIgcU k8NekSHWYJva7JGzd8KGO53lkY2L0JvdFyw8FgOBTARQtMta0ZOlbPWavFX3tdtZN/WH QNQA== X-Gm-Message-State: AOJu0Yx+/oVRbCqKCN+z+4GBq9cNG484gq2D27PsFBm6vNbXWFpi9PAl 9qD6oGLg7QNjmixvsE3xpq1Zn/ZtIgEZ28kb+pCyoIIUAH68wRA8/XgtyoUJxLLWBXHHZZA6Q5n CbeyW1mLQcvqAA5fZFAFE1Ois6G9z0U+caqrd8pnnwQ== X-Gm-Gg: ATEYQzwhcDbSRvdciO0AAikK4wu+TG7IbEuq8dvKae9WnLINFLSv24gLGepsDo0ljy5 S5N2vrolT0OPPB80fJ1YdaFlMsRD+dHulV51kHIsOyUOopgjvnTjp2j8xtHO/65yivnOWIRH0Pd MSPA/9EbkHbMKUz8MiplwJyIRKW2SQ8DYVQGQgCrBMjp7APYOwVvl+XPYDwL6LO4q8lAWUoLnUJ uYygOE7gGoEgrtWXsHu5QdPqflNJ0oeOdRJEACF+z+wgFULZsoJGkUP+oureiPzZ7HosWOnMzvO 5evh6i6GnRK0fh+zft6bkM4OqXscz/Sqs0S78LQ= X-Received: by 2002:a17:907:3944:b0:b97:a950:84cc with SMTP id a640c23a62f3a-b982f3023a0mr273422566b.37.1774026201828; Fri, 20 Mar 2026 10:03:21 -0700 (PDT) MIME-Version: 1.0 From: Jianghua Yang Date: Fri, 20 Mar 2026 10:02:44 -0700 X-Gm-Features: AaiRm50JfH1UEUqOse1J6N3HOeQ4DQqtw0jRuwygl3mpQjCM0CrEzhTaQN7oVmc Message-ID: Subject: basebackup: add missing deflateEnd() in gzip compression sink To: pgsql-hackers@lists.postgresql.org Content-Type: multipart/mixed; boundary="000000000000954c52064d77a91e" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000954c52064d77a91e Content-Type: multipart/alternative; boundary="000000000000954c51064d77a91c" --000000000000954c51064d77a91c Content-Type: text/plain; charset="UTF-8" Hi hackers, While reviewing the backup compression backends, I noticed that the gzip sink (basebackup_gzip.c) never calls deflateEnd(), unlike the lz4 and zstd sinks which properly free their compression contexts. Specifically: - lz4 calls LZ4F_freeCompressionContext() in both end_archive and a dedicated bbsink_lz4_cleanup() callback. - zstd calls ZSTD_freeCCtx() in both end_archive and a dedicated bbsink_zstd_cleanup() callback. - gzip calls deflateInit2() in begin_archive but never calls deflateEnd(). Its cleanup callback is bbsink_forward_cleanup, which just forwards to the next sink without releasing the zlib context. This means each archive (one per tablespace) leaks ~256KB of zlib internal state until the backup's memory context is destroyed. On the ERROR path, the zlib context is not released at all since there is no gzip-specific cleanup callback. The attached patch adds deflateEnd() at the end of bbsink_gzip_end_archive() for the normal path, and introduces a new bbsink_gzip_cleanup() for the error path. The new cleanup callback follows the exact same call chain as bbsink_lz4_cleanup and bbsink_zstd_cleanup: PG_FINALLY (basebackup.c:1063) -> bbsink_cleanup(sink) (basebackup.c:1065) -> sink->bbs_ops->cleanup(sink) (basebackup_sink.h:269) -> bbsink_gzip_cleanup() -- now calls deflateEnd() Previously the gzip slot in this chain pointed to bbsink_forward_cleanup, which just forwarded to the next sink without doing any gzip-specific resource release. Since z_stream is an embedded struct (not a pointer like LZ4F_cctx or ZSTD_CCtx), a bool flag "zstream_initialized" is used to track whether deflateEnd() needs to be called. Tested with pg_basebackup using gzip compression at levels 1, 5 (default), and 9, including server-side compression. All produced valid .tar.gz files that pass gzip -t integrity checks and restore correctly. Regards, Jianghua Yang --000000000000954c51064d77a91c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi hackers,

=C2=A0 While reviewing the backup compr= ession backends, I noticed that the gzip
=C2=A0 sink (basebackup_gzip.c)= never calls deflateEnd(), unlike the lz4 and
=C2=A0 zstd sinks which pr= operly free their compression contexts.

=C2=A0 Specifically:

= =C2=A0 - lz4 calls LZ4F_freeCompressionContext() in both end_archive and a<= br>=C2=A0 =C2=A0 dedicated bbsink_lz4_cleanup() callback.
=C2=A0 - zstd = calls ZSTD_freeCCtx() in both end_archive and a dedicated
=C2=A0 =C2=A0 = bbsink_zstd_cleanup() callback.
=C2=A0 - gzip calls deflateInit2() in be= gin_archive but never calls
=C2=A0 =C2=A0 deflateEnd(). Its cleanup call= back is bbsink_forward_cleanup,
=C2=A0 =C2=A0 which just forwards to the= next sink without releasing the zlib
=C2=A0 =C2=A0 context.

=C2= =A0 This means each archive (one per tablespace) leaks ~256KB of zlib
= =C2=A0 internal state until the backup's memory context is destroyed. O= n the
=C2=A0 ERROR path, the zlib context is not released at all since t= here is no
=C2=A0 gzip-specific cleanup callback.

=C2=A0 The atta= ched patch adds deflateEnd() at the end of
=C2=A0 bbsink_gzip_end_archiv= e() for the normal path, and introduces a new
=C2=A0 bbsink_gzip_cleanup= () for the error path. The new cleanup callback
=C2=A0 follows the exact= same call chain as bbsink_lz4_cleanup and
=C2=A0 bbsink_zstd_cleanup:
=C2=A0 =C2=A0 PG_FINALLY =C2=A0(basebackup.c:1063)
=C2=A0 =C2=A0 = =C2=A0 -> bbsink_cleanup(sink) =C2=A0(basebackup.c:1065)
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 -> sink->bbs_ops->cleanup(sink) =C2=A0(basebacku= p_sink.h:269)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 -> bbsink_gzip_clean= up() =C2=A0-- now calls deflateEnd()

=C2=A0 Previously the gzip slot= in this chain pointed to
=C2=A0 bbsink_forward_cleanup, which just forw= arded to the next sink
=C2=A0 without doing any gzip-specific resource r= elease.

=C2=A0 Since z_stream is an embedded struct (not a pointer l= ike LZ4F_cctx or
=C2=A0 ZSTD_CCtx), a bool flag "zstream_initialize= d" is used to track whether
=C2=A0 deflateEnd() needs to be called.=

=C2=A0 Tested with pg_basebackup using gzip compression at levels 1= , 5
=C2=A0 (default), and 9, including server-side compression. All prod= uced
=C2=A0 valid .tar.gz files that pass gzip -t integrity checks and r= estore
=C2=A0 correctly.

=C2=A0 Regards,
=C2=A0 Jianghua Yang<= /div> --000000000000954c51064d77a91c-- --000000000000954c52064d77a91e Content-Type: application/octet-stream; name="0001-basebackup-add-missing-deflateEnd-calls-in-gzip-comp.patch" Content-Disposition: attachment; filename="0001-basebackup-add-missing-deflateEnd-calls-in-gzip-comp.patch" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_mmz5cp1w0 RnJvbSA1ZDFlZGVjZWFmZDQyMjA3MmMxNzAyNmRmZDFmODYyYTE5ZmViNzkyIE1vbiBTZXAgMTcg MDA6MDA6MDAgMjAwMQpGcm9tOiBKaWFuZ2h1YSBZYW5nIDx5amhqc3R6QGdtYWlsLmNvbT4KRGF0 ZTogRnJpLCAyMCBNYXIgMjAyNiAwOTo1NzoxNyAtMDcwMApTdWJqZWN0OiBbUEFUQ0hdIGJhc2Vi YWNrdXA6IGFkZCBtaXNzaW5nIGRlZmxhdGVFbmQoKSBjYWxscyBpbiBnemlwCiBjb21wcmVzc2lv biBzaW5rCgpUaGUgZ3ppcCBiYXNlYmFja3VwIHNpbmsgY2FsbGVkIGRlZmxhdGVJbml0MigpIGlu IGJlZ2luX2FyY2hpdmUgYnV0Cm5ldmVyIGNhbGxlZCBkZWZsYXRlRW5kKCksIGxlYWtpbmcgemxp YidzIGludGVybmFsIGNvbXByZXNzaW9uIHN0YXRlCih+MjU2S0IgcGVyIGFyY2hpdmUpIHVudGls IHRoZSBtZW1vcnkgY29udGV4dCB3YXMgZGVzdHJveWVkLiBJdCBhbHNvCmxhY2tlZCBhIGRlZGlj YXRlZCBjbGVhbnVwIGNhbGxiYWNrLCBzbyBvbiBFUlJPUiB0aGUgemxpYiBjb250ZXh0CndhcyBu b3QgcmVsZWFzZWQgYXQgYWxsLgoKQWRkIGRlZmxhdGVFbmQoKSBhdCB0aGUgZW5kIG9mIGJic2lu a19nemlwX2VuZF9hcmNoaXZlKCkgZm9yIHRoZQpub3JtYWwgcGF0aCwgYW5kIGFkZCBhIG5ldyBi YnNpbmtfZ3ppcF9jbGVhbnVwKCkgZnVuY3Rpb24gZm9yIHRoZQplcnJvciBwYXRoLiAgVGhpcyBi cmluZ3MgdGhlIGd6aXAgc2luayBpbiBsaW5lIHdpdGggdGhlIGx6NCBhbmQgenN0ZApzaW5rcywg d2hpY2ggYWxyZWFkeSBwcm9wZXJseSBmcmVlIHRoZWlyIGNvbXByZXNzaW9uIGNvbnRleHRzIGlu IGJvdGgKZW5kX2FyY2hpdmUgYW5kIGNsZWFudXAgY2FsbGJhY2tzLgoKQXV0aG9yOiBKaWFuZ2h1 YSBZYW5nIDxqaWFuZ2h1YS55amhAYWxpYmFiYS1pbmMuY29tPgotLS0KIHNyYy9iYWNrZW5kL2Jh Y2t1cC9iYXNlYmFja3VwX2d6aXAuYyB8IDI3ICsrKysrKysrKysrKysrKysrKysrKysrKysrLQog MSBmaWxlIGNoYW5nZWQsIDI2IGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24oLSkKCmRpZmYgLS1n aXQgYS9zcmMvYmFja2VuZC9iYWNrdXAvYmFzZWJhY2t1cF9nemlwLmMgYi9zcmMvYmFja2VuZC9i YWNrdXAvYmFzZWJhY2t1cF9nemlwLmMKaW5kZXggMWJhMjUwMTVhYjcuLmMyNjRhODMzNDI5IDEw MDY0NAotLS0gYS9zcmMvYmFja2VuZC9iYWNrdXAvYmFzZWJhY2t1cF9nemlwLmMKKysrIGIvc3Jj L2JhY2tlbmQvYmFja3VwL2Jhc2ViYWNrdXBfZ3ppcC5jCkBAIC0zMiw2ICszMiw5IEBAIHR5cGVk ZWYgc3RydWN0IGJic2lua19nemlwCiAKIAkvKiBOdW1iZXIgb2YgYnl0ZXMgc3RhZ2VkIGluIG91 dHB1dCBidWZmZXIuICovCiAJc2l6ZV90CQlieXRlc193cml0dGVuOworCisJLyogSGFzIHRoZSB6 c3RyZWFtIGJlZW4gaW5pdGlhbGl6ZWQgd2l0aCBkZWZsYXRlSW5pdDI/ICovCisJYm9vbAkJenN0 cmVhbV9pbml0aWFsaXplZDsKIH0gYmJzaW5rX2d6aXA7CiAKIHN0YXRpYyB2b2lkIGJic2lua19n emlwX2JlZ2luX2JhY2t1cChiYnNpbmsgKnNpbmspOwpAQCAtMzksNiArNDIsNyBAQCBzdGF0aWMg dm9pZCBiYnNpbmtfZ3ppcF9iZWdpbl9hcmNoaXZlKGJic2luayAqc2luaywgY29uc3QgY2hhciAq YXJjaGl2ZV9uYW1lKTsKIHN0YXRpYyB2b2lkIGJic2lua19nemlwX2FyY2hpdmVfY29udGVudHMo YmJzaW5rICpzaW5rLCBzaXplX3QgbGVuKTsKIHN0YXRpYyB2b2lkIGJic2lua19nemlwX21hbmlm ZXN0X2NvbnRlbnRzKGJic2luayAqc2luaywgc2l6ZV90IGxlbik7CiBzdGF0aWMgdm9pZCBiYnNp bmtfZ3ppcF9lbmRfYXJjaGl2ZShiYnNpbmsgKnNpbmspOworc3RhdGljIHZvaWQgYmJzaW5rX2d6 aXBfY2xlYW51cChiYnNpbmsgKnNpbmspOwogc3RhdGljIHZvaWQgKmd6aXBfcGFsbG9jKHZvaWQg Km9wYXF1ZSwgdW5zaWduZWQgaXRlbXMsIHVuc2lnbmVkIHNpemUpOwogc3RhdGljIHZvaWQgZ3pp cF9wZnJlZSh2b2lkICpvcGFxdWUsIHZvaWQgKmFkZHJlc3MpOwogCkBAIC01MSw3ICs1NSw3IEBA IHN0YXRpYyBjb25zdCBiYnNpbmtfb3BzIGJic2lua19nemlwX29wcyA9IHsKIAkubWFuaWZlc3Rf Y29udGVudHMgPSBiYnNpbmtfZ3ppcF9tYW5pZmVzdF9jb250ZW50cywKIAkuZW5kX21hbmlmZXN0 ID0gYmJzaW5rX2ZvcndhcmRfZW5kX21hbmlmZXN0LAogCS5lbmRfYmFja3VwID0gYmJzaW5rX2Zv cndhcmRfZW5kX2JhY2t1cCwKLQkuY2xlYW51cCA9IGJic2lua19mb3J3YXJkX2NsZWFudXAKKwku Y2xlYW51cCA9IGJic2lua19nemlwX2NsZWFudXAKIH07CiAjZW5kaWYKIApAQCAtMTQxLDYgKzE0 NSw3IEBAIGJic2lua19nemlwX2JlZ2luX2FyY2hpdmUoYmJzaW5rICpzaW5rLCBjb25zdCBjaGFy ICphcmNoaXZlX25hbWUpCiAJCWVyZXBvcnQoRVJST1IsCiAJCQkJZXJyY29kZShFUlJDT0RFX0lO VEVSTkFMX0VSUk9SKSwKIAkJCQllcnJtc2coImNvdWxkIG5vdCBpbml0aWFsaXplIGNvbXByZXNz aW9uIGxpYnJhcnkiKSk7CisJbXlzaW5rLT56c3RyZWFtX2luaXRpYWxpemVkID0gdHJ1ZTsKIAog CS8qCiAJICogQWRkICIuZ3oiIHRvIHRoZSBhcmNoaXZlIG5hbWUuIE5vdGUgdGhhdCB0aGUgcGdf YmFzZWJhY2t1cCAteiBwcm9kdWNlcwpAQCAtMjY2LDYgKzI3MSwxMCBAQCBiYnNpbmtfZ3ppcF9l bmRfYXJjaGl2ZShiYnNpbmsgKnNpbmspCiAJCW15c2luay0+Ynl0ZXNfd3JpdHRlbiA9IDA7CiAJ fQogCisJLyogUmVsZWFzZSB0aGUgY29tcHJlc3Npb24gcmVzb3VyY2VzLiAqLworCWRlZmxhdGVF bmQoenMpOworCW15c2luay0+enN0cmVhbV9pbml0aWFsaXplZCA9IGZhbHNlOworCiAJLyogTXVz dCBhbHNvIHBhc3Mgb24gdGhlIGluZm9ybWF0aW9uIHRoYXQgdGhpcyBhcmNoaXZlIGhhcyBlbmRl ZC4gKi8KIAliYnNpbmtfZm9yd2FyZF9lbmRfYXJjaGl2ZShzaW5rKTsKIH0KQEAgLTMwMSw0ICsz MTAsMjAgQEAgZ3ppcF9wZnJlZSh2b2lkICpvcGFxdWUsIHZvaWQgKmFkZHJlc3MpCiAJcGZyZWUo YWRkcmVzcyk7CiB9CiAKKy8qCisgKiBJbiBjYXNlIHRoZSBiYWNrdXAgZmFpbHMsIG1ha2Ugc3Vy ZSB3ZSBmcmVlIHRoZSBjb21wcmVzc2lvbiBjb250ZXh0IGJ5CisgKiBjYWxsaW5nIGRlZmxhdGVF bmQoKSBpZiBuZWVkZWQgdG8gYXZvaWQgYSByZXNvdXJjZSBsZWFrLgorICovCitzdGF0aWMgdm9p ZAorYmJzaW5rX2d6aXBfY2xlYW51cChiYnNpbmsgKnNpbmspCit7CisJYmJzaW5rX2d6aXAgKm15 c2luayA9IChiYnNpbmtfZ3ppcCAqKSBzaW5rOworCisJaWYgKG15c2luay0+enN0cmVhbV9pbml0 aWFsaXplZCkKKwl7CisJCWRlZmxhdGVFbmQoJm15c2luay0+enN0cmVhbSk7CisJCW15c2luay0+ enN0cmVhbV9pbml0aWFsaXplZCA9IGZhbHNlOworCX0KK30KKwogI2VuZGlmCi0tIAoyLjUwLjEg KEFwcGxlIEdpdC0xNTUpCgo= --000000000000954c52064d77a91e--