diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2013-02-11 22:50:15 +0200 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2013-02-11 23:07:09 +0200 |
commit | 62401db45c4feff9be296fa78a8bb7b9947d69de (patch) | |
tree | 5d572267b5a2eae75049ba720bc1faf9f6a6694d /src/backend/access/gist | |
parent | b669f416cee77ef9025b80f9c4201688578447d1 (diff) | |
download | postgresql-62401db45c4feff9be296fa78a8bb7b9947d69de.tar.gz postgresql-62401db45c4feff9be296fa78a8bb7b9947d69de.zip |
Support unlogged GiST index.
The reason this wasn't supported before was that GiST indexes need an
increasing sequence to detect concurrent page-splits. In a regular WAL-
logged GiST index, the LSN of the page-split record is used for that
purpose, and in a temporary index, we can get away with a backend-local
counter. Neither of those methods works for an unlogged relation.
To provide such an increasing sequence of numbers, create a "fake LSN"
counter that is saved and restored across shutdowns. On recovery, unlogged
relations are blown away, so the counter doesn't need to survive that
either.
Jeevan Chalke, based on discussions with Robert Haas, Tom Lane and me.
Diffstat (limited to 'src/backend/access/gist')
-rw-r--r-- | src/backend/access/gist/gist.c | 24 | ||||
-rw-r--r-- | src/backend/access/gist/gistbuild.c | 12 | ||||
-rw-r--r-- | src/backend/access/gist/gistutil.c | 30 | ||||
-rw-r--r-- | src/backend/access/gist/gistvacuum.c | 2 |
4 files changed, 43 insertions, 25 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index e2d3390300e..eba95f18664 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -16,6 +16,7 @@ #include "access/genam.h" #include "access/gist_private.h" +#include "access/heapam_xlog.h" #include "catalog/index.h" #include "catalog/pg_collation.h" #include "miscadmin.h" @@ -71,9 +72,22 @@ createTempGistContext(void) Datum gistbuildempty(PG_FUNCTION_ARGS) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unlogged GiST indexes are not supported"))); + Relation index = (Relation) PG_GETARG_POINTER(0); + Buffer buffer; + + /* Initialize the root page */ + buffer = ReadBufferExtended(index, INIT_FORKNUM, P_NEW, RBM_NORMAL, NULL); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + + /* Initialize and xlog buffer */ + START_CRIT_SECTION(); + GISTInitBuffer(buffer, F_LEAF); + MarkBufferDirty(buffer); + log_newpage_buffer(buffer); + END_CRIT_SECTION(); + + /* Unlock and release the buffer */ + UnlockReleaseBuffer(buffer); PG_RETURN_VOID(); } @@ -391,7 +405,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, dist, oldrlink, oldnsn, leftchildbuf, markfollowright); else - recptr = GetXLogRecPtrForTemp(); + recptr = gistGetFakeLSN(rel); for (ptr = dist; ptr; ptr = ptr->next) { @@ -448,7 +462,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, } else { - recptr = GetXLogRecPtrForTemp(); + recptr = gistGetFakeLSN(rel); PageSetLSN(page, recptr); } diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index aec5b524809..0cf22cdf3a8 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -158,16 +158,6 @@ gistbuild(PG_FUNCTION_ARGS) elog(ERROR, "index \"%s\" already contains data", RelationGetRelationName(index)); - /* - * We can't yet handle unlogged GiST indexes, because we depend on LSNs. - * This is duplicative of an error in gistbuildempty, but we want to check - * here so as to throw error before doing all the index-build work. - */ - if (heap->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unlogged GiST indexes are not supported"))); - /* no locking is needed */ buildstate.giststate = initGISTstate(index); @@ -204,7 +194,7 @@ gistbuild(PG_FUNCTION_ARGS) PageSetTLI(page, ThisTimeLineID); } else - PageSetLSN(page, GetXLogRecPtrForTemp()); + PageSetLSN(page, gistGetFakeLSN(heap)); UnlockReleaseBuffer(buffer); diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index e5c3d69fca7..f7d50ddb712 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -798,16 +798,30 @@ gistoptions(PG_FUNCTION_ARGS) } /* - * 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. + * Temporary and unlogged GiST indexes are not WAL-logged, but we need LSNs + * to detect concurrent page splits anyway. This function provides a fake + * sequence of LSNs for that purpose. */ XLogRecPtr -GetXLogRecPtrForTemp(void) +gistGetFakeLSN(Relation rel) { static XLogRecPtr counter = 1; - counter++; - return counter; + + if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) + { + /* + * Temporary relations are only accessible in our session, so a + * simple backend-local counter will do. + */ + return counter++; + } + else + { + /* + * Unlogged relations are accessible from other backends, and survive + * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us. + */ + Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED); + return GetFakeLSNForUnloggedRel(); + } } diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index b5be6765d4e..1d9f8320166 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -238,7 +238,7 @@ gistbulkdelete(PG_FUNCTION_ARGS) PageSetTLI(page, ThisTimeLineID); } else - PageSetLSN(page, GetXLogRecPtrForTemp()); + PageSetLSN(page, gistGetFakeLSN(rel)); END_CRIT_SECTION(); } |