Exemplo n.º 1
0
        public void ProcessTransactionRequest(TransactionRequest transactionRequest, IClient client,
                                              SafeDictionary <string, DataStore> dataStores)
        {
            if (transactionRequest.TransactionId == default)
            {
                client.SendResponse(new ExceptionResponse(
                                        new CacheException(
                                            "Transaction request received without transaction id")));
                return;
            }


            // First try to acquire a write lock on all concerned data stores
            var types = transactionRequest.AllCollections;


            var keys = dataStores.Keys;

            if (types.Any(t => !keys.Contains(t)))
            {
                throw new NotSupportedException("Type not registered");
            }

            var transactionId = transactionRequest.TransactionId;


            // do not work too hard if it's single stage
            if (transactionRequest.IsSingleStage)
            {
                ProcessSingleStageTransactionRequest(transactionRequest, client, dataStores);
                return;
            }

            var lockAcquired = _lockManager.TryAcquireWriteLock(transactionId, Constants.DelayForLockInMilliseconds, types.ToArray());

            if (lockAcquired)
            {
                var answer = client.ShouldContinue();
                if (answer.HasValue && answer.Value)
                {
                }
                else
                {
                    _lockManager.CloseSession(transactionId);

                    return;
                }
            }
            else
            {
                client.SendResponse(new ExceptionResponse(
                                        new CacheException(
                                            $"can not acquire write lock on server for transaction {transactionRequest.TransactionId}"),
                                        ExceptionType.FailedToAcquireLock));

                return;
            }


            Dbg.Trace($"S: lock acquired by all clients for transaction {transactionRequest.TransactionId}");


            // Second register a durable delayed transaction. It can be cancelled later

            try
            {
                CheckConditions(transactionRequest, dataStores);

                // if we reach here the condition check has passed

                SaveDurableTransaction(transactionRequest, dataStores);

                client.SendResponse(new ReadyResponse());


                Dbg.Trace($"S: end writing delayed transaction {transactionRequest.TransactionId}");
            }
            catch (CacheException e)
            {
                Dbg.Trace($"error in first stage:{e.Message} ");
                client.SendResponse(new ExceptionResponse(e, e.ExceptionType));
                // failed to write a durable transaction so stop here

                // unlock
                _lockManager.CloseSession(transactionRequest.TransactionId);

                return;
            }
            catch (Exception e)
            {
                Dbg.Trace($"error in first stage:{e.Message} ");
                client.SendResponse(new ExceptionResponse(e));
                // failed to write a durable transaction so stop here

                // unlock
                _lockManager.CloseSession(transactionRequest.TransactionId);

                return;
            }


            try
            {
                Dbg.Trace($"S: begin waiting for client go {transactionRequest.TransactionId}");
                var answer = client.ShouldContinue();
                Dbg.Trace($"S: end waiting for client go answer = {answer}");

                if (answer.HasValue) // the client has answered
                {
                    if (answer.Value)
                    {
                        // update the data in memory

                        ExecuteInMemory(transactionRequest, dataStores);

                        ServerLog.LogInfo(
                            $"S: two stage transaction committed successfully  {transactionRequest.TransactionId}");
                    }
                    else
                    {
                        ServerLog.LogWarning(
                            $"S: two stage transaction cancelled by client on server {transactionRequest.TransactionId}");

                        // cancel the delayed transaction
                        _transactionLog?.CancelDelayedTransaction();
                    }
                }
                else // the client failed to answer in a reasonable delay (which is less than the delay to commit a delayed transaction )
                {
                    _transactionLog?.CancelDelayedTransaction();
                }
            }
            catch (Exception e)
            {
                ServerLog.LogInfo($"error in the second stage of a transaction:{e.Message}");
            }


            // unlock
            _lockManager.CloseSession(transactionRequest.TransactionId);
        }