예제 #1
0
 internal void Add(QueuedMessage request)
 {
     if (Requests == null)
     {
         Requests = new Dictionary <ulong, QueuedMessage>();
     }
     Requests.Add(request.Opid, request);
 }
예제 #2
0
        public void EnterLock(QueuedMessage request)
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            bool freshlyCreated   = false;
            bool alreadyProcessed = false;
            var  opid             = request.Opid;
            var  localkey         = (PartitionKey <TKey>)request.GetPartitionKey(process);
            var  parent           = request.Parent;
            var  messageType      = request.MessageType;

            if (request.LockedByCaller)
            {
                // lock has already been acquired - so we need not touch the queue
                Entering(opid, localkey.Key, request, stopwatch, messageType, parent);
            }
            else
            {
                if (!lockqueues.TryGetValue(localkey.Key, out var queue))
                {
                    queue          = new LockQueue();
                    queue.Process  = process;
                    freshlyCreated = true;
                }
                if (queue.IsEmpty)
                {
                    if (Entering(opid, localkey.Key, request, stopwatch, messageType, parent))
                    {
                        queue.Enqueue(request, stopwatch);
                        if (freshlyCreated)
                        {
                            lockqueues[localkey.Key] = queue;
                        }
                    }
                    else
                    {
                        alreadyProcessed = true;
                    }
                }
                else
                {
                    queue.Enqueue(request, stopwatch);
                }
                if (!alreadyProcessed && messageType.IsFork())
                {
                    if (!process.FinishStates.TryGetValue(parent, out var finishState))
                    {
                        process.FinishStates[parent] = finishState = new FinishState(process, parent);
                    }
                    finishState.AddPending(opid);
                }
            }
        }
예제 #3
0
        public void Enqueue(QueuedMessage request, Stopwatch stopwatch)
        {
            Process.LockTracer?.Invoke($"p{Process.ProcessId:D3} {request.GetPartitionKey(Process)} Enqueue {request.Opid}");
            var rinfo = new RInfo()
            {
                Request   = request,
                Stopwatch = stopwatch,
            };

            if (head == null)
            {
                head = tail = rinfo;
            }
            else
            {
                tail.Next = rinfo;
                tail      = rinfo;
            }
        }
예제 #4
0
 public void Remove(ulong opid, out QueuedMessage msg)
 {
     if (head.Request.Opid == opid)
     {
         msg  = head.Request;
         head = head.Next;
     }
     else
     {
         var pos = head;
         while (pos.Next.Request.Opid != opid)
         {
             pos = pos.Next;
         }
         msg = pos.Next.Request;
         if (tail == pos.Next)
         {
             tail = pos;
         }
         pos.Next = pos.Next.Next;
     }
     Process.LockTracer?.Invoke($"p{Process.ProcessId:D3} {msg.GetPartitionKey(Process)} Removed {opid}");
 }
예제 #5
0
        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");
            }
        }
예제 #6
0
        public void EnterLock(QueuedMessage request)
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            bool exitsImmediately = false;
            var  opid             = request.Opid;
            var  parent           = request.Parent;
            var  messageType      = request.MessageType;
            var  partitionkey     = request.GetPartitionKey(process);
            TKey localkey         = ((PartitionKey <TKey>)partitionkey).Key;

            if (request.LockedByCaller)
            {
                request.OnEnter(process);
                request.Enter(process, localkey, stopwatch, out exitsImmediately);
                if (exitsImmediately)
                {
                    request.OnExit(process);
                }
                else
                {
                    ((AcquireLock)lockqueues[localkey].Holder).Add(request);
                }
            }
            else
            {
                if (!lockqueues.TryGetValue(localkey, out var queue) ||
                    queue.IsEmpty)
                {
                    request.OnEnter(process);
                    request.Enter(process, localkey, stopwatch, out exitsImmediately);
                    if (exitsImmediately)
                    {
                        request.OnExit(process);
                    }
                    else
                    {
                        if (queue == null)
                        {
                            queue = new LockQueue()
                            {
                                Process = process
                            };
                            lockqueues[localkey] = queue;
                        }
                        queue.Enqueue(request, stopwatch);
                    }
                }
                else
                {
                    queue.Enqueue(request, stopwatch);
                }
            }
            if (!exitsImmediately && messageType.IsFork())
            {
                if (!process.FinishStates.TryGetValue(parent, out var finishState))
                {
                    process.FinishStates[parent] = finishState = new FinishState(process, parent);
                }
                finishState.AddPending(opid);
            }
        }