PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pg_lzcompress.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PGLZ_Strategy
 

Macros

#define PGLZ_MAX_OUTPUT(_dlen)   ((_dlen) + 4)
 

Typedefs

typedef struct PGLZ_Strategy PGLZ_Strategy
 

Functions

int32 pglz_compress (const char *source, int32 slen, char *dest, const PGLZ_Strategy *strategy)
 
int32 pglz_decompress (const char *source, int32 slen, char *dest, int32 rawsize)
 

Variables

const PGLZ_Strategy *const PGLZ_strategy_default
 
const PGLZ_Strategy *const PGLZ_strategy_always
 

Macro Definition Documentation

#define PGLZ_MAX_OUTPUT (   _dlen)    ((_dlen) + 4)

Definition at line 21 of file pg_lzcompress.h.

Referenced by toast_compress_datum().

Typedef Documentation

Function Documentation

int32 pglz_compress ( const char *  source,
int32  slen,
char *  dest,
const PGLZ_Strategy strategy 
)

Definition at line 503 of file pg_lzcompress.c.

References PGLZ_Strategy::first_success_by, hist_start, PGLZ_Strategy::match_size_drop, PGLZ_Strategy::match_size_good, PGLZ_Strategy::max_input_size, PGLZ_Strategy::min_comp_rate, NULL, pglz_find_match(), pglz_hist_add, PGLZ_MAX_MATCH, pglz_out_literal, pglz_out_tag, and PGLZ_strategy_default.

Referenced by toast_compress_datum(), and XLogCompressBackupBlock().

505 {
506  unsigned char *bp = (unsigned char *) dest;
507  unsigned char *bstart = bp;
508  int hist_next = 1;
509  bool hist_recycle = false;
510  const char *dp = source;
511  const char *dend = source + slen;
512  unsigned char ctrl_dummy = 0;
513  unsigned char *ctrlp = &ctrl_dummy;
514  unsigned char ctrlb = 0;
515  unsigned char ctrl = 0;
516  bool found_match = false;
517  int32 match_len;
518  int32 match_off;
519  int32 good_match;
520  int32 good_drop;
521  int32 result_size;
522  int32 result_max;
523  int32 need_rate;
524  int hashsz;
525  int mask;
526 
527  /*
528  * Our fallback strategy is the default.
529  */
530  if (strategy == NULL)
531  strategy = PGLZ_strategy_default;
532 
533  /*
534  * If the strategy forbids compression (at all or if source chunk size out
535  * of range), fail.
536  */
537  if (strategy->match_size_good <= 0 ||
538  slen < strategy->min_input_size ||
539  slen > strategy->max_input_size)
540  return -1;
541 
542  /*
543  * Limit the match parameters to the supported range.
544  */
545  good_match = strategy->match_size_good;
546  if (good_match > PGLZ_MAX_MATCH)
547  good_match = PGLZ_MAX_MATCH;
548  else if (good_match < 17)
549  good_match = 17;
550 
551  good_drop = strategy->match_size_drop;
552  if (good_drop < 0)
553  good_drop = 0;
554  else if (good_drop > 100)
555  good_drop = 100;
556 
557  need_rate = strategy->min_comp_rate;
558  if (need_rate < 0)
559  need_rate = 0;
560  else if (need_rate > 99)
561  need_rate = 99;
562 
563  /*
564  * Compute the maximum result size allowed by the strategy, namely the
565  * input size minus the minimum wanted compression rate. This had better
566  * be <= slen, else we might overrun the provided output buffer.
567  */
568  if (slen > (INT_MAX / 100))
569  {
570  /* Approximate to avoid overflow */
571  result_max = (slen / 100) * (100 - need_rate);
572  }
573  else
574  result_max = (slen * (100 - need_rate)) / 100;
575 
576  /*
577  * Experiments suggest that these hash sizes work pretty well. A large
578  * hash table minimizes collision, but has a higher startup cost. For a
579  * small input, the startup cost dominates. The table size must be a power
580  * of two.
581  */
582  if (slen < 128)
583  hashsz = 512;
584  else if (slen < 256)
585  hashsz = 1024;
586  else if (slen < 512)
587  hashsz = 2048;
588  else if (slen < 1024)
589  hashsz = 4096;
590  else
591  hashsz = 8192;
592  mask = hashsz - 1;
593 
594  /*
595  * Initialize the history lists to empty. We do not need to zero the
596  * hist_entries[] array; its entries are initialized as they are used.
597  */
598  memset(hist_start, 0, hashsz * sizeof(int16));
599 
600  /*
601  * Compress the source directly into the output buffer.
602  */
603  while (dp < dend)
604  {
605  /*
606  * If we already exceeded the maximum result size, fail.
607  *
608  * We check once per loop; since the loop body could emit as many as 4
609  * bytes (a control byte and 3-byte tag), PGLZ_MAX_OUTPUT() had better
610  * allow 4 slop bytes.
611  */
612  if (bp - bstart >= result_max)
613  return -1;
614 
615  /*
616  * If we've emitted more than first_success_by bytes without finding
617  * anything compressible at all, fail. This lets us fall out
618  * reasonably quickly when looking at incompressible input (such as
619  * pre-compressed data).
620  */
621  if (!found_match && bp - bstart >= strategy->first_success_by)
622  return -1;
623 
624  /*
625  * Try to find a match in the history
626  */
627  if (pglz_find_match(hist_start, dp, dend, &match_len,
628  &match_off, good_match, good_drop, mask))
629  {
630  /*
631  * Create the tag and add history entries for all matched
632  * characters.
633  */
634  pglz_out_tag(ctrlp, ctrlb, ctrl, bp, match_len, match_off);
635  while (match_len--)
636  {
638  hist_next, hist_recycle,
639  dp, dend, mask);
640  dp++; /* Do not do this ++ in the line above! */
641  /* The macro would do it four times - Jan. */
642  }
643  found_match = true;
644  }
645  else
646  {
647  /*
648  * No match found. Copy one literal byte.
649  */
650  pglz_out_literal(ctrlp, ctrlb, ctrl, bp, *dp);
652  hist_next, hist_recycle,
653  dp, dend, mask);
654  dp++; /* Do not do this ++ in the line above! */
655  /* The macro would do it four times - Jan. */
656  }
657  }
658 
659  /*
660  * Write out the last control byte and check that we haven't overrun the
661  * output size allowed by the strategy.
662  */
663  *ctrlp = ctrlb;
664  result_size = bp - bstart;
665  if (result_size >= result_max)
666  return -1;
667 
668  /* success */
669  return result_size;
670 }
signed short int16
Definition: c.h:252
#define pglz_hist_add(_hs, _he, _hn, _recycle, _s, _e, _mask)
static PGLZ_HistEntry hist_entries[PGLZ_HISTORY_SIZE+1]
signed int int32
Definition: c.h:253
int32 first_success_by
Definition: pg_lzcompress.h:62
int32 match_size_good
Definition: pg_lzcompress.h:63
#define pglz_out_tag(_ctrlp, _ctrlb, _ctrl, _buf, _len, _off)
int32 match_size_drop
Definition: pg_lzcompress.h:64
static int16 hist_start[PGLZ_MAX_HISTORY_LISTS]
static int pglz_find_match(int16 *hstart, const char *input, const char *end, int *lenp, int *offp, int good_match, int good_drop, int mask)
#define pglz_out_literal(_ctrlp, _ctrlb, _ctrl, _buf, _byte)
#define PGLZ_MAX_MATCH
#define NULL
Definition: c.h:226
int32 max_input_size
Definition: pg_lzcompress.h:60
const PGLZ_Strategy *const PGLZ_strategy_default
int32 min_comp_rate
Definition: pg_lzcompress.h:61
int32 pglz_decompress ( const char *  source,
int32  slen,
char *  dest,
int32  rawsize 
)

Definition at line 682 of file pg_lzcompress.c.

Referenced by RestoreBlockImage(), and toast_decompress_datum().

684 {
685  const unsigned char *sp;
686  const unsigned char *srcend;
687  unsigned char *dp;
688  unsigned char *destend;
689 
690  sp = (const unsigned char *) source;
691  srcend = ((const unsigned char *) source) + slen;
692  dp = (unsigned char *) dest;
693  destend = dp + rawsize;
694 
695  while (sp < srcend && dp < destend)
696  {
697  /*
698  * Read one control byte and process the next 8 items (or as many as
699  * remain in the compressed input).
700  */
701  unsigned char ctrl = *sp++;
702  int ctrlc;
703 
704  for (ctrlc = 0; ctrlc < 8 && sp < srcend; ctrlc++)
705  {
706  if (ctrl & 1)
707  {
708  /*
709  * Otherwise it contains the match length minus 3 and the
710  * upper 4 bits of the offset. The next following byte
711  * contains the lower 8 bits of the offset. If the length is
712  * coded as 18, another extension tag byte tells how much
713  * longer the match really was (0-255).
714  */
715  int32 len;
716  int32 off;
717 
718  len = (sp[0] & 0x0f) + 3;
719  off = ((sp[0] & 0xf0) << 4) | sp[1];
720  sp += 2;
721  if (len == 18)
722  len += *sp++;
723 
724  /*
725  * Check for output buffer overrun, to ensure we don't clobber
726  * memory in case of corrupt input. Note: we must advance dp
727  * here to ensure the error is detected below the loop. We
728  * don't simply put the elog inside the loop since that will
729  * probably interfere with optimization.
730  */
731  if (dp + len > destend)
732  {
733  dp += len;
734  break;
735  }
736 
737  /*
738  * Now we copy the bytes specified by the tag from OUTPUT to
739  * OUTPUT. It is dangerous and platform dependent to use
740  * memcpy() here, because the copied areas could overlap
741  * extremely!
742  */
743  while (len--)
744  {
745  *dp = dp[-off];
746  dp++;
747  }
748  }
749  else
750  {
751  /*
752  * An unset control bit means LITERAL BYTE. So we just copy
753  * one from INPUT to OUTPUT.
754  */
755  if (dp >= destend) /* check for buffer overrun */
756  break; /* do not clobber memory */
757 
758  *dp++ = *sp++;
759  }
760 
761  /*
762  * Advance the control bit
763  */
764  ctrl >>= 1;
765  }
766  }
767 
768  /*
769  * Check we decompressed the right amount.
770  */
771  if (dp != destend || sp != srcend)
772  return -1;
773 
774  /*
775  * That's it.
776  */
777  return rawsize;
778 }
signed int int32
Definition: c.h:253

Variable Documentation

const PGLZ_Strategy* const PGLZ_strategy_always

Definition at line 242 of file pg_lzcompress.c.

const PGLZ_Strategy* const PGLZ_strategy_default

Definition at line 230 of file pg_lzcompress.c.

Referenced by pglz_compress(), toast_compress_datum(), and XLogCompressBackupBlock().