Skip to content

Commit

Permalink
Merge branch 'main' into jamest/access
Browse files Browse the repository at this point in the history
  • Loading branch information
ReubenBond authored Aug 16, 2023
2 parents bd0c0e2 + aeaa64d commit 05ad9b4
Show file tree
Hide file tree
Showing 27 changed files with 1,053 additions and 689 deletions.
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageVersion Include="Azure.Data.Tables" Version="12.8.0" />
<PackageVersion Include="Azure.Core" Version="1.33.0" />
<PackageVersion Include="Azure.Messaging.EventHubs" Version="5.7.3" />
<PackageVersion Include="Azure.Messaging.EventHubs" Version="5.9.2" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.14.0" />
<PackageVersion Include="Azure.Storage.Queues" Version="12.12.0" />
<!-- 3rd party packages -->
Expand Down Expand Up @@ -99,4 +99,4 @@
<PackageVersion Include="Microsoft.SourceLink.AzureRepos.Git" Version="$(SourceLinkVersion)" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="$(SourceLinkVersion)" />
</ItemGroup>
</Project>
</Project>
23 changes: 23 additions & 0 deletions SUPPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Support

## How to file issues and get help

This project uses GitHub [Issues](https://github.com/dotnet/orleans/issues) to track bugs and feature requests. Please search the existing
issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a [new Issue](https://github.com/dotnet/orleans/issues/new).

## Community

The Orleans community enjoys a lively discussion on our [Discord server](https://aka.ms/orleans-discord), and in the Issues customers file here on GitHub. If you would like to engage with our active, friendly community, use one of the links below to find someone who can help.

[![Discord](https://discordapp.com/api/guilds/333727978460676096/widget.png?style=banner4)](https://aka.ms/orleans-discord)

* Ask questions by [opening an issue on GitHub](https://github.com/dotnet/orleans/issues) or on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=orleans)
* [Chat on Discord](https://aka.ms/orleans-discord)
* Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements.
* [OrleansContrib - GitHub organization for community add-ons to Orleans](https://github.com/OrleansContrib/) Various community projects, including Monitoring, Design Patterns, Storage Providers, etc.
* Guidelines for developers wanting to [contribute code changes to Orleans](CONTRIBUTING.md).
* You are also encouraged to report bugs or start a technical discussion by starting a new [thread](https://github.com/dotnet/orleans/issues) on GitHub.

## Microsoft Support Policy

Support for this project is limited to the resources listed above.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -21,11 +22,11 @@ public class AzureTableGrainDirectory : IGrainDirectory, ILifecycleParticipant<I

internal class GrainDirectoryEntity : ITableEntity
{
public string SiloAddress { get; set; }
public string ActivationId { get; set; }
public long MembershipVersion { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public required string SiloAddress { get; set; }
public required string ActivationId { get; set; }
public required long MembershipVersion { get; set; }
public required string PartitionKey { get; set; }
public required string RowKey { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }

Expand All @@ -42,6 +43,8 @@ public GrainAddress ToGrainAddress()

public static GrainDirectoryEntity FromGrainAddress(string clusterId, GrainAddress address)
{
ArgumentNullException.ThrowIfNull(address.SiloAddress);

return new GrainDirectoryEntity
{
PartitionKey = clusterId,
Expand All @@ -68,7 +71,7 @@ public AzureTableGrainDirectory(
this.clusterId = clusterOptions.Value.ClusterId;
}

public async Task<GrainAddress> Lookup(GrainId grainId)
public async Task<GrainAddress?> Lookup(GrainId grainId)
{
var result = await this.tableDataManager.ReadSingleTableEntryAsync(this.clusterId, GrainDirectoryEntity.GrainIdToRowKey(grainId));

Expand All @@ -80,9 +83,9 @@ public async Task<GrainAddress> Lookup(GrainId grainId)
return result.Item1.ToGrainAddress();
}

public Task<GrainAddress> Register(GrainAddress address) => Register(address, null);
public Task<GrainAddress?> Register(GrainAddress address) => Register(address, null);

public async Task<GrainAddress> Register(GrainAddress address, GrainAddress previousAddress)
public async Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress)
{
(bool isSuccess, string eTag) result;
if (previousAddress is not null)
Expand Down
2 changes: 1 addition & 1 deletion src/Azure/Shared/Storage/AzureTableDataManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace Orleans.GrainDirectory.AzureStorage
/// Utility class to encapsulate row-based access to Azure table storage.
/// </summary>
/// <typeparam name="T">Table data entry used by this table / manager.</typeparam>
internal class AzureTableDataManager<T> where T : class, ITableEntity, new()
internal class AzureTableDataManager<T> where T : class, ITableEntity
{
private readonly AzureStorageOperationOptions options;

Expand Down
56 changes: 27 additions & 29 deletions src/Orleans.Analyzers/GenerateSerializationAttributesCodeFix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Simplification;
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
Expand Down Expand Up @@ -79,33 +79,6 @@ private static async Task<Document> AddNonSerializedAttributes(SyntaxNode root,
var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false);
var analysis = SerializationAttributesHelper.AnalyzeTypeDeclaration(declaration);

var insertUsingDirective = true;
var ns = root.DescendantNodesAndSelf()
.OfType<UsingDirectiveSyntax>()
.FirstOrDefault(directive => string.Equals(directive.Name.ToString(), Constants.SystemNamespace));
if (ns is not null)
{
insertUsingDirective = false;
}

if (insertUsingDirective)
{
var usingDirective = UsingDirective(IdentifierName(Constants.SystemNamespace)).WithTrailingTrivia(EndOfLine("\r\n"));
var lastUsing = root.DescendantNodesAndSelf().OfType<UsingDirectiveSyntax>().LastOrDefault();
if (lastUsing is not null)
{
editor.InsertAfter(lastUsing, usingDirective);
}
else if (root.DescendantNodesAndSelf().OfType<NamespaceDeclarationSyntax>().FirstOrDefault() is NamespaceDeclarationSyntax firstNamespace)
{
editor.InsertBefore(lastUsing, usingDirective);
}
else if (root.DescendantNodesAndSelf().FirstOrDefault() is SyntaxNode firstNode)
{
editor.InsertBefore(firstNode, usingDirective);
}
}

foreach (var member in analysis.UnannotatedMembers)
{
// Add the [NonSerialized] attribute
Expand All @@ -120,7 +93,32 @@ private static async Task<Document> AddNonSerializedAttributes(SyntaxNode root,
editor.AddAttribute(member, attribute);
}

return editor.GetChangedDocument();
var document = editor.GetChangedDocument();
root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

var insertUsingDirective = true;
if (root is CompilationUnitSyntax rootCompilationUnit)
{
foreach (var directive in rootCompilationUnit.Usings)
{
if (string.Equals(directive.Name.ToString(), Constants.SystemNamespace, StringComparison.Ordinal))
{
insertUsingDirective = false;
break;
}
}

if (insertUsingDirective)
{
var usingDirective = UsingDirective(IdentifierName(Constants.SystemNamespace)).WithTrailingTrivia(EndOfLine("\r\n"));
if (root is CompilationUnitSyntax compilationUnit)
{
root = compilationUnit.AddUsings(usingDirective);
}
}
}

return document.WithSyntaxRoot(root);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public sealed class AlwaysInterleaveAttribute : Attribute
/// </summary>
/// <remarks>
/// The callback method name should point to a public static function declared on the same class
/// and having the following signature: <c>public static bool MayInterleave(InvokeMethodRequest req)</c>
/// and having the following signature: <c>public static bool MayInterleave(IInvokable req)</c>
/// </remarks>
[AttributeUsage(AttributeTargets.Class)]
public sealed class MayInterleaveAttribute : Attribute, IGrainPropertiesProviderAttribute
Expand All @@ -109,7 +109,8 @@ public sealed class MayInterleaveAttribute : Attribute, IGrainPropertiesProvider
/// Initializes a new instance of the <see cref="MayInterleaveAttribute"/> class.
/// </summary>
/// <param name="callbackMethodName">
/// The callback method name.
/// The callback method name. This should resolve to a method with the
/// following signature: <c>public static bool NameOfMethod(IInvokable req)</c>
/// </param>
public MayInterleaveAttribute(string callbackMethodName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface IGrainDirectory
/// </summary>
/// <param name="address">The <see cref="GrainAddress"/> to register</param>
/// <returns>The <see cref="GrainAddress"/> that is effectively registered in the directory.</returns>
Task<GrainAddress> Register(GrainAddress address);
Task<GrainAddress?> Register(GrainAddress address);

/// <summary>
/// Register a <see cref="GrainAddress"/> entry in the directory.
Expand All @@ -26,7 +26,7 @@ public interface IGrainDirectory
/// </summary>
/// <param name="address">The <see cref="GrainAddress"/> to register</param>
/// <returns>The <see cref="GrainAddress"/> that is effectively registered in the directory.</returns>
Task<GrainAddress> Register(GrainAddress address, GrainAddress? previousAddress) => GrainDirectoryExtension.Register(this, address, previousAddress);
Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress) => GrainDirectoryExtension.Register(this, address, previousAddress);

/// <summary>
/// Unregisters the specified <see cref="GrainAddress"/> entry from the directory.
Expand All @@ -44,7 +44,7 @@ public interface IGrainDirectory
/// </summary>
/// <param name="grainId">The Grain ID to lookup</param>
/// <returns>The <see cref="GrainAddress"/> entry found in the directory, if any</returns>
Task<GrainAddress> Lookup(GrainId grainId);
Task<GrainAddress?> Lookup(GrainId grainId);

/// <summary>
/// Unregisters all grain directory entries which point to any of the specified silos.
Expand All @@ -61,7 +61,7 @@ public interface IGrainDirectory

internal static class GrainDirectoryExtension
{
internal static async Task<GrainAddress> Register(IGrainDirectory directory, GrainAddress address, GrainAddress? previousAddress)
internal static async Task<GrainAddress?> Register(IGrainDirectory directory, GrainAddress address, GrainAddress? previousAddress)
{
if (previousAddress is not null)
{
Expand Down
71 changes: 60 additions & 11 deletions src/Orleans.Core.Abstractions/IDs/GrainId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Orleans.Runtime
/// </summary>
[Serializable, GenerateSerializer, Immutable]
[JsonConverter(typeof(GrainIdJsonConverter))]
public readonly struct GrainId : IEquatable<GrainId>, IComparable<GrainId>, ISerializable, ISpanFormattable
public readonly struct GrainId : IEquatable<GrainId>, IComparable<GrainId>, ISerializable, ISpanFormattable, ISpanParsable<GrainId>
{
[Id(0)]
private readonly GrainType _type;
Expand Down Expand Up @@ -64,36 +64,71 @@ private GrainId(SerializationInfo info, StreamingContext context)
public static GrainId Create(GrainType type, IdSpan key) => new GrainId(type, key);

/// <summary>
/// Creates a new <see cref="GrainType"/> instance.
/// Parses a <see cref="GrainId"/> from the span.
/// </summary>
public static GrainId Parse(string value)
public static GrainId Parse(ReadOnlySpan<char> value, IFormatProvider? provider = null)
{
if (!TryParse(value, out var result))
if (!TryParse(value, provider, out var result))
{
ThrowInvalidGrainId(value);

static void ThrowInvalidGrainId(string value) => throw new ArgumentException($"Unable to parse \"{value}\" as a grain id");
static void ThrowInvalidGrainId(ReadOnlySpan<char> value) => throw new ArgumentException($"Unable to parse \"{value}\" as a grain id");
}

return result;
}

/// <summary>
/// Creates a new <see cref="GrainType"/> instance.
/// Tries to parse a <see cref="GrainId"/> from the span.
/// </summary>
public static bool TryParse(string? value, out GrainId grainId)
/// <returns><see langword="true"/> if a valid <see cref="GrainId"/> was parsed. <see langword="false"/> otherwise</returns>
public static bool TryParse(ReadOnlySpan<char> value, IFormatProvider? provider, out GrainId result)
{
int i;
if (value is null || (i = value.IndexOf('/')) < 0)
if ((i = value.IndexOf('/')) < 0)
{
grainId = default;
result = default;
return false;
}

grainId = new(new GrainType(Encoding.UTF8.GetBytes(value, 0, i)), new IdSpan(Encoding.UTF8.GetBytes(value, i + 1, value.Length - i - 1)));
var typeSpan = value[0..i];
var type = new byte[Encoding.UTF8.GetByteCount(typeSpan)];
Encoding.UTF8.GetBytes(typeSpan, type);

var idSpan = value[(i + 1)..];
var id = new byte[Encoding.UTF8.GetByteCount(idSpan)];
Encoding.UTF8.GetBytes(idSpan, id);

result = new(new GrainType(type), new IdSpan(id));
return true;
}

/// <summary>
/// Parses a <see cref="GrainId"/> from the string.
/// </summary>
public static GrainId Parse(string value)
=> Parse(value.AsSpan(), null);

/// <summary>
/// Parses a <see cref="GrainId"/> from the string.
/// </summary>
public static GrainId Parse(string value, IFormatProvider? provider = null)
=> Parse(value.AsSpan(), provider);

/// <summary>
/// Tries to parse a <see cref="GrainId"/> from the string.
/// </summary>
/// <returns><see langword="true"/> if a valid <see cref="GrainId"/> was parsed. <see langword="false"/> otherwise</returns>
public static bool TryParse(string? value, out GrainId result)
=> TryParse(value.AsSpan(), null, out result);

/// <summary>
/// Tries to parse a <see cref="GrainId"/> from the string.
/// </summary>
/// <returns><see langword="true"/> if a valid <see cref="GrainId"/> was parsed. <see langword="false"/> otherwise</returns>
public static bool TryParse(string? value, IFormatProvider? provider, out GrainId result)
=> TryParse(value.AsSpan(), provider, out result);

/// <summary>
/// <see langword="true"/> if this instance is the default value, <see langword="false"/> if it is not.
/// </summary>
Expand Down Expand Up @@ -167,7 +202,21 @@ bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, Re
public sealed class GrainIdJsonConverter : JsonConverter<GrainId>
{
/// <inheritdoc />
public override GrainId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => GrainId.Parse(reader.GetString()!);
public override GrainId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var valueLength = reader.HasValueSequence
? checked((int)reader.ValueSequence.Length)
: reader.ValueSpan.Length;

Span<char> buf = valueLength <= 128
? (stackalloc char[128])[..valueLength]
: new char[valueLength];

var written = reader.CopyString(buf);
buf = buf[..written];

return GrainId.Parse(buf);
}

/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, GrainId value, JsonSerializerOptions options)
Expand Down
6 changes: 3 additions & 3 deletions src/Orleans.Reminders/GrainReminderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,17 @@ private static Task UnregisterReminder(IGrainContext? grainContext, IGrainRemind
/// <param name="grain">The grain instance.</param>
/// <param name="reminderName">Reminder to return</param>
/// <returns>Promise for Reminder handle.</returns>
public static Task<IGrainReminder> GetReminder(this Grain grain, string reminderName) => GetReminder(grain?.GrainContext, reminderName);
public static Task<IGrainReminder?> GetReminder(this Grain grain, string reminderName) => GetReminder(grain?.GrainContext, reminderName);

/// <summary>
/// Returns a previously registered reminder.
/// </summary>
/// <param name="grain">A grain.</param>
/// <param name="reminderName">Reminder to return</param>
/// <returns>Promise for Reminder handle.</returns>
public static Task<IGrainReminder> GetReminder(this IGrainBase grain, string reminderName) => GetReminder(grain?.GrainContext, reminderName);
public static Task<IGrainReminder?> GetReminder(this IGrainBase grain, string reminderName) => GetReminder(grain?.GrainContext, reminderName);

private static Task<IGrainReminder> GetReminder(IGrainContext? grainContext, string reminderName)
private static Task<IGrainReminder?> GetReminder(IGrainContext? grainContext, string reminderName)
{
ArgumentNullException.ThrowIfNull(grainContext, "grain");
if (string.IsNullOrWhiteSpace(reminderName)) throw new ArgumentNullException(nameof(reminderName));
Expand Down
30 changes: 30 additions & 0 deletions src/Orleans.Runtime/Activation/ConfigureDefaultGrainActivator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using Orleans.Metadata;

namespace Orleans.Runtime
{
internal class ConfigureDefaultGrainActivator : IConfigureGrainTypeComponents
{
private readonly IServiceProvider _serviceProvider;
private readonly GrainClassMap _grainClassMap;

public ConfigureDefaultGrainActivator(GrainClassMap grainClassMap, IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_grainClassMap = grainClassMap;
}

public void Configure(GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared)
{
if (shared.GetComponent<IGrainActivator>() is object) return;

if (!_grainClassMap.TryGetGrainClass(grainType, out var grainClass))
{
return;
}

var instanceActivator = new DefaultGrainActivator(_serviceProvider, grainClass);
shared.SetComponent<IGrainActivator>(instanceActivator);
}
}
}
Loading

0 comments on commit 05ad9b4

Please sign in to comment.