diff options
Diffstat (limited to 'src/backend/access/heap/tuptoaster.c')
-rw-r--r-- | src/backend/access/heap/tuptoaster.c | 87 |
1 files changed, 65 insertions, 22 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 2d53c8e5ff7..d19e7220c54 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -35,9 +35,9 @@ #include "access/tuptoaster.h" #include "access/xact.h" #include "catalog/catalog.h" +#include "common/pg_lzcompress.h" #include "miscadmin.h" #include "utils/fmgroids.h" -#include "utils/pg_lzcompress.h" #include "utils/rel.h" #include "utils/typcache.h" #include "utils/tqual.h" @@ -45,6 +45,26 @@ #undef TOAST_DEBUG +/* + * The information at the start of the compressed toast data. + */ +typedef struct toast_compress_header +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 rawsize; +} toast_compress_header; + +/* + * Utilities for manipulation of header information for compressed + * toast entries. + */ +#define TOAST_COMPRESS_HDRSZ ((int32) sizeof(toast_compress_header)) +#define TOAST_COMPRESS_RAWSIZE(ptr) (((toast_compress_header *) ptr)->rawsize) +#define TOAST_COMPRESS_RAWDATA(ptr) \ + (((char *) ptr) + TOAST_COMPRESS_HDRSZ) +#define TOAST_COMPRESS_SET_RAWSIZE(ptr, len) \ + (((toast_compress_header *) ptr)->rawsize = len) + static void toast_delete_datum(Relation rel, Datum value); static Datum toast_save_datum(Relation rel, Datum value, struct varlena * oldexternal, int options); @@ -53,6 +73,7 @@ static bool toastid_valueid_exists(Oid toastrelid, Oid valueid); static struct varlena *toast_fetch_datum(struct varlena * attr); static struct varlena *toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length); +static struct varlena *toast_decompress_datum(struct varlena * attr); static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, @@ -138,11 +159,8 @@ heap_tuple_untoast_attr(struct varlena * attr) /* If it's compressed, decompress it */ if (VARATT_IS_COMPRESSED(attr)) { - PGLZ_Header *tmp = (PGLZ_Header *) attr; - - attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - pglz_decompress(tmp, VARDATA(attr)); + struct varlena *tmp = attr; + attr = toast_decompress_datum(tmp); pfree(tmp); } } @@ -163,11 +181,7 @@ heap_tuple_untoast_attr(struct varlena * attr) /* * This is a compressed value inside of the main tuple */ - PGLZ_Header *tmp = (PGLZ_Header *) attr; - - attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - pglz_decompress(tmp, VARDATA(attr)); + attr = toast_decompress_datum(attr); } else if (VARATT_IS_SHORT(attr)) { @@ -234,14 +248,10 @@ heap_tuple_untoast_attr_slice(struct varlena * attr, if (VARATT_IS_COMPRESSED(preslice)) { - PGLZ_Header *tmp = (PGLZ_Header *) preslice; - Size size = PGLZ_RAW_SIZE(tmp) + VARHDRSZ; - - preslice = (struct varlena *) palloc(size); - SET_VARSIZE(preslice, size); - pglz_decompress(tmp, VARDATA(preslice)); + struct varlena *tmp = preslice; + preslice = toast_decompress_datum(tmp); - if (tmp != (PGLZ_Header *) attr) + if (tmp != attr) pfree(tmp); } @@ -1228,6 +1238,7 @@ toast_compress_datum(Datum value) { struct varlena *tmp; int32 valsize = VARSIZE_ANY_EXHDR(DatumGetPointer(value)); + int32 len; Assert(!VARATT_IS_EXTERNAL(DatumGetPointer(value))); Assert(!VARATT_IS_COMPRESSED(DatumGetPointer(value))); @@ -1240,7 +1251,8 @@ toast_compress_datum(Datum value) valsize > PGLZ_strategy_default->max_input_size) return PointerGetDatum(NULL); - tmp = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(valsize)); + tmp = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(valsize) + + TOAST_COMPRESS_HDRSZ); /* * We recheck the actual size even if pglz_compress() reports success, @@ -1252,10 +1264,15 @@ toast_compress_datum(Datum value) * only one header byte and no padding if the value is short enough. So * we insist on a savings of more than 2 bytes to ensure we have a gain. */ - if (pglz_compress(VARDATA_ANY(DatumGetPointer(value)), valsize, - (PGLZ_Header *) tmp, PGLZ_strategy_default) && - VARSIZE(tmp) < valsize - 2) + len = pglz_compress(VARDATA_ANY(DatumGetPointer(value)), + valsize, + TOAST_COMPRESS_RAWDATA(tmp), + PGLZ_strategy_default); + if (len >= 0 && + len + TOAST_COMPRESS_HDRSZ < valsize - 2) { + TOAST_COMPRESS_SET_RAWSIZE(tmp, valsize); + SET_VARSIZE_COMPRESSED(tmp, len + TOAST_COMPRESS_HDRSZ); /* successful compression */ return PointerGetDatum(tmp); } @@ -2101,6 +2118,32 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length) } /* ---------- + * toast_decompress_datum - + * + * Decompress a compressed version of a varlena datum + */ +static struct varlena * +toast_decompress_datum(struct varlena * attr) +{ + struct varlena *result; + + Assert(VARATT_IS_COMPRESSED(attr)); + + result = (struct varlena *) + palloc(TOAST_COMPRESS_RAWSIZE(attr) + VARHDRSZ); + SET_VARSIZE(result, TOAST_COMPRESS_RAWSIZE(attr) + VARHDRSZ); + + if (pglz_decompress(TOAST_COMPRESS_RAWDATA(attr), + VARSIZE(attr) - TOAST_COMPRESS_HDRSZ, + VARDATA(result), + TOAST_COMPRESS_RAWSIZE(attr)) < 0) + elog(ERROR, "compressed data is corrupted"); + + return result; +} + + +/* ---------- * toast_open_indexes * * Get an array of the indexes associated to the given toast relation |