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(); } }
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( ¤tMirrorDataLossTrackingSessionNum); 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; } }