Hello. I made some bugfixes and rewrite the patch.

Simon Riggs писал 2017-09-05 14:44:
As Alexander says, simply skipping truncation if standby is busy isn't
a great plan.

If we defer an action on standby replay, when and who will we apply
it? What happens if the standby is shutdown or crashes while an action
is pending.

After crash standby server will go to the nearest checkout and will replay all his wal`s to reach consistent state and then open for read-only load.
(all collected wal`s will be replayed in right way, I meant wal`s that
truncates table and wal`s that make table grow)

--
Ivan Kartyshov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 9a5fde0..68decab 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -31,6 +31,9 @@
 #include "storage/smgr.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
+#include "storage/lmgr.h"
+#include "storage/procarray.h"
+#include "access/transam.h"
 
 /*
  * We keep a list of all relations (represented as RelFileNode values)
@@ -498,50 +501,56 @@ smgr_redo(XLogReaderState *record)
 
 		reln = smgropen(xlrec->rnode, InvalidBackendId);
 
-		/*
-		 * Forcibly create relation if it doesn't exist (which suggests that
-		 * it was dropped somewhere later in the WAL sequence).  As in
-		 * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
-		 * log as best we can until the drop is seen.
-		 */
-		smgrcreate(reln, MAIN_FORKNUM, true);
-
-		/*
-		 * Before we perform the truncation, update minimum recovery point to
-		 * cover this WAL record. Once the relation is truncated, there's no
-		 * going back. The buffer manager enforces the WAL-first rule for
-		 * normal updates to relation files, so that the minimum recovery
-		 * point is always updated before the corresponding change in the data
-		 * file is flushed to disk. We have to do the same manually here.
-		 *
-		 * Doing this before the truncation means that if the truncation fails
-		 * for some reason, you cannot start up the system even after restart,
-		 * until you fix the underlying situation so that the truncation will
-		 * succeed. Alternatively, we could update the minimum recovery point
-		 * after truncation, but that would leave a small window where the
-		 * WAL-first rule could be violated.
-		 */
-		XLogFlush(lsn);
-
-		if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
+		if (!ConditionalLockRelationOid(reln->smgr_rnode.node.relNode, AccessExclusiveLock))
 		{
-			smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
+			/*
+			 * Forcibly create relation if it doesn't exist (which suggests that
+			 * it was dropped somewhere later in the WAL sequence).  As in
+			 * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
+			 * log as best we can until the drop is seen.
+			 */
+			smgrcreate(reln, MAIN_FORKNUM, true);
+
+			/*
+			 * Before we perform the truncation, update minimum recovery point to
+			 * cover this WAL record. Once the relation is truncated, there's no
+			 * going back. The buffer manager enforces the WAL-first rule for
+			 * normal updates to relation files, so that the minimum recovery
+			 * point is always updated before the corresponding change in the data
+			 * file is flushed to disk. We have to do the same manually here.
+			 *
+			 * Doing this before the truncation means that if the truncation fails
+			 * for some reason, you cannot start up the system even after restart,
+			 * until you fix the underlying situation so that the truncation will
+			 * succeed. Alternatively, we could update the minimum recovery point
+			 * after truncation, but that would leave a small window where the
+			 * WAL-first rule could be violated.
+			 */
+			XLogFlush(lsn);
 
-			/* Also tell xlogutils.c about it */
-			XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
-		}
+			if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
+			{
+				smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
+
+				/* Also tell xlogutils.c about it */
+				XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
+			}
 
-		/* Truncate FSM and VM too */
-		rel = CreateFakeRelcacheEntry(xlrec->rnode);
+			/* Truncate FSM and VM too */
+			rel = CreateFakeRelcacheEntry(xlrec->rnode);
 
-		if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
-			smgrexists(reln, FSM_FORKNUM))
-			FreeSpaceMapTruncateRel(rel, xlrec->blkno);
-		if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
-			smgrexists(reln, VISIBILITYMAP_FORKNUM))
-			visibilitymap_truncate(rel, xlrec->blkno);
+			if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
+				smgrexists(reln, FSM_FORKNUM))
+				FreeSpaceMapTruncateRel(rel, xlrec->blkno);
+			if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
+				smgrexists(reln, VISIBILITYMAP_FORKNUM))
+				visibilitymap_truncate(rel, xlrec->blkno);
 
-		FreeFakeRelcacheEntry(rel);
+			FreeFakeRelcacheEntry(rel);
+		} else
+		{
+			XLogFlush(lsn);
+		}
 	}
 	else
 		elog(PANIC, "smgr_redo: unknown op code %u", info);
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 45b1859..487b079 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -61,6 +61,8 @@
 #include "utils/pg_rusage.h"
 #include "utils/timestamp.h"
 #include "utils/tqual.h"
+#include "catalog/storage_xlog.h"
+#include "access/rmgr.h"
 
 
 /*
@@ -281,6 +283,31 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
 	 */
 	if (should_attempt_truncation(vacrelstats))
 		lazy_truncate_heap(onerel, vacrelstats);
+	else
+	{
+		if (RelationNeedsWAL(onerel))
+		{
+			/*
+			* Make an XLOG entry reporting the file truncation.
+			*/
+			XLogRecPtr      lsn;
+			xl_smgr_truncate xlrec;
+
+			/* Get the current relation length */
+			LockRelationForExtension(onerel, ExclusiveLock);
+
+			xlrec.blkno = vacrelstats->rel_pages;
+			xlrec.rnode = onerel->rd_node;
+
+			XLogBeginInsert();
+			XLogRegisterData((char *) &xlrec, sizeof(xlrec));
+
+			lsn = XLogInsert(RM_SMGR_ID,
+											XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
+			UnlockRelationForExtension(onerel, ExclusiveLock);
+			XLogFlush(lsn);
+		}
+	}
 
 	/* Report that we are now doing final cleanup */
 	pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index d491ece..6f952bf 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -624,7 +624,7 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
 
 	SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);
 
-	LockAcquireExtended(&locktag, AccessExclusiveLock, true, false, false);
+	LockAcquireExtended(&locktag, AccessExclusiveLock, true, false, false, true);
 }
 
 static void
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index fe98898..e960b26 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -232,7 +231,7 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
 						 relation->rd_lockInfo.lockRelId.dbId,
 						 relation->rd_lockInfo.lockRelId.relId);
 
-	res = LockAcquire(&tag, lockmode, false, true);
+	res = LockAcquireExtended(&tag, lockmode, false, true, true, false);
 
 	if (res == LOCKACQUIRE_NOT_AVAIL)
 		return false;
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 2b26173..40d390a 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -49,6 +49,8 @@
 #include "utils/ps_status.h"
 #include "utils/resowner_private.h"
 
+#include <execinfo.h>
+#include <dlfcn.h>
 
 /* This configuration variable is used to set the lock table size */
 int			max_locks_per_xact; /* set by guc.c */
@@ -685,7 +686,7 @@ LockAcquire(const LOCKTAG *locktag,
 			bool sessionLock,
 			bool dontWait)
 {
-	return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, true);
+	return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, true, true);
 }
 
 /*
@@ -702,7 +703,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
 					LOCKMODE lockmode,
 					bool sessionLock,
 					bool dontWait,
-					bool reportMemoryError)
+					bool reportMemoryError,
+					bool walStandby)
 {
 	LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
 	LockMethod	lockMethodTable;
@@ -813,7 +816,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	if (lockmode >= AccessExclusiveLock &&
 		locktag->locktag_type == LOCKTAG_RELATION &&
 		!RecoveryInProgress() &&
-		XLogStandbyInfoActive())
+		XLogStandbyInfoActive() &&
+		walStandby)
 	{
 		LogAccessExclusiveLockPrepare();
 		log_lock = true;
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 765431e..258b707 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -528,7 +528,8 @@ extern LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag,
 					LOCKMODE lockmode,
 					bool sessionLock,
 					bool dontWait,
-					bool report_memory_error);
+					bool report_memory_error,
+					bool walStandby);
 extern void AbortStrongLockAcquire(void);
 extern bool LockRelease(const LOCKTAG *locktag,
 			LOCKMODE lockmode, bool sessionLock);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to