diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c index 54c9caffe3f..a49794845d2 100644 --- a/src/backend/access/gin/ginpostinglist.c +++ b/src/backend/access/gin/ginpostinglist.c @@ -23,25 +23,32 @@ /* * For encoding purposes, item pointers are represented as 64-bit unsigned * integers. The lowest 11 bits represent the offset number, and the next - * lowest 32 bits are the block number. That leaves 17 bits unused, i.e. + * lowest 32 bits are the block number. That leaves 21 bits unused, i.e. * only 43 low bits are used. * + * 11 bits is enough for the offset number, because MaxHeapTuplesPerPage < + * 2^11 on all supported block sizes. We are frugal with the bits, because + * smaller integers use fewer bytes in the varbyte encoding, saving disk + * space. (If we get a new table AM in the future that wants to use the full + * range of possible offset numbers, we'll need to change this.) + * * These 43-bit integers are encoded using varbyte encoding. In each byte, * the 7 low bits contain data, while the highest bit is a continuation bit. * When the continuation bit is set, the next byte is part of the same - * integer, otherwise this is the last byte of this integer. 43 bits fit - * conveniently in at most 6 bytes when varbyte encoded (the 6th byte does - * not need a continuation bit, because we know the max size to be 43 bits): + * integer, otherwise this is the last byte of this integer. 43 bits need + * at most 7 bytes in this encoding: * * 0XXXXXXX * 1XXXXXXX 0XXXXYYY * 1XXXXXXX 1XXXXYYY 0YYYYYYY * 1XXXXXXX 1XXXXYYY 1YYYYYYY 0YYYYYYY * 1XXXXXXX 1XXXXYYY 1YYYYYYY 1YYYYYYY 0YYYYYYY - * 1XXXXXXX 1XXXXYYY 1YYYYYYY 1YYYYYYY 1YYYYYYY YYYYYYYY + * 1XXXXXXX 1XXXXYYY 1YYYYYYY 1YYYYYYY 1YYYYYYY 0YYYYYYY + * 1XXXXXXX 1XXXXYYY 1YYYYYYY 1YYYYYYY 1YYYYYYY 1YYYYYYY 0uuuuuuY * * X = bits used for offset number * Y = bits used for block number + * u = unused bit * * The bytes are in stored in little-endian order. * @@ -73,6 +80,9 @@ */ #define MaxHeapTuplesPerPageBits 11 +/* Max. number of bytes needed to encode the largest supported integer. */ +#define MaxBytesPerInteger 7 + static inline uint64 itemptr_to_uint64(const ItemPointer iptr) { @@ -126,33 +136,40 @@ decode_varbyte(unsigned char **ptr) unsigned char *p = *ptr; uint64 c; + /* 1st byte */ c = *(p++); val = c & 0x7F; if (c & 0x80) { + /* 2nd byte */ c = *(p++); val |= (c & 0x7F) << 7; if (c & 0x80) { + /* 3rd byte */ c = *(p++); val |= (c & 0x7F) << 14; if (c & 0x80) { + /* 4th byte */ c = *(p++); val |= (c & 0x7F) << 21; if (c & 0x80) { + /* 5th byte */ c = *(p++); val |= (c & 0x7F) << 28; if (c & 0x80) { + /* 6th byte */ c = *(p++); val |= (c & 0x7F) << 35; if (c & 0x80) { - /* last byte, no continuation bit */ + /* 7th byte, should not have continuation bit */ c = *(p++); val |= c << 42; + Assert((c & 0x80) == 0); } } } @@ -208,15 +225,15 @@ ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, Assert(val > prev); - if (endptr - ptr >= 6) + if (endptr - ptr >= MaxBytesPerInteger) encode_varbyte(delta, &ptr); else { /* - * There are less than 6 bytes left. Have to check if the next + * There are less than 7 bytes left. Have to check if the next * item fits in that space before writing it out. */ - unsigned char buf[6]; + unsigned char buf[MaxBytesPerInteger]; unsigned char *p = buf; encode_varbyte(delta, &p);