From: Kyotaro Horiguchi Date: Thu, 21 Nov 2019 16:12:03 +0900 Subject: [PATCH v26 5/6] Fix gistGetFakeLSN() GiST needs to set page LSN to monotically incresing numbers on updates even if it is not WAL-logged at all. We use a simple counter for UNLOGGESD/TEMP relations but the number must be smaller than the LSN at the next commit for WAL-skipped relations. WAL-insertione pointer works in major cases but we sometimes need to emit a WAL record to generate an unique LSN for update. This patch adds a new WAL record kind XLOG_GIST_ASSIGN_LSN, which conveys no substantial content and emits it if needed. --- src/backend/access/gist/gistutil.c | 38 ++++++++++++++++++-------- src/backend/access/gist/gistxlog.c | 21 ++++++++++++++ src/backend/access/rmgrdesc/gistdesc.c | 5 ++++ src/include/access/gist_private.h | 2 ++ src/include/access/gistxlog.h | 1 + 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 66c52d6dd6..8347673c5e 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -1004,28 +1004,44 @@ gistproperty(Oid index_oid, int attno, } /* - * 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. + * Temporary, unlogged GiST and WAL-skipped 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 gistGetFakeLSN(Relation rel) { - static XLogRecPtr counter = FirstNormalUnloggedLSN; - - /* - * XXX before commit fix this. This is not correct for - * RELPERSISTENCE_PERMANENT, but it suffices to make tests pass. - */ - if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP - || rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT) + if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) { /* * Temporary relations are only accessible in our session, so a simple * backend-local counter will do. */ + static XLogRecPtr counter = FirstNormalUnloggedLSN; + return counter++; } + else if (rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT) + { + /* + * WAL-logging on this relation will start after commit, so the LSN + * must be distinct numbers smaller than the LSN at the next + * commit. Emit a dummy WAL record if insert-LSN hasn't advanced after + * the last call. + */ + static XLogRecPtr lastlsn = InvalidXLogRecPtr; + XLogRecPtr currlsn = GetXLogInsertRecPtr(); + + /* Shouldn't be called for WAL-logging relations */ + Assert(!RelationNeedsWAL(rel)); + + /* No need for an actual record if we alredy have a distinct LSN */ + if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn) + currlsn = gistXLogAssignLSN(); + + lastlsn = currlsn; + return currlsn; + } else { /* diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c index 3b28f54646..ce17bc9dc3 100644 --- a/src/backend/access/gist/gistxlog.c +++ b/src/backend/access/gist/gistxlog.c @@ -449,6 +449,9 @@ gist_redo(XLogReaderState *record) case XLOG_GIST_PAGE_DELETE: gistRedoPageDelete(record); break; + case XLOG_GIST_ASSIGN_LSN: + /* nop. See gistGetFakeLSN(). */ + break; default: elog(PANIC, "gist_redo: unknown op code %u", info); } @@ -592,6 +595,24 @@ gistXLogPageDelete(Buffer buffer, FullTransactionId xid, return recptr; } +/* + * Write an empty XLOG record to assign a distinct LSN. + */ +XLogRecPtr +gistXLogAssignLSN(void) +{ + int dummy = 0; + + /* + * Records other than SWITCH_WAL must have content. We use an integer 0 to + * follow the restriction. + */ + XLogBeginInsert(); + XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT); + XLogRegisterData((char*) &dummy, sizeof(dummy)); + return XLogInsert(RM_GIST_ID, XLOG_GIST_ASSIGN_LSN); +} + /* * Write XLOG record about reuse of a deleted page. */ diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c index eccb6fd942..48cda40ac0 100644 --- a/src/backend/access/rmgrdesc/gistdesc.c +++ b/src/backend/access/rmgrdesc/gistdesc.c @@ -80,6 +80,9 @@ gist_desc(StringInfo buf, XLogReaderState *record) case XLOG_GIST_PAGE_DELETE: out_gistxlogPageDelete(buf, (gistxlogPageDelete *) rec); break; + case XLOG_GIST_ASSIGN_LSN: + /* No details to write out */ + break; } } @@ -104,6 +107,8 @@ gist_identify(uint8 info) break; case XLOG_GIST_PAGE_DELETE: id = "PAGE_DELETE"; + case XLOG_GIST_ASSIGN_LSN: + id = "ASSIGN_LSN"; break; } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index a409975db1..3455dd242d 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -455,6 +455,8 @@ extern XLogRecPtr gistXLogSplit(bool page_is_leaf, BlockNumber origrlink, GistNSN oldnsn, Buffer leftchild, bool markfollowright); +extern XLogRecPtr gistXLogAssignLSN(void); + /* gistget.c */ extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir); extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h index e44922d915..1eae06c0fb 100644 --- a/src/include/access/gistxlog.h +++ b/src/include/access/gistxlog.h @@ -26,6 +26,7 @@ /* #define XLOG_GIST_INSERT_COMPLETE 0x40 */ /* not used anymore */ /* #define XLOG_GIST_CREATE_INDEX 0x50 */ /* not used anymore */ #define XLOG_GIST_PAGE_DELETE 0x60 +#define XLOG_GIST_ASSIGN_LSN 0x70 /* nop, assign an new LSN */ /* * Backup Blk 0: updated page. -- 2.23.0 ----Next_Part(Thu_Nov_28_20_56_20_2019_909)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v26-0006-Sync-files-shrinked-by-truncation.patch"