예제 #1
0
        private void ProcessSingleStageTransactionRequest(TransactionRequest transactionRequest, IClient client)
        {
            var typesToPut    = transactionRequest.ItemsToPut.Select(i => i.FullTypeName).Distinct().ToList();
            var typesToDelete = transactionRequest.ItemsToDelete.Select(i => i.FullTypeName).Distinct().ToList();
            var types         = typesToPut.Union(typesToDelete).Distinct();


            try
            {
                foreach (var type in types)
                {
                    if (!DataStores[type].Lock.TryEnterWriteLock(Constants.DelayForLock))
                    {
                        throw new CacheException("Failed to acquire write locks for single-stage transaction",
                                                 ExceptionType.FailedToAcquireLock);
                    }
                }

                Dbg.Trace($"S: fallback to single stage for transaction {transactionRequest.TransactionId}");


                // check the conditions (in case of conditional update)
                int index = 0;
                foreach (var condition in transactionRequest.Conditions)
                {
                    if (!condition.IsEmpty())
                    {
                        var ds = DataStores[condition.TypeName];

                        ds.CheckCondition(transactionRequest.ItemsToPut[index].PrimaryKey, condition);
                    }

                    index++;
                }


                PersistenceEngine?.NewTransaction(new MixedTransaction
                {
                    ItemsToDelete = transactionRequest.ItemsToDelete,
                    ItemsToPut    = transactionRequest.ItemsToPut
                }
                                                  );

                // update the data in memory
                var dataRequests = transactionRequest.SplitByType();

                foreach (var dataRequest in dataRequests)
                {
                    if (!DataStores.ContainsKey(dataRequest.FullTypeName))
                    {
                        throw new NotSupportedException($"The type {dataRequest.FullTypeName} is not registered");
                    }

                    DataStores[dataRequest.FullTypeName].ProcessRequest(dataRequest, client, null);
                }

                client.SendResponse(new NullResponse());

                Dbg.Trace($"S: end writing delayed transaction {transactionRequest.TransactionId}");
            }
            catch (CacheException e)
            {
                client.SendResponse(new ExceptionResponse(e, e.ExceptionType));
            }
            catch (Exception e)
            {
                Dbg.Trace($"error writing delayed transaction:{e.Message}");
                client.SendResponse(new ExceptionResponse(e));
                // failed to write a durable transaction so stop here
            }
            finally
            {
                // release acquired locks
                foreach (var type in types)
                {
                    if (DataStores[type].Lock.IsWriteLockHeld)
                    {
                        DataStores[type].Lock.ExitWriteLock();
                    }
                }
            }
        }
예제 #2
0
        private void ProcessTransactionRequest(TransactionRequest transactionRequest, IClient client)
        {
            // First try to acquire a write lock on all concerned data stores

            var typesToPut    = transactionRequest.ItemsToPut.Select(i => i.FullTypeName).Distinct().ToList();
            var typesToDelete = transactionRequest.ItemsToDelete.Select(i => i.FullTypeName).Distinct().ToList();
            var types         = typesToPut.Union(typesToDelete).Distinct().ToList();

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


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


            if (!AcquireWriteLock(client, types, transactionRequest.TransactionId))
            {
                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
            {
                // check the conditions (in case of conditional update)
                int index = 0;
                foreach (var condition in transactionRequest.Conditions)
                {
                    if (!condition.IsEmpty())
                    {
                        var ds = DataStores[condition.TypeName];

                        ds.CheckCondition(transactionRequest.ItemsToPut[index].PrimaryKey, condition);
                    }

                    index++;
                }

                Dbg.Trace($"S: begin writing delayed transaction {transactionRequest.TransactionId}");
                PersistenceEngine?.NewTransaction(new MixedTransaction
                {
                    ItemsToDelete = transactionRequest.ItemsToDelete,
                    ItemsToPut    = transactionRequest.ItemsToPut
                },
                                                  true
                                                  );

                client.SendResponse(new ReadyResponse());


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

                // unlock
                foreach (var type in types)
                {
                    if (DataStores[type].Lock.IsWriteLockHeld)
                    {
                        DataStores[type].Lock.ExitWriteLock();
                    }
                }
                return;
            }
            catch (Exception e)
            {
                Dbg.Trace($"error in first stage:{e.Message} server {ShardIndex}");
                client.SendResponse(new ExceptionResponse(e));
                // failed to write a durable transaction so stop here

                // unlock
                foreach (var type in types)
                {
                    if (DataStores[type].Lock.IsWriteLockHeld)
                    {
                        DataStores[type].Lock.ExitWriteLock();
                    }
                }
                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
                        var dataRequests = transactionRequest.SplitByType();

                        foreach (var dataRequest in dataRequests)
                        {
                            if (!DataStores.ContainsKey(dataRequest.FullTypeName))
                            {
                                throw new NotSupportedException(
                                          $"The type {dataRequest.FullTypeName} is not registered");
                            }
                            DataStores[dataRequest.FullTypeName].ProcessRequest(dataRequest, client, null);
                        }

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

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


            // unlock
            foreach (var type in types)
            {
                if (DataStores[type].Lock.IsWriteLockHeld)
                {
                    DataStores[type].Lock.ExitWriteLock();
                }
            }
        }