Ejemplo n.º 1
0
        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));
        }