Skip to content

Commit

Permalink
Merge pull request #1 from ReubenBond/main
Browse files Browse the repository at this point in the history
Update to Orleans 7.x
  • Loading branch information
oising authored Sep 6, 2023
2 parents f2c14ef + 55076dd commit f0d5172
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ public interface INamedStorageInterceptorFactory
/// <typeparam name="TState"></typeparam>
/// <param name="context"></param>
/// <param name="config"></param>
IPersistentState<TState> Create<TState>(IGrainActivationContext context, IStorageInterceptorConfig config);
IPersistentState<TState> Create<TState>(IGrainContext context, IStorageInterceptorConfig config);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public interface IStorageInterceptorFullConfig<TState> : IStorageInterceptorConf
/// <summary>
/// .
/// </summary>
IGrainActivationContext Context { get; set; }
IGrainContext Context { get; set; }
/// <summary>
/// .
/// </summary>
Expand Down Expand Up @@ -58,7 +58,7 @@ public StorageInterceptorFullConfig(string stateName, string storageName)
/// <summary>
/// .
/// </summary>
public IGrainActivationContext Context { get; set; } = default!;
public IGrainContext Context { get; set; } = default!;
/// <summary>
/// .
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ public interface IStorageInterceptorFactory
/// <param name="config"></param>
/// <param name="fullStateName"></param>
/// <param name="storageProvider"></param>
IStorageInterceptor Create(IGrainActivationContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider);
IStorageInterceptor Create(IGrainContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ namespace Orleans.StorageProviderInterceptors.Infrastructure;
using Orleans;
using Orleans.Runtime;
using Orleans.Storage;
using Orleans.Utilities;
using Orleans.StorageProviderInterceptors.Abstractions;
using System.Text;
using System.Collections.Concurrent;
using Orleans.Hosting;
using Orleans.Serialization.TypeSystem;

/// <summary>
/// TODO
Expand All @@ -30,7 +28,7 @@ public class NamedStorageInterceptorFactory : INamedStorageInterceptorFactory
/// <param name="context"></param>
/// <param name="config"></param>
/// <exception cref="InvalidOperationException"></exception>
public IPersistentState<TState> Create<TState>(IGrainActivationContext context, IStorageInterceptorConfig config)
public IPersistentState<TState> Create<TState>(IGrainContext context, IStorageInterceptorConfig config)
{
//var factory = string.IsNullOrEmpty(config.StorageName)
// ? this.services.GetService<IStorageInterceptorFactory>()
Expand Down Expand Up @@ -64,13 +62,12 @@ public IPersistentState<TState> Create<TState>(IGrainActivationContext context,
/// </summary>
/// <param name="context"></param>
/// <param name="cfg"></param>
protected virtual string GetFullStateName(IGrainActivationContext context, IStorageInterceptorConfig cfg) => $"{RuntimeTypeNameFormatter.Format(context.GrainType)}.{cfg.StateName}";
internal static TypeFormattingOptions LogFormat { get; } = new TypeFormattingOptions(includeGlobal: false);
protected virtual string GetFullStateName(IGrainContext context, IStorageInterceptorConfig cfg) => $"{RuntimeTypeNameFormatter.Format(context.GrainInstance!.GetType())}.{cfg.StateName}";

private static void ThrowMissingProviderException(IGrainActivationContext context, IStorageInterceptorConfig cfg)
private static void ThrowMissingProviderException(IGrainContext context, IStorageInterceptorConfig cfg)
{
string errMsg;
var grainTypeName = BuildParseableName(context.GrainType);
var grainTypeName = context.GrainInstance!.GetType();
if (string.IsNullOrEmpty(cfg.StorageName))
{
errMsg = $"No default storage provider found loading grain type {grainTypeName}.";
Expand All @@ -80,22 +77,7 @@ private static void ThrowMissingProviderException(IGrainActivationContext contex
errMsg = $"No storage provider named \"{cfg.StorageName}\" found loading grain type {grainTypeName}.";
}

throw new BadGrainStorageConfigException(errMsg);
}

private static string BuildParseableName(Type type)
{
var builder = new StringBuilder();
GetParseableName(
type,
builder,
new Queue<Type>(
type.IsGenericTypeDefinition
? type.GetGenericArguments()
: type.GenericTypeArguments),
LogFormat,
t => GetUnadornedTypeName(t) + LogFormat.NameSuffix);
return builder.ToString();
throw new InvalidOperationException(errMsg);
}

/// <summary>
Expand All @@ -114,159 +96,20 @@ public static string GetUnadornedTypeName(Type type)
// An ampersand can appear as a suffix to a by-ref type.
return (index > 0 ? type.Name[..index] : type.Name).TrimEnd('&');
}
internal static TypeFormattingOptions Default { get; } = new TypeFormattingOptions();
private static readonly ConcurrentDictionary<Tuple<Type, TypeFormattingOptions>, string> ParseableNameCache = new();
private readonly IServiceProvider services;

internal static string GetParseableName(Type type, TypeFormattingOptions? options = null, Func<Type, string>? getNameFunc = null)
{
options ??= Default;

// If a naming function has been specified, skip the cache.
if (getNameFunc != null)
{
return BuildParseableName();
}

return ParseableNameCache.GetOrAdd(Tuple.Create(type, options), _ => BuildParseableName());

string BuildParseableName()
{
var builder = new StringBuilder();
GetParseableName(
type,
builder,
new Queue<Type>(
type.IsGenericTypeDefinition
? type.GetGenericArguments()
: type.GenericTypeArguments),
options,
t => GetUnadornedTypeName(t) + options.NameSuffix);
return builder.ToString();
}
}
/// <summary>Returns a string representation of <paramref name="type"/>.</summary>
/// <param name="type">The type.</param>
/// <param name="builder">The <see cref="StringBuilder"/> to append results to.</param>
/// <param name="typeArguments">The type arguments of <paramref name="type"/>.</param>
/// <param name="options">The type formatting options.</param>
/// <param name="getNameFunc">Delegate that returns name for a type.</param>
private static void GetParseableName(
Type type,
StringBuilder builder,
Queue<Type> typeArguments,
TypeFormattingOptions options,
Func<Type, string> getNameFunc)
{
if (type.IsArray)
{
var elementType = GetParseableName(type.GetElementType()!, options);
if (!string.IsNullOrWhiteSpace(elementType))
{
_ = builder.Append(elementType).Append('[').Append(new string(',', type.GetArrayRank() - 1)).Append(']');
}

return;
}

if (type.IsGenericParameter)
{
if (options.IncludeGenericTypeParameters)
{
builder.Append(GetUnadornedTypeName(type));
}

return;
}

if (type.DeclaringType != null)
{
// This is not the root type.
GetParseableName(type.DeclaringType, builder, typeArguments, options, t => GetUnadornedTypeName(t));
builder.Append(options.NestedTypeSeparator);
}
else if (!string.IsNullOrWhiteSpace(type.Namespace) && options.IncludeNamespace)
{
// This is the root type, so include the namespace.
var namespaceName = type.Namespace;
if (options.NestedTypeSeparator != '.')
{
namespaceName = namespaceName.Replace('.', options.NestedTypeSeparator);
}

if (options.IncludeGlobal)
{
builder.Append("global::");
}

builder.Append(namespaceName).Append(options.NestedTypeSeparator);
}

if (type.IsConstructedGenericType)
{
// Get the unadorned name, the generic parameters, and add them together.
var unadornedTypeName = getNameFunc(type);
builder.Append(EscapeIdentifier(unadornedTypeName));
var generics =
Enumerable.Range(0, Math.Min(type.GetGenericArguments().Length, typeArguments.Count))
.Select(_ => typeArguments.Dequeue())
.ToList();
if (generics.Count > 0 && options.IncludeTypeParameters)
{
var genericParameters = string.Join(
",",
generics.Select(generic => GetParseableName(generic, options)));
builder.Append('<').Append(genericParameters).Append('>');
}
}
else if (type.IsGenericTypeDefinition)
{
// Get the unadorned name, the generic parameters, and add them together.
var unadornedTypeName = getNameFunc(type);
builder.Append(EscapeIdentifier(unadornedTypeName));
var generics =
Enumerable.Range(0, Math.Min(type.GetGenericArguments().Length, typeArguments.Count))
.Select(_ => typeArguments.Dequeue())
.ToList();
if (generics.Count > 0 && options.IncludeTypeParameters)
{
var genericParameters = string.Join(
",",
generics.Select(_ => options.IncludeGenericTypeParameters ? _.ToString() : string.Empty));
builder.Append('<').Append(genericParameters).Append('>');
}
}
else
{
builder.Append(EscapeIdentifier(getNameFunc(type)));
}
}
private static string EscapeIdentifier(string identifier)
{
if (IsCSharpKeyword(identifier))
{
return "@" + identifier;
}

return identifier;
}
internal static bool IsCSharpKeyword(string identifier) => identifier switch
{
"abstract" or "add" or "alias" or "as" or "ascending" or "async" or "await" or "base" or "bool" or "break" or "byte" or "case" or "catch" or "char" or "checked" or "class" or "const" or "continue" or "decimal" or "default" or "delegate" or "descending" or "do" or "double" or "dynamic" or "else" or "enum" or "event" or "explicit" or "extern" or "false" or "finally" or "fixed" or "float" or "for" or "foreach" or "from" or "get" or "global" or "goto" or "group" or "if" or "implicit" or "in" or "int" or "interface" or "internal" or "into" or "is" or "join" or "let" or "lock" or "long" or "nameof" or "namespace" or "new" or "null" or "object" or "operator" or "orderby" or "out" or "override" or "params" or "partial" or "private" or "protected" or "public" or "readonly" or "ref" or "remove" or "return" or "sbyte" or "sealed" or "select" or "set" or "short" or "sizeof" or "stackalloc" or "static" or "string" or "struct" or "switch" or "this" or "throw" or "true" or "try" or "typeof" or "uint" or "ulong" or "unchecked" or "unsafe" or "ushort" or "using" or "value" or "var" or "virtual" or "void" or "volatile" or "when" or "where" or "while" or "yield" => true,
_ => false,
};
/// <inheritdoc/>
public IPersistentState<TState> Create<TState>(IGrainActivationContext context, IStorageInterceptorFullConfig<TState> config) => throw new NotImplementedException();
public IPersistentState<TState> Create<TState>(IGrainContext context, IStorageInterceptorFullConfig<TState> config) => throw new NotImplementedException();

private sealed class PersistentStateBridge<TState> : IPersistentState<TState>, ILifecycleParticipant<IGrainLifecycle>
{
private readonly string fullStateName;
private readonly IGrainActivationContext context;
private readonly IGrainContext context;
private readonly IGrainStorage storageProvider;
private readonly StorageInterceptorOptions<TState> options;
private IStorage<TState> storage = default!;
private StateStorageBridge<TState> storage = default!;

public PersistentStateBridge(string fullStateName, IGrainActivationContext context, IGrainStorage storageProvider, StorageInterceptorOptions<TState> options)
public PersistentStateBridge(string fullStateName, IGrainContext context, IGrainStorage storageProvider, StorageInterceptorOptions<TState> options)
{
ArgumentNullException.ThrowIfNull(fullStateName);
ArgumentNullException.ThrowIfNull(context);
Expand All @@ -285,7 +128,7 @@ public TState State
set => this.storage.State = value;
}

public string Etag => this.storage.Etag;
public string? Etag => this.storage.Etag;

public bool RecordExists => this.storage.RecordExists;

Expand Down Expand Up @@ -331,7 +174,7 @@ private Task OnSetupState(CancellationToken ct)
return Task.CompletedTask;
}

this.storage = new StateStorageBridge<TState>(this.fullStateName, this.context.GrainInstance.GrainReference, this.storageProvider, this.context.ActivationServices.GetService<ILoggerFactory>());
this.storage = new StateStorageBridge<TState>(this.fullStateName, this.context, this.storageProvider, this.context.ActivationServices.GetRequiredService<ILoggerFactory>());
return this.ReadStateAsync();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class StorageInterceptorAttributeMapper : IAttributeToFactoryMapper<Stora
/// </summary>
/// <param name="parameter"></param>
/// <param name="metadata"></param>
public Factory<IGrainActivationContext, object> GetFactory(ParameterInfo parameter, StorageInterceptorAttribute metadata)
public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, StorageInterceptorAttribute metadata)
{
ArgumentNullException.ThrowIfNull(parameter);
IStorageInterceptorConfig config = metadata;
Expand All @@ -30,7 +30,7 @@ public Factory<IGrainActivationContext, object> GetFactory(ParameterInfo paramet
return context => Create(context, genericCreate, config);
}

private static object Create(IGrainActivationContext context, MethodInfo genericCreate, IStorageInterceptorConfig config)
private static object Create(IGrainContext context, MethodInfo genericCreate, IStorageInterceptorConfig config)
{
var factory = context.ActivationServices.GetRequiredService<INamedStorageInterceptorFactory>();
var args = new object[] { context, config };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,30 @@ public class StorageInterceptorOptions<TState>
/// <summary>
/// Called before a ClearStateAsync(); return false to prevent writing.
/// </summary>
public Func<IGrainActivationContext, IPersistentState<TState>, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeClearStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null));
public Func<IGrainContext, IPersistentState<TState>, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeClearStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null));

/// <summary>
/// Called after ClearStateAsync();
/// </summary>
public Func<IGrainActivationContext, IPersistentState<TState>, object?, ValueTask> OnAfterClearStateAsync { get; set; } = (_, _, _) => ValueTask.CompletedTask;
public Func<IGrainContext, IPersistentState<TState>, object?, ValueTask> OnAfterClearStateAsync { get; set; } = (_, _, _) => ValueTask.CompletedTask;

/// <summary>
/// Called before ReadStateAsync(); return false to prevent Reading
/// </summary>
public Func<IGrainActivationContext, IPersistentState<TState>, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeReadStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null));
public Func<IGrainContext, IPersistentState<TState>, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeReadStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null));

/// <summary>
/// Called after ReadStateAsync()
/// </summary>
public Func<IGrainActivationContext, IPersistentState<TState>, object?, ValueTask> OnAfterReadStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask;
public Func<IGrainContext, IPersistentState<TState>, object?, ValueTask> OnAfterReadStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask;

/// <summary>
/// Called before WriteStateAsync(); return false to prevent writing
/// </summary>
public Func<IGrainActivationContext, IPersistentState<TState>, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeWriteStateFunc { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null));
public Func<IGrainContext, IPersistentState<TState>, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeWriteStateFunc { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null));

/// <summary>
/// Called after WriteStateAsync()
/// </summary>
public Func<IGrainActivationContext, IPersistentState<TState>, object?, ValueTask> OnAfterWriteStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask;
public Func<IGrainContext, IPersistentState<TState>, object?, ValueTask> OnAfterWriteStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
///// </summary>
//public class GenericStorageInterceptorFactory : IStorageInterceptorFactory
//{
// private readonly IGrainActivationContext context;
// private readonly IGrainContext context;
// /// <summary>
// /// TODO
// /// </summary>
// /// <param name="context"></param>
// public GenericStorageInterceptorFactory(IGrainActivationContext context) => this.context = context;
// public GenericStorageInterceptorFactory(IGrainContext context) => this.context = context;
// /// <inheritdoc/>
// public IStorageInterceptor Create<TState>(IGrainActivationContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider)
// public IStorageInterceptor Create<TState>(IGrainContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider)
// {
// var storage = this.context.ActivationServices.GetRequiredService<GenericStorageInterceptor<TState>>();
// var options = this.context.ActivationServices.GetRequiredServiceByName<StorageInterceptorOptions<TState>>(config.StorageName);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup Label="Build">
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Label="Package">
Expand All @@ -11,8 +11,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.6.5" />
<PackageReference Include="Microsoft.Orleans.Runtime.Abstractions" Version="3.6.5" />
<PackageReference Include="Microsoft.Orleans.Runtime" Version="7.2.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.CodeStyle" Version="4.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Update="Microsoft.VisualStudio.Threading.Analyzers" Version="17.7.30" />
<PackageReference Update="MinVer" Version="4.3.0" />
</ItemGroup>

</Project>
Loading

0 comments on commit f0d5172

Please sign in to comment.