Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/Orleans/Core/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,26 @@ protected OrleansMessageRejectionException(SerializationInfo info, StreamingCont
: base(info, context)
{ }
}

/// <summary>
/// Indicates a lifecycle was canceled, either by request or due to observer error.
/// </summary>
[Serializable]
public class OrleansLifecycleCanceledException : OrleansException
{
internal OrleansLifecycleCanceledException(string message)
: base(message)
{
}

internal OrleansLifecycleCanceledException(string message,
Exception innerException) : base(message, innerException)
{
}

protected OrleansLifecycleCanceledException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

53 changes: 34 additions & 19 deletions src/Orleans/Core/Grain.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Orleans.Core;
using Orleans.Runtime;
using Orleans.Storage;
using Orleans.Streams;
using System.Diagnostics;

namespace Orleans
{
Expand Down Expand Up @@ -268,30 +270,26 @@ private void EnsureRuntime()
/// Base class for a Grain with declared persistent state.
/// </summary>
/// <typeparam name="TGrainState">The class of the persistent state object</typeparam>
public class Grain<TGrainState> : Grain, IStatefulGrain where TGrainState : new()
public class Grain<TGrainState> : Grain, ILifecycleParticipant<GrainLifecycleStage> where TGrainState : new()
{
private readonly GrainState<TGrainState> grainState;

private IStorage storage;
private IStorage<TGrainState> storage;

/// <summary>
/// This constructor should never be invoked. We expose it so that client code (subclasses of this class) do not have to add a constructor.
/// Client code should use the GrainFactory to get a reference to a Grain.
/// </summary>
protected Grain()
{
grainState = new GrainState<TGrainState>();
}

/// <summary>
/// Grain implementers do NOT have to expose this constructor but can choose to do so.
/// 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 Grain(IGrainIdentity identity, IGrainRuntime runtime, TGrainState state, IStorage storage)
protected Grain(IGrainIdentity identity, IGrainRuntime runtime, IStorage<TGrainState> storage)
: base(identity, runtime)
{
grainState = new GrainState<TGrainState>(state);
this.storage = storage;
}

Expand All @@ -300,18 +298,8 @@ protected Grain(IGrainIdentity identity, IGrainRuntime runtime, TGrainState stat
/// </summary>
protected TGrainState State
{
get { return grainState.State; }
set { grainState.State = value; }
}

void IStatefulGrain.SetStorage(IStorage storage)
{
this.storage = storage;
}

IGrainState IStatefulGrain.GrainState
{
get { return grainState; }
get { return this.storage.State; }
set { this.storage.State = value; }
}

/// <summary>Clear the current grain state data from backing store.</summary>
Expand All @@ -332,5 +320,32 @@ protected virtual Task ReadStateAsync()
{
return storage.ReadStateAsync();
}

public virtual void Participate(ILifecycleObservable<GrainLifecycleStage> lifecycle)
{
lifecycle.Subscribe(GrainLifecycleStage.SetupState, OnSetupState);
}

private async Task OnSetupState(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return;
IStorageProvider storageProvider = this.GetStorageProvider(this.ServiceProvider);
string grainTypeName = this.GetType().FullName;
this.storage = new StateStorageBridge<TGrainState>(grainTypeName, this.GrainReference, storageProvider);
Stopwatch sw = Stopwatch.StartNew();
try
{
await this.ReadStateAsync();
sw.Stop();
StorageStatisticsGroup.OnStorageActivate(grainTypeName, sw.Elapsed);
}
catch (Exception)
{
sw.Stop();
StorageStatisticsGroup.OnStorageActivateError(grainTypeName);
throw;
}
}
}
}
2 changes: 1 addition & 1 deletion src/Orleans/Core/GrainAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ public StorageProviderAttribute()
/// The [Orleans.Providers.LogConsistencyProvider] attribute is used to define which consistency provider to use for grains using the log-view state abstraction.
/// <para>
/// Specifying [Orleans.Providers.LogConsistencyProvider] property is recommended for all grains that derive
/// from ILogConsistentGrain, such as JournaledGrain.
/// from LogConsistentGrain, such as JournaledGrain.
/// If no [Orleans.Providers.LogConsistencyProvider] attribute is specified, then the runtime tries to locate
/// one as follows. First, it looks for a
/// "Default" provider in the configuration file, then it checks if the grain type defines a default.
Expand Down
184 changes: 0 additions & 184 deletions src/Orleans/Core/GrainStateStorageBridge.cs

This file was deleted.

11 changes: 0 additions & 11 deletions src/Orleans/Core/IStatefulGrain.cs

This file was deleted.

5 changes: 4 additions & 1 deletion src/Orleans/Core/IStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

namespace Orleans.Core
{
public interface IStorage
public interface IStorage<TState>
where TState : new()
{
TState State { get; set; }

/// <summary>
/// Async method to cause the current grain state data to be cleared and reset.
/// This will usually mean the state record is deleted from backing store, but the specific behavior is defined by the storage provider instance configured for this grain.
Expand Down
Loading