diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index ea83655..973830b 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -35,11 +35,14 @@
 #include "access/clog.h"
 #include "access/slru.h"
 #include "access/transam.h"
+#include "access/twophase.h"
 #include "access/xlog.h"
 #include "access/xloginsert.h"
 #include "access/xlogutils.h"
 #include "miscadmin.h"
 #include "pg_trace.h"
+#include "storage/ipc.h"
+#include "storage/proc.h"
 
 /*
  * Defines for CLOG page sizes.  A page is the same BLCKSZ as is used
@@ -86,12 +89,19 @@ static void WriteZeroPageXlogRec(int pageno);
 static void WriteTruncateXlogRec(int pageno);
 static void TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
 						   TransactionId *subxids, XidStatus status,
-						   XLogRecPtr lsn, int pageno);
+						   XLogRecPtr lsn, int pageno,
+						   bool all_trans_same_page);
 static void TransactionIdSetStatusBit(TransactionId xid, XidStatus status,
 						  XLogRecPtr lsn, int slotno);
 static void set_status_by_pages(int nsubxids, TransactionId *subxids,
 					XidStatus status, XLogRecPtr lsn);
-
+static bool TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
+								XLogRecPtr lsn, int pageno);
+static void TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
+								   TransactionId *subxids, XidStatus status,
+								   XLogRecPtr lsn, int pageno);
+static void finish_transaction_set_status_callback(int code, Datum arg);
+static inline void wake_clog_group(uint32 wakeidx);
 
 /*
  * TransactionIdSetTreeStatus
@@ -173,7 +183,7 @@ TransactionIdSetTreeStatus(TransactionId xid, int nsubxids,
 		 * Set the parent and all subtransactions in a single call
 		 */
 		TransactionIdSetPageStatus(xid, nsubxids, subxids, status, lsn,
-								   pageno);
+								   pageno, true);
 	}
 	else
 	{
@@ -200,7 +210,7 @@ TransactionIdSetTreeStatus(TransactionId xid, int nsubxids,
 		 */
 		pageno = TransactionIdToPage(xid);
 		TransactionIdSetPageStatus(xid, nsubxids_on_first_page, subxids, status,
-								   lsn, pageno);
+								   lsn, pageno, false);
 
 		/*
 		 * Now work through the rest of the subxids one clog page at a time,
@@ -238,7 +248,7 @@ set_status_by_pages(int nsubxids, TransactionId *subxids,
 
 		TransactionIdSetPageStatus(InvalidTransactionId,
 								   num_on_page, subxids + offset,
-								   status, lsn, pageno);
+								   status, lsn, pageno, false);
 		offset = i;
 		pageno = TransactionIdToPage(subxids[offset]);
 	}
@@ -248,12 +258,78 @@ set_status_by_pages(int nsubxids, TransactionId *subxids,
  * Record the final state of transaction entries in the commit log for
  * all entries on a single page.  Atomic only on this page.
  *
+ * Group the status update for transactions. This improves the efficiency
+ * of the transaction status update by reducing the number of lock
+ * acquisitions required for it.  To achieve the group transaction status
+ * update, we need to populate the transaction status related information
+ * in shared memory and doing it for overflowed sub-transactions would need
+ * a big chunk of shared memory, so we are not doing this optimization for
+ * such cases. This optimization is only applicable if the transaction and
+ * all child sub-transactions belong to same page which we presume to be the
+ * most common case, we might be able to apply this when they are not on same
+ * page, but that needs us to map sub-transactions in proc's XidCache based
+ * on pageno for which each time Group leader needs to set the transaction
+ * status and that can lead to some performance penalty as well because it
+ * needs to be done after acquiring CLogControlLock, so let's leave that
+ * case for now.  We don't do this optimization for prepared transactions
+ * as the dummy proc associated with such transactions doesn't have a
+ * semaphore associated with it and the same is required for group status
+ * update.  We choose not to create a semaphore for dummy procs for this
+ * purpose as the advantage of using this optimization for prepared transactions
+ * is not clear.
+ *
  * Otherwise API is same as TransactionIdSetTreeStatus()
  */
 static void
 TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
 						   TransactionId *subxids, XidStatus status,
-						   XLogRecPtr lsn, int pageno)
+						   XLogRecPtr lsn, int pageno,
+						   bool all_trans_same_page)
+{
+	if (!InRecovery &&
+		all_trans_same_page &&
+		nsubxids < PGPROC_MAX_CACHED_SUBXIDS &&
+		!IsGXactActive())
+	{
+		/*
+		 * If we can immediately acquire CLogControlLock, we update the status
+		 * of our own XID and release the lock.  If not, use group XID status
+		 * update to improve efficiency and if still not able to update, then
+		 * acquire CLogControlLock and update it.
+		 */
+		if (LWLockConditionalAcquire(CLogControlLock, LW_EXCLUSIVE))
+		{
+			TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status, lsn, pageno);
+			LWLockRelease(CLogControlLock);
+		}
+		else if (!TransactionGroupUpdateXidStatus(xid, status, lsn, pageno))
+		{
+			LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
+
+			TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status, lsn, pageno);
+
+			LWLockRelease(CLogControlLock);
+		}
+	}
+	else
+	{
+		LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
+
+		TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status, lsn, pageno);
+
+		LWLockRelease(CLogControlLock);
+	}
+}
+
+/*
+ * Record the final state of transaction entry in the commit log
+ *
+ * We don't do any locking here; caller must handle that.
+ */
+static void
+TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
+								   TransactionId *subxids, XidStatus status,
+								   XLogRecPtr lsn, int pageno)
 {
 	int			slotno;
 	int			i;
@@ -262,8 +338,6 @@ TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
 		   status == TRANSACTION_STATUS_ABORTED ||
 		   (status == TRANSACTION_STATUS_SUB_COMMITTED && !TransactionIdIsValid(xid)));
 
-	LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
-
 	/*
 	 * If we're doing an async commit (ie, lsn is valid), then we must wait
 	 * for any active write on the page slot to complete.  Otherwise our
@@ -310,8 +384,166 @@ TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
 	}
 
 	ClogCtl->shared->page_dirty[slotno] = true;
+}
+
+/*
+ * When we cannot immediately acquire CLogControlLock in exclusive mode at
+ * commit time, add ourselves to a list of processes that need their XIDs
+ * status update.  The first process to add itself to the list will acquire
+ * CLogControlLock in exclusive mode and perform TransactionIdSetPageStatusInternal
+ * on behalf of all group members.  This avoids a great deal of contention
+ * around CLogControlLock when many processes are trying to commit at once,
+ * since the lock need not be repeatedly handed off from one committing
+ * process to the next.
+ *
+ * Returns true, if transaction status is updated in clog page, else return
+ * false.
+ */
+static bool
+TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
+								XLogRecPtr lsn, int pageno)
+{
+	volatile PROC_HDR *procglobal = ProcGlobal;
+	PGPROC	   *proc = MyProc;
+	uint32		nextidx;
+	uint32		wakeidx;
+	int			extraWaits = -1;
+
+	/* We should definitely have an XID whose status needs to be updated. */
+	Assert(TransactionIdIsValid(xid));
+
+	/*
+	 * Add ourselves to the list of processes needing a group XID status
+	 * update.
+	 */
+	proc->clogGroupMember = true;
+	proc->clogGroupMemberSuccess = false;
+	proc->clogGroupMemberXid = xid;
+	proc->clogGroupMemberXidStatus = status;
+	proc->clogGroupMemberPage = pageno;
+	proc->clogGroupMemberLsn = lsn;
+	while (true)
+	{
+		nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+
+		/*
+		 * Add the proc to list if the clog page where we need to update the
+		 * current transaction status is same as group leader's clog page.
+		 */
+		if (nextidx != INVALID_PGPROCNO &&
+			*(&procglobal->allProcs[nextidx].clogGroupMemberPage) != proc->clogGroupMemberPage)
+			return false;
+
+		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
+
+		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+										   &nextidx,
+										   (uint32) proc->pgprocno))
+			break;
+	}
+
+	/*
+	 * If the list was not empty, the leader will update the status of our
+	 * XID. It is impossible to have followers without a leader because the
+	 * first process that has added itself to the list will always have
+	 * nextidx as INVALID_PGPROCNO.
+	 */
+	if (nextidx != INVALID_PGPROCNO)
+	{
+		/* Sleep until the leader updates our XID status. */
+		for (;;)
+		{
+			/* acts as a read barrier */
+			PGSemaphoreLock(&proc->sem);
+			if (!proc->clogGroupMember)
+				break;
+			extraWaits++;
+		}
 
+		Assert(pg_atomic_read_u32(&proc->clogGroupNext) == INVALID_PGPROCNO);
+
+		/* Fix semaphore count for any absorbed wakeups */
+		while (extraWaits-- > 0)
+			PGSemaphoreUnlock(&proc->sem);
+
+		/*
+		 * if the transaction status is not update successfully, then allow the
+		 * caller to do it
+		 */
+		if (proc->clogGroupMemberSuccess)
+			return true;
+		else
+			return false;
+	}
+
+	/* We are the leader.  Acquire the lock on behalf of everyone. */
+	LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
+
+	/*
+	 * Now that we've got the lock, clear the list of processes waiting for
+	 * group XID status update, saving a pointer to the head of the list.
+	 * Trying to pop elements one at a time could lead to an ABA problem.
+	 */
+	while (true)
+	{
+		nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+										   &nextidx,
+										   INVALID_PGPROCNO))
+			break;
+	}
+
+	/* Remember head of list so we can perform wakeups after dropping lock. */
+	wakeidx = nextidx;
+
+
+	/*
+	 * The ENSURE stuff ensures that on error, we wakeup procs waiting for
+	 * transaction status update.
+	 */
+	PG_ENSURE_ERROR_CLEANUP(finish_transaction_set_status_callback, PointerGetDatum(&wakeidx));
+	{
+		/* Walk the list and update the status of all XIDs. */
+		while (nextidx != INVALID_PGPROCNO)
+		{
+			PGPROC	   *proc = &ProcGlobal->allProcs[nextidx];
+			PGXACT	   *pgxact = &ProcGlobal->allPgXact[nextidx];
+
+			/*
+			 * Overflowed transactions should not use group XID status update
+			 * mechanism.
+			 */
+			Assert(!pgxact->overflowed);
+
+			TransactionIdSetPageStatusInternal(proc->clogGroupMemberXid,
+											   pgxact->nxids,
+											   proc->subxids.xids,
+											   proc->clogGroupMemberXidStatus,
+											   proc->clogGroupMemberLsn,
+											   proc->clogGroupMemberPage);
+
+			/* successfully updated the transaction status */
+			proc->clogGroupMemberSuccess = true;
+
+			/* Move to next proc in list. */
+			nextidx = pg_atomic_read_u32(&proc->clogGroupNext);
+		}
+	}
+	PG_END_ENSURE_ERROR_CLEANUP(finish_transaction_set_status_callback, PointerGetDatum(&wakeidx));
+
+	/* We're done with the lock now. */
 	LWLockRelease(CLogControlLock);
+
+	/*
+	 * Now that we've released the lock, go back and wake everybody up.  We
+	 * don't do this under the lock so as to keep lock hold times to a
+	 * minimum.  The system calls we need to perform to wake other processes
+	 * up are probably much slower than the simple memory writes we did while
+	 * holding the lock.
+	 */
+	wake_clog_group(wakeidx);
+
+	return true;
 }
 
 /*
@@ -374,6 +606,40 @@ TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, i
 }
 
 /*
+ * Wake all the procs waiting for transaction status update.
+ */
+static inline void wake_clog_group(uint32 wakeidx)
+{
+	while (wakeidx != INVALID_PGPROCNO)
+	{
+		PGPROC	   *proc = &ProcGlobal->allProcs[wakeidx];
+
+		wakeidx = pg_atomic_read_u32(&proc->clogGroupNext);
+		pg_atomic_write_u32(&proc->clogGroupNext, INVALID_PGPROCNO);
+
+		/* ensure all previous writes are visible before follower continues. */
+		pg_write_barrier();
+
+		proc->clogGroupMember = false;
+
+		if (proc != MyProc)
+			PGSemaphoreUnlock(&proc->sem);
+	}
+}
+
+/*
+ * Callback to wakeup all the procs waiting for transaction status
+ * update on error.
+ */
+static void
+finish_transaction_set_status_callback(int code, Datum arg)
+{
+	uint32	*wakeidx = (uint32 *) DatumGetPointer(arg);
+
+	wake_clog_group(*wakeidx);
+}
+
+/*
  * Interrogate the state of a transaction in the commit log.
  *
  * Aside from the actual commit status, this function returns (into *lsn)
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 8c47e0f..471280f 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -828,6 +828,17 @@ TwoPhaseGetDummyProc(TransactionId xid)
 	return &ProcGlobal->allProcs[gxact->pgprocno];
 }
 
+/*
+ * IsGXactActive
+ *		Return true if there is a Global transaction entry currently
+ *		locked by us.
+ */
+bool
+IsGXactActive(void)
+{
+	return MyLockedGxact ? true : false;
+}
+
 /************************************************************************/
 /* State file support													*/
 /************************************************************************/
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index bb10c1b..d7bb1f9 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -182,6 +182,7 @@ InitProcGlobal(void)
 	ProcGlobal->walwriterLatch = NULL;
 	ProcGlobal->checkpointerLatch = NULL;
 	pg_atomic_init_u32(&ProcGlobal->firstClearXidElem, INVALID_PGPROCNO);
+	pg_atomic_init_u32(&ProcGlobal->clogGroupFirst, INVALID_PGPROCNO);
 
 	/*
 	 * Create and initialize all the PGPROC structures we'll need.  There are
@@ -397,6 +398,15 @@ InitProcess(void)
 	MyProc->backendLatestXid = InvalidTransactionId;
 	pg_atomic_init_u32(&MyProc->nextClearXidElem, INVALID_PGPROCNO);
 
+	/* Initialize fields for group transaction status update. */
+	MyProc->clogGroupMember = false;
+	MyProc->clogGroupMemberSuccess = false;
+	MyProc->clogGroupMemberXid = InvalidTransactionId;
+	MyProc->clogGroupMemberXidStatus = TRANSACTION_STATUS_IN_PROGRESS;
+	MyProc->clogGroupMemberPage = -1;
+	MyProc->clogGroupMemberLsn = InvalidXLogRecPtr;
+	pg_atomic_init_u32(&MyProc->clogGroupNext, INVALID_PGPROCNO);
+
 	/*
 	 * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch
 	 * on it.  That allows us to repoint the process latch, which so far
diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h
index 71ddff7..feec01d 100644
--- a/src/include/access/twophase.h
+++ b/src/include/access/twophase.h
@@ -35,6 +35,7 @@ extern void PostPrepare_Twophase(void);
 
 extern PGPROC *TwoPhaseGetDummyProc(TransactionId xid);
 extern BackendId TwoPhaseGetDummyBackendId(TransactionId xid);
+extern bool IsGXactActive(void);
 
 extern GlobalTransaction MarkAsPreparing(TransactionId xid, const char *gid,
 				TimestampTz prepared_at,
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 3d68017..45aef86 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -14,6 +14,7 @@
 #ifndef _PROC_H_
 #define _PROC_H_
 
+#include "access/clog.h"
 #include "access/xlogdefs.h"
 #include "lib/ilist.h"
 #include "storage/latch.h"
@@ -146,6 +147,22 @@ struct PGPROC
 	pg_atomic_uint32	nextClearXidElem;
 	TransactionId	backendLatestXid;
 
+	/* Support for group transaction status update. */
+	/* true, if member of clog Group updating transaction status  */
+	bool		clogGroupMember;
+	/* true, if transaction status is updated successfully   */
+	bool		clogGroupMemberSuccess;
+	/* pgprocno of next clog group member  */
+	pg_atomic_uint32 clogGroupNext;
+	/* transactionid whose status needs to be updated */
+	TransactionId clogGroupMemberXid;
+	/* status of transaction */
+	XidStatus	clogGroupMemberXidStatus;
+	/* page no. on which transaction status needs to be updated */
+	int			clogGroupMemberPage;
+	/* lsn for async transaction commit */
+	XLogRecPtr	clogGroupMemberLsn;
+
 	/* Per-backend LWLock.  Protects fields below. */
 	LWLock	   *backendLock;	/* protects the fields below */
 
@@ -209,6 +226,8 @@ typedef struct PROC_HDR
 	PGPROC	   *bgworkerFreeProcs;
 	/* First pgproc waiting for group XID clear */
 	pg_atomic_uint32 firstClearXidElem;
+	/* First pgproc waiting for group transaction status update */
+	pg_atomic_uint32 clogGroupFirst;
 	/* WALWriter process's latch */
 	Latch	   *walwriterLatch;
 	/* Checkpointer process's latch */
