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);
                    }
                }
            }
        }
Пример #2
0
        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);
        }