]> granicus.if.org Git - postgresql/commitdiff
The GiST scan algorithm uses LSNs to detect concurrent pages splits, but
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 16 Nov 2010 09:02:11 +0000 (11:02 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 16 Nov 2010 09:32:02 +0000 (11:32 +0200)
temporary indexes are not WAL-logged. We used a constant LSN for temporary
indexes, on the assumption that we don't need to worry about concurrent page
splits in temporary indexes because they're only visible to the current
session. But that assumption is wrong, it's possible to insert rows and
split pages in the same session, while a scan is in progress. For example,
by opening a cursor and fetching some rows, and INSERTing new rows before
fetching some more.

Fix by generating fake increasing LSNs, used in place of real LSNs in
temporary GiST indexes.

src/backend/access/gist/gist.c
src/backend/access/gist/gistutil.c
src/backend/access/gist/gistvacuum.c
src/include/access/gist_private.h

index cec08c7226722152317903dddc45be4095bd9f9e..4a5d4bf6f102dc546c2159d1428388343659fee8 100644 (file)
@@ -22,8 +22,6 @@
 #include "storage/indexfsm.h"
 #include "utils/memutils.h"
 
-const XLogRecPtr XLogRecPtrForTemp = {1, 1};
-
 /* Working state for gistbuild and its callback */
 typedef struct
 {
@@ -132,7 +130,7 @@ gistbuild(PG_FUNCTION_ARGS)
                PageSetTLI(page, ThisTimeLineID);
        }
        else
-               PageSetLSN(page, XLogRecPtrForTemp);
+               PageSetLSN(page, GetXLogRecPtrForTemp());
 
        UnlockReleaseBuffer(buffer);
 
@@ -423,7 +421,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
                {
                        for (ptr = dist; ptr; ptr = ptr->next)
                        {
-                               PageSetLSN(ptr->page, XLogRecPtrForTemp);
+                               PageSetLSN(ptr->page, GetXLogRecPtrForTemp());
                        }
                }
 
@@ -491,7 +489,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
                        PageSetTLI(state->stack->page, ThisTimeLineID);
                }
                else
-                       PageSetLSN(state->stack->page, XLogRecPtrForTemp);
+                       PageSetLSN(state->stack->page, GetXLogRecPtrForTemp());
 
                if (state->stack->blkno == GIST_ROOT_BLKNO)
                        state->needInsertComplete = false;
@@ -1027,7 +1025,7 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke
                PageSetTLI(page, ThisTimeLineID);
        }
        else
-               PageSetLSN(page, XLogRecPtrForTemp);
+               PageSetLSN(page, GetXLogRecPtrForTemp());
 
        END_CRIT_SECTION();
 }
index 03c5773d4d352982d11b35a2cfa1684d68f9bd9b..a23047642fde9499502d059439e93160fdb70217 100644 (file)
@@ -677,3 +677,24 @@ gistoptions(PG_FUNCTION_ARGS)
                PG_RETURN_BYTEA_P(result);
        PG_RETURN_NULL();
 }
+
+/*
+ * Temporary GiST indexes are not WAL-logged, but we need LSNs to detect
+ * concurrent page splits anyway. GetXLogRecPtrForTemp() provides a fake
+ * sequence of LSNs for that purpose. Each call generates an LSN that is
+ * greater than any previous value returned by this function in the same
+ * session.
+ */
+XLogRecPtr
+GetXLogRecPtrForTemp(void)
+{
+       static XLogRecPtr counter = {0, 1};
+
+       counter.xrecoff++;
+       if (counter.xrecoff == 0)
+       {
+               counter.xlogid++;
+               counter.xrecoff++;
+       }
+       return counter;
+}
index abd3d999565320a8f01a7dd539fce03a891606ae..33f7c8c76aeacd8d264ae2680586341819bae4b2 100644 (file)
@@ -268,7 +268,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
                                        pfree(rdata);
                                }
                                else
-                                       PageSetLSN(page, XLogRecPtrForTemp);
+                                       PageSetLSN(page, GetXLogRecPtrForTemp());
 
                                END_CRIT_SECTION();
                        }
index a85da662cececcb50243551f485fbc9cff22d55f..4df5fed116b39b76c90a255bf223dd92602ba17f 100644 (file)
@@ -87,7 +87,6 @@ typedef struct GISTScanOpaqueData
 typedef GISTScanOpaqueData *GISTScanOpaque;
 
 /* XLog stuff */
-extern const XLogRecPtr XLogRecPtrForTemp;
 
 #define XLOG_GIST_PAGE_UPDATE          0x00
 #define XLOG_GIST_NEW_ROOT                     0x20
@@ -326,6 +325,8 @@ extern void gistMakeUnionKey(GISTSTATE *giststate, int attno,
                                 GISTENTRY *entry2, bool isnull2,
                                 Datum *dst, bool *dstisnull);
 
+extern XLogRecPtr GetXLogRecPtrForTemp(void);
+
 /* gistvacuum.c */
 extern Datum gistbulkdelete(PG_FUNCTION_ARGS);
 extern Datum gistvacuumcleanup(PG_FUNCTION_ARGS);