Beispiel #1
0
        private void LoadAllTransactions()
        {
            _transactionLog.Seek(0, SeekOrigin.Begin);

            var reader = new BinaryReader(_transactionLog);

            _lastOffset = reader.ReadInt64();



            try
            {
                while (true)
                {
                    var transaction = ReadTransaction(reader);


                    if (!transaction.EndMarkerOk)
                    {
                        throw new FormatException(
                                  "Inconsistent transaction log. End marker not found at the end of a transaction");
                    }


                    if (transaction.TransactionStatus != TransactionStatus.Processed &&
                        transaction.TransactionStatus != TransactionStatus.Canceled)
                    {
                        _transactionQueue.Enqueue(transaction);
                    }
                }
            }

            catch (EndOfStreamException)
            {
                // ignore (end of log)
            }


            if (_transactionQueue.Count > 0)
            {
                // only the last transaction may be in "Processing" status. In this case there was a failure during transaction processing
                // we mark it "ToProcess". Transactions are idempotent
                var lastTransaction = _transactionQueue.Peek();
                if (lastTransaction.TransactionStatus == TransactionStatus.Processing)
                {
                    ServerLog.LogWarning("Reprocessing incomplete transaction");

                    lastTransaction.TransactionStatus = TransactionStatus.ToProcess;
                    UpdateTransactionStatus(lastTransaction);
                }

                _queueNotEmpty.Set();
            }
        }
Beispiel #2
0
        private void LoadAllTransactions()
        {
            _transactionLog.Seek(0, SeekOrigin.Begin);

            var reader = new BinaryReader(_transactionLog);

            _lastOffset = reader.ReadInt64();

            var completeTransaction = true;

            try
            {
                while (true)
                {
                    var status = reader.ReadInt32();

                    completeTransaction = false;

                    var timestamp = reader.ReadInt64();
                    var length    = reader.ReadInt32();
                    var data      = reader.ReadBytes(length);
                    var offset    = reader.ReadInt64();
                    var id        = reader.ReadInt64();
                    var delay     = reader.ReadInt32();
                    var endMarker = reader.ReadInt64();

                    if (endMarker != EndMarker)
                    {
                        throw new FormatException(
                                  "Inconsistent transaction log. End marker not found at the end of a transaction");
                    }

                    completeTransaction = true;

                    var time = new DateTime(timestamp);


                    var transaction = new TransactionData
                    {
                        TransactionStatus = (TransactionStaus)status,
                        TimeStamp         = time,
                        Data   = data,
                        Offset = offset,
                        Id     = id,
                        DelayInMilliseconds = delay
                    };

                    if (transaction.TransactionStatus != TransactionStaus.Processed &&
                        transaction.TransactionStatus != TransactionStaus.Canceled)
                    {
                        _transactionQueue.Enqueue(transaction);
                    }
                }
            }

            catch (EndOfStreamException)
            {
                if (!completeTransaction)
                {
                    throw new FormatException(
                              "Inconsistent transaction log. End of file reached in the middle of a transaction");
                }
            }


            if (_transactionQueue.Count > 0)
            {
                // only the last transaction may be in "Processing" status. In this case there was a failure during transaction processing
                // we mark it "ToProcess". Transactions are idempotent
                var lastTransaction = _transactionQueue.Peek();
                if (lastTransaction.TransactionStatus == TransactionStaus.Processing)
                {
                    ServerLog.LogWarning("Reprocessing incomplete transaction");

                    lastTransaction.TransactionStatus = TransactionStaus.ToProcess;
                    UpdateTransactionStatus(lastTransaction);
                }

                _queueNotEmpty.Set();
            }
        }
        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);
        }