From c22128e0e63ab83f9009a1466ea50c46878d7650 Mon Sep 17 00:00:00 2001 From: Matthias van de Meent Date: Mon, 28 Mar 2022 14:53:43 +0200 Subject: [PATCH v2 1/3] Add known-size pre-aligned special area pointer macro This removes 1 layer of indirection for special areas of which we know the type (=size) and location. Special area access through the page header is an extra cache line that needs to be fetched. If might only want to look at the special area, it is much less effort to calculate the offset to the special area directly instead of first checking the page header - saving one cache line to fetch. Assertions are added to check that the page has a correctly sized special area, and that the page is of the expected size. This detects data corruption, instead of doing random reads/writes into the page or data allocated next to the page being accessed. Additionally, updates the GIN, GIST and SP-GIST [Index]PageGetOpaque macros with the new pre-aligned special area accessor. --- src/include/access/ginblock.h | 3 ++- src/include/access/gist.h | 3 ++- src/include/access/spgist_private.h | 3 ++- src/include/storage/bufpage.h | 14 ++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/include/access/ginblock.h b/src/include/access/ginblock.h index 9347f464f3..3680098c98 100644 --- a/src/include/access/ginblock.h +++ b/src/include/access/ginblock.h @@ -108,7 +108,8 @@ typedef struct GinMetaPageData /* * Macros for accessing a GIN index page's opaque data */ -#define GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) ) +#define GinPageGetOpaque(page) \ + ((GinPageOpaque) PageGetSpecialOpaque(page, GinPageOpaqueData)) #define GinPageIsLeaf(page) ( (GinPageGetOpaque(page)->flags & GIN_LEAF) != 0 ) #define GinPageSetLeaf(page) ( GinPageGetOpaque(page)->flags |= GIN_LEAF ) diff --git a/src/include/access/gist.h b/src/include/access/gist.h index a3337627b8..51223e9051 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -164,7 +164,8 @@ typedef struct GISTENTRY bool leafkey; } GISTENTRY; -#define GistPageGetOpaque(page) ( (GISTPageOpaque) PageGetSpecialPointer(page) ) +#define GistPageGetOpaque(page) \ + ((GISTPageOpaque) PageGetSpecialOpaque(page, GISTPageOpaqueData)) #define GistPageIsLeaf(page) ( GistPageGetOpaque(page)->flags & F_LEAF) #define GIST_LEAF(entry) (GistPageIsLeaf((entry)->page)) diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index eb56b1c6b8..b0bdc7df3e 100644 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -75,7 +75,8 @@ typedef SpGistPageOpaqueData *SpGistPageOpaque; #define SPGIST_LEAF (1<<2) #define SPGIST_NULLS (1<<3) -#define SpGistPageGetOpaque(page) ((SpGistPageOpaque) PageGetSpecialPointer(page)) +#define SpGistPageGetOpaque(page) \ + ((SpGistPageOpaque) PageGetSpecialOpaque(page, SpGistPageOpaqueData)) #define SpGistPageIsMeta(page) (SpGistPageGetOpaque(page)->flags & SPGIST_META) #define SpGistPageIsDeleted(page) (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED) #define SpGistPageIsLeaf(page) (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF) diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index e9f253f2c8..e96595f338 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -329,6 +329,20 @@ PageValidateSpecialPointer(Page page) (char *) ((char *) (page) + ((PageHeader) (page))->pd_special) \ ) +/* + * PageGetSpecialOpaque + * Returns pointer to special space on a page, of the given type. + * This removes the data dependency on the page header in builds + * without asserts enabled. + */ +#define PageGetSpecialOpaque(page, OpaqueDataType) \ +( \ + AssertMacro(PageGetPageSize(page) == BLCKSZ && \ + PageGetSpecialSize(page) == MAXALIGN(sizeof(OpaqueDataType))), \ + (OpaqueDataType *) ((char *) (page) + \ + (BLCKSZ - MAXALIGN(sizeof(OpaqueDataType)))) \ +) + /* * PageGetItem * Retrieves an item on the given page. -- 2.30.2