Beispiel #1
0
        public override void OnWireReceived(UnsafeReader stream)
        {
            var header       = stream.ReadInt();
            var msgVersioned = (header >> versionedFlagShift) != 0;
            var opType       = header & ((1 << versionedFlagShift) - 1);

            var version = msgVersioned ? stream.ReadLong() : 0L;

            var key = ReadKeyDelegate(SerializationContext, stream);

            if (opType == Ack)
            {
                string error = null;

                if (!msgVersioned)
                {
                    error = "Received ACK while msg hasn't versioned flag set";
                }
                else if (!IsMaster)
                {
                    error = "Received ACK when not a Master";
                }
                else if (!myPendingForAck.TryGetValue(key, out var pendingVersion))
                {
                    error = "No pending for ACK";
                }
                else if (pendingVersion < version)
                {
                    error = string.Format("Pending version `{0}` < ACK version `{1}`", pendingVersion, version);
                }
                // Good scenario
                else if (pendingVersion == version)
                {
                    myPendingForAck.Remove(key);
                }
                //else do nothing, silently drop

                var isError = !string.IsNullOrEmpty(error);
                if (LogReceived.IsTraceEnabled() || isError)
                {
                    LogReceived.LogFormat(isError ? LoggingLevel.ERROR : LoggingLevel.TRACE,
                                          "map `{0}` ({1})  :: ACK :: key = {2} :: version = {3}{4}", Location, RdId, key.PrintToString(), version,
                                          isError ? " >> " + error : "");
                }
            }
            else
            {
                using (UsingDebugInfo())
                {
                    var kind = (AddUpdateRemove)opType;
                    switch (kind)
                    {
                    case AddUpdateRemove.Add:
                    case AddUpdateRemove.Update:
                        var value = ReadValueDelegate(SerializationContext, stream);
                        if (LogReceived.IsTraceEnabled())
                        {
                            LogReceived.Trace("map `{0}` ({1})  :: {2} :: key = {3}{4} :: value = {5}", Location, RdId, kind,
                                              key.PrintToString(), msgVersioned ? " :: version = " + version : "", value.PrintToString());
                        }

                        if (msgVersioned || !IsMaster || !myPendingForAck.ContainsKey(key))
                        {
                            myMap[key] = value;
                        }
                        else
                        {
                            LogReceived.Trace(">> CHANGE IGNORED");
                        }

                        break;

                    case AddUpdateRemove.Remove:
                        if (LogReceived.IsTraceEnabled())
                        {
                            LogReceived.Trace("map `{0}` ({1})  :: {2} :: key = {3}{4}", Location, RdId, kind,
                                              key.PrintToString(), msgVersioned ? " :: version = " + version : "");
                        }

                        if (msgVersioned || !IsMaster || !myPendingForAck.ContainsKey(key))
                        {
                            myMap.Remove(key);
                        }
                        else
                        {
                            LogReceived.Trace(">> CHANGE IGNORED");
                        }

                        break;

                    default:
                        throw new ArgumentOutOfRangeException(kind.ToString());
                    }
                }

                if (msgVersioned)
                {
                    Wire.Send(RdId, (innerWriter) =>
                    {
                        innerWriter.Write((1 << versionedFlagShift) | Ack);
                        innerWriter.Write(version);
                        WriteKeyDelegate.Invoke(SerializationContext, innerWriter, key);

                        if (LogSend.IsTraceEnabled())
                        {
                            LogSend.Trace("map `{0}` ({1}) :: ACK :: key = {2} :: version = {3}", Location, RdId, key.PrintToString(), version);
                        }
                    });

                    if (IsMaster)
                    {
                        LogReceived.Error("Both ends are masters: {0}", Location);
                    }
                }
            }
        }