public static CopyModeResult CreateCopyNoneResult(SharedProgressVectorEntry sharedProgressVectorEntry)
 {
     return(new CopyModeResult
     {
         SharedProgressVectorEntry = sharedProgressVectorEntry,
         SourceStartingLsn = LogicalSequenceNumber.InvalidLsn,
         TargetStartingLsn = LogicalSequenceNumber.InvalidLsn,
         CopyMode = CopyMode.None
     });
 }
 public static CopyModeResult CreatePartialCopyResult(
     SharedProgressVectorEntry sharedProgressVectorEntry,
     LogicalSequenceNumber sourceStartingLsn,
     LogicalSequenceNumber targetStartingLsn)
 {
     return(new CopyModeResult
     {
         SourceStartingLsn = sourceStartingLsn,
         TargetStartingLsn = targetStartingLsn,
         CopyMode = CopyMode.Partial,
         SharedProgressVectorEntry = sharedProgressVectorEntry
     });
 }
        public static CopyModeResult CreateFullCopyResult(
            SharedProgressVectorEntry sharedProgressVectorEntry,
            FullCopyReason reason)
        {
            Utility.Assert(reason != FullCopyReason.Invalid, "reason!= FullCopyReason.Invalid");

            return(new CopyModeResult
            {
                SharedProgressVectorEntry = sharedProgressVectorEntry,
                SourceStartingLsn = LogicalSequenceNumber.InvalidLsn,
                TargetStartingLsn = LogicalSequenceNumber.InvalidLsn,
                CopyMode = CopyMode.Full,
                FullCopyReason = reason
            });
        }
        public static CopyModeResult CreateFalseProgressResult(
            long lastRecoveredAtomicRedoOperationLsnAtTarget,
            SharedProgressVectorEntry sharedProgressVectorEntry,
            LogicalSequenceNumber sourceStartingLsn,
            LogicalSequenceNumber targetStartingLsn)
        {
            if (lastRecoveredAtomicRedoOperationLsnAtTarget > sourceStartingLsn.LSN)
            {
                // Atomic Redo operations cannot be undone in false progress.
                // So resort to full copy
                return(CreateFullCopyResult(sharedProgressVectorEntry, FullCopyReason.AtomicRedoOperationFalseProgressed));
            }

            return(new CopyModeResult
            {
                SourceStartingLsn = sourceStartingLsn,
                TargetStartingLsn = targetStartingLsn,
                CopyMode = CopyMode.FalseProgress | CopyMode.Partial,
                SharedProgressVectorEntry = sharedProgressVectorEntry
            });
        }
        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);
        }
        internal static SharedProgressVectorEntry FindSharedVector(
            ProgressVector sourceProgressVector,
            ProgressVector targetProgressVector)
        {
            // Initialize indices
            var sourceIndex = sourceProgressVector.vectors.Count - 1;
            var targetIndex = targetProgressVector.vectors.Count - 1;

            Utility.Assert(
                targetProgressVector.vectors[targetIndex].Epoch.DataLossNumber <= sourceProgressVector.vectors[sourceIndex].Epoch.DataLossNumber,
                "targetDataLossNumber ({0}) <= sourceDataLossNumber ({1})",
                targetProgressVector.vectors[targetIndex].Epoch.DataLossNumber, sourceProgressVector.vectors[sourceIndex].Epoch.DataLossNumber);

            SharedProgressVectorEntry progrssVectorTrimmedResult = new SharedProgressVectorEntry()
            {
                FullCopyReason = FullCopyReason.ProgressVectorTrimmed
            };

            do
            {
                bool decrementIndexSuccess = DecrementIndexUntilLeq(
                    ref targetIndex,
                    targetProgressVector,
                    sourceProgressVector.vectors[sourceIndex]);

                if (!decrementIndexSuccess)
                {
                    return(progrssVectorTrimmedResult);
                }

                decrementIndexSuccess = DecrementIndexUntilLeq(
                    ref sourceIndex,
                    sourceProgressVector,
                    targetProgressVector.vectors[targetIndex]);

                if (!decrementIndexSuccess)
                {
                    return(progrssVectorTrimmedResult);
                }
            } while (sourceProgressVector.vectors[sourceIndex] != targetProgressVector.vectors[targetIndex]);

            var sourceProgressVectorEntry = sourceProgressVector.vectors[sourceIndex];
            var targetProgressVectorEntry = targetProgressVector.vectors[targetIndex];

            // WITHOUT MINI RECONFIG ENABLED, it is not possible for the target to make VALID progress TWICE from the shared epoch
            // Note that this check is only valid in the absence of dataloss and restore.

            // E.g

            /*
             * Target Replica Copy Context: 131383889527030885
             *      TargetLogHeadEpoch: 0,0 TargetLogHeadLsn: 0 TargetLogTailEpoch: 131383889406148342,64424509440 TargetLogTailLSN: 73
             *      SourceLogHeadEpoch: 0,0 SourceLogHeadLsn: 0 SourceLogTailEpoch: 131383889406148342,68719476736 SourceLogTailLSN: 68
             *      Target ProgressVector: [(131383889406148342,64424509440),73,131383889527030885,2017-05-04T16:32:22]
             *                              [(131383889406148342,55834574848),68,131383889527030885,2017-05-04T16:31:54]
             *                              [(131383889406148342,51539607552),62,131383889416461059,2017-05-04T16:31:37]
             *                              [(131383889406148342,47244640256),56,131383889527030885,2017-05-04T16:31:20]
             *                              [(0,0),0,0,2017-05-04T16:29:07]
             *      Source ProgressVector: [(131383889406148342,68719476736),68,131383890970495929,2017-05-04T16:32:33]
             *                              [(131383889406148342,60129542144),68,131383890970495929,2017-05-04T16:32:09]
             *                              [(131383889406148342,51539607552),62,131383889416461059,2017-05-04T16:31:37]
             *                              [(131383889406148342,47244640256),56,131383889527030885,2017-05-04T16:31:20]
             *                              [(0,0),0,0,2017-05-04T16:31:33]
             *      LastRecoveredAtomicRedoOperationLsn: 0.
             *
             *
             *  Target Replica Copy Context: 131399770096882719
             *      TargetLogHeadEpoch: 0,0 TargetLogHeadLsn: 0 TargetLogTailEpoch: 131399758616683034,390842023936 TargetLogTailLSN: 374
             *      SourceLogHeadEpoch: 0,0 SourceLogHeadLsn: 0 SourceLogTailEpoch: 131399758616683034,395136991232 SourceLogTailLSN: 369
             *      Target ProgressVector:
             *                  [(131399758616683034,390842023936),374,131399770096882719,2017-05-23T01:42:03]
             *                  [(131399758616683034,382252089344),374,131399770096882719,2017-05-23T01:41:29]
             *                  [(131399758616683034,377957122048),369,131399770096882719,2017-05-23T01:41:00]
             *                  [(131399758616683034,373662154752),338,131399758632647497,2017-05-23T01:40:31]
             *      Source ProgressVector:
             *                  [(131399758616683034,395136991232),369,131399758701866693,2017-05-23T01:42:19]
             *                  [(131399758616683034,386547056640),369,131399758701866693,2017-05-23T01:41:44]
             *                  [(131399758616683034,373662154752),338,131399758632647497,2017-05-23T01:40:31]
             *      LastRecoveredAtomicRedoOperationLsn: 0
             */

            string failureMsg;

            if (targetProgressVector.LastProgressVectorEntry.Epoch.DataLossNumber
                == sourceProgressVector.LastProgressVectorEntry.Epoch.DataLossNumber &&
                targetIndex < targetProgressVector.vectors.Count - 1 &&
                targetProgressVector.LastProgressVectorEntry.Epoch.DataLossNumber == targetProgressVector.vectors[targetIndex].Epoch.DataLossNumber)
            {
                // Target replica could only have repeatedly attempted to become a
                // primary without ever making progress at the shared dataloss number
                // We can do "double progress check" only if there has NOT been any other data loss happening on the target after shared point. Having a differnt dataloss numbers in shared vector and target's tail
                // means that target has been a valid primary and progressed in LSN until hitting a dataloss and then a very old secondary can become primary and invalidate all the progress made by the target.
                var failureLsn            = targetProgressVector.vectors[targetIndex + 1].Lsn;
                var failureLsnIncremented = 0;

                for (var n = targetIndex + 2; n <= targetProgressVector.vectors.Count - 1; n++)
                {
                    var vector = targetProgressVector.vectors[n];
                    if (vector.Epoch.DataLossNumber != targetProgressVectorEntry.Epoch.DataLossNumber)
                    {
                        break;
                    }

                    if (vector.Lsn != failureLsn)
                    {
                        // Update failureLsn to ensure we don't assert if there are multiple entries for same LSN like in 2nd example above
                        failureLsn = vector.Lsn;
                        failureLsnIncremented++;
                    }
                }

                failureMsg = string.Format(
                    "FailureLsn incremented must be <= 1. It is {0}",
                    failureLsnIncremented);

                if (!ValidateIfDebugEnabled(
                        failureLsnIncremented <= 1,
                        failureMsg))
                {
                    return(new SharedProgressVectorEntry
                    {
                        SourceIndex = sourceIndex,
                        TargetIndex = targetIndex,
                        SourceProgressVectorEntry = sourceProgressVectorEntry,
                        TargetProgressVectorEntry = targetProgressVectorEntry,
                        FullCopyReason = FullCopyReason.ValidationFailed,
                        FailedValidationMessage = failureMsg
                    });
                }
            }

            // Sanity check that source and target progress vectors are always in
            // agreement upto above determined ProgressVectorEntry shared by both of them
            var i           = sourceIndex;
            var sourceEntry = sourceProgressVectorEntry;
            var j           = targetIndex;
            var targetEntry = targetProgressVectorEntry;

            failureMsg = "sourceEntry == targetEntry";

            do
            {
                sourceEntry = DecrementIndexUntilLsnIsEqual(ref i, sourceProgressVector, sourceEntry.Lsn.LSN);
                if (i == 0)
                {
                    break;
                }

                targetEntry = DecrementIndexUntilLsnIsEqual(ref j, targetProgressVector, targetEntry.Lsn.LSN);
                if (j == 0)
                {
                    break;
                }

                if (!ValidateIfDebugEnabled(
                        sourceEntry == targetEntry,
                        failureMsg))
                {
                    return(new SharedProgressVectorEntry
                    {
                        SourceIndex = sourceIndex,
                        TargetIndex = targetIndex,
                        SourceProgressVectorEntry = sourceProgressVectorEntry,
                        TargetProgressVectorEntry = targetProgressVectorEntry,
                        FullCopyReason = FullCopyReason.ValidationFailed,
                        FailedValidationMessage = failureMsg
                    });
                }
            } while (true);

            Utility.Assert(sourceProgressVectorEntry != null && targetProgressVectorEntry != null, "Source and target expected to be non null");

            return(new SharedProgressVectorEntry
            {
                SourceIndex = sourceIndex,
                TargetIndex = targetIndex,
                SourceProgressVectorEntry = sourceProgressVectorEntry,
                TargetProgressVectorEntry = targetProgressVectorEntry
            });
        }