Search Postgresql Archives

Re: New 8.4 hot standby feature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2009-01-27 at 12:53 -0500, Gabi Julien wrote:
> I have merged the last hot standby patch (v9g) to 8.4 devel and I am pleased  
> with the experience. This is promising stuff. 

Thanks,

> Perhaps it is a bit too soon to  
> ask questions here but here it is:

Thanks very much for the bug report.

> 1. Speed of recovery
> 
> With a archive_timeout of 60 seconds, it can take about 4 minutes before I see 
> the reflected changes in the replica. This is normal since, in addition to 
> the WAL log shipping, it takes more time to do the recovery itself. Still, is 
> there any way besides the archive_timeout config option to speed up the 
> recovery of WAL logs on the hot standby? 

There was a reported bug whose apparent symptoms were delay of WAL
files. The bug was not in fact anything to do with that at all, it was
just delayed *visibility*. So I doubt very much that you have a
performance problem.

The bug fix patch is attached, verified to solve the problem.

-- 
 Simon Riggs           www.2ndQuadrant.com
 PostgreSQL Training, Services and Support
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 1381,1387 **** RecordTransactionAbort(bool isSubXact)
  	 * main xacts, the equivalent happens just after this function returns.
  	 */
  	if (isSubXact)
! 		XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
  	if (!isSubXact)
--- 1381,1387 ----
  	 * main xacts, the equivalent happens just after this function returns.
  	 */
  	if (isSubXact)
! 		XidCacheRemoveRunningXids(MyProc, xid, nchildren, children, latestXid);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
  	if (!isSubXact)
***************
*** 4536,4541 **** RecordKnownAssignedTransactionIds(XLogRecPtr lsn, TransactionId top_xid, Transac
--- 4536,4548 ----
  		{
  			int			nxids = myproc->subxids.nxids;
  
+ 			/*
+ 			 * It's possible for us to overflow the subxid cache and then
+ 			 * for a subtransaction abort to reduce the number of subxids
+ 			 * in the cache below the cache threshold again. If that happens
+ 			 * then it's still OK for us to use the subxid cache again, since
+ 			 * once its in the cache it lives there till abort or commit.
+ 			 */
  			if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
  			{
  				/* 
***************
*** 4621,4629 **** RecordKnownAssignedTransactionIds(XLogRecPtr lsn, TransactionId top_xid, Transac
  	LWLockRelease(ProcArrayLock);
  
  	elog(trace_recovery(DEBUG4), 
! 					"record known xact top_xid %u child_xid %u %slatestObservedXid %u",
  					top_xid, child_xid,
  					(unobserved ? "unobserved " : " "),
  					latestObservedXid);
  
  	/* 
--- 4628,4637 ----
  	LWLockRelease(ProcArrayLock);
  
  	elog(trace_recovery(DEBUG4), 
! 					"record known xact top_xid %u child_xid %u %s%slatestObservedXid %u",
  					top_xid, child_xid,
  					(unobserved ? "unobserved " : " "),
+ 					(mark_subtrans ? "mark subtrans " : " "),
  					latestObservedXid);
  
  	/* 
***************
*** 4690,4707 **** xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, bool preparedXact)
  	PGPROC	   *proc;
  	int			i;
  
- 	/* Make sure nextXid is beyond any XID mentioned in the record */
- 	max_xid = xid;
  	sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
  
! 	/*
! 	 * Find the highest xid and remove unobserved xids if required.
! 	 */
! 	for (i = 0; i < xlrec->nsubxacts; i++)
! 	{
! 		if (TransactionIdPrecedes(max_xid, sub_xids[i]))
! 			max_xid = sub_xids[i];
! 	}
  
  	/* Mark the transaction committed in pg_clog */
  	TransactionIdCommitTree(xid, xlrec->nsubxacts, sub_xids);
--- 4698,4706 ----
  	PGPROC	   *proc;
  	int			i;
  
  	sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
  
! 	max_xid = TransactionIdLatest(xid, xlrec->nsubxacts, sub_xids);
  
  	/* Mark the transaction committed in pg_clog */
  	TransactionIdCommitTree(xid, xlrec->nsubxacts, sub_xids);
***************
*** 4720,4726 **** xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, bool preparedXact)
  		 */
  		if (IsRunningXactDataValid() && !preparedXact)
  		{
! 			ProcArrayRemove(proc, InvalidTransactionId, xlrec->nsubxacts, sub_xids);
  			FreeRecoveryProcess(proc);
  		}
  
--- 4719,4725 ----
  		 */
  		if (IsRunningXactDataValid() && !preparedXact)
  		{
! 			ProcArrayRemove(proc, max_xid, xlrec->nsubxacts, sub_xids);
  			FreeRecoveryProcess(proc);
  		}
  
***************
*** 4790,4821 **** xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, bool preparedXact)
  /*
   * Be careful with the order of execution, as with xact_redo_commit().
   * The two functions are similar but differ in key places.
   */
  static void
! xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid, bool preparedXact)
  {
  	PGPROC		*proc = NULL;
  	TransactionId *sub_xids;
  	TransactionId max_xid;
  	int			i;
  
- 	/* Make sure nextXid is beyond any XID mentioned in the record */
- 	max_xid = xid;
  	sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
! 
! 	/*
! 	 * Find the highest xid and remove unobserved xids if required.
! 	 */
! 	for (i = 0; i < xlrec->nsubxacts; i++)
! 	{
! 		if (TransactionIdPrecedes(max_xid, sub_xids[i]))
! 			max_xid = sub_xids[i];
! 	}
  
  	/* Mark the transaction aborted in pg_clog */
  	TransactionIdAbortTree(xid, xlrec->nsubxacts, sub_xids);
  
! 	if (InArchiveRecovery && (proc = BackendXidGetProc(xid)) != NULL)
  	{
  		/*
  		 * We must mark clog before we update the ProcArray. Only update
--- 4789,4815 ----
  /*
   * Be careful with the order of execution, as with xact_redo_commit().
   * The two functions are similar but differ in key places.
+  *
+  * Note also that an abort can be for a subtransaction and its children,
+  * not just for a top level abort. That means we have to consider
+  * topxid != xid, whereas in commit we would find topxid == xid always
+  * because subtransaction commit is never WAL logged.
   */
  static void
! xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid, TransactionId topxid, bool preparedXact)
  {
  	PGPROC		*proc = NULL;
  	TransactionId *sub_xids;
  	TransactionId max_xid;
  	int			i;
  
  	sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
! 	max_xid = TransactionIdLatest(xid, xlrec->nsubxacts, sub_xids);
  
  	/* Mark the transaction aborted in pg_clog */
  	TransactionIdAbortTree(xid, xlrec->nsubxacts, sub_xids);
  
! 	if (InArchiveRecovery && (proc = BackendXidGetProc(topxid)) != NULL)
  	{
  		/*
  		 * We must mark clog before we update the ProcArray. Only update
***************
*** 4827,4840 **** xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid, bool preparedXact)
  		 * happened, but there are cases where they might sneak through.
  		 * Leave these for the periodic cleanup by XACT_RUNNING_XACT records.
  		 */
! 		if (IsRunningXactDataValid() && 
! 			TransactionIdIsValid(proc->xid) && !preparedXact)
  		{
! 			ProcArrayRemove(proc, InvalidTransactionId, xlrec->nsubxacts, sub_xids);
! 			FreeRecoveryProcess(proc);
  		}
  
  		/*
  		 * Release locks, if any. There are no invalidations to send.
  		 */
  		RelationReleaseRecoveryLockTree(xid, xlrec->nsubxacts, sub_xids);
--- 4821,4846 ----
  		 * happened, but there are cases where they might sneak through.
  		 * Leave these for the periodic cleanup by XACT_RUNNING_XACT records.
  		 */
! 		if (IsRunningXactDataValid() && !preparedXact)
  		{
! 			/*
! 			 * Do we have a top-level transaction abort, or not?
! 			 */
! 			if (topxid == xid)
! 			{
! 				ProcArrayRemove(proc, max_xid, xlrec->nsubxacts, sub_xids);
! 				FreeRecoveryProcess(proc);
! 			}
! 			else
! 				XidCacheRemoveRunningXids(proc, xid, xlrec->nsubxacts, sub_xids, max_xid);
  		}
  
  		/*
+ 		 * There are no flat files that need updating, nor invalidation
+ 		 * messages to send or undo.
+ 		 */
+ 
+ 		/*
  		 * Release locks, if any. There are no invalidations to send.
  		 */
  		RelationReleaseRecoveryLockTree(xid, xlrec->nsubxacts, sub_xids);
***************
*** 4937,4943 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
  	{
  		xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
  
! 		xact_redo_abort(xlrec, record->xl_xid, false);
  	}
  	else if (info == XLOG_XACT_PREPARE)
  	{
--- 4943,4949 ----
  	{
  		xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
  
! 		xact_redo_abort(xlrec, record->xl_xid, record->xl_topxid, false);
  	}
  	else if (info == XLOG_XACT_PREPARE)
  	{
***************
*** 4956,4962 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
  	{
  		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) XLogRecGetData(record);
  
! 		xact_redo_abort(&xlrec->arec, xlrec->xid, true);
  		RemoveTwoPhaseFile(xlrec->xid, false);
  	}
  	else
--- 4962,4968 ----
  	{
  		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) XLogRecGetData(record);
  
! 		xact_redo_abort(&xlrec->arec, xlrec->xid, record->xl_topxid, true);
  		RemoveTwoPhaseFile(xlrec->xid, false);
  	}
  	else
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
***************
*** 2061,2068 **** CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
  
  #define XidCacheRemove(i) \
  	do { \
! 		MyProc->subxids.xids[i] = MyProc->subxids.xids[MyProc->subxids.nxids - 1]; \
! 		MyProc->subxids.nxids--; \
  	} while (0)
  
  /*
--- 2061,2068 ----
  
  #define XidCacheRemove(i) \
  	do { \
! 		proc->subxids.xids[i] = proc->subxids.xids[proc->subxids.nxids - 1]; \
! 		proc->subxids.nxids--; \
  	} while (0)
  
  /*
***************
*** 2074,2080 **** CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
   * latestXid must be the latest XID among the group.
   */
  void
! XidCacheRemoveRunningXids(TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid)
  {
--- 2074,2080 ----
   * latestXid must be the latest XID among the group.
   */
  void
! XidCacheRemoveRunningXids(PGPROC *proc, TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid)
  {
***************
*** 2101,2109 **** XidCacheRemoveRunningXids(TransactionId xid,
  	{
  		TransactionId anxid = xids[i];
  
! 		for (j = MyProc->subxids.nxids - 1; j >= 0; j--)
  		{
! 			if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
  			{
  				XidCacheRemove(j);
  				break;
--- 2101,2109 ----
  	{
  		TransactionId anxid = xids[i];
  
! 		for (j = proc->subxids.nxids - 1; j >= 0; j--)
  		{
! 			if (TransactionIdEquals(proc->subxids.xids[j], anxid))
  			{
  				XidCacheRemove(j);
  				break;
***************
*** 2117,2137 **** XidCacheRemoveRunningXids(TransactionId xid,
  		 * error during AbortSubTransaction.  So instead of Assert, emit a
  		 * debug warning.
  		 */
! 		if (j < 0 && !MyProc->subxids.overflowed)
! 			elog(WARNING, "did not find subXID %u in MyProc", anxid);
  	}
  
! 	for (j = MyProc->subxids.nxids - 1; j >= 0; j--)
  	{
! 		if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
  		{
  			XidCacheRemove(j);
  			break;
  		}
  	}
  	/* Ordinarily we should have found it, unless the cache has overflowed */
! 	if (j < 0 && !MyProc->subxids.overflowed)
! 		elog(WARNING, "did not find subXID %u in MyProc", xid);
  
  	/* Also advance global latestCompletedXid while holding the lock */
  	if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
--- 2117,2137 ----
  		 * error during AbortSubTransaction.  So instead of Assert, emit a
  		 * debug warning.
  		 */
! 		if (j < 0 && !proc->subxids.overflowed)
! 			elog(WARNING, "did not find subXID %u in proc", anxid);
  	}
  
! 	for (j = proc->subxids.nxids - 1; j >= 0; j--)
  	{
! 		if (TransactionIdEquals(proc->subxids.xids[j], xid))
  		{
  			XidCacheRemove(j);
  			break;
  		}
  	}
  	/* Ordinarily we should have found it, unless the cache has overflowed */
! 	if (j < 0 && !proc->subxids.overflowed)
! 		elog(WARNING, "did not find subXID %u in proc", xid);
  
  	/* Also advance global latestCompletedXid while holding the lock */
  	if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
*** a/src/backend/utils/cache/inval.c
--- b/src/backend/utils/cache/inval.c
***************
*** 1635,1641 **** ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
   * We only keep track of AccessExclusiveLocks, which are only ever held by
   * one transaction on one relation, and don't worry about lock queuing.
   * 
!  * We keep a single dynamically expandible locks list in local memory.
   * List elements use type xl_rel_lock, since the WAL record type exactly
   * matches the information that we need to keep track of.
   *
--- 1635,1644 ----
   * We only keep track of AccessExclusiveLocks, which are only ever held by
   * one transaction on one relation, and don't worry about lock queuing.
   * 
!  * We keep a single dynamically expandible list of locks in local memory,
!  * RelationLockList, so we can keep track of the various entried made by 
!  * the Startup process's virtual xid in the shared lock table.
!  *
   * List elements use type xl_rel_lock, since the WAL record type exactly
   * matches the information that we need to keep track of.
   *
*** a/src/include/storage/procarray.h
--- b/src/include/storage/procarray.h
***************
*** 63,69 **** extern int	CountUserBackends(Oid roleid);
  extern bool CountOtherDBBackends(Oid databaseId,
  								 int *nbackends, int *nprepared);
  
! extern void XidCacheRemoveRunningXids(TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid);
  
--- 63,69 ----
  extern bool CountOtherDBBackends(Oid databaseId,
  								 int *nbackends, int *nprepared);
  
! extern void XidCacheRemoveRunningXids(PGPROC *proc, TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid);
  
-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux