public void CommitTx(string shardId, CommitTxMessage msg, int timeoutMs) { var ongoingTx = this.EnsureTxIsOngoing(msg.TxID, timeoutMs); lock (this.mutex) { lock (ongoingTx.localMutex) { if (ongoingTx.hasFinished) { return; } ongoingTx.tx.ShardKeyValue[msg.ShardID] = msg.KeyValueUpdate; if (ongoingTx.IsReady) { ongoingTx.hasFinished = true; this.txs.Remove(ongoingTx.tx.TxID); _ = Execute(ongoingTx.tx); } } } }
public async Task InitiateTx(string clientId, InitiateTxMessage msg, int timeoutMs) { Dictionary <string, string> values; try { values = await this.storage.ReadAndBlock(msg.TxID, msg.TxName, msg.ShardIDs, msg.Keys); } catch (AlreadyBlockedException ex) { this.bus.NotifyExecutionConflicted(clientId, new ExecutionConflictedMessage(msg.TxID, ex.BlockedKeyTxPairs)); return; } var acceptors = this.locator.GetAcceptorIDs(); var result = new TaskCompletionSource <Dictionary <string, string> >(); var localMutex = new object(); var acks = new HashSet <string>(); var hasFinished = false; var confirmation = new CommitTxMessage(this.bus.SelfID, msg.TxID, values); foreach (var acceptorID in acceptors) { this.bus.CommitTx(acceptorID, confirmation.Clone()); } var handler1 = this.bus.WaitForSubTxAccepted(msg.TxID, (subTxAccepted, acceptorId) => { lock (localMutex) { if (hasFinished) { return(WaitStrategy.StopWaiting); } if (!acceptors.Contains(acceptorId)) { return(WaitStrategy.KeepWaiting); } acks.Add(acceptorId); if (acks.Count < 1 + acceptors.Count / 2) { return(WaitStrategy.KeepWaiting); } hasFinished = true; result.SetResult(subTxAccepted.KeyValueUpdate); return(WaitStrategy.StopWaiting); } }); this.timer.SetTimeout(() => { lock (localMutex) { if (hasFinished) { return; } hasFinished = true; result.SetException(new AbortException()); handler1.Dispose(); } }, timeoutMs); Dictionary <string, string> update; try { update = await result.Task; } catch (AbortException) { return; } await this.storage.UpdateAndUnblock(msg.TxID, update); }