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); } } }
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; } }
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}"); }
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"); } }
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); } }