Example #1
0
 void ReleaseLocks()
 {
     if (!RecordOrReplayCall(MessageType.ReleaseLock, out var opid, out var clock, out var instanceId))
     {
         foreach (var key in LockSet)
         {
             var destination = key.Locate(process);
             var message     = new ReleaseLock()
             {
                 Key = key, LockOpid = LockOpid
             };
             message.Opid   = opid;
             message.Clock  = clock;
             message.Parent = this.Opid;
             process.Send(destination, message);
         }
     }
 }
        private bool Entering(ulong opid, TKey localkey, QueuedMessage payload, Stopwatch stopwatch, MessageType messageType, ulong parent)
        {
            process.LockTracer?.Invoke($"p{process.ProcessId:D3} {payload.GetPartitionKey(process)} Enter {payload.Opid}");
            var timestamp = process.NextOpid;

            switch (messageType)
            {
            case (MessageType.RequestLocal):
            case (MessageType.ForkLocal):

                var result = payload.Execute <TKey>(process, opid);
                if (messageType == MessageType.RequestLocal)
                {
                    process.Send(process.GetOrigin(opid), new RespondToLocal()
                    {
                        Opid = opid, Parent = parent, Result = result
                    });
                }

                process.Telemetry?.OnApplicationEvent(
                    processId: process.ProcessId,
                    id: opid.ToString(),
                    name: payload.Payload.ToString(),
                    parent: parent.ToString(),
                    opSide: OperationSide.Callee,
                    opType: OperationType.Local,
                    duration: stopwatch.Elapsed.TotalMilliseconds
                    );

                process.LockTracer?.Invoke($"p{process.ProcessId:D3} {payload.GetPartitionKey(process)} Exit {payload.Opid}");
                return(false);    // in and out of the lock

            case (MessageType.PerformEvent):
            case (MessageType.ForkEvent):
            {
                var req     = (PerformEvent)payload;
                var effects = req.GetEffects(process);

                // apply the event to all the affected states
                req.Execute <TKey>(process, opid);

                // if we are not the last partition with an effect, forward to next
                if (req.Position < effects.Count - 1)
                {
                    var nextReq     = req.NextMessage(timestamp);
                    var destination = nextReq.GetCurrent(process).Locate(process);
                    process.Send(destination, nextReq);
                    return(true);        // stays in the lock
                }

                // if we are the last partition
                else
                {
                    // if we are not running in locked orchestration,
                    // release all previously locked partitions now
                    if (!payload.LockedByCaller && effects.Count > 1)
                    {
                        for (int i = 0; i < effects.Count - 1; i++)
                        {
                            var key         = effects[i].UntypedKey;
                            var destination = key.Locate(process);
                            var message     = new ReleaseLock()
                            {
                                Key = key, LockOpid = req.Opid
                            };
                            message.Clock  = timestamp;
                            message.Parent = req.Parent;
                            message.Opid   = opid;
                            process.Send(destination, message);
                        }
                    }

                    // return ack to orchestration
                    if (messageType == MessageType.PerformEvent)
                    {
                        process.Send(process.GetOrigin(opid), new AckEvent()
                            {
                                Opid = opid, Parent = parent, Clock = timestamp
                            });
                    }

                    process.Telemetry?.OnApplicationEvent(
                        processId: process.ProcessId,
                        id: opid.ToString(),
                        name: payload.Payload.ToString(),
                        parent: parent.ToString(),
                        opSide: OperationSide.Callee,
                        opType: OperationType.Event,
                        duration: stopwatch.Elapsed.TotalMilliseconds
                        );

                    process.LockTracer?.Invoke($"p{process.ProcessId:D3} {payload.GetPartitionKey(process)} Exit {payload.Opid}");
                    return(false);        // in and out of the lock
                }
            }

            case (MessageType.AcquireLock):
            {
                var req = (AcquireLock)payload;

                // if we are not the last partition to lock send next lock message
                if (req.Position < req.LockSet.Count - 1)
                {
                    var nextReq     = req.NextMessage(timestamp);
                    var destination = nextReq.LockSet[nextReq.Position].Locate(process);
                    process.Send(destination, nextReq);
                }

                // if we are the last partition to lock return ack to orchestration
                else
                {
                    process.Send(process.GetOrigin(opid), new GrantLock()
                        {
                            Opid = opid, Parent = parent, Clock = timestamp
                        });
                }

                return(true);        // stays in the lock
            }

            default:
                throw new InvalidOperationException("unhandled case for messageType");
            }
        }