dist, oldrlink, oldnsn, leftchildbuf,
markfollowright);
else
- recptr = gistGetFakeLSN(rel);
+ recptr = XLogGetFakeLSN(rel);
}
for (ptr = dist; ptr; ptr = ptr->next)
leftchildbuf);
}
else
- recptr = gistGetFakeLSN(rel);
+ recptr = XLogGetFakeLSN(rel);
}
PageSetLSN(page, recptr);
PageSetLSN(page, recptr);
}
else
- PageSetLSN(page, gistGetFakeLSN(rel));
+ PageSetLSN(page, XLogGetFakeLSN(rel));
END_CRIT_SECTION();
}
return true;
}
-/*
- * Some 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)
-{
- 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 (RelationIsPermanent(rel))
- {
- /*
- * WAL-logging on this relation will start after commit, so its LSNs
- * 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 = GetXLogInsertEndRecPtr();
-
- /* Shouldn't be called for WAL-logging relations */
- Assert(!RelationNeedsWAL(rel));
-
- /* No need for an actual record if we already have a distinct LSN */
- if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
- currlsn = gistXLogAssignLSN();
-
- lastlsn = currlsn;
- return currlsn;
- }
- 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();
- }
-}
-
/*
* This is a stratnum translation support function for GiST opclasses that use
* the RT*StrategyNumber constants.
#include "access/genam.h"
#include "access/gist_private.h"
-#include "access/transam.h"
+#include "access/xloginsert.h"
#include "commands/vacuum.h"
#include "lib/integerset.h"
#include "miscadmin.h"
if (RelationNeedsWAL(rel))
vstate.startNSN = GetInsertRecPtr();
else
- vstate.startNSN = gistGetFakeLSN(rel);
+ vstate.startNSN = XLogGetFakeLSN(rel);
/*
* The outer loop iterates over all index pages, in physical order (we
PageSetLSN(page, recptr);
}
else
- PageSetLSN(page, gistGetFakeLSN(rel));
+ PageSetLSN(page, XLogGetFakeLSN(rel));
END_CRIT_SECTION();
if (RelationNeedsWAL(info->index))
recptr = gistXLogPageDelete(leafBuffer, txid, parentBuffer, downlink);
else
- recptr = gistGetFakeLSN(info->index);
+ recptr = XLogGetFakeLSN(info->index);
PageSetLSN(parentPage, recptr);
PageSetLSN(leafPage, recptr);
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);
}
return recptr;
}
-/*
- * Write an empty XLOG record to assign a distinct LSN.
- */
-XLogRecPtr
-gistXLogAssignLSN(void)
-{
- int dummy = 0;
-
- /*
- * Records other than XLOG_SWITCH must have content. We use an integer 0
- * to follow the restriction.
- */
- XLogBeginInsert();
- XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);
- XLogRegisterData(&dummy, sizeof(dummy));
- return XLogInsert(RM_GIST_ID, XLOG_GIST_ASSIGN_LSN);
-}
-
/*
* Write XLOG record about reuse of a deleted page.
*/
case XLOG_GIST_PAGE_DELETE:
out_gistxlogPageDelete(buf, (gistxlogPageDelete *) rec);
break;
- case XLOG_GIST_ASSIGN_LSN:
- /* No details to write out */
- break;
}
}
case XLOG_GIST_PAGE_DELETE:
id = "PAGE_DELETE";
break;
- case XLOG_GIST_ASSIGN_LSN:
- id = "ASSIGN_LSN";
- break;
}
return id;
memcpy(&enabled, rec, sizeof(bool));
appendStringInfoString(buf, enabled ? "true" : "false");
}
+ else if (info == XLOG_ASSIGN_LSN)
+ {
+ /* no further information to print */
+ }
}
const char *
case XLOG_LOGICAL_DECODING_STATUS_CHANGE:
id = "LOGICAL_DECODING_STATUS_CHANGE";
break;
+ case XLOG_ASSIGN_LSN:
+ id = "ASSIGN_LSN";
+ break;
}
return id;
return RecPtr;
}
+/*
+ * Write an empty XLOG record to assign a distinct LSN.
+ *
+ * This is used by some index AMs when building indexes on permanent relations
+ * with wal_level=minimal. In that scenario, WAL-logging will start after
+ * commit, but the index AM needs distinct LSNs to detect concurrent page
+ * modifications. When the current WAL insert position hasn't advanced since
+ * the last call, we emit a dummy record to ensure we get a new, distinct LSN.
+ */
+XLogRecPtr
+XLogAssignLSN(void)
+{
+ int dummy = 0;
+
+ /*
+ * Records other than XLOG_SWITCH must have content. We use an integer 0
+ * to satisfy this restriction.
+ */
+ XLogBeginInsert();
+ XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);
+ XLogRegisterData(&dummy, sizeof(dummy));
+ return XLogInsert(RM_XLOG_ID, XLOG_ASSIGN_LSN);
+}
+
/*
* Check if any of the GUC parameters that are critical for hot standby
* have changed, and update the value in pg_control file if necessary.
{
/* nothing to do here, handled in xlogrecovery.c */
}
+ else if (info == XLOG_ASSIGN_LSN)
+ {
+ /* nothing to do here, see XLogGetFakeLSN() */
+ }
else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
{
/*
#include "storage/proc.h"
#include "utils/memutils.h"
#include "utils/pgstat_internal.h"
+#include "utils/rel.h"
/*
* Guess the maximum buffer size required to store a compressed version of
return XLogInsert(rmid, info);
}
+/*
+ * XLogGetFakeLSN - get a fake LSN for an index page that isn't WAL-logged.
+ *
+ * Some index AMs use LSNs to detect concurrent page modifications, but not
+ * all index pages are WAL-logged. This function provides a sequence of fake
+ * LSNs for that purpose.
+ */
+XLogRecPtr
+XLogGetFakeLSN(Relation rel)
+{
+ 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_UNLOGGED)
+ {
+ /*
+ * Unlogged relations are accessible from other backends, and survive
+ * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
+ */
+ return GetFakeLSNForUnloggedRel();
+ }
+ else
+ {
+ /*
+ * WAL-logging on this relation will start after commit, so its LSNs
+ * 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 = GetXLogInsertEndRecPtr();
+
+ Assert(!RelationNeedsWAL(rel));
+ Assert(RelationIsPermanent(rel));
+
+ /* No need for an actual record if we already have a distinct LSN */
+ if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
+ currlsn = XLogAssignLSN();
+
+ lastlsn = currlsn;
+ return currlsn;
+ }
+}
+
/*
* Assemble a WAL record from the registered data and buffers into an
* XLogRecData chain, ready for insertion with XLogInsertRecord().
* lost after a crash anyway. Most unlogged relation pages do not bear
* LSNs since we never emit WAL records for them, and therefore flushing
* up through the buffer LSN would be useless, but harmless. However,
- * GiST indexes use LSNs internally to track page-splits, and therefore
- * unlogged GiST pages bear "fake" LSNs generated by
- * GetFakeLSNForUnloggedRel. It is unlikely but possible that the fake
+ * some index AMs use LSNs internally to detect concurrent page
+ * modifications, and therefore unlogged index pages bear "fake" LSNs
+ * generated by XLogGetFakeLSN. It is unlikely but possible that the fake
* LSN counter could advance past the WAL insertion point; and if it did
* happen, attempting to flush WAL through that location would fail, with
* disastrous system-wide consequences. To make sure that can't happen,
BlockNumber origrlink, GistNSN orignsn,
Buffer leftchildbuf, bool markfollowright);
-extern XLogRecPtr gistXLogAssignLSN(void);
-
/* gistget.c */
extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir);
extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull);
-extern XLogRecPtr gistGetFakeLSN(Relation rel);
-
/* gistvacuum.c */
extern IndexBulkDeleteResult *gistbulkdelete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats,
/* #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 new LSN */
+ /* #define XLOG_GIST_ASSIGN_LSN 0x70 */ /* not used anymore */
/*
* Backup Blk 0: updated page.
extern WALAvailability GetWALAvailability(XLogRecPtr targetLSN);
extern void XLogPutNextOid(Oid nextOid);
extern XLogRecPtr XLogRestorePoint(const char *rpName);
+extern XLogRecPtr XLogAssignLSN(void);
extern void UpdateFullPageWrites(void);
extern void GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p);
extern XLogRecPtr GetRedoRecPtr(void);
/*
* Each page of XLOG file has a header like this:
*/
-#define XLOG_PAGE_MAGIC 0xD11C /* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD11D /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
BlockNumber startblk, BlockNumber endblk, bool page_std);
extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std);
+extern XLogRecPtr XLogGetFakeLSN(Relation rel);
+
extern void InitXLogInsert(void);
#endif /* XLOGINSERT_H */
#define XLOG_END_OF_RECOVERY 0x90
#define XLOG_FPI_FOR_HINT 0xA0
#define XLOG_FPI 0xB0
-/* 0xC0 is used in Postgres 9.5-11 */
+#define XLOG_ASSIGN_LSN 0xC0
#define XLOG_OVERWRITE_CONTRECORD 0xD0
#define XLOG_CHECKPOINT_REDO 0xE0
#define XLOG_LOGICAL_DECODING_STATUS_CHANGE 0xF0