START_CRIT_SECTION();
if (RelationNeedsWAL(btree->index) && !btree->isBuild)
- {
XLogBeginInsert();
- XLogRegisterBuffer(0, stack->buffer, REGBUF_STANDARD);
- if (BufferIsValid(childbuf))
- XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
- }
- /* Perform the page update, and register any extra WAL data */
+ /*
+ * Perform the page update, dirty and register stack->buffer, and
+ * register any extra WAL data.
+ */
btree->execPlaceToPage(btree, stack->buffer, stack,
insertdata, updateblkno, ptp_workspace);
- MarkBufferDirty(stack->buffer);
-
/* An insert to an internal page finishes the split of the child. */
if (BufferIsValid(childbuf))
{
GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
MarkBufferDirty(childbuf);
+ if (RelationNeedsWAL(btree->index) && !btree->isBuild)
+ XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
}
if (RelationNeedsWAL(btree->index) && !btree->isBuild)
/* Apply changes to page */
dataPlaceToPageLeafRecompress(buf, leaf);
+ MarkBufferDirty(buf);
+
/* If needed, register WAL data built by computeLeafRecompressWALData */
if (RelationNeedsWAL(btree->index) && !btree->isBuild)
{
+ XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
}
}
pitem = (PostingItem *) insertdata;
GinDataPageAddPostingItem(page, pitem, off);
+ MarkBufferDirty(buf);
+
if (RelationNeedsWAL(btree->index) && !btree->isBuild)
{
/*
data.offset = off;
data.newitem = *pitem;
+ XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
XLogRegisterBufData(0, (char *) &data,
sizeof(ginxlogInsertDataInternal));
}
elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(btree->index));
+ MarkBufferDirty(buf);
+
if (RelationNeedsWAL(btree->index) && !btree->isBuild)
{
/*
data.isDelete = insertData->isDelete;
data.offset = off;
+ XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
XLogRegisterBufData(0, (char *) &data,
offsetof(ginxlogInsertEntry, tuple));
XLogRegisterBufData(0, (char *) insertData->entry,
}
Assert((ptr - collectordata) <= collector->sumsize);
+
+ MarkBufferDirty(buffer);
+
if (needWal)
{
XLogRegisterBuffer(1, buffer, REGBUF_STANDARD);
}
metadata->tailFreeSize = PageGetExactFreeSpace(page);
-
- MarkBufferDirty(buffer);
}
/*
XLogRegisterData((char *) &xlrec, SizeOfHashDelete);
/*
- * bucket buffer needs to be registered to ensure that we can
- * acquire a cleanup lock on it during replay.
+ * bucket buffer was not changed, but still needs to be
+ * registered to ensure that we can acquire a cleanup lock on
+ * it during replay.
*/
if (!xlrec.is_primary_bucket_page)
- XLogRegisterBuffer(0, bucket_buf, REGBUF_STANDARD | REGBUF_NO_IMAGE);
+ {
+ uint8 flags = REGBUF_STANDARD | REGBUF_NO_IMAGE | REGBUF_NO_CHANGE;
+
+ XLogRegisterBuffer(0, bucket_buf, flags);
+ }
XLogRegisterBuffer(1, buf, REGBUF_STANDARD);
XLogRegisterBufData(1, (char *) deletable,
XLogRegisterData((char *) &xlrec, SizeOfHashSqueezePage);
/*
- * bucket buffer needs to be registered to ensure that we can acquire
- * a cleanup lock on it during replay.
+ * bucket buffer was not changed, but still needs to be registered to
+ * ensure that we can acquire a cleanup lock on it during replay.
*/
if (!xlrec.is_prim_bucket_same_wrt)
- XLogRegisterBuffer(0, bucketbuf, REGBUF_STANDARD | REGBUF_NO_IMAGE);
+ {
+ uint8 flags = REGBUF_STANDARD | REGBUF_NO_IMAGE | REGBUF_NO_CHANGE;
+
+ XLogRegisterBuffer(0, bucketbuf, flags);
+ }
XLogRegisterBuffer(1, wbuf, REGBUF_STANDARD);
if (xlrec.ntups > 0)
XLogRegisterData((char *) &xlrec, SizeOfHashMovePageContents);
/*
- * bucket buffer needs to be registered to ensure that
- * we can acquire a cleanup lock on it during replay.
+ * bucket buffer was not changed, but still needs to
+ * be registered to ensure that we can acquire a
+ * cleanup lock on it during replay.
*/
if (!xlrec.is_prim_bucket_same_wrt)
- XLogRegisterBuffer(0, bucket_buf, REGBUF_STANDARD | REGBUF_NO_IMAGE);
+ {
+ int flags = REGBUF_STANDARD | REGBUF_NO_IMAGE | REGBUF_NO_CHANGE;
+
+ XLogRegisterBuffer(0, bucket_buf, flags);
+ }
XLogRegisterBuffer(1, wbuf, REGBUF_STANDARD);
XLogRegisterBufData(1, (char *) itup_offsets,
Assert(!((flags & REGBUF_FORCE_IMAGE) && (flags & (REGBUF_NO_IMAGE))));
Assert(begininsert_called);
+ /*
+ * Ordinarily, buffer should be exclusive-locked and marked dirty before
+ * we get here, otherwise we could end up violating one of the rules in
+ * access/transam/README.
+ *
+ * Some callers intentionally register a clean page and never update that
+ * page's LSN; in that case they can pass the flag REGBUF_NO_CHANGE to
+ * bypass these checks.
+ */
+#ifdef USE_ASSERT_CHECKING
+ if (!(flags & REGBUF_NO_CHANGE))
+ Assert(BufferIsExclusiveLocked(buffer) && BufferIsDirty(buffer));
+#endif
+
if (block_id >= max_registered_block_id)
{
if (block_id >= max_registered_buffers)
START_CRIT_SECTION();
for (i = 0; i < nbufs; i++)
{
- XLogRegisterBuffer(i, bufpack[i], flags);
MarkBufferDirty(bufpack[i]);
+ XLogRegisterBuffer(i, bufpack[i], flags);
}
recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI);
return first_block;
}
+/*
+ * BufferIsExclusiveLocked
+ *
+ * Checks if buffer is exclusive-locked.
+ *
+ * Buffer must be pinned.
+ */
+bool
+BufferIsExclusiveLocked(Buffer buffer)
+{
+ BufferDesc *bufHdr;
+
+ if (BufferIsLocal(buffer))
+ {
+ int bufid = -buffer - 1;
+
+ bufHdr = GetLocalBufferDescriptor(bufid);
+ }
+ else
+ {
+ bufHdr = GetBufferDescriptor(buffer - 1);
+ }
+
+ Assert(BufferIsPinned(buffer));
+ return LWLockHeldByMeInMode(BufferDescriptorGetContentLock(bufHdr),
+ LW_EXCLUSIVE);
+}
+
+/*
+ * BufferIsDirty
+ *
+ * Checks if buffer is already dirty.
+ *
+ * Buffer must be pinned and exclusive-locked. (Without an exclusive lock,
+ * the result may be stale before it's returned.)
+ */
+bool
+BufferIsDirty(Buffer buffer)
+{
+ BufferDesc *bufHdr;
+
+ if (BufferIsLocal(buffer))
+ {
+ int bufid = -buffer - 1;
+
+ bufHdr = GetLocalBufferDescriptor(bufid);
+ }
+ else
+ {
+ bufHdr = GetBufferDescriptor(buffer - 1);
+ }
+
+ Assert(BufferIsPinned(buffer));
+ Assert(LWLockHeldByMeInMode(BufferDescriptorGetContentLock(bufHdr),
+ LW_EXCLUSIVE));
+
+ return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY;
+}
+
/*
* MarkBufferDirty
*
* will be skipped) */
#define REGBUF_KEEP_DATA 0x10 /* include data even if a full-page image
* is taken */
+#define REGBUF_NO_CHANGE 0x20 /* intentionally register clean buffer */
/* prototypes for public functions in xloginsert.c: */
extern void XLogBeginInsert(void);
bool permanent);
extern void ReleaseBuffer(Buffer buffer);
extern void UnlockReleaseBuffer(Buffer buffer);
+extern bool BufferIsExclusiveLocked(Buffer buffer);
+extern bool BufferIsDirty(Buffer buffer);
extern void MarkBufferDirty(Buffer buffer);
extern void IncrBufferRefCount(Buffer buffer);
extern void CheckBufferIsPinnedOnce(Buffer buffer);