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));
                    }
                }
            }
        }
Пример #3
0
 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")}");
         }
     }
 }
Пример #4
0
        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;
        }
Пример #5
0
 private bool LeaseIsNotSafelyExpired(Lease lease, DateTime now)
 {
     return lease != null
            && lease.ExpiresAt < now
            && lease.ExpiresAt + config.ClockDrift > now;
 }
Пример #6
0
 private static bool LeaseNullOrExpired(Lease lease, DateTime now)
 {
     return lease == null || lease.ExpiresAt < now;
 }
Пример #7
0
 private bool IsLeaseOwner(Lease lease)
 {
     return lease != null && Unsafe.Equals(lease.OwnerIdentity, localNode.SocketIdentity);
 }
Пример #8
0
        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;
        }
Пример #9
0
 private bool ProcessBecameLeader(Lease nextLease, Lease previousLease)
 {
     return ((previousLease == null || !Unsafe.Equals(previousLease.OwnerIdentity, localNode.SocketIdentity))
             && nextLease != null && Unsafe.Equals(nextLease.OwnerIdentity, localNode.SocketIdentity));
 }
Пример #10
0
 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);
                    }
                }
            }
        }