diff --git a/src/backend/access/common/toast_compression.c b/src/backend/access/common/toast_compression.c index 849ec174539..ef7c65e1276 100644 --- a/src/backend/access/common/toast_compression.c +++ b/src/backend/access/common/toast_compression.c @@ -29,6 +29,30 @@ /* GUC */ int default_toast_compression = DEFAULT_TOAST_COMPRESSION; +#ifdef USE_ZSTD +/* + * zstd decompression context, created on first use and kept for the life of + * the backend. Creating one per value costs more than decompressing a small + * value. It is reset at the start of each use, so an error in the middle of + * a decompression leaves nothing behind that matters. + */ +static ZSTD_DCtx *zstd_dctx = NULL; + +static ZSTD_DCtx * +zstd_get_dctx(void) +{ + if (zstd_dctx == NULL) + { + zstd_dctx = ZSTD_createDCtx(); + if (zstd_dctx == NULL) + elog(ERROR, "could not create zstd decompression context"); + } + else + ZSTD_DCtx_reset(zstd_dctx, ZSTD_reset_session_only); + return zstd_dctx; +} +#endif + #define NO_COMPRESSION_SUPPORT(method) \ ereport(ERROR, \ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ @@ -327,7 +351,8 @@ zstd_decompress_datum(const varlena *value) result = (varlena *) palloc(VARDATA_COMPRESSED_GET_EXTSIZE(value) + VARHDRSZ); /* decompress the data */ - rawsize = ZSTD_decompress(VARDATA(result), + rawsize = ZSTD_decompressDCtx(zstd_get_dctx(), + VARDATA(result), VARDATA_COMPRESSED_GET_EXTSIZE(value), (const char *) value + VARHDRSZ_COMPRESSED_LONG, VARSIZE(value) - VARHDRSZ_COMPRESSED_LONG); @@ -374,9 +399,7 @@ zstd_decompress_datum_slice(const varlena *value, int32 slicelength) */ result = (varlena *) palloc(slicelength + VARHDRSZ); - dctx = ZSTD_createDCtx(); - if (dctx == NULL) - elog(ERROR, "could not create zstd decompression context"); + dctx = zstd_get_dctx(); inbuf.src = (const char *) value + VARHDRSZ_COMPRESSED_LONG; inbuf.size = VARSIZE(value) - VARHDRSZ_COMPRESSED_LONG; @@ -409,9 +432,6 @@ zstd_decompress_datum_slice(const varlena *value, int32 slicelength) } } - /* release the context before any possible error is thrown */ - ZSTD_freeDCtx(dctx); - if (failed) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),