Make GiST indexes on-disk compatible with 9.2 again.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 17 Jan 2013 14:35:46 +0000 (16:35 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 17 Jan 2013 14:46:16 +0000 (16:46 +0200)
The patch that turned XLogRecPtr into a uint64 inadvertently changed the
on-disk format of GiST indexes, because the NSN field in the GiST page
opaque is an XLogRecPtr. That breaks pg_upgrade. Revert the format of that
field back to the two-field struct that XLogRecPtr was before. This is the
same we did to LSNs in the page header to avoid changing on-disk format.

Bump catversion, as this invalidates any existing GiST indexes built on
9.3devel.

src/backend/access/gist/gist.c
src/backend/access/gist/gistget.c
src/backend/access/gist/gistvacuum.c
src/backend/access/gist/gistxlog.c
src/include/access/gist.h
src/include/catalog/catversion.h
src/include/storage/bufpage.h

index 95d33c8945b8e45cfc6f8040127aa32f7edc45e6..4686242802dce9a19f81f941706b305ccd3efd0f 100644 (file)
@@ -240,7 +240,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
                {
                        /* save old rightlink and NSN */
                        oldrlink = GistPageGetOpaque(page)->rightlink;
-                       oldnsn = GistPageGetOpaque(page)->nsn;
+                       oldnsn = GistPageGetNSN(page);
 
                        dist->buffer = buffer;
                        dist->block.blkno = BufferGetBlockNumber(buffer);
@@ -364,7 +364,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
                         * F_FOLLOW_RIGHT flags ensure that scans will follow the
                         * rightlinks until the downlinks are inserted.
                         */
-                       GistPageGetOpaque(ptr->page)->nsn = oldnsn;
+                       GistPageSetNSN(ptr->page, oldnsn);
                }
 
                START_CRIT_SECTION();
@@ -473,7 +473,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
        {
                Page            leftpg = BufferGetPage(leftchildbuf);
 
-               GistPageGetOpaque(leftpg)->nsn = recptr;
+               GistPageSetNSN(leftpg, recptr);
                GistClearFollowRight(leftpg);
 
                PageSetLSN(leftpg, recptr);
@@ -561,7 +561,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
                }
 
                if (stack->blkno != GIST_ROOT_BLKNO &&
-                       stack->parent->lsn < GistPageGetOpaque(stack->page)->nsn)
+                       stack->parent->lsn < GistPageGetNSN(stack->page))
                {
                        /*
                         * Concurrent split detected. There's no guarantee that the
@@ -707,8 +707,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
                                         */
                                }
                                else if (GistFollowRight(stack->page) ||
-                                                stack->parent->lsn <
-                                                                 GistPageGetOpaque(stack->page)->nsn)
+                                                stack->parent->lsn < GistPageGetNSN(stack->page))
                                {
                                        /*
                                         * The page was split while we momentarily unlocked the
@@ -793,7 +792,7 @@ gistFindPath(Relation r, BlockNumber child, OffsetNumber *downlinkoffnum)
                if (GistFollowRight(page))
                        elog(ERROR, "concurrent GiST page split was incomplete");
 
-               if (top->parent && top->parent->lsn < GistPageGetOpaque(page)->nsn &&
+               if (top->parent && top->parent->lsn < GistPageGetNSN(page) &&
                        GistPageGetOpaque(page)->rightlink != InvalidBlockNumber /* sanity check */ )
                {
                        /*
index 79996a235f01e017adba696117a448bca26dfb71..3300fec644ece33f43532a842583f80e5bd8c10b 100644 (file)
@@ -263,7 +263,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
         */
        if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
                (GistFollowRight(page) ||
-                pageItem->data.parentlsn < opaque->nsn) &&
+                pageItem->data.parentlsn < GistPageGetNSN(page)) &&
                opaque->rightlink != InvalidBlockNumber /* sanity check */ )
        {
                /* There was a page split, follow right link to add pages */
index dcad36ea3ec226ca5ebbc0b04ef54b7c76338a27..b5be6765d4ed77d8c0ae86980b8e78565ecfe5ee 100644 (file)
@@ -114,7 +114,7 @@ pushStackIfSplited(Page page, GistBDItem *stack)
        GISTPageOpaque opaque = GistPageGetOpaque(page);
 
        if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&
-               (GistFollowRight(page) || stack->parentlsn < opaque->nsn) &&
+               (GistFollowRight(page) || stack->parentlsn < GistPageGetNSN(page)) &&
                opaque->rightlink != InvalidBlockNumber /* sanity check */ )
        {
                /* split page detected, install right link to the stack */
index e3a213e7daa086ae2f0d72bab54366717ee0d1b6..c18065a780f2852f54cad4f3bfceff2808e0ae30 100644 (file)
@@ -66,7 +66,7 @@ gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, int block_index,
         */
        if (lsn >= PageGetLSN(page))
        {
-               GistPageGetOpaque(page)->nsn = lsn;
+               GistPageSetNSN(page, lsn);
                GistClearFollowRight(page);
 
                PageSetLSN(page, lsn);
@@ -271,7 +271,7 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
                if (newpage->header->blkno == GIST_ROOT_BLKNO)
                {
                        GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
-                       GistPageGetOpaque(page)->nsn = xldata->orignsn;
+                       GistPageSetNSN(page, xldata->orignsn);
                        GistClearFollowRight(page);
                }
                else
@@ -280,7 +280,7 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
                                GistPageGetOpaque(page)->rightlink = xlrec.page[i + 1].header->blkno;
                        else
                                GistPageGetOpaque(page)->rightlink = xldata->origrlink;
-                       GistPageGetOpaque(page)->nsn = xldata->orignsn;
+                       GistPageSetNSN(page, xldata->orignsn);
                        if (i < xlrec.data->npage - 1 && !isrootsplit &&
                                xldata->markfollowright)
                                GistMarkFollowRight(page);
index 69e4ec03fb624ab03dc0ae69a50a11052d4a09f2..a487a0be3ad27652bc0dceb939595f0367ebc341 100644 (file)
 #define F_FOLLOW_RIGHT         (1 << 3)        /* page to the right has no downlink */
 
 typedef XLogRecPtr GistNSN;
+/*
+ * For on-disk compatibility with pre-9.3 servers, NSN is stored as two
+ * 32-bit fields on disk, same as LSNs.
+ */
+typedef PageXLogRecPtr PageGistNSN;
 
 typedef struct GISTPageOpaqueData
 {
-       GistNSN         nsn;                    /* this value must change on page split */
+       PageGistNSN     nsn;                    /* this value must change on page split */
        BlockNumber rightlink;          /* next page if any */
        uint16          flags;                  /* see bit definitions above */
        uint16          gist_page_id;   /* for identification of GiST indexes */
@@ -137,6 +142,9 @@ typedef struct GISTENTRY
 #define GistMarkFollowRight(page) ( GistPageGetOpaque(page)->flags |= F_FOLLOW_RIGHT)
 #define GistClearFollowRight(page)     ( GistPageGetOpaque(page)->flags &= ~F_FOLLOW_RIGHT)
 
+#define GistPageGetNSN(page) ( PageXLogRecPtrGet(GistPageGetOpaque(page)->nsn))
+#define GistPageSetNSN(page, val) ( PageXLogRecPtrSet(GistPageGetOpaque(page)->nsn, val))
+
 /*
  * Vector of GISTENTRY structs; user-defined methods union and picksplit
  * take it as one of their arguments
index 1e235c6d1ee42ecc429a0680c4c2901b9e056d81..cd562ef40cb41ce03a62a5e254d5ca5a02520e87 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201212081
+#define CATALOG_VERSION_NO     201301171
 
 #endif
index 7758407098f04be49a3c24845ecea5d909d021cf..8c887cab735ed70c07da2972ef27915b078e50f2 100644 (file)
@@ -82,6 +82,21 @@ typedef Pointer Page;
 typedef uint16 LocationIndex;
 
 
+/*
+ * For historical reasons, the 64-bit LSN value is stored as two 32-bit
+ * values.
+ */
+typedef struct
+{
+       uint32          xlogid;                 /* high bits */
+       uint32          xrecoff;                /* low bits */
+} PageXLogRecPtr;
+
+#define PageXLogRecPtrGet(val) \
+       ((uint64) (val).xlogid << 32 | (val).xrecoff)
+#define PageXLogRecPtrSet(ptr, lsn) \
+       ((ptr).xlogid = (uint32) ((lsn) >> 32), (ptr).xrecoff = (uint32) (lsn))
+
 /*
  * disk page organization
  *
@@ -120,13 +135,6 @@ typedef uint16 LocationIndex;
  * are 15 bits.
  */
 
-/* for historical reasons, the LSN is stored as two 32-bit values. */
-typedef struct
-{
-       uint32          xlogid;                 /* high bits */
-       uint32          xrecoff;                /* low bits */
-} PageXLogRecPtr;
-
 typedef struct PageHeaderData
 {
        /* XXX LSN is member of *any* block, not only page-organized ones */
@@ -319,13 +327,13 @@ typedef PageHeaderData *PageHeader;
          / sizeof(ItemIdData)))
 
 /*
- * Additional macros for access to page headers
+ * Additional macros for access to page headers. (Beware multiple evaluation
+ * of the arguments!)
  */
 #define PageGetLSN(page) \
-       ((uint64) ((PageHeader) (page))->pd_lsn.xlogid << 32 | ((PageHeader) (page))->pd_lsn.xrecoff)
+       PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn)
 #define PageSetLSN(page, lsn) \
-       (((PageHeader) (page))->pd_lsn.xlogid = (uint32) ((lsn) >> 32), \
-        ((PageHeader) (page))->pd_lsn.xrecoff = (uint32) (lsn))
+       PageXLogRecPtrSet(((PageHeader) (page))->pd_lsn, lsn)
 
 /* NOTE: only the 16 least significant bits are stored */
 #define PageGetTLI(page) \