Hi, hackers.
Right now if replication level is rgeater or equal than "replica",
vacuum of relation copies all its data to WAL:
/*
* We need to log the copied data in WAL iff WAL archiving/streaming is
* enabled AND it's a WAL-logged rel.
*/
use_wal = XLogIsNeeded() && RelationNeedsWAL(NewHeap);
Obviously we have to do it for physical replication and WAL archiving.
But why do we need to do so expensive operation (actually copy all table
data three times) if we use logical replication?
Logically vacuum doesn't change relation so there is no need to write
any data to the log and process it by WAL sender.
I wonder if we can check that
1. wal_revel is "logical"
2. There are no physical replication slots
3. WAL archiving is disables
and in this cases do not write cloned relation to the WAL?
Small patch implementing such behavior is attached to this mail.
It allows to significantly reduce WAL size when performing vacuum at
multimaster, which uses logical replication between cluster nodes.
What can be wrong with such optimization?
--
Konstantin Knizhnik
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index f1ff01e..1d0a957 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -36,6 +36,7 @@
#include "commands/progress.h"
#include "executor/executor.h"
#include "pgstat.h"
+#include "replication/slot.h"
#include "storage/bufmgr.h"
#include "storage/bufpage.h"
#include "storage/bufmgr.h"
@@ -719,7 +720,8 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
* We need to log the copied data in WAL iff WAL archiving/streaming is
* enabled AND it's a WAL-logged rel.
*/
- use_wal = XLogIsNeeded() && RelationNeedsWAL(NewHeap);
+ use_wal = XLogIsNeeded() && RelationNeedsWAL(NewHeap)
+ && (wal_level != WAL_LEVEL_LOGICAL || ReplicationSlotsCountPhysicalSlots() != 0 || XLogArchiveMode != ARCHIVE_MODE_OFF);
/* use_wal off requires smgr_targblock be initially invalid */
Assert(RelationGetTargetBlock(NewHeap) == InvalidBlockNumber);
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 62342a6..7961056 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -829,6 +829,27 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
}
/*
+ * Count physical replication slots
+ */
+int
+ReplicationSlotsCountPhysicalSlots(void)
+{
+ int i;
+ int n_slots = 0;
+
+ LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
+ for (i = 0; i < max_replication_slots; i++)
+ {
+ ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
+ n_slots += !SlotIsLogical(s);
+ }
+ LWLockRelease(ReplicationSlotControlLock);
+
+ return n_slots;
+}
+
+
+/*
* ReplicationSlotsCountDBSlots -- count the number of slots that refer to the
* passed database oid.
*
diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h
index 8fbddea..50ca192 100644
--- a/src/include/replication/slot.h
+++ b/src/include/replication/slot.h
@@ -199,6 +199,7 @@ extern void ReplicationSlotsComputeRequiredLSN(void);
extern XLogRecPtr ReplicationSlotsComputeLogicalRestartLSN(void);
extern bool ReplicationSlotsCountDBSlots(Oid dboid, int *nslots, int *nactive);
extern void ReplicationSlotsDropDBSlots(Oid dboid);
+extern int ReplicationSlotsCountPhysicalSlots(void);
extern void StartupReplicationSlots(void);
extern void CheckPointReplicationSlots(void);