public void TestWriteIsAborted_AfterWriteWithBallotGreaterThanCurrent() { using (CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().First())) { using (CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().Second())) { using (var testSetup = CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().Third())) { var ballotGenerator = testSetup.BallotGenerator; var localNode = testSetup.LocalNode; var roundBasedRegister = testSetup.RoundBasedRegister; var ballot0 = ballotGenerator.New(localNode.SocketIdentity); var lease = new Lease(localNode.SocketIdentity, ownerEndpoint, DateTime.UtcNow); var txResult = roundBasedRegister.Write(ballot0, lease); Assert.AreEqual(TxOutcome.Commit, txResult.TxOutcome); var ballot1 = new Ballot(ballot0.Timestamp - TimeSpan.FromSeconds(10), ballot0.MessageNumber, localNode.SocketIdentity); Assert.IsTrue(ballot0 > ballot1); txResult = roundBasedRegister.Write(ballot1, lease); Assert.AreEqual(TxOutcome.Abort, txResult.TxOutcome); } } } }
public void TestReadCommitsWithNonEmptyLease_IfWriteCommittedLeaseWithBallotLessThanCurrent() { using (CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().First())) { using (CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().Second())) { using (var testSetup = CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().Third())) { var ballotGenerator = testSetup.BallotGenerator; var localNode = testSetup.LocalNode; var roundBasedRegister = testSetup.RoundBasedRegister; var ballot0 = ballotGenerator.New(localNode.SocketIdentity); var lease = new Lease(localNode.SocketIdentity, ownerEndpoint, DateTime.UtcNow); var txResult = roundBasedRegister.Write(ballot0, lease); Assert.AreEqual(TxOutcome.Commit, txResult.TxOutcome); var ballot1 = ballotGenerator.New(localNode.SocketIdentity); Assert.IsTrue(ballot0 < ballot1); txResult = roundBasedRegister.Read(ballot1); Assert.AreEqual(TxOutcome.Commit, txResult.TxOutcome); Assert.AreEqual(lease.ExpiresAt, txResult.Lease.ExpiresAt); Assert.AreEqual(lease.OwnerEndpoint.MulticastUri, txResult.Lease.OwnerEndpoint.MulticastUri); Assert.AreEqual(lease.OwnerEndpoint.UnicastUri, txResult.Lease.OwnerEndpoint.UnicastUri); Assert.IsTrue(Unsafe.Equals(lease.OwnerIdentity, txResult.Lease.OwnerIdentity)); } } } }
private void LogLeaseProlonged(Lease lastReadLease) { if (lastReadLease != null) { if (IsLeaseOwner(lastReadLease)) { logger.Debug($"[{DateTime.UtcNow.ToString("HH:mm:ss fff")}] " + "PROLONG === process " + $"{localNode.Uri.AbsoluteUri} " + "wants to prolong it's lease " + $"{lastReadLease.ExpiresAt.ToString("HH:mm:ss fff")}"); } else { logger.Debug($"[{DateTime.UtcNow.ToString("HH:mm:ss fff")}] " + "RENEW === process " + $"{localNode.Uri.AbsoluteUri} " + "wants to renew lease " + $"{lastReadLease.ExpiresAt.ToString("HH:mm:ss fff")}"); } } }
private void ReadOrRenewLease() { var now = DateTime.UtcNow; var lease = AсquireOrLearnLease(ballotGenerator.New(localNode.SocketIdentity), now); if (ProcessBecameLeader(lease, lastKnownLease) || ProcessLostLeadership(lease, lastKnownLease)) { var renewPeriod = CalcLeaseRenewPeriod(ProcessBecameLeader(lease, lastKnownLease)); leaseTimer.Change(renewPeriod, renewPeriod); } lastKnownLease = lease; }
private bool LeaseIsNotSafelyExpired(Lease lease, DateTime now) { return lease != null && lease.ExpiresAt < now && lease.ExpiresAt + config.ClockDrift > now; }
private static bool LeaseNullOrExpired(Lease lease, DateTime now) { return lease == null || lease.ExpiresAt < now; }
private bool IsLeaseOwner(Lease lease) { return lease != null && Unsafe.Equals(lease.OwnerIdentity, localNode.SocketIdentity); }
private Lease AсquireOrLearnLease(Ballot ballot, DateTime now) { var read = register.Read(ballot); if (read.TxOutcome == TxOutcome.Commit) { var lease = read.Lease; if (LeaseIsNotSafelyExpired(lease, now)) { LogStartSleep(); Sleep(config.ClockDrift); LogAwake(); // TODO: Add recursion exit condition return AсquireOrLearnLease(ballotGenerator.New(localNode.SocketIdentity), DateTime.UtcNow); } if (LeaseNullOrExpired(lease, now) || IsLeaseOwner(lease)) { LogLeaseProlonged(lease); var ownerEndpoint = new OwnerEndpoint {UnicastUri = rendezvousConfig.UnicastUri, MulticastUri = rendezvousConfig.MulticastUri}; lease = new Lease(localNode.SocketIdentity, ownerEndpoint, now + config.MaxLeaseTimeSpan); } var write = register.Write(ballot, lease); if (write.TxOutcome == TxOutcome.Commit) { return lease; } } return null; }
private bool ProcessBecameLeader(Lease nextLease, Lease previousLease) { return ((previousLease == null || !Unsafe.Equals(previousLease.OwnerIdentity, localNode.SocketIdentity)) && nextLease != null && Unsafe.Equals(nextLease.OwnerIdentity, localNode.SocketIdentity)); }
private bool ProcessLostLeadership(Lease nextLease, Lease previousLease) { return (previousLease != null && Unsafe.Equals(previousLease.OwnerIdentity, localNode.SocketIdentity) && nextLease != null && !Unsafe.Equals(nextLease.OwnerIdentity, localNode.SocketIdentity)); }
public void TestReadIsAborted_AfterWriteWithBallotEqualToCurrent() { using (CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().First())) { using (CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().Second())) { using (var testSetup = CreateRoundBasedRegister(GetSynodMembers(), GetSynodMembers().Third())) { var ballotGenerator = testSetup.BallotGenerator; var localNode = testSetup.LocalNode; var roundBasedRegister = testSetup.RoundBasedRegister; var ballot0 = ballotGenerator.New(localNode.SocketIdentity); var lease = new Lease(localNode.SocketIdentity, ownerEndpoint, DateTime.UtcNow); var txResult = roundBasedRegister.Write(ballot0, lease); Assert.AreEqual(TxOutcome.Commit, txResult.TxOutcome); txResult = roundBasedRegister.Read(ballot0); Assert.AreEqual(TxOutcome.Abort, txResult.TxOutcome); } } } }