Example #1
0
        private long GetValidLogPosition(long logPosition, Epoch[] epochs, IPEndPoint replicaEndPoint, Guid subscriptionId)
        {
            if (epochs.Length == 0)
            {
                if (logPosition > 0)
                {
                    // slave has some data, but doesn't have any epoch
                    // for now we'll just report error and close connection
                    var msg = string.Format("Replica [{0},S:{1},{2}] has positive LogPosition {3} (0x{3:X}), but does not have epochs.",
                                            replicaEndPoint, subscriptionId,
                                            string.Join(", ", epochs.Select(x => x.AsString())), logPosition);
                    Log.Info(
                        "Replica [{replicaEndPoint},S:{subscriptionId},{epochs}] has positive LogPosition {logPosition} (0x{logPosition:X}), but does not have epochs.",
                        replicaEndPoint, subscriptionId,
                        string.Join(", ", epochs.Select(x => x.AsString())), logPosition, logPosition);
                    throw new Exception(msg);
                }
                return(0);
            }

            var   masterCheckpoint = _db.Config.WriterCheckpoint.Read();
            Epoch afterCommonEpoch = null;
            Epoch commonEpoch      = null;

            for (int i = 0; i < epochs.Length; ++i)
            {
                var epoch = epochs[i];
                if (_epochManager.IsCorrectEpochAt(epoch.EpochPosition, epoch.EpochNumber, epoch.EpochId))
                {
                    commonEpoch      = epoch;
                    afterCommonEpoch = i > 0 ? epochs[i - 1] : null;
                    break;
                }
            }
            if (commonEpoch == null)
            {
                Log.Error("No common epoch found for replica [{replicaEndPoint},S{subscriptionId},{logPosition}(0x{logPosition:X}),{epochs}]. Subscribing at 0. Master LogPosition: {masterCheckpoint} (0x{masterCheckpoint:X}), known epochs: {knownEpochs}.",
                          replicaEndPoint, subscriptionId,
                          logPosition, logPosition,
                          string.Join(", ", epochs.Select(x => x.AsString())),
                          masterCheckpoint, masterCheckpoint,
                          string.Join(", ", _epochManager.GetLastEpochs(int.MaxValue).Select(x => x.AsString())));
                return(0);
            }

            // if afterCommonEpoch is present, logPosition > afterCommonEpoch.EpochPosition,
            // so safe position is definitely the start of afterCommonEpoch
            var replicaPosition = afterCommonEpoch == null ? logPosition : afterCommonEpoch.EpochPosition;

            if (commonEpoch.EpochNumber == _epochManager.LastEpochNumber)
            {
                return(Math.Min(replicaPosition, masterCheckpoint));
            }

            var nextEpoch = _epochManager.GetEpoch(commonEpoch.EpochNumber + 1, throwIfNotFound: false);

            if (nextEpoch == null)
            {
                nextEpoch = _epochManager.GetEpochWithAllEpochs(commonEpoch.EpochNumber + 1, throwIfNotFound: false);
            }
            if (nextEpoch == null)
            {
                var msg = string.Format("Replica [{0},S:{1},{2}(0x{3:X}),epochs:\n{4}]\n provided epochs which are not in "
                                        + "EpochManager (possibly too old, known epochs:\n{5}).\nMaster LogPosition: {6} (0x{7:X}). "
                                        + "We do not support this case as of now.\n"
                                        + "CommonEpoch: {8}, AfterCommonEpoch: {9}",
                                        replicaEndPoint, subscriptionId, logPosition, logPosition,
                                        string.Join("\n", epochs.Select(x => x.AsString())),
                                        string.Join("\n", _epochManager.GetLastEpochs(int.MaxValue).Select(x => x.AsString())), masterCheckpoint, masterCheckpoint,
                                        commonEpoch.AsString(), afterCommonEpoch == null ? "<none>" : afterCommonEpoch.AsString());
                Log.Error(
                    "Replica [{replicaEndPoint},S:{subscriptionId},{logPosition}(0x{logPosition:X}),epochs:\n{epochs}]\n provided epochs which are not in "
                    + "EpochManager (possibly too old, known epochs:\n{lastEpochs}).\nMaster LogPosition: {masterCheckpoint} (0x{masterCheckpoint:X}). "
                    + "We do not support this case as of now.\n"
                    + "CommonEpoch: {commonEpoch}, AfterCommonEpoch: {afterCommonEpoch}",
                    replicaEndPoint,
                    subscriptionId,
                    logPosition,
                    logPosition,
                    string.Join("\n", epochs.Select(x => x.AsString())),
                    string.Join("\n", _epochManager.GetLastEpochs(int.MaxValue).Select(x => x.AsString())),
                    masterCheckpoint,
                    masterCheckpoint,
                    commonEpoch.AsString(),
                    afterCommonEpoch == null ? "<none>" : afterCommonEpoch.AsString()
                    );
                throw new Exception(msg);
            }

            return(Math.Min(replicaPosition, nextEpoch.EpochPosition));
        }