/*
* 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.
*
*/
#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)
{
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);
}
}
}
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);