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); }