public void PrepareTxArguments(string senderId, PrepareTxArgumentsMessage msg, int timeoutMs) { var ongoingTx = this.EnsureTxIsOngoing(msg.TxID, timeoutMs); lock (this.mutex) { lock (ongoingTx.localMutex) { if (ongoingTx.hasFinished) { return; } if (ongoingTx.hasArgs) { return; } ongoingTx.hasArgs = true; ongoingTx.tx.Args = msg.Args; ongoingTx.tx.ShardIDs = msg.ShardIDs; ongoingTx.tx.TxName = msg.TxName; ongoingTx.tx.ClientID = msg.ClientID; if (ongoingTx.IsReady) { ongoingTx.hasFinished = true; this.txs.Remove(ongoingTx.tx.TxID); _ = Execute(ongoingTx.tx); } } } }
public Task <Dictionary <string, string> > ExecuteTx(string name, ISet <string> keys, Dictionary <string, string> args, int timeoutMs) { var txId = Guid.NewGuid().ToString(); var shardIDs = new HashSet <string>(keys.Select(this.locator.GetShardIdByKey)); 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 shardSubTXs = from key in keys group key by this.locator.GetShardIdByKey(key) into shard select( shardId : shard.Key, subTx : new InitiateTxMessage(txId, name, new HashSet <string>(shard), shardIDs) ); var argsMsg = new PrepareTxArgumentsMessage(this.bus.SelfID, txId, name, args, shardIDs); foreach (var acceptorId in acceptors) { this.bus.PrepareTxArguments(acceptorId, argsMsg.Clone()); } foreach (var(shardId, subTx) in shardSubTXs) { this.bus.ExecuteSubTx(shardId, subTx); } var handler1 = this.bus.WaitForExecutionAccepted(txId, (msg, acceptorId) => { lock (localMutex) { if (hasFinished) { return(WaitStrategy.StopWaiting); } if (!acceptors.Contains(acceptorId)) { return(WaitStrategy.KeepWaiting); } if (acks.Add(acceptorId)) { if (acks.Count >= shardIDs.Count / 2 + 1) { result.SetResult(msg.Result); return(WaitStrategy.StopWaiting); } } return(WaitStrategy.KeepWaiting); } }); var handler2 = this.bus.WaitForExecutionConflicted(txId, (msg, shardId) => { lock (localMutex) { if (hasFinished) { return(WaitStrategy.StopWaiting); } if (!shardIDs.Contains(shardId)) { return(WaitStrategy.KeepWaiting); } hasFinished = true; result.SetException(new TxConflictException(txId, msg.KeyBlockedByTX)); return(WaitStrategy.StopWaiting); } }); this.timer.SetTimeout(() => { lock (localMutex) { if (!hasFinished) { hasFinished = true; result.SetException(new TxUnknownException(txId)); handler1.Dispose(); handler2.Dispose(); } } }, timeoutMs); return(result.Task); }