-
Notifications
You must be signed in to change notification settings - Fork 2k
/
FaultInjectionTransactionState.cs
102 lines (89 loc) · 4.21 KB
/
FaultInjectionTransactionState.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Orleans.Runtime;
using Orleans.Transactions.Abstractions;
using Orleans.Transactions.State;
namespace Orleans.Transactions.TestKit
{
public class FaultInjectionControl
{
public TransactionFaultInjectPhase FaultInjectionPhase = TransactionFaultInjectPhase.None;
public FaultInjectionType FaultInjectionType = FaultInjectionType.None;
public void Reset()
{
this.FaultInjectionType = FaultInjectionType.None;
this.FaultInjectionPhase = TransactionFaultInjectPhase.None;
}
}
public enum TransactionFaultInjectPhase
{
None,
//deactivation injection phase
AfterCommitReadOnly,
AfterPrepare,
AfterPrepareAndCommit,
AfterAbort,
AfterPrepared,
AfterCancel,
AfterConfirm,
AfterPing,
//storage exception injection phase
BeforeConfirm,
BeforePrepare,
BeforePrepareAndCommit
}
public enum FaultInjectionType
{
None,
Deactivation,
ExceptionBeforeStore,
ExceptionAfterStore
}
public interface IFaultInjectionTransactionalState<TState> : ITransactionalState<TState> where TState : class, new()
{
FaultInjectionControl FaultInjectionControl { get; set; }
}
internal class FaultInjectionTransactionalState<TState> : IFaultInjectionTransactionalState<TState>, ILifecycleParticipant<IGrainLifecycle>
where TState : class, new()
{
private readonly IGrainRuntime grainRuntime;
private readonly TransactionalState<TState> txState;
private readonly ILogger logger;
public FaultInjectionControl FaultInjectionControl { get; set; }
private IControlledTransactionFaultInjector faultInjector;
public string CurrentTransactionId => this.txState.CurrentTransactionId;
public FaultInjectionTransactionalState(TransactionalState<TState> txState, IGrainActivationContext activationContext, IGrainRuntime grainRuntime, ILogger<FaultInjectionTransactionalState<TState>> logger)
{
this.grainRuntime = grainRuntime;
this.txState = txState;
this.logger = logger;
this.FaultInjectionControl = new FaultInjectionControl();
//fault injector has to be injected to DI as a scoped service, so each grain activation share one injector. but different grain activation use different ones.
this.faultInjector = activationContext.ActivationServices.GetService<IControlledTransactionFaultInjector>();
if(this.faultInjector == null)
throw new ArgumentOutOfRangeException($"Incorrect {nameof(faultInjector)} type configured. Only {nameof(IControlledTransactionFaultInjector)} is allowed.");
}
public void Participate(IGrainLifecycle lifecycle)
{
lifecycle.Subscribe<FaultInjectionTransactionalState<TState>>(GrainLifecycleStage.SetupState,
(ct) => this.txState.OnSetupState(ct, this.SetupResourceFactory));
}
internal void SetupResourceFactory(IGrainActivationContext context, string stateName, TransactionQueue<TState> queue)
{
// Add resources factory to the grain context
context.RegisterResourceFactory<ITransactionalResource>(stateName, () => new FaultInjectionTransactionalResource<TState>(this.faultInjector, FaultInjectionControl, new TransactionalResource<TState>(queue), context, logger, grainRuntime));
// Add tm factory to the grain context
context.RegisterResourceFactory<ITransactionManager>(stateName, () => new FaultInjectionTransactionManager<TState>(this.faultInjector, FaultInjectionControl, new TransactionManager<TState>(queue), context, logger, grainRuntime));
}
public Task<TResult> PerformRead<TResult>(Func<TState, TResult> readFunction)
{
return this.txState.PerformRead(readFunction);
}
public Task<TResult> PerformUpdate<TResult>(Func<TState, TResult> updateFunction)
{
return this.txState.PerformUpdate(updateFunction);
}
}
}