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