Example #1
0
/*
 * Find a page in a shared buffer, reading it in if necessary.
 * The page number must correspond to an already-initialized page.
 * The caller must intend only read-only access to the page.
 *
 * The passed-in xid is used only for error reporting, and may be
 * InvalidTransactionId if no specific xid is associated with the action.
 *
 * Return value is the shared-buffer slot number now holding the page.
 * The buffer's LRU access info is updated.
 *
 * Control lock must NOT be held at entry, but will be held at exit.
 * It is unspecified whether the lock will be shared or exclusive.
 */
int
SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
{
	SlruShared	shared = ctl->shared;
	int			slotno;

	/* Try to find the page while holding only shared lock */
	LWLockAcquire(shared->ControlLock, LW_SHARED);

	/* See if page is already in a buffer */
	for (slotno = 0; slotno < shared->num_slots; slotno++)
	{
		if (shared->page_number[slotno] == pageno &&
			shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
			shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
		{
			/* See comments for SlruRecentlyUsed macro */
			SlruRecentlyUsed(shared, slotno);
			return slotno;
		}
	}

	/* No luck, so switch to normal exclusive lock and do regular read */
	LWLockRelease(shared->ControlLock);
	LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);

	return SimpleLruReadPage(ctl, pageno, true, xid);
}
Example #2
0
/*
 * Record the parent of a subtransaction in the subtrans log.
 */
void
SubTransSetParent(TransactionId xid, TransactionId parent)
{
	int			pageno = TransactionIdToPage(xid);
	int			entryno = TransactionIdToEntry(xid);
	int			slotno;
	TransactionId *ptr;

	Assert(TransactionIdIsValid(parent));
	Assert(TransactionIdFollows(xid, parent));

	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);

	slotno = SimpleLruReadPage(SubTransCtl, pageno, true, xid);
	ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
	ptr += entryno;

	/*
	 * It's possible we'll try to set the parent xid multiple times but we
	 * shouldn't ever be changing the xid from one valid xid to another valid
	 * xid, which would corrupt the data structure.
	 */
	if (*ptr != parent)
	{
		Assert(*ptr == InvalidTransactionId);
		*ptr = parent;
		SubTransCtl->shared->page_dirty[slotno] = true;
	}

	LWLockRelease(SubtransControlLock);
}
Example #3
0
/*
 * Record the parent of a subtransaction in the subtrans log.
 *
 * In some cases we may need to overwrite an existing value.
 */
void
SubTransSetParent(TransactionId xid, TransactionId parent, bool overwriteOK)
{
	int			pageno = TransactionIdToPage(xid);
	int			entryno = TransactionIdToEntry(xid);
	int			slotno;
	TransactionId *ptr;

	Assert(TransactionIdIsValid(parent));

	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);

	slotno = SimpleLruReadPage(SubTransCtl, pageno, true, xid);
	ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
	ptr += entryno;

	/* Current state should be 0 */
	Assert(*ptr == InvalidTransactionId ||
		   (*ptr == parent && overwriteOK));

	*ptr = parent;

	SubTransCtl->shared->page_dirty[slotno] = true;

	LWLockRelease(SubtransControlLock);
}
/*
 * Add local XID for any new distributed transactions.
 */
void
PreallocLocalXidsForOpenDistributedTransactions(DistributedTransactionId *gxidArray, uint32 count)
{
	int							i;
	DistributedTransactionId 	gxid;
	int							pageno;
	int							entryno;
	int							slotno;
	DISTRIBUTEDXIDMAP_ENTRY		*ptr;

	LWLockAcquire(DistributedXidMapControlLock, LW_EXCLUSIVE);
	
	for (i = 0; i < count; i++)
	{
		gxid = gxidArray[i];
		
		pageno = DistributedTransactionIdToPage(gxid);
		entryno = DistributedTransactionIdToEntry(gxid);

		elog((Debug_print_full_dtm ? LOG : DEBUG5), "PreallocLocalXidsForOpenDistributedTransactions: gxidArray[%d] is %u (pageno %d, entryno %d)",
			 i, gxid, pageno, entryno);

		if (pageno > *shmDistributedXidMapHighestPageNo)
		{
			/*
			 * Zero out the new page(s).
			 */
			DistributedXidMapMakeMorePages(pageno);
		}
		
		if (*shmMaxDistributedXid < gxid)
		{
			*shmMaxDistributedXid = gxid;
		}
		
		slotno = SimpleLruReadPage(DistributedXidMapCtl, pageno, InvalidTransactionId);
		ptr = (DISTRIBUTEDXIDMAP_ENTRY *) DistributedXidMapCtl->shared->page_buffer[slotno];
		ptr += entryno;

		if (ptr->state == DISTRIBUTEDXIDMAP_STATE_NONE)
		{
			ptr->state = DISTRIBUTEDXIDMAP_STATE_PREALLOC_FOR_OPEN_TRANS;
			ptr->pid = MyProcPid;
			ptr->xid = GetNewTransactionId(false, false);	// NOT subtrans, DO NOT Set PROC struct xid
			DistributedXidMapCtl->shared->page_dirty[slotno] = true;
			elog((Debug_print_full_dtm ? LOG : DEBUG5), "PreallocLocalXidsForOpenDistributedTransactions: Allocated local XID = %u for global XID = %u",
				 ptr->xid, gxid);
		}
	}
	
	LWLockRelease(DistributedXidMapControlLock);
}
void
UpdateDistributedXidMapState(DistributedTransactionId gxid, DistributedMapState newState)
{
	int			pageno = DistributedTransactionIdToPage(gxid);
	int			entryno = DistributedTransactionIdToEntry(gxid);
	int			slotno;
	DISTRIBUTEDXIDMAP_ENTRY *ptr;
	DistributedMapState oldState;
	TransactionId xid;

	Assert(newState == DISTRIBUTEDXIDMAP_STATE_PREPARED ||
		   newState == DISTRIBUTEDXIDMAP_STATE_COMMITTED ||
		   newState == DISTRIBUTEDXIDMAP_STATE_ABORTED);

	elog((Debug_print_full_dtm ? LOG : DEBUG5), "Entering UpdateDistributedXidMapState with distributed xid = %d (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
		 gxid, pageno, entryno, *shmDistributedXidMapHighestPageNo);
	
	LWLockAcquire(DistributedXidMapControlLock, LW_EXCLUSIVE);

	if (pageno > *shmDistributedXidMapHighestPageNo)
	{
		LWLockRelease(DistributedXidMapControlLock);
		
		elog(ERROR, "UpdateDistributedXidMapState distributed xid = %d invalid (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
			 gxid, pageno, entryno, *shmDistributedXidMapHighestPageNo);
	}

	slotno = SimpleLruReadPage(DistributedXidMapCtl, pageno, InvalidTransactionId);
	ptr = (DISTRIBUTEDXIDMAP_ENTRY *) DistributedXidMapCtl->shared->page_buffer[slotno];
	ptr += entryno;

	oldState = ptr->state;
	if (oldState == DISTRIBUTEDXIDMAP_STATE_IN_PROGRESS)
	{
		ptr->state = newState;
	}
	else if (oldState == DISTRIBUTEDXIDMAP_STATE_PREPARED)
	{
		Assert(newState != DISTRIBUTEDXIDMAP_STATE_PREPARED);
		ptr->state = newState;
	}
	xid = ptr->xid;
	DistributedXidMapCtl->shared->page_dirty[slotno] = true;
	LWLockRelease(DistributedXidMapControlLock);

	elog((Debug_print_full_dtm ? LOG : DEBUG5), "UpdateDistributedXidMapState state for local xid = %u and distributed xid = %d from state %s to new state %s (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
		 xid, gxid, DistributedMapStateToString(oldState), DistributedMapStateToString(newState),pageno, entryno, *shmDistributedXidMapHighestPageNo);
}
Example #6
0
/*
 * Record the parent of a subtransaction in the subtrans log.
 */
void
SubTransSetParent(TransactionId xid, TransactionId parent)
{
	MIRRORED_LOCK_DECLARE;

	int			pageno = TransactionIdToPage(xid);
	int			entryno = TransactionIdToEntry(xid);
	int			slotno;
	SubTransData *ptr;
	SubTransData subData;

	/*
	 * Main Xact has parent and topMostParent as InvalidTransactionId
	 */
	if ( parent != InvalidTransactionId )
	{
		/* Get the topMostParent for Parent */
		SubTransGetData(parent, &subData);
	}
	else
	{
		subData.topMostParent = InvalidTransactionId;
	}

	MIRRORED_LOCK;

	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);

	slotno = SimpleLruReadPage(SubTransCtl, pageno, xid);
	ptr = (SubTransData *) SubTransCtl->shared->page_buffer[slotno];
	ptr += entryno;

	/* Current state should be 0 */
	Assert(ptr->parent == InvalidTransactionId);
	Assert(ptr->topMostParent == InvalidTransactionId);

	ptr->parent = parent;
	ptr->topMostParent = subData.topMostParent;

	SubTransCtl->shared->page_dirty[slotno] = true;

	LWLockRelease(SubtransControlLock);

	MIRRORED_UNLOCK;
}
Example #7
0
/*
 * Record the commit timestamp of transaction entries in the commit log for all
 * entries on a single page.  Atomic only on this page.
 */
static void
SetXidCommitTsInPage(TransactionId xid, int nsubxids,
					 TransactionId *subxids, TimestampTz ts,
					 RepOriginId nodeid, int pageno)
{
	int			slotno;
	int			i;

	LWLockAcquire(CommitTsControlLock, LW_EXCLUSIVE);

	slotno = SimpleLruReadPage(CommitTsCtl, pageno, true, xid);

	TransactionIdSetCommitTs(xid, ts, nodeid, slotno);
	for (i = 0; i < nsubxids; i++)
		TransactionIdSetCommitTs(subxids[i], ts, nodeid, slotno);

	CommitTsCtl->shared->page_dirty[slotno] = true;

	LWLockRelease(CommitTsControlLock);
}
/*
 * Get the local XID associated with a distributed transaction.
 */
TransactionId
GetLocalXidForDistributedTransaction(DistributedTransactionId gxid)
{
	int			pageno = DistributedTransactionIdToPage(gxid);
	int			entryno = DistributedTransactionIdToEntry(gxid);
	int			slotno;
	DISTRIBUTEDXIDMAP_ENTRY *ptr;
	TransactionId xid;
	DistributedMapState state;

	elog((Debug_print_full_dtm ? LOG : DEBUG5), "Entering GetLocalXidForDistributedTransaction with distributed xid = %d (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
		 gxid, pageno, entryno, *shmDistributedXidMapHighestPageNo);
	
	LWLockAcquire(DistributedXidMapControlLock, LW_EXCLUSIVE);

	if (pageno > *shmDistributedXidMapHighestPageNo)
	{
		LWLockRelease(DistributedXidMapControlLock);
		
		elog((Debug_print_full_dtm ? LOG : DEBUG5), "GetLocalXidForDistributedTransaction returning InvalidTransactionId for local xid for distributed xid = %d (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
			 gxid, pageno, entryno, *shmDistributedXidMapHighestPageNo);
		return InvalidTransactionId;
	}

	slotno = SimpleLruReadPage(DistributedXidMapCtl, pageno, InvalidTransactionId);
	ptr = (DISTRIBUTEDXIDMAP_ENTRY *) DistributedXidMapCtl->shared->page_buffer[slotno];
	ptr += entryno;

	xid = ptr->xid;
	state = ptr->state;

	LWLockRelease(DistributedXidMapControlLock);

	elog((Debug_print_full_dtm ? LOG : DEBUG5), "GetLocalXidForDistributedTransaction found local xid = %u for distributed xid = %d in state %s (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
		 xid, gxid, DistributedMapStateToString(state), pageno, entryno, *shmDistributedXidMapHighestPageNo);
	return xid;
}
/*
 * Get the local XID associated with a distributed transaction.  We will
 * allocate the local XID and assign its value in the map if necessary.
 */
void
AllocOrGetLocalXidForStartDistributedTransaction(DistributedTransactionId gxid, TransactionId *xid)
{
	int			pageno = DistributedTransactionIdToPage(gxid);
	int			entryno = DistributedTransactionIdToEntry(gxid);
	int			slotno;
	DISTRIBUTEDXIDMAP_ENTRY *ptr;

	Assert(gxid != InvalidDistributedTransactionId);
	Assert(xid != NULL);

	elog((Debug_print_full_dtm ? LOG : DEBUG5), "Entering AllocOrGetLocalXidForStartDistributedTransaction with distributed xid = %d (pageno = %d, entryno = %d, DistributedXidMapHighestPageNo = %d)",
		 gxid, pageno, entryno, *shmDistributedXidMapHighestPageNo);
	
	LWLockAcquire(DistributedXidMapControlLock, LW_EXCLUSIVE);

	if (pageno > *shmDistributedXidMapHighestPageNo)
	{
		/*
		 * Zero out the new page(s).
		 */
		DistributedXidMapMakeMorePages(pageno);
	}

	if (*shmMaxDistributedXid < gxid)
	{
		*shmMaxDistributedXid = gxid;
	}

	slotno = SimpleLruReadPage(DistributedXidMapCtl, pageno, InvalidTransactionId);
	ptr = (DISTRIBUTEDXIDMAP_ENTRY *) DistributedXidMapCtl->shared->page_buffer[slotno];
	ptr += entryno;

	if (ptr->state == DISTRIBUTEDXIDMAP_STATE_NONE)
	{
		/*
		 * Need to allocate a local XID and assign the map entry.
		 */
		*xid = GetNewTransactionId(false, false);	// NOT subtrans, DO NOT Set PROC struct xid
		ptr->state = DISTRIBUTEDXIDMAP_STATE_IN_PROGRESS;
		ptr->pid = MyProcPid;
		ptr->xid = *xid;
		
		elog((Debug_print_full_dtm ? LOG : DEBUG5), "AllocOrGetLocalXidForStartDistributedTransaction allocated local XID = %d", *xid);

		DistributedXidMapCtl->shared->page_dirty[slotno] = true;
	}
	else if (ptr->state == DISTRIBUTEDXIDMAP_STATE_PREALLOC_FOR_OPEN_TRANS)
	{
		/*
		 * The local XID was pre-allocated by another QE when it
		 * received a distributed snapshot that listed the distributed transaction
		 * in its in-doubt list.
		 */
		ptr->state = DISTRIBUTEDXIDMAP_STATE_IN_PROGRESS;
		ptr->pid = MyProcPid;
		*xid = ptr->xid;
		elog((Debug_print_full_dtm ? LOG : DEBUG5), "AllocOrGetLocalXidForStartDistributedTransaction found pre-allocated local XID = %d", *xid);

		DistributedXidMapCtl->shared->page_dirty[slotno] = true;
	}
	else
	{
		int pid = ptr->pid;
		TransactionId reuseXid = ptr->xid;
		DistributedMapState state = ptr->state;
		LWLockRelease(DistributedXidMapControlLock);

		elog(ERROR,"Attempting re-use local xid %u and distributed xid %u again (original start pid was %d, state = %s, pageno %d, entryno %d, slotno %d)",
			 reuseXid, gxid, pid, DistributedMapStateToString(state), pageno, entryno, slotno);
	}

	SetProcXid(*xid, gxid);

	LWLockRelease(DistributedXidMapControlLock);
}
Example #10
0
/*
 * Record that a distributed transaction committed in the distributed log.
 *
 */
void
DistributedLog_SetCommitted(
	TransactionId 						localXid,
	DistributedTransactionTimeStamp		distribTimeStamp,
	DistributedTransactionId 			distribXid,
	bool								isRedo)
{
	MIRRORED_LOCK_DECLARE;

	int			page = TransactionIdToPage(localXid);
	int			entryno = TransactionIdToEntry(localXid);
	int			slotno;
	
	DistributedLogEntry *ptr;

	bool alreadyThere = false;

	MIRRORED_LOCK;
	
	LWLockAcquire(DistributedLogControlLock, LW_EXCLUSIVE);

	if (isRedo)
	{
		elog((Debug_print_full_dtm ? LOG : DEBUG5),
			 "DistributedLog_SetCommitted check if page %d is present", 
			 page);
		if (!SimpleLruPageExists(DistributedLogCtl, page))
		{
			DistributedLog_ZeroPage(page, /* writeXLog */ false);
			elog((Debug_print_full_dtm ? LOG : DEBUG5),
				 "DistributedLog_SetCommitted zeroed page %d",
				 page);
		}
	}
	
	slotno = SimpleLruReadPage(DistributedLogCtl, page, localXid);
	ptr = (DistributedLogEntry *) DistributedLogCtl->shared->page_buffer[slotno];
	ptr += entryno;

	if (ptr->distribTimeStamp != 0 || ptr->distribXid != 0)
	{
		if (ptr->distribTimeStamp != distribTimeStamp)
			elog(ERROR, 
			     "Current distributed timestamp = %u does not match input timestamp = %u for local xid = %u in distributed log (page = %d, entryno = %d)",
			     ptr->distribTimeStamp, distribTimeStamp, localXid, page, entryno);
		
		if (ptr->distribXid != distribXid)
			elog(ERROR, 
			     "Current distributed xid = %u does not match input distributed xid = %u for local xid = %u in distributed log (page = %d, entryno = %d)",
			     ptr->distribXid, distribXid, localXid, page, entryno);

		alreadyThere = true;
	}
	else
	{
		ptr->distribTimeStamp = distribTimeStamp;
		ptr->distribXid = distribXid;
		
		DistributedLogCtl->shared->page_dirty[slotno] = true;
	}
	
	LWLockRelease(DistributedLogControlLock);

	MIRRORED_UNLOCK;
	
	elog((Debug_print_full_dtm ? LOG : DEBUG5), 
		 "DistributedLog_SetCommitted with local xid = %d (page = %d, entryno = %d) and distributed transaction xid = %u (timestamp = %u) status = %s",
		 localXid, page, entryno, distribXid, distribTimeStamp,
		 (alreadyThere ? "already there" : "set"));
	
}
Example #11
0
/*
 * This must be called ONCE during postmaster or standalone-backend startup,
 * after StartupXLOG has initialized ShmemVariableCache->nextXid.
 */
void
DistributedLog_Startup(
					TransactionId oldestActiveXid,
					TransactionId nextXid)
{
	MIRRORED_LOCK_DECLARE;

	int	startPage;
	int	endPage;

	/*
	 * UNDONE: We really need oldest frozen xid.  If we can't get it, then
	 * we will need to tolerate not finiding a page in 
	 * DistributedLog_SetCommitted and DistributedLog_IsCommitted.
	 */
	startPage = TransactionIdToPage(oldestActiveXid);
	endPage = TransactionIdToPage(nextXid);

	MIRRORED_LOCK;

	LWLockAcquire(DistributedLogControlLock, LW_EXCLUSIVE);

	elog((Debug_print_full_dtm ? LOG : DEBUG5),
		 "DistributedLog_Startup startPage %d, endPage %d", 
		 startPage, endPage);

	/*
	 * Initialize our idea of the latest page number.
	 */
	DistributedLogCtl->shared->latest_page_number = endPage;

	/*
	 * Zero out the remainder of the current DistributedLog page.  Under normal
	 * circumstances it should be zeroes already, but it seems at least
	 * theoretically possible that XLOG replay will have settled on a nextXID
	 * value that is less than the last XID actually used and marked by the
	 * previous database lifecycle (since subtransaction commit writes clog
	 * but makes no WAL entry).  Let's just be safe. (We need not worry about
	 * pages beyond the current one, since those will be zeroed when first
	 * used.  For the same reason, there is no need to do anything when
	 * nextXid is exactly at a page boundary; and it's likely that the
	 * "current" page doesn't exist yet in that case.)
	 */
	if (TransactionIdToEntry(nextXid) != 0)
	{
		int			entryno = TransactionIdToEntry(nextXid);
		int			slotno;
		
		DistributedLogEntry *ptr;

		int			remainingEntries;

		slotno = SimpleLruReadPage(DistributedLogCtl, endPage, nextXid);
		ptr = (DistributedLogEntry *) DistributedLogCtl->shared->page_buffer[slotno];
		ptr += entryno;

		/* Zero the rest of the page */
		remainingEntries = ENTRIES_PER_PAGE - entryno;
		MemSet(ptr, 0, remainingEntries * sizeof(DistributedLogEntry));

		DistributedLogCtl->shared->page_dirty[slotno] = true;
	}

	LWLockRelease(DistributedLogControlLock);

	MIRRORED_UNLOCK;
}
Example #12
0
/*
 * Find the next lowest transaction with a logged or recorded status.
 * Currently on distributed commits are recorded.
 */
bool
DistributedLog_ScanForPrevCommitted(
	TransactionId 						*indexXid,
	DistributedTransactionTimeStamp 	*distribTimeStamp,
	DistributedTransactionId 			*distribXid)
{
	MIRRORED_LOCK_DECLARE;

	TransactionId highXid;
	int pageno;
	TransactionId lowXid;
	int slotno;
	TransactionId xid;

	*distribTimeStamp = 0;	// Set it to something.
	*distribXid = 0;

	if ((*indexXid) == InvalidTransactionId)
		return false;
	highXid = (*indexXid) - 1;
	if (highXid < FirstNormalTransactionId)
		return false;

	MIRRORED_LOCK;

	while (true)
	{
		pageno = TransactionIdToPage(highXid);

		/*
		 * Compute the xid floor for the page.
		 */
		lowXid = pageno * (TransactionId) ENTRIES_PER_PAGE;
		if (lowXid == InvalidTransactionId)
			lowXid = FirstNormalTransactionId;

		LWLockAcquire(DistributedLogControlLock, LW_EXCLUSIVE);

		/*
		 * Peek to see if page exists.
		 */
		if (!SimpleLruPageExists(DistributedLogCtl, pageno))
		{
			LWLockRelease(DistributedLogControlLock);

			MIRRORED_UNLOCK;

			*indexXid = InvalidTransactionId;
			*distribTimeStamp = 0;	// Set it to something.
			*distribXid = 0;
			return false;
		}
			
		slotno = SimpleLruReadPage(DistributedLogCtl, pageno, highXid);

		for (xid = highXid; xid >= lowXid; xid--)
		{
			int						entryno = TransactionIdToEntry(xid);
			DistributedLogEntry 	*ptr;
			
			ptr = (DistributedLogEntry *) DistributedLogCtl->shared->page_buffer[slotno];
			ptr += entryno;

			if (ptr->distribTimeStamp != 0 && ptr->distribXid != 0)
			{
				*indexXid = xid;
				*distribTimeStamp = ptr->distribTimeStamp;
				*distribXid = ptr->distribXid;
				LWLockRelease(DistributedLogControlLock);

				MIRRORED_UNLOCK;

				return true;
			}
		}

		LWLockRelease(DistributedLogControlLock);

		if (lowXid == FirstNormalTransactionId)
		{
			MIRRORED_UNLOCK;

			*indexXid = InvalidTransactionId;
			*distribTimeStamp = 0;	// Set it to something.
			*distribXid = 0;
			return false;
		}
		
		highXid = lowXid - 1;	// Go to last xid of previous page.
	}

	MIRRORED_UNLOCK;

	return false;	// We'll never reach this.
}
Example #13
0
/*
 * Determine if a distributed transaction committed in the distributed log.
 */
bool
DistributedLog_CommittedCheck(
	TransactionId 						localXid,
	DistributedTransactionTimeStamp		*distribTimeStamp,
	DistributedTransactionId 			*distribXid)
{
	MIRRORED_LOCK_DECLARE;

	int			page = TransactionIdToPage(localXid);
	int			entryno = TransactionIdToEntry(localXid);
	int			slotno;
	
	DistributedLogEntry *ptr;

	MIRRORED_LOCK;

	LWLockAcquire(DistributedLogControlLock, LW_EXCLUSIVE);

	if (DistributedLogShared->knowHighestUnusedPage &&
		page <= DistributedLogShared->highestUnusedPage)
	{
		/*
		 * We prevously discovered we didn't have the page...
		 */
		LWLockRelease(DistributedLogControlLock);

		MIRRORED_UNLOCK;

		*distribTimeStamp = 0;	// Set it to something.
		*distribXid = 0;

		return false;
	}
	
	/*
	 * Peek to see if page exists.
	 */
	if (!SimpleLruPageExists(DistributedLogCtl, page))
	{
		if (DistributedLogShared->knowHighestUnusedPage)
		{
			if (DistributedLogShared->highestUnusedPage > page)
				DistributedLogShared->highestUnusedPage = page;
		}
		else
		{
			DistributedLogShared->knowHighestUnusedPage = true;
			DistributedLogShared->highestUnusedPage = page;
		}
		
		LWLockRelease(DistributedLogControlLock);

		MIRRORED_UNLOCK;

		*distribTimeStamp = 0;	// Set it to something.
		*distribXid = 0;

		return false;
	}
		
	slotno = SimpleLruReadPage(DistributedLogCtl, page, localXid);
	ptr = (DistributedLogEntry *) DistributedLogCtl->shared->page_buffer[slotno];
	ptr += entryno;
	*distribTimeStamp = ptr->distribTimeStamp;
	*distribXid = ptr->distribXid;
	ptr = NULL;
	LWLockRelease(DistributedLogControlLock);

	MIRRORED_UNLOCK;

	if (*distribTimeStamp != 0 && *distribXid != 0)
	{
		return true;
	}
	else if (*distribTimeStamp == 0 && *distribXid == 0)
	{
		// Not found.
		return false;
	}
	else
	{
		if (*distribTimeStamp == 0)
			elog(ERROR, "Found zero timestamp for local xid = %u in distributed log (distributed xid = %u, page = %d, entryno = %d)",
			     localXid, *distribXid, page, entryno);
		
		elog(ERROR, "Found zero distributed xid for local xid = %u in distributed log (dtx start time = %u, page = %d, entryno = %d)",
			     localXid, *distribTimeStamp, page, entryno);

		return false;	// We'll never reach here.
	}

}