diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 8872920..af11eb0 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -182,8 +182,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI automatically truncated after a crash or unclean shutdown. The contents of an unlogged table are also not replicated to standby servers. Any indexes created on an unlogged table are automatically unlogged as - well; however, unlogged GiST indexes are - currently not supported and cannot be created on an unlogged table. + well. diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 95d33c8..58d033cc 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -71,9 +71,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 +404,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, dist, oldrlink, oldnsn, leftchildbuf, markfollowright); else - recptr = GetXLogRecPtrForTemp(); + recptr = GetXLogRecPtrForUnloggedRel(rel); for (ptr = dist; ptr; ptr = ptr->next) { @@ -448,7 +461,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, } else { - recptr = GetXLogRecPtrForTemp(); + recptr = GetXLogRecPtrForUnloggedRel(rel); PageSetLSN(page, recptr); } diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index aec5b52..235365d 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, GetXLogRecPtrForUnloggedRel(heap)); UnlockReleaseBuffer(buffer); diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 8b60774..1dce570 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -743,18 +743,3 @@ gistoptions(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(rdopts); } - -/* - * 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 = 1; - counter++; - return counter; -} diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index dcad36e..7c19092 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, GetXLogRecPtrForUnloggedRel(rel)); END_CRIT_SECTION(); } diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 51a515a..58ea5fd 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -55,6 +55,7 @@ #include "utils/builtins.h" #include "utils/guc.h" #include "utils/ps_status.h" +#include "utils/rel.h" #include "utils/relmapper.h" #include "utils/snapmgr.h" #include "utils/timestamp.h" @@ -4208,6 +4209,42 @@ GetSystemIdentifier(void) } /* + * Temporary GiST indexes are not WAL-logged, but we need LSNs to detect + * concurrent page splits anyway. GetXLogRecPtrForUnloggedRel() 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 using static counter + * Similarily unlogged GiST indexes are also not WAL-logged. But we need a + * persistent counter across clean shutdown. Use counter from ControlFile to + * accomplish that + * If relation is UNLOGGED, return persistent counter from ControlFile else + * return session wide temporary counter + */ +XLogRecPtr +GetXLogRecPtrForUnloggedRel(Relation rel) +{ + XLogRecPtr nextUnloggedLSN; + static XLogRecPtr counter = 1; + + /* Make sure relation is either UNLOGGED or TEMP */ + Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED || + rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP); + + if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED) + { + Assert(ControlFile != NULL); + /* increment the unloggedLSN counter, need ControlFileLock */ + LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); + nextUnloggedLSN = ControlFile->unloggedLSN++; + LWLockRelease(ControlFileLock); + } + else + nextUnloggedLSN = counter++; /* TEMP relation, use static counter */ + + return nextUnloggedLSN; +} + +/* * Auto-tune the number of XLOG buffers. * * The preferred setting for wal_buffers is about 3% of shared_buffers, with @@ -4496,6 +4533,7 @@ BootStrapXLOG(void) ControlFile->time = checkPoint.time; ControlFile->checkPoint = checkPoint.redo; ControlFile->checkPointCopy = checkPoint; + ControlFile->unloggedLSN = 1; /* Set important parameter values for use when replaying WAL */ ControlFile->MaxConnections = MaxConnections; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 03ed41d..fe740c3 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1921,8 +1921,11 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln) * rule that log updates must hit disk before any of the data-file changes * they describe do. */ - recptr = BufferGetLSN(buf); - XLogFlush(recptr); + if (buf->flags & BM_PERMANENT) + { + recptr = BufferGetLSN(buf); + XLogFlush(recptr); + } /* * Now it's safe to write buffer to disk. Note that no one else should diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 357b8c9..8d4fa9d 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -16,6 +16,7 @@ #include "access/gist.h" #include "access/itup.h" +#include "access/xlog.h" #include "fmgr.h" #include "storage/bufmgr.h" #include "storage/buffile.h" @@ -511,8 +512,6 @@ 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); diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 885b5fc..856bf04 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -16,6 +16,7 @@ #include "datatype/timestamp.h" #include "lib/stringinfo.h" #include "storage/buf.h" +#include "utils/rel.h" #include "utils/pg_crc.h" /* @@ -294,6 +295,7 @@ extern char *XLogFileNameP(TimeLineID tli, XLogSegNo segno); extern void UpdateControlFile(void); extern uint64 GetSystemIdentifier(void); +extern XLogRecPtr GetXLogRecPtrForUnloggedRel(Relation rel); extern Size XLOGShmemSize(void); extern void XLOGShmemInit(void); extern void BootStrapXLOG(void); diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index ead3a6e..17522d0 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -157,6 +157,7 @@ typedef struct ControlFileData XLogRecPtr backupStartPoint; XLogRecPtr backupEndPoint; bool backupEndRequired; + XLogRecPtr unloggedLSN; /* fake LSN for unlogged GiST index */ /* * Parameter settings that determine if the WAL can be used for archival