internal static CopyModeResult FindCopyMode( CopyContextParameters sourceParamaters, CopyContextParameters targetParameters, long lastRecoveredAtomicRedoOperationLsnAtTarget) { var result = FindCopyModePrivate(sourceParamaters, targetParameters, lastRecoveredAtomicRedoOperationLsnAtTarget); if (result.CopyMode.HasFlag(CopyMode.FalseProgress)) { string failureMsg = string.Format( "(sourceStartingLsn is expected to be lesser or equal to targetStartingLsn). Source starting lsn : {0}, target starting lsn :{1} ", result.SourceStartingLsn.LSN, result.TargetStartingLsn.LSN); if (!ValidateIfDebugEnabled( result.SourceStartingLsn <= result.TargetStartingLsn, failureMsg)) { SharedProgressVectorEntry failedValidationResult = new SharedProgressVectorEntry { SourceIndex = result.SharedProgressVectorEntry.SourceIndex, TargetIndex = result.SharedProgressVectorEntry.TargetIndex, SourceProgressVectorEntry = result.SharedProgressVectorEntry.SourceProgressVectorEntry, TargetProgressVectorEntry = result.SharedProgressVectorEntry.TargetProgressVectorEntry, FullCopyReason = FullCopyReason.ValidationFailed, FailedValidationMessage = failureMsg }; return(CopyModeResult.CreateFullCopyResult( failedValidationResult, FullCopyReason.ValidationFailed)); } } return(result); }
private static CopyModeResult FindCopyModePrivate( CopyContextParameters sourceParamaters, CopyContextParameters targetParameters, long lastRecoveredAtomicRedoOperationLsnAtTarget) { // We can perform the check for CASE 1(Shown Below) before finding the shared ProgressVectorEntry. // However, we do not do that because the shared ProgressVectorEntry method provides additional checks of epoch history var sharedProgressVectorEntry = FindSharedVector( sourceParamaters.ProgressVector, targetParameters.ProgressVector); // If we detect that the shared progress vector cannot be obtained because of a trimmed progress vector, we decide to do a full copy if (sharedProgressVectorEntry.FullCopyReason == FullCopyReason.ProgressVectorTrimmed) { return(CopyModeResult.CreateFullCopyResult(null, FullCopyReason.ProgressVectorTrimmed)); } // Validation failed, perform full copy if (sharedProgressVectorEntry.FullCopyReason == FullCopyReason.ValidationFailed) { return(CopyModeResult.CreateFullCopyResult(sharedProgressVectorEntry, FullCopyReason.ValidationFailed)); } // *******************************************CASE 1 - COPY_NONE*********************************************************** // // The last entry in the source and the target vectors are same with the same tail. // This can happen if target goes down and comes back up and the primary made no progress if (sourceParamaters.ProgressVector.LastProgressVectorEntry == targetParameters.ProgressVector.LastProgressVectorEntry && sourceParamaters.LogTailLsn == targetParameters.LogTailLsn) { // Note that copy none covers only cases where nothing needs to be copied (including the UpdateEpochLogRecord) // Hence, service creation scenario is Partial copy, not None. return(CopyModeResult.CreateCopyNoneResult(sharedProgressVectorEntry)); } // *******************************************CASE 2a - COPY_FULL - Due to Data Loss****************************************** // // Check for any dataloss in the source or target log // If there was data loss, perform full copy // No full copy with DataLoss reason, if the target is a brand new replica if (!ProgressVector.IsBrandNewReplica(targetParameters)) { if (sharedProgressVectorEntry.SourceProgressVectorEntry.Epoch.DataLossNumber != sourceParamaters.ProgressVector.LastProgressVectorEntry.Epoch.DataLossNumber || sharedProgressVectorEntry.TargetProgressVectorEntry.Epoch.DataLossNumber != targetParameters.ProgressVector.LastProgressVectorEntry.Epoch.DataLossNumber || sourceParamaters.LogHeadEpoch.DataLossNumber > sharedProgressVectorEntry.TargetProgressVectorEntry.Epoch.DataLossNumber || targetParameters.LogHeadEpoch.DataLossNumber > sharedProgressVectorEntry.SourceProgressVectorEntry.Epoch.DataLossNumber) { return(CopyModeResult.CreateFullCopyResult(sharedProgressVectorEntry, FullCopyReason.DataLoss)); } } var sourceStartingLsn = (sharedProgressVectorEntry.SourceIndex == (sourceParamaters.ProgressVector.vectors.Count - 1)) ? sourceParamaters.LogTailLsn : sourceParamaters.ProgressVector.vectors[sharedProgressVectorEntry.SourceIndex + 1].Lsn; var targetStartingLsn = (sharedProgressVectorEntry.TargetIndex == (targetParameters.ProgressVector.vectors.Count - 1)) ? targetParameters.LogTailLsn : targetParameters.ProgressVector.vectors[sharedProgressVectorEntry.TargetIndex + 1].Lsn; // *******************************************CASE 2b - COPY_FULL - Due to Insufficient Loss****************************************** // // Since there was no data loss, check if we can perform partial copy and there are sufficient logs in the source // and target to do so if (sourceParamaters.LogHeadLsn > targetParameters.LogTailLsn || sourceStartingLsn < sourceParamaters.LogHeadLsn || targetParameters.LogHeadLsn > sourceStartingLsn) { return(CopyModeResult.CreateFullCopyResult(sharedProgressVectorEntry, FullCopyReason.InsufficientLogs)); } // *******************************************CASE 3a - FALSE_PROGRESS -Basic Case****************************************** // // The simple case where target made more progress in an epoch than the primary // Source = (1,1,0) (1,3,10) (1,4,15) Tail = 16 // Target = (1,1,0) (1,3,10) Tail = 20 if (sourceStartingLsn < targetStartingLsn) { return(CopyModeResult.CreateFalseProgressResult( lastRecoveredAtomicRedoOperationLsnAtTarget, sharedProgressVectorEntry, sourceStartingLsn, targetStartingLsn)); } // *******************************************CASE 3b - FALSE_PROGRESS -Advanced Case****************************************** // // The cases where target has made progress in an epoch that the primary has no knowledge of // Series of crashes could lead to the target having made false progress in an epoch that the primary DOES NOT KNOW about // Source = (1,1,0) (1,3,10) Tail = 15 // Target = (1,1,0) (1,2,10) Tail = 12 // Source = (1,1,0) (1,3,10) Tail = 15 // Target = (1,1,0) (1,2,10) Tail = 10 // Source = (1,3,10) (1,5,17) Tail = 18 // Target = (1,3,10) (1,4,15) Tail = 17 if (targetStartingLsn != targetParameters.LogTailLsn) { sourceStartingLsn = targetStartingLsn; return(CopyModeResult.CreateFalseProgressResult( lastRecoveredAtomicRedoOperationLsnAtTarget, sharedProgressVectorEntry, sourceStartingLsn, targetStartingLsn)); } // *******************************************CASE 4 - Work Around Case to be able to assert****************************************** // RDBUG : 3374739 // Source = (1,1,0) (1,3,10) Tail >= 10 // Target = (1,1,0) (1,2,5) Tail = 5 // Target got UpdateEpoch(e5) at 5, while source got UpdateEpoch(e6) at 10 (without having an entry for e5) // Source should detect this and do a full build - (We cannot undo false progress since the process at the target until 5 could be true progress and could be checkpointed) if (sourceParamaters.ProgressVector.vectors[sharedProgressVectorEntry.SourceIndex].Epoch < targetParameters.ProgressVector.LastProgressVectorEntry.Epoch) { return(CopyModeResult.CreateFullCopyResult(sharedProgressVectorEntry, FullCopyReason.Other)); } return(CopyModeResult.CreatePartialCopyResult(sharedProgressVectorEntry, sourceStartingLsn, targetStartingLsn)); }