LCOV - differential code coverage report
Current view: top level - src/backend/access/common - toast_compression.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 88.9 % 90 80 7 1 2 55 1 24 8 49
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 9 9 9 9
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * toast_compression.c
       4                 :  *    Functions for toast compression.
       5                 :  *
       6                 :  * Copyright (c) 2021-2023, PostgreSQL Global Development Group
       7                 :  *
       8                 :  *
       9                 :  * IDENTIFICATION
      10                 :  *    src/backend/access/common/toast_compression.c
      11                 :  *
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : #include "postgres.h"
      15                 : 
      16                 : #ifdef USE_LZ4
      17                 : #include <lz4.h>
      18                 : #endif
      19                 : 
      20                 : #include "access/detoast.h"
      21                 : #include "access/toast_compression.h"
      22                 : #include "common/pg_lzcompress.h"
      23                 : #include "fmgr.h"
      24                 : #include "utils/builtins.h"
      25                 : #include "varatt.h"
      26                 : 
      27                 : /* GUC */
      28                 : int         default_toast_compression = TOAST_PGLZ_COMPRESSION;
      29                 : 
      30                 : #define NO_LZ4_SUPPORT() \
      31                 :     ereport(ERROR, \
      32                 :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
      33                 :              errmsg("compression method lz4 not supported"), \
      34                 :              errdetail("This functionality requires the server to be built with lz4 support.")))
      35                 : 
      36                 : /*
      37                 :  * Compress a varlena using PGLZ.
      38                 :  *
      39                 :  * Returns the compressed varlena, or NULL if compression fails.
      40                 :  */
      41                 : struct varlena *
      42 GIC       70161 : pglz_compress_datum(const struct varlena *value)
      43 ECB             : {
      44                 :     int32       valsize,
      45                 :                 len;
      46 GIC       70161 :     struct varlena *tmp = NULL;
      47 ECB             : 
      48 GNC       70161 :     valsize = VARSIZE_ANY_EXHDR(value);
      49 ECB             : 
      50                 :     /*
      51                 :      * No point in wasting a palloc cycle if value size is outside the allowed
      52                 :      * range for compression.
      53                 :      */
      54 GIC       70161 :     if (valsize < PGLZ_strategy_default->min_input_size ||
      55 CBC       69161 :         valsize > PGLZ_strategy_default->max_input_size)
      56            1000 :         return NULL;
      57 ECB             : 
      58                 :     /*
      59                 :      * Figure out the maximum possible size of the pglz output, add the bytes
      60                 :      * that will be needed for varlena overhead, and allocate that amount.
      61                 :      */
      62 GIC       69161 :     tmp = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(valsize) +
      63 ECB             :                                     VARHDRSZ_COMPRESSED);
      64                 : 
      65 GIC       69161 :     len = pglz_compress(VARDATA_ANY(value),
      66 ECB             :                         valsize,
      67                 :                         (char *) tmp + VARHDRSZ_COMPRESSED,
      68                 :                         NULL);
      69 GIC       69161 :     if (len < 0)
      70 ECB             :     {
      71 GIC        1775 :         pfree(tmp);
      72 CBC        1775 :         return NULL;
      73 ECB             :     }
      74                 : 
      75 GIC       67386 :     SET_VARSIZE_COMPRESSED(tmp, len + VARHDRSZ_COMPRESSED);
      76 ECB             : 
      77 GIC       67386 :     return tmp;
      78 ECB             : }
      79                 : 
      80                 : /*
      81                 :  * Decompress a varlena that was compressed using PGLZ.
      82                 :  */
      83                 : struct varlena *
      84 GIC       86368 : pglz_decompress_datum(const struct varlena *value)
      85 ECB             : {
      86                 :     struct varlena *result;
      87                 :     int32       rawsize;
      88                 : 
      89                 :     /* allocate memory for the uncompressed data */
      90 GIC       86368 :     result = (struct varlena *) palloc(VARDATA_COMPRESSED_GET_EXTSIZE(value) + VARHDRSZ);
      91 ECB             : 
      92                 :     /* decompress the data */
      93 GIC       86368 :     rawsize = pglz_decompress((char *) value + VARHDRSZ_COMPRESSED,
      94 CBC       86368 :                               VARSIZE(value) - VARHDRSZ_COMPRESSED,
      95           86368 :                               VARDATA(result),
      96           86368 :                               VARDATA_COMPRESSED_GET_EXTSIZE(value), true);
      97           86368 :     if (rawsize < 0)
      98 LBC           0 :         ereport(ERROR,
      99 EUB             :                 (errcode(ERRCODE_DATA_CORRUPTED),
     100                 :                  errmsg_internal("compressed pglz data is corrupt")));
     101                 : 
     102 GIC       86368 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
     103 ECB             : 
     104 GIC       86368 :     return result;
     105 ECB             : }
     106                 : 
     107                 : /*
     108                 :  * Decompress part of a varlena that was compressed using PGLZ.
     109                 :  */
     110                 : struct varlena *
     111 GIC          33 : pglz_decompress_datum_slice(const struct varlena *value,
     112 ECB             :                             int32 slicelength)
     113                 : {
     114                 :     struct varlena *result;
     115                 :     int32       rawsize;
     116                 : 
     117                 :     /* allocate memory for the uncompressed data */
     118 GIC          33 :     result = (struct varlena *) palloc(slicelength + VARHDRSZ);
     119 ECB             : 
     120                 :     /* decompress the data */
     121 GIC          33 :     rawsize = pglz_decompress((char *) value + VARHDRSZ_COMPRESSED,
     122 CBC          33 :                               VARSIZE(value) - VARHDRSZ_COMPRESSED,
     123              33 :                               VARDATA(result),
     124 ECB             :                               slicelength, false);
     125 GIC          33 :     if (rawsize < 0)
     126 LBC           0 :         ereport(ERROR,
     127 EUB             :                 (errcode(ERRCODE_DATA_CORRUPTED),
     128                 :                  errmsg_internal("compressed pglz data is corrupt")));
     129                 : 
     130 GIC          33 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
     131 ECB             : 
     132 GIC          33 :     return result;
     133 ECB             : }
     134                 : 
     135                 : /*
     136                 :  * Compress a varlena using LZ4.
     137                 :  *
     138                 :  * Returns the compressed varlena, or NULL if compression fails.
     139                 :  */
     140                 : struct varlena *
     141 GIC          18 : lz4_compress_datum(const struct varlena *value)
     142 ECB             : {
     143                 : #ifndef USE_LZ4
     144                 :     NO_LZ4_SUPPORT();
     145                 :     return NULL;                /* keep compiler quiet */
     146                 : #else
     147                 :     int32       valsize;
     148                 :     int32       len;
     149                 :     int32       max_size;
     150 GIC          18 :     struct varlena *tmp = NULL;
     151 ECB             : 
     152 GIC          18 :     valsize = VARSIZE_ANY_EXHDR(value);
     153 ECB             : 
     154                 :     /*
     155                 :      * Figure out the maximum possible size of the LZ4 output, add the bytes
     156                 :      * that will be needed for varlena overhead, and allocate that amount.
     157                 :      */
     158 GIC          18 :     max_size = LZ4_compressBound(valsize);
     159 CBC          18 :     tmp = (struct varlena *) palloc(max_size + VARHDRSZ_COMPRESSED);
     160 ECB             : 
     161 GIC          18 :     len = LZ4_compress_default(VARDATA_ANY(value),
     162 ECB             :                                (char *) tmp + VARHDRSZ_COMPRESSED,
     163                 :                                valsize, max_size);
     164 GIC          18 :     if (len <= 0)
     165 LBC           0 :         elog(ERROR, "lz4 compression failed");
     166 EUB             : 
     167                 :     /* data is incompressible so just free the memory and return NULL */
     168 GIC          18 :     if (len > valsize)
     169 ECB             :     {
     170 UIC           0 :         pfree(tmp);
     171 UBC           0 :         return NULL;
     172 EUB             :     }
     173                 : 
     174 GIC          18 :     SET_VARSIZE_COMPRESSED(tmp, len + VARHDRSZ_COMPRESSED);
     175 ECB             : 
     176 GIC          18 :     return tmp;
     177 ECB             : #endif
     178                 : }
     179                 : 
     180                 : /*
     181                 :  * Decompress a varlena that was compressed using LZ4.
     182                 :  */
     183                 : struct varlena *
     184 GIC          52 : lz4_decompress_datum(const struct varlena *value)
     185 ECB             : {
     186                 : #ifndef USE_LZ4
     187                 :     NO_LZ4_SUPPORT();
     188                 :     return NULL;                /* keep compiler quiet */
     189                 : #else
     190                 :     int32       rawsize;
     191                 :     struct varlena *result;
     192                 : 
     193                 :     /* allocate memory for the uncompressed data */
     194 GIC          52 :     result = (struct varlena *) palloc(VARDATA_COMPRESSED_GET_EXTSIZE(value) + VARHDRSZ);
     195 ECB             : 
     196                 :     /* decompress the data */
     197 GIC          52 :     rawsize = LZ4_decompress_safe((char *) value + VARHDRSZ_COMPRESSED,
     198 CBC          52 :                                   VARDATA(result),
     199              52 :                                   VARSIZE(value) - VARHDRSZ_COMPRESSED,
     200              52 :                                   VARDATA_COMPRESSED_GET_EXTSIZE(value));
     201              52 :     if (rawsize < 0)
     202 LBC           0 :         ereport(ERROR,
     203 EUB             :                 (errcode(ERRCODE_DATA_CORRUPTED),
     204                 :                  errmsg_internal("compressed lz4 data is corrupt")));
     205                 : 
     206                 : 
     207 GIC          52 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
     208 ECB             : 
     209 GIC          52 :     return result;
     210 ECB             : #endif
     211                 : }
     212                 : 
     213                 : /*
     214                 :  * Decompress part of a varlena that was compressed using LZ4.
     215                 :  */
     216                 : struct varlena *
     217 GIC           9 : lz4_decompress_datum_slice(const struct varlena *value, int32 slicelength)
     218 ECB             : {
     219                 : #ifndef USE_LZ4
     220                 :     NO_LZ4_SUPPORT();
     221                 :     return NULL;                /* keep compiler quiet */
     222                 : #else
     223                 :     int32       rawsize;
     224                 :     struct varlena *result;
     225                 : 
     226                 :     /* slice decompression not supported prior to 1.8.3 */
     227 GIC           9 :     if (LZ4_versionNumber() < 10803)
     228 LBC           0 :         return lz4_decompress_datum(value);
     229 EUB             : 
     230                 :     /* allocate memory for the uncompressed data */
     231 GIC           9 :     result = (struct varlena *) palloc(slicelength + VARHDRSZ);
     232 ECB             : 
     233                 :     /* decompress the data */
     234 GIC           9 :     rawsize = LZ4_decompress_safe_partial((char *) value + VARHDRSZ_COMPRESSED,
     235 CBC           9 :                                           VARDATA(result),
     236               9 :                                           VARSIZE(value) - VARHDRSZ_COMPRESSED,
     237 ECB             :                                           slicelength,
     238                 :                                           slicelength);
     239 GIC           9 :     if (rawsize < 0)
     240 LBC           0 :         ereport(ERROR,
     241 EUB             :                 (errcode(ERRCODE_DATA_CORRUPTED),
     242                 :                  errmsg_internal("compressed lz4 data is corrupt")));
     243                 : 
     244 GIC           9 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
     245 ECB             : 
     246 GIC           9 :     return result;
     247 ECB             : #endif
     248                 : }
     249                 : 
     250                 : /*
     251                 :  * Extract compression ID from a varlena.
     252                 :  *
     253                 :  * Returns TOAST_INVALID_COMPRESSION_ID if the varlena is not compressed.
     254                 :  */
     255                 : ToastCompressionId
     256 GIC          81 : toast_get_compression_id(struct varlena *attr)
     257 ECB             : {
     258 GIC          81 :     ToastCompressionId cmid = TOAST_INVALID_COMPRESSION_ID;
     259 ECB             : 
     260                 :     /*
     261                 :      * If it is stored externally then fetch the compression method id from
     262                 :      * the external toast pointer.  If compressed inline, fetch it from the
     263                 :      * toast compression header.
     264                 :      */
     265 GIC          81 :     if (VARATT_IS_EXTERNAL_ONDISK(attr))
     266 CBC          12 :     {
     267 ECB             :         struct varatt_external toast_pointer;
     268                 : 
     269 GIC          12 :         VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
     270 ECB             : 
     271 GIC          12 :         if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
     272 CBC          12 :             cmid = VARATT_EXTERNAL_GET_COMPRESS_METHOD(toast_pointer);
     273 ECB             :     }
     274 GIC          69 :     else if (VARATT_IS_COMPRESSED(attr))
     275 CBC          66 :         cmid = VARDATA_COMPRESSED_GET_COMPRESS_METHOD(attr);
     276 ECB             : 
     277 GIC          81 :     return cmid;
     278 ECB             : }
     279                 : 
     280                 : /*
     281                 :  * CompressionNameToMethod - Get compression method from compression name
     282                 :  *
     283                 :  * Search in the available built-in methods.  If the compression not found
     284                 :  * in the built-in methods then return InvalidCompressionMethod.
     285                 :  */
     286                 : char
     287 GIC          68 : CompressionNameToMethod(const char *compression)
     288 ECB             : {
     289 GIC          68 :     if (strcmp(compression, "pglz") == 0)
     290 CBC          30 :         return TOAST_PGLZ_COMPRESSION;
     291              38 :     else if (strcmp(compression, "lz4") == 0)
     292 ECB             :     {
     293                 : #ifndef USE_LZ4
     294                 :         NO_LZ4_SUPPORT();
     295                 : #endif
     296 GIC          32 :         return TOAST_LZ4_COMPRESSION;
     297 ECB             :     }
     298                 : 
     299 GIC           6 :     return InvalidCompressionMethod;
     300 ECB             : }
     301                 : 
     302                 : /*
     303                 :  * GetCompressionMethodName - Get compression method name
     304                 :  */
     305                 : const char *
     306 GIC          15 : GetCompressionMethodName(char method)
     307 ECB             : {
     308 GIC          15 :     switch (method)
     309 ECB             :     {
     310 GIC           6 :         case TOAST_PGLZ_COMPRESSION:
     311 CBC           6 :             return "pglz";
     312               9 :         case TOAST_LZ4_COMPRESSION:
     313               9 :             return "lz4";
     314 LBC           0 :         default:
     315 UBC           0 :             elog(ERROR, "invalid compression method %c", method);
     316 EUB             :             return NULL;        /* keep compiler quiet */
     317                 :     }
     318                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a