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);
                    }
                }
            }
        }
Example #2
0
        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);
        }