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)); }