wal-minimal-copy-truncate-v2-v3.diff
text/x-patch
Filename: wal-minimal-copy-truncate-v2-v3.diff
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam.c | 18 | 0 |
| src/backend/commands/copy.c | 2 | 4 |
| src/backend/commands/tablecmds.c | 3 | 0 |
| src/backend/utils/cache/relcache.c | 2 | 0 |
| src/include/utils/rel.h | 3 | 0 |
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 72395a50b8..e5c651b498 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2509,6 +2509,18 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
MarkBufferDirty(buffer);
+ /*
+ * Bulk insertion is not safe after a WAL-logging insertion in the same
+ * transaction. We don't start bulk insertion under inhibitin conditions
+ * but we also need to cancel WAL-skipping in the case where WAL-logging
+ * insertion happens during a bulk insertion. This happens by anything
+ * that can insert a tuple during bulk insertion such like triggers,
+ * constraints or type conversions. We need not worry about relcache flush
+ * happening while a bulk insertion is running.
+ */
+ if (relation->last_logged_insert_xid == xid)
+ options &= ~HEAP_INSERT_SKIP_WAL;
+
/* XLOG stuff */
if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
{
@@ -2582,6 +2594,12 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
recptr = XLogInsert(RM_HEAP_ID, info);
PageSetLSN(page, recptr);
+
+ /*
+ * If this happens during a bulk insertion, stop WAL skipping for the
+ * rest of the current command.
+ */
+ relation->last_logged_insert_xid = xid;
}
END_CRIT_SECTION();
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 7674369613..7b9a7af2d2 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2416,10 +2416,8 @@ CopyFrom(CopyState cstate)
{
hi_options |= HEAP_INSERT_SKIP_FSM;
- if (!XLogIsNeeded() &&
- cstate->rel->trigdesc == NULL &&
- RelationGetNumberOfBlocks(cstate->rel) == 0)
- hi_options |= HEAP_INSERT_SKIP_WAL;
+ if (!XLogIsNeeded() && RelationGetNumberOfBlocks(cstate->rel) == 0)
+ hi_options |= HEAP_INSERT_SKIP_WAL;
}
/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 30a956822f..34a692a497 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1575,6 +1575,9 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
{
/* Immediate, non-rollbackable truncation is OK */
heap_truncate_one_rel(rel);
+
+ /* Allow bulk-insert */
+ rel->last_logged_insert_xid = InvalidTransactionId;
}
else
{
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 6125421d39..99fb7e1dd8 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1243,6 +1243,8 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
/* It's fully valid */
relation->rd_isvalid = true;
+ relation->last_logged_insert_xid = InvalidTransactionId;
+
return relation;
}
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index c97f9d1b43..6ee575ad14 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -188,6 +188,9 @@ typedef struct RelationData
/* use "struct" here to avoid needing to include pgstat.h: */
struct PgStat_TableStatus *pgstat_info; /* statistics collection area */
+
+ /* XID of the last transaction on which WAL-logged insertion happened */
+ TransactionId last_logged_insert_xid;
} RelationData;