void MirroredBufferPool_BeginBulkLoad(
	RelFileNode 					*relFileNode,
				/* The tablespace, database, and relation OIDs for the relation. */

	ItemPointer						persistentTid,

	int64							persistentSerialNum,

	MirroredBufferPoolBulkLoadInfo *bulkLoadInfo)
{
	MIRROREDLOCK_BUFMGR_DECLARE;

	MemSet(bulkLoadInfo, 0, sizeof(MirroredBufferPoolBulkLoadInfo));

	// -------- MirroredLock ----------
	MIRROREDLOCK_BUFMGR_LOCK;

	/*
	 * Make this call while under the MirroredLock (unless we are a resync worker).
	 */
	bulkLoadInfo->mirrorDataLossTrackingState = 
				FileRepPrimary_GetMirrorDataLossTrackingSessionNum(
												&bulkLoadInfo->mirrorDataLossTrackingSessionNum);
	
	MIRROREDLOCK_BUFMGR_UNLOCK;
	// -------- MirroredLock ----------

	bulkLoadInfo->relFileNode = *relFileNode;
	bulkLoadInfo->persistentTid = *persistentTid;
	bulkLoadInfo->persistentSerialNum = persistentSerialNum;

	if (Debug_persistent_print)
	{
		SUPPRESS_ERRCONTEXT_DECLARE;

		SUPPRESS_ERRCONTEXT_PUSH();

		elog(Persistent_DebugPrintLevel(),
			 "MirroredBufferPool_BeginBulkLoad %u/%u/%u: mirror data loss tracking (state '%s', session num " INT64_FORMAT "), persistent serial num " INT64_FORMAT ", TID %s",
			 relFileNode->spcNode,
			 relFileNode->dbNode,
			 relFileNode->relNode,
			 MirrorDataLossTrackingState_Name(bulkLoadInfo->mirrorDataLossTrackingState),
			 bulkLoadInfo->mirrorDataLossTrackingSessionNum,
			 persistentSerialNum,
			 ItemPointerToString(persistentTid));

		SUPPRESS_ERRCONTEXT_POP();
	}
}
Beispiel #2
0
void
AppendOnlyMirrorResyncEofs_Merge(RelFileNode *relFileNode,
								 int32 segmentFileNum,
								 int nestLevel, /* Transaction nesting level. */
								 char *relationName,
								 ItemPointer persistentTid,
								 int64 persistentSerialNum,
								 bool mirrorCatchupRequired,
								 MirrorDataLossTrackingState mirrorDataLossTrackingState,
								 int64 mirrorDataLossTrackingSessionNum,
								 int64 mirrorNewEof)
{
	int64		previousMirrorNewEof = 0;

	AppendOnlyMirrorResyncEofsKey key;
	AppendOnlyMirrorResyncEofs *entry;
	bool		found;

	if (AppendOnlyMirrorResyncEofsTable == NULL)
		AppendOnlyMirrorResyncEofs_HashTableInit();

	AppendOnlyMirrorResyncEofs_InitKey(
									   &key,
									   relFileNode,
									   segmentFileNum,
									   nestLevel);

	entry =
		(AppendOnlyMirrorResyncEofs *)
		hash_search(AppendOnlyMirrorResyncEofsTable,
					(void *) &key,
					HASH_ENTER,
					&found);

	if (!found)
	{
		entry->relationName = MemoryContextStrdup(TopMemoryContext, relationName);
		entry->persistentSerialNum = persistentSerialNum;
		entry->persistentTid = *persistentTid;
		entry->didIncrementCommitCount = false;
		entry->isDistributedTransaction = false;
		entry->gid[0] = '\0';
		entry->mirrorCatchupRequired = mirrorCatchupRequired;
		entry->mirrorDataLossTrackingState = mirrorDataLossTrackingState;
		entry->mirrorDataLossTrackingSessionNum = mirrorDataLossTrackingSessionNum;
		entry->mirrorNewEof = mirrorNewEof;
	}
	else
	{
		previousMirrorNewEof = entry->mirrorNewEof;

		/*
		 * UNDONE: What is the purpose of this IF stmt?  Shouldn't we always
		 * set the new EOF?
		 */
		if (mirrorNewEof > entry->mirrorNewEof)
			entry->mirrorNewEof = mirrorNewEof;

		/*
		 * We adopt the newer FileRep state because we accurately track the
		 * state of mirror data.  For example, the first write session might
		 * have had loss because the mirror was down.  But then the second
		 * write session discovered we were in sync and copied both the first
		 * and second write session to the mirror and flushed it.
		 */
		entry->mirrorCatchupRequired = mirrorCatchupRequired;
		entry->mirrorDataLossTrackingState = mirrorDataLossTrackingState;
		entry->mirrorDataLossTrackingSessionNum = mirrorDataLossTrackingSessionNum;
	}

	if (Debug_persistent_print ||
		Debug_persistent_appendonly_commit_count_print)
		elog(Persistent_DebugPrintLevel(),
			 "Storage Manager: %s Append-Only mirror resync eofs entry: %u/%u/%u, segment file #%d, relation name '%s' (transaction nest level %d, persistent TID %s, persistent serial number " INT64_FORMAT ", "
			 "mirror data loss tracking (state '%s', session num " INT64_FORMAT "), "
			 "previous mirror new EOF " INT64_FORMAT ", input mirror new EOF " INT64_FORMAT ", saved mirror new EOF " INT64_FORMAT ")",
			 (found ? "Merge" : "New"),
			 entry->key.relFileNode.spcNode,
			 entry->key.relFileNode.dbNode,
			 entry->key.relFileNode.relNode,
			 entry->key.segmentFileNum,
			 (entry->relationName == NULL ? "<null>" : entry->relationName),
			 entry->key.nestLevel,
			 ItemPointerToString(&entry->persistentTid),
			 entry->persistentSerialNum,
			 MirrorDataLossTrackingState_Name(mirrorDataLossTrackingState),
			 mirrorDataLossTrackingSessionNum,
			 previousMirrorNewEof,
			 mirrorNewEof,
			 entry->mirrorNewEof);
}
bool MirroredBufferPool_EvaluateBulkLoadFinish(
	MirroredBufferPoolBulkLoadInfo *bulkLoadInfo)
{
	MIRROREDLOCK_BUFMGR_DECLARE;

	MirrorDataLossTrackingState mirrorDataLossTrackingState;
	int64 mirrorDataLossTrackingSessionNum;

	bool bulkLoadFinished;

	// -------- MirroredLock ----------
	MIRROREDLOCK_BUFMGR_LOCK;

	/*
	 * Make this call while under the MirroredLock (unless we are a resync worker).
	 */
	mirrorDataLossTrackingState = 
				FileRepPrimary_GetMirrorDataLossTrackingSessionNum(
												&mirrorDataLossTrackingSessionNum);

	bulkLoadFinished = false;	// Assume.
	if (mirrorDataLossTrackingSessionNum == bulkLoadInfo->mirrorDataLossTrackingSessionNum)
	{
		if (bulkLoadInfo->mirrorDataLossTrackingState == MirrorDataLossTrackingState_MirrorDown &&
			mirrorDataLossTrackingState != bulkLoadInfo->mirrorDataLossTrackingState)
		{
			/*
			 * We started with the mirror down and ended with the mirror up in either
			 * Resynchronized or Synchronized state (or not configured).
			 *
			 * So, there was mirror data loss.
			 */
		}
		else
		{
			bulkLoadFinished = true;
		}
	}

	if (bulkLoadFinished)
	{
		if (Debug_persistent_print)
		{
			SUPPRESS_ERRCONTEXT_DECLARE;
		
			SUPPRESS_ERRCONTEXT_PUSH();
		
			elog(Persistent_DebugPrintLevel(),
				 "MirroredBufferPool_EvaluateBulkLoadFinish %u/%u/%u: no change -- mirror stayed up whole time.  Mirror data loss tracking (state '%s', session num " INT64_FORMAT "), persistent serial num " INT64_FORMAT ", TID %s",
				 bulkLoadInfo->relFileNode.spcNode,
				 bulkLoadInfo->relFileNode.dbNode,
				 bulkLoadInfo->relFileNode.relNode,
				 MirrorDataLossTrackingState_Name(bulkLoadInfo->mirrorDataLossTrackingState),
				 bulkLoadInfo->mirrorDataLossTrackingSessionNum,
				 bulkLoadInfo->persistentSerialNum,
				 ItemPointerToString(&bulkLoadInfo->persistentTid));
		
			SUPPRESS_ERRCONTEXT_POP();
		}
	}
	else
	{
		if (Debug_persistent_print)
		{
			SUPPRESS_ERRCONTEXT_DECLARE;
		
			SUPPRESS_ERRCONTEXT_PUSH();
		
			elog(Persistent_DebugPrintLevel(),
				 "MirroredBufferPool_EvaluateBulkLoadFinish %u/%u/%u: change.  Original mirror data loss tracking (state '%s', session num " INT64_FORMAT "), new mirror data loss tracking (state %d, session num " INT64_FORMAT "), persistent serial num " INT64_FORMAT ", TID %s",
				 bulkLoadInfo->relFileNode.spcNode,
				 bulkLoadInfo->relFileNode.dbNode,
				 bulkLoadInfo->relFileNode.relNode,
				 MirrorDataLossTrackingState_Name(bulkLoadInfo->mirrorDataLossTrackingState),
				 bulkLoadInfo->mirrorDataLossTrackingSessionNum,
				 mirrorDataLossTrackingState,
				 mirrorDataLossTrackingSessionNum,
				 bulkLoadInfo->persistentSerialNum,
				 ItemPointerToString(&bulkLoadInfo->persistentTid));
		
			SUPPRESS_ERRCONTEXT_POP();
		}

		switch (mirrorDataLossTrackingState)
		{
		case MirrorDataLossTrackingState_MirrorNotConfigured:
			bulkLoadFinished = true;
			break;
			
		case MirrorDataLossTrackingState_MirrorCurrentlyUpInSync:
		case MirrorDataLossTrackingState_MirrorCurrentlyUpInResync:
			bulkLoadFinished = false;	// We lost data along the way.
			break;
			
		case MirrorDataLossTrackingState_MirrorDown:
			bulkLoadFinished = true;	// Give the problem to resync.
			break;
			
		default:
			elog(ERROR, "Unexpected mirror data loss tracking state: %d",
				 mirrorDataLossTrackingState);
			bulkLoadFinished = false; 	// A happy optimizer is the sound of one hand clapping.
		}
	}

	if (bulkLoadFinished)
	{
		PersistentRelation_FinishBufferPoolBulkLoad(
											&bulkLoadInfo->relFileNode,
											&bulkLoadInfo->persistentTid,
											bulkLoadInfo->persistentSerialNum);
	}
	else
	{
		/*
		 * Save new information so caller can copy to mirror and reevaluate again.
		 */
		bulkLoadInfo->mirrorDataLossTrackingState = mirrorDataLossTrackingState;
		bulkLoadInfo->mirrorDataLossTrackingSessionNum = mirrorDataLossTrackingSessionNum;
	}
	
	MIRROREDLOCK_BUFMGR_UNLOCK;
	// -------- MirroredLock ----------

	return bulkLoadFinished;
}
void MirroredBufferPool_CopyToMirror(
	RelFileNode						*relFileNode,

	char							*relationName,

	ItemPointer						persistentTid,

	int64							persistentSerialNum,

	MirrorDataLossTrackingState 	mirrorDataLossTrackingState,

	int64 							mirrorDataLossTrackingSessionNum,

	int32							numOfBlocks,
	
	bool							*mirrorDataLossOccurred)
{
	MirroredBufferPoolOpen 		mirroredOpen;
	
	MirrorDataLossTrackingState 	currentMirrorDataLossTrackingState;
	int64 							currentMirrorDataLossTrackingSessionNum;

	int32	numOfSegments;
	int32	numOfRemainingBlocks;
	int		segmentFileNum;
	int32	numOfBlocksToCopy;

	int 	primaryError;

	Assert(numOfBlocks > 0);

	numOfSegments = ((numOfBlocks - 1) / RELSEG_SIZE) + 1;

	Assert(numOfSegments > 0);

	numOfRemainingBlocks = numOfBlocks;

	if (Debug_persistent_print)
	{
		SUPPRESS_ERRCONTEXT_DECLARE;
	
		SUPPRESS_ERRCONTEXT_PUSH();
	
		elog(Persistent_DebugPrintLevel(),
			 "MirroredBufferPool_CopyToMirror %u/%u/%u: copy %d blocks (%d segments).  Mirror data loss tracking (state '%s', session num " INT64_FORMAT "), persistent serial num " INT64_FORMAT ", TID %s",
			 relFileNode->spcNode,
			 relFileNode->dbNode,
			 relFileNode->relNode,
			 numOfBlocks,
			 numOfSegments,
			 MirrorDataLossTrackingState_Name(mirrorDataLossTrackingState),
			 mirrorDataLossTrackingSessionNum,
			 persistentSerialNum,
			 ItemPointerToString(persistentTid));
	
		SUPPRESS_ERRCONTEXT_POP();
	}

	for (segmentFileNum = 0; segmentFileNum < numOfSegments; segmentFileNum++)
	{
		Assert(numOfRemainingBlocks > 0);

		LWLockAcquire(MirroredLock, LW_SHARED);
		
		currentMirrorDataLossTrackingState = 
					FileRepPrimary_GetMirrorDataLossTrackingSessionNum(
													&currentMirrorDataLossTrackingSessionNum);
		if (currentMirrorDataLossTrackingSessionNum != mirrorDataLossTrackingSessionNum)
		{
			*mirrorDataLossOccurred = true;
			LWLockRelease(MirroredLock);

			return;
		}
		Assert(currentMirrorDataLossTrackingState == mirrorDataLossTrackingState);
		
		MirroredBufferPool_DoOpen(
						&mirroredOpen, 
						relFileNode,
						segmentFileNum,
						relationName,
						mirrorDataLossTrackingState,
						mirrorDataLossTrackingSessionNum,
						/* create */ false,
						/* mirrorOnly */ false,
						/* copyToMirror */ true,
						&primaryError,
						mirrorDataLossOccurred);
		
		if (primaryError != 0)
		{
			ereport(ERROR,
				(errcode_for_file_access(),
				 errmsg("could not open relation file '%s', relation name '%s': %s",
						relpath(*relFileNode),
						relationName,
						strerror(primaryError))));
		}
		
		LWLockRelease(MirroredLock);
		
		if (*mirrorDataLossOccurred)
		{
			return;
		}

		if (numOfRemainingBlocks > RELSEG_SIZE)
			numOfBlocksToCopy = RELSEG_SIZE;
		else
			numOfBlocksToCopy = numOfRemainingBlocks;

		MirroredBufferPool_DoCopyDataToMirror(
									&mirroredOpen,
									numOfBlocksToCopy,
									mirrorDataLossOccurred);
		
		if (*mirrorDataLossOccurred)
		{
			MirroredBufferPool_Close(&mirroredOpen);
			return;
		}

		if (!MirroredBufferPool_Flush(&mirroredOpen))
		{
			ereport(ERROR,
				(errcode_for_file_access(),
				 errmsg("could not flush relation file '%s', relation name '%s': %s",
						relpath(*relFileNode),
						relationName,
						strerror(primaryError))));
		}

		if (mirroredOpen.mirrorDataLossOccurred)
		{
			*mirrorDataLossOccurred = true;
			MirroredBufferPool_Close(&mirroredOpen);
			return;
		}

		MirroredBufferPool_Close(&mirroredOpen);

		numOfRemainingBlocks -= numOfBlocksToCopy;
	}
}