Exemplo n.º 1
0
        //TODO: move it into easily testable class
        public static bool ShouldBeDelivered(ReplicaId origin, VClock local, VClock remote)
        {
            var lver = local.Value;

            foreach ((var rkey, var rtime) in remote.Value)
            {
                if (lver.TryGetValue(rkey, out var ltime))
                {
                    if (rkey == origin)
                    {
                        if (rtime != ltime + 1)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        if (rtime > ltime)
                        {
                            return(false);
                        }
                    }
                }
                else if (!(rkey == origin && rtime == 1))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 2
0
 public JsonRow(string streamId, ReplicaId replicaId, VClock timestamp, string jsonPayload)
 {
     StreamId    = streamId;
     ReplicaId   = replicaId;
     Timestamp   = timestamp;
     JsonPayload = jsonPayload;
 }
Exemplo n.º 3
0
 public ReplicatorState <T> WithLocalVersion(VClock localVersion) =>
 new ReplicatorState <T>(
     localVersion: localVersion,
     stableVersion: StableVersion,
     remoteVersions: RemoteVersions,
     pendingDeliveries: PendingDeliveries,
     pendingAcks: PendingAcks);
Exemplo n.º 4
0
 public PayloadRow(string streamId, ReplicaId replicaId, VClock timestamp, int serializerId, byte[] payload)
 {
     StreamId     = streamId;
     ReplicaId    = replicaId;
     Timestamp    = timestamp;
     SerializerId = serializerId;
     Payload      = payload;
 }
Exemplo n.º 5
0
        public void VectorTime_should_be_mergeable()
        {
            var t1 = new VClock(new KeyValuePair <int, long>(A, 1), new KeyValuePair <int, long>(B, 2), new KeyValuePair <int, long>(C, 2));
            var t2 = new VClock(new KeyValuePair <int, long>(A, 4), new KeyValuePair <int, long>(C, 1));

            t1.Merge(t2).Should().Be(new VClock(new KeyValuePair <int, long>(A, 4), new KeyValuePair <int, long>(B, 2), new KeyValuePair <int, long>(C, 2)));
            t2.Merge(t1).Should().Be(new VClock(new KeyValuePair <int, long>(A, 4), new KeyValuePair <int, long>(B, 2), new KeyValuePair <int, long>(C, 2)));
        }
Exemplo n.º 6
0
 private void Assert(VClock t1, VClock t2, bool eq, bool conc, bool lt, bool lteq, bool gt, bool gteq)
 {
     (t1 == t2).Should().Be(eq, "{0} should be equal to {1}", t1, t2);
     (t1.IsConcurrent(t2)).Should().Be(conc, "{0} should be concurrent to {1}", t1, t2);
     (t1 < t2).Should().Be(lt, "{0} should be less than {1}", t1, t2);
     (t1 <= t2).Should().Be(lteq, "{0} should be less or equal to {1}", t1, t2);
     (t1 > t2).Should().Be(gt, "{0} should be greater than {1}", t1, t2);
     (t1 >= t2).Should().Be(gteq, "{0} should be greater or equal to {1}", t1, t2);
 }
Exemplo n.º 7
0
 public ReplicatorState(
     VClock localVersion,
     VClock stableVersion,
     ImmutableDictionary <ReplicaId, VClock> remoteVersions,
     ImmutableHashSet <Deliver <T> > pendingDeliveries,
     ImmutableHashSet <PendingAck <T> > pendingAcks)
 {
     LocalVersion      = localVersion;
     StableVersion     = stableVersion;
     RemoteVersions    = remoteVersions;
     PendingDeliveries = pendingDeliveries;
     PendingAcks       = pendingAcks;
 }
Exemplo n.º 8
0
        /// <summary>
        /// Check and possibly deliver a message if it should be delivered.
        /// </summary>
        /// <returns></returns>
        private bool TryToCasuallyDeliver(Deliver <T> delivery)
        {
            if (ShouldBeDelivered(delivery.Origin, localVersion, delivery.Versioned.Version))
            {
                foreach (var subscriber in subscribers)
                {
                    subscriber.Tell(delivery.Versioned);
                }

                pendingDelivery = pendingDelivery.Remove(delivery);
                localVersion    = localVersion.Increment(delivery.Origin);

                return(true);
            }
            return(false);
        }
Exemplo n.º 9
0
        public void VectorTime_should_conform_to_partial_ordering()
        {
            var t1 = new VClock(new KeyValuePair <int, long>(A, 1), new KeyValuePair <int, long>(B, 2));
            var t2 = new VClock(new KeyValuePair <int, long>(A, 1), new KeyValuePair <int, long>(B, 1));
            var t3 = new VClock(new KeyValuePair <int, long>(A, 2), new KeyValuePair <int, long>(B, 1));
            var t4 = new VClock(new KeyValuePair <int, long>(A, 1), new KeyValuePair <int, long>(B, 2), new KeyValuePair <int, long>(C, 2));
            var t5 = new VClock(new KeyValuePair <int, long>(A, 1), new KeyValuePair <int, long>(C, 2));
            var t6 = new VClock(new KeyValuePair <int, long>(A, 1), new KeyValuePair <int, long>(C, 0));

            Assert(t1, t1, eq: true, conc: false, lt: false, lteq: true, gt: false, gteq: true);
            Assert(t1, t2, eq: false, conc: false, lt: false, lteq: false, gt: true, gteq: true);
            Assert(t2, t1, eq: false, conc: false, lt: true, lteq: true, gt: false, gteq: false);
            Assert(t1, t3, eq: false, conc: true, lt: false, lteq: false, gt: false, gteq: false);
            Assert(t3, t1, eq: false, conc: true, lt: false, lteq: false, gt: false, gteq: false);
            Assert(t1, t4, eq: false, conc: false, lt: true, lteq: true, gt: false, gteq: false);
            Assert(t4, t1, eq: false, conc: false, lt: false, lteq: false, gt: true, gteq: true);
            Assert(t1, t5, eq: false, conc: true, lt: false, lteq: false, gt: false, gteq: false);
            Assert(t5, t1, eq: false, conc: true, lt: false, lteq: false, gt: false, gteq: false);
            Assert(t1, t6, eq: false, conc: false, lt: false, lteq: false, gt: true, gteq: true);
            Assert(t6, t1, eq: false, conc: false, lt: true, lteq: true, gt: false, gteq: false);
        }
Exemplo n.º 10
0
        public ReplicatorActor(ReplicaId myself, ReplicatorSettings settings)
        {
            this.myself            = myself;
            this.settings          = settings;
            replicatorRelativePath = Self.Path.ToStringWithoutAddress();

            Receive <ClusterEvent.MemberUp>(up =>
            {
                if (HasRole(up.Member) && up.Member.Address != cluster.SelfAddress)
                {
                    // send invitation to a new member
                    var path = up.Member.Address.ToString() + replicatorRelativePath;
                    Context.ActorSelection(path).Tell(new Invitation(myself, Self));
                }
            });
            Receive <ClusterEvent.IMemberEvent>(_ => { /* ignore */ });
            Receive <Broadcast <T> >(bcast =>
            {
                var version   = localVersion.Increment(myself);
                var versioned = new Versioned <T>(version, bcast.Message);
                var send      = new Send <T>(myself, myself, versioned);

                if (log.IsInfoEnabled)
                {
                    log.Info("Sending {0} to: {1}", send, string.Join(", ", members));
                }

                foreach (var member in members)
                {
                    member.Value.Forward(send);
                }

                var pendingAck = new PendingAck <T>(myself, versioned, DateTime.UtcNow, members.Keys.ToImmutableHashSet());

                this.pendingAcks  = pendingAcks.Add(pendingAck);
                this.localVersion = version;
            });
            Receive <Send <T> >(send =>
            {
                if (AlreadySeen(send.Versioned.Version))
                {
                    log.Info("Received duplicate message {0}", send);
                }
                else
                {
                    var receivers = members.Remove(send.Origin);

                    var forward = send.WithLastSeenBy(myself);
                    if (log.IsInfoEnabled)
                    {
                        log.Info("Broadcasting message {0} to: {1}", forward, string.Join(", ", receivers.Values));
                    }

                    foreach (var member in receivers.Values)
                    {
                        member.Forward(forward);
                    }

                    if (members.TryGetValue(send.LastSeenBy, out var sender))
                    {
                        sender.Tell(new SendAck(myself, send.Versioned.Version), ActorRefs.NoSender);
                    }

                    var deliver = new Deliver <T>(send.Origin, send.Versioned);
                    Self.Forward(deliver);

                    this.pendingDelivery = pendingDelivery.Add(deliver);
                    this.pendingAcks     = pendingAcks.Add(new PendingAck <T>(myself, send.Versioned, DateTime.UtcNow, receivers.Keys.ToImmutableHashSet()));
                }
            });
            Receive <SendAck>(ack =>
            {
                log.Info("Received ACK from {0} (version: {1})", Sender, ack.Version);

                var pendingAck  = this.pendingAcks.First(x => x.Versioned.Version == ack.Version);
                var membersLeft = pendingAck.Members.Remove(ack.ReplicaId);

                this.pendingAcks = pendingAcks.Remove(pendingAck);
                if (!membersLeft.IsEmpty)
                {
                    this.pendingAcks = pendingAcks.Add(pendingAck.WithMembers(membersLeft));
                }
            });
            Receive <Deliver <T> >(deliver =>
            {
                TryToCasuallyDeliver(deliver);

                remoteVersions      = remoteVersions.SetItem(deliver.Origin, deliver.Versioned.Version);
                latestStableVersion = UpdateStableVersion(remoteVersions);
            });
            Receive <Resend>(_ =>
            {
                var now     = DateTime.UtcNow;
                var builder = pendingAcks.ToBuilder();
                foreach (var ack in pendingAcks)
                {
                    if (now - ack.Timestamp > settings.RetryTimeout)
                    {
                        builder.Remove(ack);
                        var send = new Send <T>(myself, myself, ack.Versioned);
                        foreach (var replicaId in ack.Members)
                        {
                            if (members.TryGetValue(replicaId, out var member))
                            {
                                member.Tell(send, ActorRefs.NoSender);
                            }
                        }
                        builder.Add(ack.WithTimestamp(now));
                    }
                }
                pendingAcks = builder.ToImmutable();
            });
            Receive <Invitation>(invitation =>
            {
                log.Info("Received invitation from {0} (ID: {1})", invitation.ReplicatorRef, invitation.ReplicaId);
                members = members.Add(invitation.ReplicaId, invitation.ReplicatorRef);
                Context.Watch(invitation.ReplicatorRef);
            });
            Receive <StableReq>(sync =>
            {
                var reply = sync.Versions.Where(ver => latestStableVersion >= ver).ToArray();
                Sender.Tell(new StableRep(reply));
            });
            Receive <Subscribe <T> >(subscribe =>
            {
                subscribers = subscribers.Add(subscribe.Ref);
                if (subscribe.Ack != null)
                {
                    subscribe.Ref.Tell(subscribe.Ack);
                }
            });
            Receive <Unsubscribe>(unsubscribe =>
            {
                subscribers = subscribers.Remove(unsubscribe.Ref);
                if (unsubscribe.Ack != null)
                {
                    unsubscribe.Ref.Tell(unsubscribe.Ack);
                }
            });
            Receive <Terminated>(terminated =>
            {
                subscribers   = subscribers.Remove(terminated.ActorRef);
                var replicaId = members.FirstOrDefault(kv => Equals(kv.Value, terminated.ActorRef));
                members       = members.Remove(replicaId.Key);
            });

            resendTask = Context.System.Scheduler
                         .ScheduleTellOnceCancelable(settings.ResendInterval, Self, Resend.Instance, ActorRefs.NoSender);
        }
Exemplo n.º 11
0
 private bool AlreadySeen(VClock version) => localVersion >= version || pendingDelivery.Any(x => x.Versioned.Version == version);
Exemplo n.º 12
0
 public Versioned(VClock version, T message)
 {
     Version = version;
     Message = message;
 }
Exemplo n.º 13
0
 public SendAck(ReplicaId replicaId, VClock version)
 {
     ReplicaId = replicaId;
     Version   = version;
 }