aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2010-11-16 11:02:11 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2010-11-16 11:25:43 +0200
commitedc211424326ffd63933c8e20d5614dc39ce2566 (patch)
tree04b6184c70594da478ffe2f9c2bf602d092e5cb2 /src/backend
parent0c6c5b8a2d94c3ee74e7bba5eedcaae64471e463 (diff)
downloadpostgresql-edc211424326ffd63933c8e20d5614dc39ce2566.tar.gz
postgresql-edc211424326ffd63933c8e20d5614dc39ce2566.zip
The GiST scan algorithm uses LSNs to detect concurrent pages splits, but
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.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/gist/gist.c10
-rw-r--r--src/backend/access/gist/gistutil.c21
-rw-r--r--src/backend/access/gist/gistvacuum.c8
3 files changed, 29 insertions, 10 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 987d8c702a8..0ff334daf84 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -20,8 +20,6 @@
#include "miscadmin.h"
#include "utils/memutils.h"
-const XLogRecPtr XLogRecPtrForTemp = {1, 1};
-
/* Working state for gistbuild and its callback */
typedef struct
{
@@ -130,7 +128,7 @@ gistbuild(PG_FUNCTION_ARGS)
PageSetTLI(page, ThisTimeLineID);
}
else
- PageSetLSN(page, XLogRecPtrForTemp);
+ PageSetLSN(page, GetXLogRecPtrForTemp());
UnlockReleaseBuffer(buffer);
@@ -421,7 +419,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
{
for (ptr = dist; ptr; ptr = ptr->next)
{
- PageSetLSN(ptr->page, XLogRecPtrForTemp);
+ PageSetLSN(ptr->page, GetXLogRecPtrForTemp());
}
}
@@ -489,7 +487,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;
@@ -1025,7 +1023,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();
}
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index ff22bd2b652..fda7c5df2ee 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -676,3 +676,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;
+}
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 5f5060280dd..b941e0a4a08 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -133,7 +133,7 @@ gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
PageSetTLI(page, ThisTimeLineID);
}
else
- PageSetLSN(page, XLogRecPtrForTemp);
+ PageSetLSN(page, GetXLogRecPtrForTemp());
END_CRIT_SECTION();
@@ -252,7 +252,7 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
else
{
for (ptr = dist; ptr; ptr = ptr->next)
- PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
+ PageSetLSN(BufferGetPage(ptr->buffer), GetXLogRecPtrForTemp());
}
for (ptr = dist; ptr; ptr = ptr->next)
@@ -466,7 +466,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
pfree(rdata);
}
else
- PageSetLSN(page, XLogRecPtrForTemp);
+ PageSetLSN(page, GetXLogRecPtrForTemp());
}
END_CRIT_SECTION();
@@ -789,7 +789,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
pfree(rdata);
}
else
- PageSetLSN(page, XLogRecPtrForTemp);
+ PageSetLSN(page, GetXLogRecPtrForTemp());
END_CRIT_SECTION();
}