-
Notifications
You must be signed in to change notification settings - Fork 2k
/
LogConsistentGrain.cs
123 lines (107 loc) · 5.52 KB
/
LogConsistentGrain.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Orleans.Core;
using Orleans.Runtime;
using Orleans.Storage;
using Orleans.GrainDirectory;
using Orleans.Providers;
using Orleans.MultiCluster;
namespace Orleans.LogConsistency
{
/// <summary>
/// Base class for all grains that use log-consistency for managing the state.
/// It is the equivalent of <see cref="Grain{T}"/> for grains using log-consistency.
/// (SiloAssemblyLoader uses it to extract type)
/// </summary>
/// <typeparam name="TView">The type of the view</typeparam>
public abstract class LogConsistentGrain<TView> : Grain, ILifecycleParticipant<IGrainLifecycle>
{
protected LogConsistentGrain()
{
}
/// <summary>
/// This constructor is particularly useful for unit testing where test code can create a Grain and replace
/// the IGrainIdentity, IGrainRuntime and State with test doubles (mocks/stubs).
/// </summary>
protected LogConsistentGrain(IGrainIdentity identity, IGrainRuntime runtime)
: base(identity, runtime)
{
}
/// <summary>
/// called right after grain construction to install the log view adaptor
/// </summary>
/// <param name="factory"> The adaptor factory to use </param>
/// <param name="state"> The initial state of the view </param>
/// <param name="grainTypeName"> The type name of the grain </param>
/// <param name="grainStorage"> The grain storage, if needed </param>
/// <param name="services"> Protocol services </param>
protected abstract void InstallAdaptor(ILogViewAdaptorFactory factory, object state, string grainTypeName, IGrainStorage grainStorage, ILogConsistencyProtocolServices services);
/// <summary>
/// Gets the default adaptor factory to use, or null if there is no default
/// (in which case user MUST configure a consistency provider)
/// </summary>
protected abstract ILogViewAdaptorFactory DefaultAdaptorFactory { get; }
public override void Participate(IGrainLifecycle lifecycle)
{
base.Participate(lifecycle);
lifecycle.Subscribe<ClientOptionsLogger>(GrainLifecycleStage.SetupState, OnSetupState);
if(this is ILogConsistencyProtocolParticipant)
{
lifecycle.Subscribe<LogConsistentGrain<TView>>(GrainLifecycleStage.Activate - 1, PreActivate);
lifecycle.Subscribe<LogConsistentGrain<TView>>(GrainLifecycleStage.Activate + 1, PostActivate);
}
}
private Task OnSetupState(CancellationToken ct)
{
if (ct.IsCancellationRequested) return Task.CompletedTask;
IGrainActivationContext activationContext = this.ServiceProvider.GetRequiredService<IGrainActivationContext>();
Factory<Grain, ILogConsistencyProtocolServices> protocolServicesFactory = this.ServiceProvider.GetRequiredService<Factory<Grain, ILogConsistencyProtocolServices>>();
ILogViewAdaptorFactory consistencyProvider = SetupLogConsistencyProvider(activationContext);
IGrainStorage grainStorage = consistencyProvider.UsesStorageProvider ? this.GetGrainStorage(this.ServiceProvider) : null;
InstallLogViewAdaptor(protocolServicesFactory, consistencyProvider, grainStorage);
return Task.CompletedTask;
}
private async Task PreActivate(CancellationToken ct)
{
await ((ILogConsistencyProtocolParticipant)this).PreActivateProtocolParticipant();
}
private async Task PostActivate(CancellationToken ct)
{
await ((ILogConsistencyProtocolParticipant)this).PostActivateProtocolParticipant();
}
private void InstallLogViewAdaptor(
Factory<Grain, ILogConsistencyProtocolServices> protocolServicesFactory,
ILogViewAdaptorFactory factory,
IGrainStorage grainStorage)
{
// encapsulate runtime services used by consistency adaptors
ILogConsistencyProtocolServices svc = protocolServicesFactory(this);
TView state = (TView)Activator.CreateInstance(typeof(TView));
this.InstallAdaptor(factory, state, this.GetType().FullName, grainStorage, svc);
}
private ILogViewAdaptorFactory SetupLogConsistencyProvider(IGrainActivationContext activationContext)
{
var attr = this.GetType().GetCustomAttributes<LogConsistencyProviderAttribute>(true).FirstOrDefault();
ILogViewAdaptorFactory defaultFactory = attr != null
? this.ServiceProvider.GetServiceByName<ILogViewAdaptorFactory>(attr.ProviderName)
: this.ServiceProvider.GetService<ILogViewAdaptorFactory>();
if (attr != null && defaultFactory == null)
{
var errMsg = $"Cannot find consistency provider with Name={attr.ProviderName} for grain type {this.GetType().FullName}";
throw new BadGrainStorageConfigException(errMsg);
}
// use default if none found
defaultFactory = defaultFactory ?? this.DefaultAdaptorFactory;
if (defaultFactory == null)
{
var errMsg = $"No log consistency provider found loading grain type {this.GetType().FullName}";
throw new BadGrainStorageConfigException(errMsg);
};
return defaultFactory;
}
}
}