From b9bd5c82336decc3124b10a6d34d8222d0dd487f Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Wed, 8 Mar 2017 13:49:22 -0300
Subject: [PATCH 4/6] freeup 3bits ip_posid v16

---
 src/backend/access/gin/ginget.c         |  2 +-
 src/backend/access/gin/ginpostinglist.c |  2 +-
 src/include/access/ginblock.h           | 10 +++++-----
 src/include/access/gist_private.h       |  4 ++--
 src/include/access/htup_details.h       |  2 +-
 src/include/storage/itemptr.h           | 32 ++++++++++++++++++++++++++++----
 src/include/storage/off.h               |  9 ++++++++-
 7 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index aa0b02f..1e1c978 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -928,7 +928,7 @@ keyGetItem(GinState *ginstate, MemoryContext tempCtx, GinScanKey key,
 	 * Find the minimum item > advancePast among the active entry streams.
 	 *
 	 * Note: a lossy-page entry is encoded by a ItemPointer with max value for
-	 * offset (0xffff), so that it will sort after any exact entries for the
+	 * offset (0x1fff), so that it will sort after any exact entries for the
 	 * same page.  So we'll prefer to return exact pointers not lossy
 	 * pointers, which is good.
 	 */
diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c
index 8d2d31a..b22b9f5 100644
--- a/src/backend/access/gin/ginpostinglist.c
+++ b/src/backend/access/gin/ginpostinglist.c
@@ -253,7 +253,7 @@ ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize,
 
 		Assert(ndecoded == totalpacked);
 		for (i = 0; i < ndecoded; i++)
-			Assert(memcmp(&tmp[i], &ipd[i], sizeof(ItemPointerData)) == 0);
+			Assert(ItemPointerEquals(&tmp[i], &ipd[i]));
 		pfree(tmp);
 	}
 #endif
diff --git a/src/include/access/ginblock.h b/src/include/access/ginblock.h
index 438912c..3f7a3f0 100644
--- a/src/include/access/ginblock.h
+++ b/src/include/access/ginblock.h
@@ -160,14 +160,14 @@ typedef struct GinMetaPageData
 	(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0 && \
 	 GinItemPointerGetBlockNumber(p) == (BlockNumber)0)
 #define ItemPointerSetMax(p)  \
-	ItemPointerSet((p), InvalidBlockNumber, (OffsetNumber)0xffff)
+	ItemPointerSet((p), InvalidBlockNumber, (OffsetNumber)OffsetNumberMask)
 #define ItemPointerIsMax(p)  \
-	(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \
+	(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)OffsetNumberMask && \
 	 GinItemPointerGetBlockNumber(p) == InvalidBlockNumber)
 #define ItemPointerSetLossyPage(p, b)  \
-	ItemPointerSet((p), (b), (OffsetNumber)0xffff)
+	ItemPointerSet((p), (b), (OffsetNumber)OffsetNumberMask)
 #define ItemPointerIsLossyPage(p)  \
-	(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \
+	(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)OffsetNumberMask && \
 	 GinItemPointerGetBlockNumber(p) != InvalidBlockNumber)
 
 /*
@@ -218,7 +218,7 @@ typedef signed char GinNullCategory;
  */
 #define GinGetNPosting(itup)	GinItemPointerGetOffsetNumber(&(itup)->t_tid)
 #define GinSetNPosting(itup,n)	ItemPointerSetOffsetNumber(&(itup)->t_tid,n)
-#define GIN_TREE_POSTING		((OffsetNumber)0xffff)
+#define GIN_TREE_POSTING		((OffsetNumber)OffsetNumberMask)
 #define GinIsPostingTree(itup)	(GinGetNPosting(itup) == GIN_TREE_POSTING)
 #define GinSetPostingTree(itup, blkno)	( GinSetNPosting((itup),GIN_TREE_POSTING), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) )
 #define GinGetPostingTree(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 1ad4ed6..0ad11f1 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -269,8 +269,8 @@ typedef struct
  * invalid tuples in an index, so throwing an error is as far as we go with
  * supporting that.
  */
-#define TUPLE_IS_VALID		0xffff
-#define TUPLE_IS_INVALID	0xfffe
+#define TUPLE_IS_VALID		OffsetNumberMask
+#define TUPLE_IS_INVALID	OffsetNumberPrev(OffsetNumberMask)
 
 #define  GistTupleIsInvalid(itup)	( ItemPointerGetOffsetNumber( &((itup)->t_tid) ) == TUPLE_IS_INVALID )
 #define  GistTupleSetValid(itup)	ItemPointerSetOffsetNumber( &((itup)->t_tid), TUPLE_IS_VALID )
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 24433c7..4d614b7 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -288,7 +288,7 @@ struct HeapTupleHeaderData
  * than MaxOffsetNumber, so that it can be distinguished from a valid
  * offset number in a regular item pointer.
  */
-#define SpecTokenOffsetNumber		0xfffe
+#define SpecTokenOffsetNumber		OffsetNumberPrev(OffsetNumberMask)
 
 /*
  * HeapTupleHeader accessor macros
diff --git a/src/include/storage/itemptr.h b/src/include/storage/itemptr.h
index 60d0070..3144bdd 100644
--- a/src/include/storage/itemptr.h
+++ b/src/include/storage/itemptr.h
@@ -57,7 +57,7 @@ typedef ItemPointerData *ItemPointer;
  *		True iff the disk item pointer is not NULL.
  */
 #define ItemPointerIsValid(pointer) \
-	((bool) (PointerIsValid(pointer) && ((pointer)->ip_posid != 0)))
+	((bool) (PointerIsValid(pointer) && (((pointer)->ip_posid & OffsetNumberMask) != 0)))
 
 /*
  * ItemPointerGetBlockNumber
@@ -82,13 +82,37 @@ typedef ItemPointerData *ItemPointer;
 #define ItemPointerGetOffsetNumber(pointer) \
 ( \
 	AssertMacro(ItemPointerIsValid(pointer)), \
-	(pointer)->ip_posid \
+	((pointer)->ip_posid & OffsetNumberMask) \
 )
 
 /* Same as ItemPointerGetOffsetNumber but without any assert-checks */
 #define ItemPointerGetOffsetNumberNoCheck(pointer) \
 ( \
-	(pointer)->ip_posid \
+	((pointer)->ip_posid & OffsetNumberMask) \
+)
+
+/*
+ * Get the flags stored in high order bits in the OffsetNumber.
+ */
+#define ItemPointerGetFlags(pointer) \
+( \
+	((pointer)->ip_posid & ~OffsetNumberMask) >> OffsetNumberBits \
+)
+
+/*
+ * Set the flag bits. We first left-shift since flags are defined starting 0x01
+ */
+#define ItemPointerSetFlags(pointer, flags) \
+( \
+	((pointer)->ip_posid |= ((flags) << OffsetNumberBits)) \
+)
+
+/*
+ * Clear all flags.
+ */
+#define ItemPointerClearFlags(pointer) \
+( \
+	((pointer)->ip_posid &= OffsetNumberMask) \
 )
 
 /*
@@ -99,7 +123,7 @@ typedef ItemPointerData *ItemPointer;
 ( \
 	AssertMacro(PointerIsValid(pointer)), \
 	BlockIdSet(&((pointer)->ip_blkid), blockNumber), \
-	(pointer)->ip_posid = offNum \
+	(pointer)->ip_posid = (offNum) \
 )
 
 /*
diff --git a/src/include/storage/off.h b/src/include/storage/off.h
index fe8638f..fe1834c 100644
--- a/src/include/storage/off.h
+++ b/src/include/storage/off.h
@@ -26,8 +26,15 @@ typedef uint16 OffsetNumber;
 #define InvalidOffsetNumber		((OffsetNumber) 0)
 #define FirstOffsetNumber		((OffsetNumber) 1)
 #define MaxOffsetNumber			((OffsetNumber) (BLCKSZ / sizeof(ItemIdData)))
-#define OffsetNumberMask		(0xffff)		/* valid uint16 bits */
 
+/*
+ * Currently we support maxinum 32kB blocks and each ItemId takes 6 bytes. That
+ * limits the number of line pointers to (32kB/6 = 5461). 13 bits are enought o
+ * represent all line pointers. Hence we can reuse the high order bits in
+ * OffsetNumber for other purposes.
+ */
+#define OffsetNumberMask		(0x1fff)		/* valid uint16 bits */
+#define OffsetNumberBits		13	/* number of valid bits in OffsetNumber */
 /* ----------------
  *		support macros
  * ----------------
-- 
2.1.4

