public async Task <object> SendBtcAsync( ITransactionInfo info, CancellationToken ct ) { var wallet = await _context .Wallets .FirstOrDefaultAsync(e => e.Balance > info.Amount, ct); if (wallet == null) { throw new Exception("Wallet not found for the transaction"); } var transaction = new TransactionEntity { Address = info.Address, Amount = info.Amount, IdempotencyKey = info.IdempotencyKey, Data = DateTime.UtcNow, WalletId = wallet.Id, Type = TransactionType.Send }; await _context .Transactions .AddAsync(transaction, ct); await _context .SaveChangesAsync(ct); return(Transaction.FromDbo(transaction)); }
public Task <TransactionalStatus> Commit(ITransactionInfo info) { var transactionInfo = (TransactionInfo)info; transactionInfo.TimeStamp = this.clock.MergeUtcNow(transactionInfo.TimeStamp); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} prepare {transactionInfo}"); } List <ITransactionParticipant> writeParticipants = null; foreach (var p in transactionInfo.Participants) { if (p.Value.Writes > 0) { if (writeParticipants == null) { writeParticipants = new List <ITransactionParticipant>(); } writeParticipants.Add(p.Key); } } if (writeParticipants == null) { return(CommitReadOnlyTransaction(transactionInfo)); } else { return(CommitReadWriteTransaction(transactionInfo, writeParticipants)); } }
public Message CreateMessage(InvokeMethodRequest request, InvokeMethodOptions options) { var direction = (options & InvokeMethodOptions.OneWay) != 0 ? Message.Directions.OneWay : Message.Directions.Request; var message = new Message { Category = Message.Categories.Application, Direction = direction, Id = CorrelationId.GetNext(), IsReadOnly = (options & InvokeMethodOptions.ReadOnly) != 0, IsUnordered = (options & InvokeMethodOptions.Unordered) != 0, IsTransactionRequired = (options & InvokeMethodOptions.TransactionRequiresNew) != 0 || (options & InvokeMethodOptions.TransactionRequired) != 0, BodyObject = request, IsUsingInterfaceVersions = request.InterfaceVersion > 0, }; ITransactionInfo transactionInfo = message.IsTransactionRequired ? TransactionContext.GetTransactionInfo() : null; if (transactionInfo != null) { message.TransactionInfo = transactionInfo.Fork(); } if ((options & InvokeMethodOptions.AlwaysInterleave) != 0) { message.IsAlwaysInterleave = true; } message.RequestContextData = RequestContextExtensions.Export(this.serializationManager); return(message); }
public async Task Commit(ITransactionInfo info) { var transactionInfo = (TransactionInfo)info; transactionInfo.TimeStamp = MergeAndReadClock(transactionInfo.TimeStamp); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} prepare {transactionInfo}"); } List <ITransactionParticipant> writeParticipants = null; foreach (var p in transactionInfo.Participants) { if (p.Value.Writes > 0) { if (writeParticipants == null) { writeParticipants = new List <ITransactionParticipant>(); } writeParticipants.Add(p.Key); } } if (writeParticipants == null) { await CommitReadOnlyTransaction(transactionInfo); } else { await CommitReadWriteTransaction(transactionInfo, writeParticipants); } }
internal static void SetTransactionInfo(ITransactionInfo info) { Dictionary <string, object> values = GetContextData(); values = values == null ? new Dictionary <string, object>() : new Dictionary <string, object>(values); values[TransactionInfoHeader] = info; SetContextData(values); }
public async Task Commit(ITransactionInfo info) { var transactionInfo = (TransactionInfo)info; TransactionsStatisticsGroup.OnTransactionCommitRequest(); if (transactionInfo.IsReadOnly) { return; } var completion = new TaskCompletionSource <bool>(); bool canCommit = true; List <Task <bool> > prepareTasks = new List <Task <bool> >(transactionInfo.WriteSet.Count); foreach (var g in transactionInfo.WriteSet.Keys) { TransactionalResourceVersion write = TransactionalResourceVersion.Create(transactionInfo.TransactionId, transactionInfo.WriteSet[g]); TransactionalResourceVersion?read = null; if (transactionInfo.ReadSet.ContainsKey(g)) { read = transactionInfo.ReadSet[g]; transactionInfo.ReadSet.Remove(g); } prepareTasks.Add(g.Prepare(transactionInfo.TransactionId, write, read)); } foreach (var g in transactionInfo.ReadSet.Keys) { TransactionalResourceVersion read = transactionInfo.ReadSet[g]; prepareTasks.Add(g.Prepare(transactionInfo.TransactionId, null, read)); } await Task.WhenAll(prepareTasks); foreach (var t in prepareTasks) { if (!t.Result) { canCommit = false; } } if (!canCommit) { TransactionsStatisticsGroup.OnTransactionAborted(); abortedTransactions.TryAdd(transactionInfo.TransactionId, 0); throw new OrleansPrepareFailedException(transactionInfo.TransactionId); } commitCompletions.TryAdd(transactionInfo.TransactionId, completion); transactionCommitQueue.Enqueue(transactionInfo); await completion.Task; }
private static TransactionResponseModel MakeResponseObject(ITransactionInfo transactionInfo) { return(new TransactionResponseModel { Id = transactionInfo.Id, JobId = transactionInfo.JobId, StoreName = transactionInfo.StoreName, StartTime = transactionInfo.StartTime, Status = transactionInfo.Status.ToString(), TransactionType = transactionInfo.TransactionType.ToString() }); }
private static TransactionResponseModel MakeResponseObject(ITransactionInfo transactionInfo) { return new TransactionResponseModel { Id = transactionInfo.Id, JobId = transactionInfo.JobId, StoreName = transactionInfo.StoreName, StartTime = transactionInfo.StartTime, Status = transactionInfo.Status.ToString(), TransactionType = transactionInfo.TransactionType.ToString() }; }
public async Task Abort(ITransactionInfo info) { this.statistics.TrackTransactionFailed(); var transactionInfo = (TransactionInfo)info; List <ParticipantId> participants = transactionInfo.Participants.Keys.ToList(); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"abort {transactionInfo} {string.Join(",", participants.Select(p => p.ToString()))}"); } // send one-way abort messages to release the locks and roll back any updates await Task.WhenAll(participants.Select(p => p.Reference.AsReference <ITransactionalResourceExtension>() .Abort(p.Name, transactionInfo.TransactionId))); }
public async Task <TransactionalStatus> Commit(ITransactionInfo info) { var transactionInfo = (TransactionInfo)info; transactionInfo.TimeStamp = this.clock.MergeUtcNow(transactionInfo.TimeStamp); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} prepare {transactionInfo}"); } List <ParticipantId> writeParticipants = null; foreach (var p in transactionInfo.Participants) { if (p.Value.Writes > 0) { if (writeParticipants == null) { writeParticipants = new List <ParticipantId>(); } writeParticipants.Add(p.Key); } } try { TransactionalStatus status = (writeParticipants == null) ? await CommitReadOnlyTransaction(transactionInfo) : await CommitReadWriteTransaction(transactionInfo, writeParticipants); if (status == TransactionalStatus.Ok) { this.statistics.TrackTransactionSucceeded(); } else { this.statistics.TrackTransactionFailed(); } return(status); } catch (Exception) { this.statistics.TrackTransactionFailed(); throw; } }
public void Abort(ITransactionInfo info, OrleansTransactionAbortedException reason) { var transactionInfo = (TransactionInfo)info; abortedTransactions.TryAdd(transactionInfo.TransactionId, 0); foreach (var g in transactionInfo.WriteSet.Keys) { g.Abort(transactionInfo.TransactionId).Ignore(); } // TODO: should we wait for the abort tasks to complete before returning? // If so, how do we handle exceptions? // There is no guarantee that the WriteSet is complete and has all the grains. // Notify the TM of the abort as well. this.tmService.AbortTransaction(transactionInfo.TransactionId, reason).Ignore(); }
public void Abort(ITransactionInfo info, OrleansTransactionAbortedException reason) { var transactionInfo = (TransactionInfo)info; var participants = transactionInfo.Participants.Keys.ToList(); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"abort {transactionInfo} {string.Join(",", participants.Select(p => p.ToString()))} {reason}"); } // send one-way abort messages to release the locks and roll back any updates foreach (var p in participants) { p.Abort(transactionInfo.TransactionId); } }
public async Task <(TransactionalStatus, Exception)> Resolve(ITransactionInfo info) { var transactionInfo = (TransactionInfo)info; transactionInfo.TimeStamp = this.clock.MergeUtcNow(transactionInfo.TimeStamp); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} prepare {transactionInfo}"); } if (transactionInfo.Participants.Count == 0) { this.statistics.TrackTransactionSucceeded(); return(TransactionalStatus.Ok, null); } KeyValuePair <ParticipantId, AccessCounter>?manager; List <ParticipantId> writeParticipants; List <KeyValuePair <ParticipantId, AccessCounter> > resources; CollateParticipants(transactionInfo.Participants, out writeParticipants, out resources, out manager); try { var(status, exception) = (writeParticipants == null) ? await CommitReadOnlyTransaction(transactionInfo, resources) : await CommitReadWriteTransaction(transactionInfo, writeParticipants, resources, manager.Value); if (status == TransactionalStatus.Ok) { this.statistics.TrackTransactionSucceeded(); } else { this.statistics.TrackTransactionFailed(); } return(status, exception); } catch (Exception) { this.statistics.TrackTransactionFailed(); throw; } }
public void Abort(ITransactionInfo info, OrleansTransactionAbortedException reason) { this.statistics.TrackTransactionFailed(); var transactionInfo = (TransactionInfo)info; List <ParticipantId> participants = transactionInfo.Participants.Keys.ToList(); if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"abort {transactionInfo} {string.Join(",", participants.Select(p => p.ToString()))} {reason}"); } // send one-way abort messages to release the locks and roll back any updates foreach (var p in participants) { p.Reference.AsReference <ITransactionalResourceExtension>() .Abort(p.Name, transactionInfo.TransactionId) .Ignore(); } }
public void Abort(ITransactionInfo info, OrleansTransactionAbortedException reason) { var transactionInfo = (TransactionInfo)info; if (logger.IsEnabled(LogLevel.Trace)) { logger.Trace($"abort {transactionInfo} {reason}"); } var participants = transactionInfo.Participants.Keys.ToList(); if (!transactionInfo.PrepareMessagesSent) { // send one-way abort messages to release the locks and roll back any updates foreach (var p in participants) { p.Abort(transactionInfo.TransactionId); } } }
public static async Task <List <string>[]> GetNestedTransactionIds(int tier, List <ITransactionAttributionGrain>[] tiers) { ITransactionInfo ti = TransactionContext.GetTransactionInfo(); List <string>[] results = new List <string> [tier + 1 + tiers.Length]; results[tier] = new List <string>(new[] { ti?.Id }); if (tiers.Length == 0) { return(results); } List <ITransactionAttributionGrain> nextTier = tiers.FirstOrDefault(); List <ITransactionAttributionGrain>[] nextTiers = tiers.Skip(1).ToArray(); List <string>[][] tiersResults = await Task.WhenAll(nextTier.Select(g => g.GetNestedTransactionIds(tier + 1, nextTiers))); foreach (List <string>[] result in tiersResults) { if (result.Length != results.Length) { throw new ApplicationException("Invalid result length"); } for (int i = tier + 1; i < results.Length; i++) { if (results[i] != null) { results[i].AddRange(result[i]); } else { results[i] = result[i]; } } } return(results); }
/// <summary> /// Executes a previous transaction /// </summary> /// <param name="storeName"></param> /// <param name="transactionInfo"></param> public IJobInfo ReExecuteTransaction(string storeName, ITransactionInfo transactionInfo) { ValidateStoreName(storeName); if (transactionInfo == null) { throw new ArgumentNullException("transactionInfo"); } if (!(transactionInfo is TransactionInfoWrapper)) { throw new ArgumentException(Strings.BrightstarServiceClient_InvalidTransactionInfoObject, "transactionInfo"); } try { return (new JobInfoWrapper(_service.ReExecuteTransaction(storeName, (transactionInfo as TransactionInfoWrapper). TransactionInfo))); } catch (FaultException <ExceptionDetail> fault) { throw new BrightstarClientException(fault); } }
private void SetTransaction(Message message, InvokeMethodOptions options) { // clear transaction info if transaction operation requires new transaction. ITransactionInfo transactionInfo = TransactionContext.GetTransactionInfo(); // enforce join transaction calls if (options.IsTransactionOption(InvokeMethodOptions.TransactionJoin) && transactionInfo == null) { throw new NotSupportedException("Call cannot be made outside of a transaction."); } // enforce not allowed transaction calls if (options.IsTransactionOption(InvokeMethodOptions.TransactionNotAllowed) && transactionInfo != null) { throw new NotSupportedException("Call cannot be made within a transaction."); } // clear transaction context if creating a transaction or transaction is suppressed if (options.IsTransactionOption(InvokeMethodOptions.TransactionCreate) || options.IsTransactionOption(InvokeMethodOptions.TransactionSuppress)) { transactionInfo = null; } bool isTransactionRequired = options.IsTransactionOption(InvokeMethodOptions.TransactionCreate) || options.IsTransactionOption(InvokeMethodOptions.TransactionCreateOrJoin) || options.IsTransactionOption(InvokeMethodOptions.TransactionJoin); message.TransactionInfo = transactionInfo?.Fork(); message.IsTransactionRequired = isTransactionRequired; if (transactionInfo == null) { // if we're leaving a transaction context, make sure it's been cleared from the request context. message.RequestContextData?.Remove(TransactionContext.Orleans_TransactionContext_Key); } }
public Task <TransactionalStatus> Resolve(ITransactionInfo transactionInfo) { throw new OrleansTransactionsDisabledException(); }
public async Task Invoke(IGrainContext target, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { this.messagingTrace.OnDropExpiredMessage(message, MessagingStatisticsGroup.Phase.Invoke); return; } RequestContextExtensions.Import(message.RequestContextData); bool startNewTransaction = false; ITransactionInfo transactionInfo = message.TransactionInfo; if (message.IsTransactionRequired && transactionInfo == null) { // TODO: this should be a configurable parameter var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10); // Start a new transaction transactionInfo = await this.transactionAgent.StartTransaction(message.IsReadOnly, transactionTimeout); startNewTransaction = true; } if (transactionInfo != null) { TransactionContext.SetTransactionInfo(transactionInfo); } object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request); } if (!this.invokers.TryGet(message.InterfaceType, out var invoker)) { throw new KeyNotFoundException($"Could not find an invoker for interface {message.InterfaceType}"); } messagingTrace.OnInvokeMessage(message); var requestInvoker = new GrainMethodInvoker(target, request, invoker, GrainCallFilters, interfaceToImplementationMapping); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (message.Direction == Message.Directions.OneWay) { this.invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } else if (invokeExceptionLogger.IsEnabled(LogLevel.Debug)) { this.invokeExceptionLogger.Debug(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } if (transactionInfo != null) { transactionInfo.ReconcilePending(); // Record reason for abort, if not already set. transactionInfo.RecordException(exc1, serializationManager); if (startNewTransaction) { exc1 = transactionInfo.MustAbort(serializationManager); await this.transactionAgent.Abort(transactionInfo); TransactionContext.Clear(); } } // If a grain allowed an inconsistent state exception to escape and the exception originated from // this activation, then deactivate it. var ise = exc1 as InconsistentStateException; if (ise != null && ise.IsSourceActivation) { // Mark the exception so that it doesn't deactivate any other activations. ise.IsSourceActivation = false; this.invokeExceptionLogger.Info($"Deactivating {target} due to inconsistent state."); this.DeactivateOnIdle(target.ActivationId); } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } OrleansTransactionException transactionException = null; if (transactionInfo != null) { try { transactionInfo.ReconcilePending(); transactionException = transactionInfo.MustAbort(serializationManager); // This request started the transaction, so we try to commit before returning, // or if it must abort, tell participants that it aborted if (startNewTransaction) { try { if (transactionException is null) { var(status, exception) = await this.transactionAgent.Resolve(transactionInfo); if (status != TransactionalStatus.Ok) { transactionException = status.ConvertToUserException(transactionInfo.Id, exception); } } else { await this.transactionAgent.Abort(transactionInfo); } } finally { TransactionContext.Clear(); } } } catch (Exception e) { // we should never hit this, but if we do, the following message will help us diagnose this.logger.LogError(e, "Error in transaction post-grain-method-invocation code"); throw; } } if (message.Direction != Message.Directions.OneWay) { if (transactionException != null) { SafeSendExceptionResponse(message, transactionException); } else { SafeSendResponse(message, resultObject); } } return; } catch (Exception exc2) { this.logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); TransactionContext.Clear(); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } finally { RequestContext.Clear(); } }
/// <summary> /// Executes a previous transaction /// </summary> /// <param name="storeName"></param> /// <param name="transactionInfo"></param> public IJobInfo ReExecuteTransaction(string storeName, ITransactionInfo transactionInfo) { ValidateStoreName(storeName); if(transactionInfo == null) throw new ArgumentNullException("transactionInfo"); if (!(transactionInfo is TransactionInfoWrapper)) throw new ArgumentException(Strings.BrightstarServiceClient_InvalidTransactionInfoObject, "transactionInfo"); try { return new JobInfoWrapper(_service.ReExecuteTransaction(storeName, (transactionInfo as TransactionInfoWrapper). TransactionInfo)); } catch (FaultException<ExceptionDetail> fault) { throw new BrightstarClientException(fault); } }
/// <summary> /// Executes a previous transaction /// </summary> /// <param name="storeName">Name of the store</param> /// <param name="transactionInfo">Transaction to execute.</param> /// <param name="label">Optional user-friendly label for the job.</param> public IJobInfo ReExecuteTransaction(string storeName, ITransactionInfo transactionInfo, string label = null) { if (storeName == null) throw new ArgumentNullException("storeName"); if (transactionInfo == null) throw new ArgumentNullException("transactionInfo"); try { var jobId = _serverCore.ReExecuteTransaction(storeName, transactionInfo.Id, transactionInfo.TransactionType, label); return GetJobInfo(storeName, jobId.ToString()); } catch (Exception ex) { Logging.LogError(BrightstarEventId.ServerCoreException, "Error rexecuting transaction with JobId {0} for store {1}", transactionInfo.JobId, storeName); throw new BrightstarClientException(String.Format("Error rexecuting transaction with JobId {0} for store {1}. {2}", transactionInfo.JobId, storeName, ex.Message), ex); } }
public async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { this.messagingTrace.OnDropExpiredMessage(message, MessagingStatisticsGroup.Phase.Invoke); return; } RequestContextExtensions.Import(message.RequestContextData); if (schedulingOptions.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget()) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message.TargetGrain, message.TargetActivation)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContextExtensions.ExportToMessage(message); } bool startNewTransaction = false; ITransactionInfo transactionInfo = message.TransactionInfo; if (message.IsTransactionRequired && transactionInfo == null) { // TODO: this should be a configurable parameter var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10); // Start a new transaction transactionInfo = await this.transactionAgent.StartTransaction(message.IsReadOnly, transactionTimeout); startNewTransaction = true; } if (transactionInfo != null) { TransactionContext.SetTransactionInfo(transactionInfo); } object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, this.loggerFactory, logger, this, this.cancellationTokenRuntime); } var invoker = invokable.GetInvoker(typeManager, request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension) && !TryInstallExtension(request.InterfaceId, invokable, message.GenericGrainType, ref invoker)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = Utils.GetStackTrace(); #endif this.logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } messagingTrace.OnInvokeMessage(message); var requestInvoker = new GrainMethodInvoker(target, request, invoker, GrainCallFilters, interfaceToImplementationMapping); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (message.Direction == Message.Directions.OneWay) { this.invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } else if (invokeExceptionLogger.IsEnabled(LogLevel.Debug)) { this.invokeExceptionLogger.Debug(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } if (transactionInfo != null) { transactionInfo.ReconcilePending(); // Record reason for abort, if not alread set transactionInfo.RecordException(exc1, serializationManager); if (startNewTransaction) { exc1 = transactionInfo.MustAbort(serializationManager); await this.transactionAgent.Abort(transactionInfo); TransactionContext.Clear(); } } // If a grain allowed an inconsistent state exception to escape and the exception originated from // this activation, then deactivate it. var ise = exc1 as InconsistentStateException; if (ise != null && ise.IsSourceActivation) { // Mark the exception so that it doesn't deactivate any other activations. ise.IsSourceActivation = false; var activation = (target as Grain)?.Data; if (activation != null) { this.invokeExceptionLogger.Info($"Deactivating {activation} due to inconsistent state."); this.DeactivateOnIdle(activation.ActivationId); } } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } OrleansTransactionException transactionException = null; if (transactionInfo != null) { try { transactionInfo.ReconcilePending(); transactionException = transactionInfo.MustAbort(serializationManager); // This request started the transaction, so we try to commit before returning, // or if it must abort, tell participants that it aborted if (startNewTransaction) { try { if (transactionException == null) { var status = await this.transactionAgent.Resolve(transactionInfo); if (status != TransactionalStatus.Ok) { transactionException = status.ConvertToUserException(transactionInfo.Id); } } else { await this.transactionAgent.Abort(transactionInfo); } } finally { TransactionContext.Clear(); } } } catch (Exception e) { // we should never hit this, but if we do, the following message will help us diagnose this.logger.LogError(e, "Error in transaction post-grain-method-invocation code"); throw; } } if (message.Direction != Message.Directions.OneWay) { if (transactionException != null) { SafeSendExceptionResponse(message, transactionException); } else { SafeSendResponse(message, resultObject); } } return; } catch (Exception exc2) { this.logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); TransactionContext.Clear(); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } finally { RequestContext.Clear(); } }
public void Abort(ITransactionInfo transactionInfo, OrleansTransactionAbortedException reason) { throw new OrleansTransactionsDisabledException(); }
public void Join(ITransactionInfo x) { this.joined.Enqueue((TransactionInfo)x); }
public Task Abort(ITransactionInfo transactionInfo) { throw new OrleansTransactionsDisabledException(); }
public async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke); return; } RequestContextExtensions.Import(message.RequestContextData); if (schedulingOptions.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message.TargetGrain, message.TargetActivation, message.DebugContext)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContextExtensions.ExportToMessage(message); } bool startNewTransaction = false; ITransactionInfo transactionInfo = message.TransactionInfo; if (message.IsTransactionRequired && transactionInfo == null) { // TODO: this should be a configurable parameter var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10); // Start a new transaction transactionInfo = await this.transactionAgent.Value.StartTransaction(message.IsReadOnly, transactionTimeout); startNewTransaction = true; } if (transactionInfo != null) { TransactionContext.SetTransactionInfo(transactionInfo); } object resultObject; try { var request = (InvokeMethodRequest)message.GetDeserializedBody(this.serializationManager); if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, this.loggerFactory, logger, this, this.cancellationTokenRuntime); } var invoker = invokable.GetInvoker(typeManager, request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = Utils.GetStackTrace(); #endif logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } var requestInvoker = new GrainMethodInvoker(target, request, invoker, GrainCallFilters, interfaceToImplementationMapping); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (invokeExceptionLogger.IsEnabled(LogLevel.Debug) || message.Direction == Message.Directions.OneWay) { invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message, exc1); } transactionInfo = TransactionContext.GetTransactionInfo(); if (transactionInfo != null) { // Must abort the transaction on exceptions transactionInfo.IsAborted = true; if (startNewTransaction) { var abortException = (exc1 as OrleansTransactionAbortedException) ?? new OrleansTransactionAbortedException(transactionInfo.TransactionId.ToString(), exc1); this.transactionAgent.Value.Abort(transactionInfo, abortException); exc1 = abortException; } } // If a grain allowed an inconsistent state exception to escape and the exception originated from // this activation, then deactivate it. var ise = exc1 as InconsistentStateException; if (ise != null && ise.IsSourceActivation) { // Mark the exception so that it doesn't deactivate any other activations. ise.IsSourceActivation = false; var activation = (target as Grain)?.Data; if (activation != null) { invokeExceptionLogger.Info($"Deactivating {activation} due to inconsistent state."); this.DeactivateOnIdle(activation.ActivationId); } } if (message.Direction != Message.Directions.OneWay) { TransactionContext.Clear(); SafeSendExceptionResponse(message, exc1); } return; } transactionInfo = TransactionContext.GetTransactionInfo(); if (transactionInfo != null && !transactionInfo.ReconcilePending(out var numberOrphans)) { var abortException = new OrleansOrphanCallException(transactionInfo.TransactionId.ToString(), numberOrphans); // Can't exit before the transaction completes. TransactionContext.GetTransactionInfo().IsAborted = true; if (startNewTransaction) { this.transactionAgent.Value.Abort(TransactionContext.GetTransactionInfo(), abortException); } if (message.Direction != Message.Directions.OneWay) { TransactionContext.Clear(); SafeSendExceptionResponse(message, abortException); } return; } if (startNewTransaction) { // This request started the transaction, so we try to commit before returning. await this.transactionAgent.Value.Commit(transactionInfo); TransactionContext.Clear(); } if (message.Direction == Message.Directions.OneWay) { return; } SafeSendResponse(message, resultObject); } catch (Exception exc2) { logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); try { if (exc2 is OrleansTransactionInDoubtException) { this.logger.LogError(exc2, "Transaction failed due to in doubt transaction"); } else if (TransactionContext.GetTransactionInfo() != null) { // Must abort the transaction on exceptions TransactionContext.GetTransactionInfo().IsAborted = true; var abortException = (exc2 as OrleansTransactionAbortedException) ?? new OrleansTransactionAbortedException(TransactionContext.GetTransactionInfo().TransactionId.ToString(), exc2); this.transactionAgent.Value.Abort(TransactionContext.GetTransactionInfo(), abortException); } } finally { TransactionContext.Clear(); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } } finally { TransactionContext.Clear(); } }
/// <summary> /// Executes a previous transaction /// </summary> /// <param name="storeName">Name of the store</param> /// <param name="transactionInfo">Transaction to execute.</param> public IJobInfo ReExecuteTransaction(string storeName, ITransactionInfo transactionInfo) { try { var tInfoWrapper = transactionInfo as TransactionInfoWrapper; if (tInfoWrapper == null) throw new ArgumentException("Invalid TransactionInfo object received.", "transactionInfo"); var tInfo = tInfoWrapper.TransactionInfo; var jobId = _serverCore.ReExecuteTransaction(storeName, tInfo.Id, (Storage.TransactionType)((int) tInfo.TransactionType)); return new JobInfoWrapper(new JobInfo { JobId = jobId.ToString(), JobPending = true }); } catch (Exception ex) { Logging.LogError(BrightstarEventId.ServerCoreException, "Error rexecuting transaction with JobId {0} for store {1}", transactionInfo.JobId, storeName); throw new BrightstarClientException(String.Format("Error rexecuting transaction with JobId {0} for store {1}. {2}", transactionInfo.JobId, storeName, ex.Message), ex); } }
/// <summary> /// Executes a previous transaction /// </summary> /// <param name="storeName">The name of the store to re-apply the transaction to</param> /// <param name="transactionInfo">The transaction to be applied</param> public IJobInfo ReExecuteTransaction(string storeName, ITransactionInfo transactionInfo) { throw new NotImplementedException(); }
public void Join(ITransactionInfo other) { this.joined.Enqueue((TransactionInfo)other); }