public void Handle(ReplicationMessage.ReplicaSubscribed message) { if (_activeChunk != null) { _activeChunk.MarkForDeletion(); _activeChunk = null; } _framer.Reset(); _subscriptionId = message.SubscriptionId; _ackedSubscriptionPos = _subscriptionPos = message.SubscriptionPosition; Log.Info("=== SUBSCRIBED to [{masterEndPoint},{masterId:B}] at {subscriptionPosition} (0x{subscriptionPosition:X}). SubscriptionId: {subscriptionId:B}.", message.MasterEndPoint, message.MasterId, message.SubscriptionPosition, message.SubscriptionPosition, message.SubscriptionId); var writerCheck = Db.Config.WriterCheckpoint.ReadNonFlushed(); if (message.SubscriptionPosition > writerCheck) { ReplicationFail( "Master [{0},{1:B}] subscribed us at {2} (0x{3:X}), which is greater than our writer checkpoint {4} (0x{5:X}). REPLICATION BUG.", "Master [{masterEndpoint},{masterId:B}] subscribed us at {subscriptionPosition} (0x{subscriptionPosition:X}), which is greater than our writer checkpoint {writerCheckpoint} (0x{writerCheckpoint:X}). REPLICATION BUG.", message.MasterEndPoint, message.MasterId, message.SubscriptionPosition, message.SubscriptionPosition, writerCheck, writerCheck); } if (message.SubscriptionPosition < writerCheck) { Log.Info("Master [{masterEndPoint},{masterId:B}] subscribed us at {subscriptionPosition} (0x{subscriptionPosition:X}), which is less than our writer checkpoint {writerCheckpoint} (0x{writerCheckpoint:X}). TRUNCATION IS NEEDED.", message.MasterEndPoint, message.MasterId, message.SubscriptionPosition, message.SubscriptionPosition, writerCheck, writerCheck); var lastCommitPosition = _getLastCommitPosition(); if (message.SubscriptionPosition > lastCommitPosition) { Log.Info("ONLINE TRUNCATION IS NEEDED. NOT IMPLEMENTED. OFFLINE TRUNCATION WILL BE PERFORMED. SHUTTING DOWN NODE."); } else { Log.Info("OFFLINE TRUNCATION IS NEEDED (SubscribedAt {subscriptionPosition} (0x{subscriptionPosition:X}) <= LastCommitPosition {lastCommitPosition} (0x{lastCommitPosition:X})). SHUTTING DOWN NODE.", message.SubscriptionPosition, message.SubscriptionPosition, lastCommitPosition, lastCommitPosition); } EpochRecord lastEpoch = EpochManager.GetLastEpoch(); if (AreAnyCommittedRecordsTruncatedWithLastEpoch(message.SubscriptionPosition, lastEpoch, lastCommitPosition)) { Log.Error("Master [{masterEndPoint},{masterId:B}] subscribed us at {subscriptionPosition} (0x{subscriptionPosition:X}), which is less than our last epoch and LastCommitPosition {lastCommitPosition} (0x{lastCommitPosition:X}) >= lastEpoch.EpochPosition {lastEpochPosition} (0x{lastEpochPosition:X}). That might be bad, especially if the LastCommitPosition is way beyond EpochPosition.", message.MasterEndPoint, message.MasterId, message.SubscriptionPosition, message.SubscriptionPosition, lastCommitPosition, lastCommitPosition, lastEpoch.EpochPosition, lastEpoch.EpochPosition); Log.Error("ATTEMPT TO TRUNCATE EPOCH WITH COMMITTED RECORDS. THIS MAY BE BAD, BUT IT IS OK IF JUST-ELECTED MASTER FAILS IMMEDIATELY AFTER ITS ELECTION."); } Db.Config.TruncateCheckpoint.Write(message.SubscriptionPosition); Db.Config.TruncateCheckpoint.Flush(); BlockWriter = true; Bus.Publish(new ClientMessage.RequestShutdown(exitProcess: true, shutdownHttp: true)); return; } // subscription position == writer checkpoint // everything is ok }
public void subscription_is_sent_replica_subscribed_message_for_leaders_epoch_after_common_epoch() { var subscribed = GetTcpSendsFor(_replicaManager).Select(x => x.Message) .OfType <ReplicationMessage.ReplicaSubscribed>().ToArray(); Assert.AreEqual(1, subscribed.Length); Assert.AreEqual(EpochManager.GetLastEpoch().EpochPosition, subscribed[0].SubscriptionPosition); Assert.AreEqual(_replicaId, subscribed[0].SubscriptionId); Assert.AreEqual(LeaderId, subscribed[0].LeaderId); }
public override void When() { EpochManager.WriteNewEpoch(0); Writer.Write(CreateLogRecord(0), out _); Writer.Write(CreateLogRecord(1), out _); Writer.Write(CreateLogRecord(2), out _); Writer.Write(CreateLogRecord(3), out _); Writer.Write(CreateLogRecord(4), out _subscribedPosition); EpochManager.WriteNewEpoch(1); _lastEpoch = EpochManager.GetLastEpoch(); var epochs = EpochManager.GetLastEpochs(10) .Select(e => new Epoch(e.EpochPosition, e.EpochNumber, e.EpochId)).ToArray(); AddSubscription(_replicaId, true, epochs, _subscribedPosition, out _replicaManager); }
public void epoch_should_be_updated() { AssertEx.IsOrBecomesTrue(() => EpochManager.GetLastEpoch() != null); Assert.AreEqual(_epochId, EpochManager.GetLastEpoch().EpochId); Assert.AreEqual(_epochNumber, EpochManager.GetLastEpoch().EpochNumber); }