diff --git a/src/NuGet/BondSerializerInstall.ps1 b/src/NuGet/BondSerializerInstall.ps1
index 7e859f7819..c38e0326b6 100644
--- a/src/NuGet/BondSerializerInstall.ps1
+++ b/src/NuGet/BondSerializerInstall.ps1
@@ -1,6 +1,6 @@
param($installPath, $toolsPath, $package, $project)
-$bondSerializerTypeName = 'Orleans.Serialization.BondSerializer, BondSerializer'
+$bondSerializerTypeName = 'Orleans.Serialization.BondSerializer, OrleansBondUtils'
function AddOrGetElement(
[OutputType([System.Xml.XmlElement])]
@@ -9,7 +9,7 @@ function AddOrGetElement(
[Parameter(Mandatory=$true)]
[string]$name,
[Parameter(Mandatory=$true)]
- [System.Xml.XmlNamespaceManager]$namespaceManager
+ [System.Xml.XmlNamespaceManager]$namespaceManager
)
{
$node = $xml.ChildNodes | where { $_.Name -eq $name }
@@ -51,7 +51,7 @@ function RegisterSerializer(
$bondTypeProvider = $providersnode.Provider | where { $_.type -eq $type }
- if ($bondTypeProvider -eq $null)
+ if ($bondTypeProvider -eq $null)
{
$provider = AddOrGetElement -xml $providersNode -name "Provider" -namespaceManager $namespaceManager
$typeAttribute = $fileXml.CreateAttribute("type");
diff --git a/src/NuGet/BondSerializerUninstall.ps1 b/src/NuGet/BondSerializerUninstall.ps1
index ec8103351b..30d277d61a 100644
--- a/src/NuGet/BondSerializerUninstall.ps1
+++ b/src/NuGet/BondSerializerUninstall.ps1
@@ -1,6 +1,6 @@
param($installPath, $toolsPath, $package, $project)
-$bondSerializerTypeName = 'Orleans.Serialization.BondSerializer, BondSerializer'
+$bondSerializerTypeName = 'Orleans.Serialization.BondSerializer, OrleansBondUtils'
function UnregisterSerializer(
[Parameter(Mandatory=$true)]
diff --git a/src/NuGet/Microsoft.Orleans.OrleansAzureUtils.nuspec b/src/NuGet/Microsoft.Orleans.OrleansAzureUtils.nuspec
index d1429f8a67..baa6338602 100644
--- a/src/NuGet/Microsoft.Orleans.OrleansAzureUtils.nuspec
+++ b/src/NuGet/Microsoft.Orleans.OrleansAzureUtils.nuspec
@@ -22,8 +22,7 @@
-
-
+
diff --git a/src/Orleans/CodeGeneration/TypeFormattingOptions.cs b/src/Orleans/CodeGeneration/TypeFormattingOptions.cs
new file mode 100644
index 0000000000..65d977f70b
--- /dev/null
+++ b/src/Orleans/CodeGeneration/TypeFormattingOptions.cs
@@ -0,0 +1,135 @@
+namespace Orleans.Runtime
+{
+ using System;
+
+ ///
+ /// Options for formatting type names.
+ ///
+ public class TypeFormattingOptions : IEquatable
+ {
+ public TypeFormattingOptions(
+ string nameSuffix = null,
+ bool includeNamespace = true,
+ bool includeGenericParameters = true,
+ bool includeTypeParameters = true,
+ char nestedClassSeparator = '.',
+ bool includeGlobal = true)
+ {
+
+ this.NameSuffix = nameSuffix;
+ this.IncludeNamespace = includeNamespace;
+ this.IncludeGenericTypeParameters = includeGenericParameters;
+ this.IncludeTypeParameters = includeTypeParameters;
+ this.NestedTypeSeparator = nestedClassSeparator;
+ this.IncludeGlobal = includeGlobal;
+ }
+
+ ///
+ /// Gets a value indicating whether or not to include the fully-qualified namespace of the class in the result.
+ ///
+ public bool IncludeNamespace { get; private set; }
+
+ ///
+ /// Gets a value indicating whether or not to include concrete type parameters in the result.
+ ///
+ public bool IncludeTypeParameters { get; private set; }
+
+ ///
+ /// Gets a value indicating whether or not to include generic type parameters in the result.
+ ///
+ public bool IncludeGenericTypeParameters { get; private set; }
+
+ ///
+ /// Gets the separator used between declaring types and their declared types.
+ ///
+ public char NestedTypeSeparator { get; private set; }
+
+ ///
+ /// Gets the name to append to the formatted name, before any type parameters.
+ ///
+ public string NameSuffix { get; private set; }
+
+ ///
+ /// Gets a value indicating whether or not to include the global namespace qualifier.
+ ///
+ public bool IncludeGlobal { get; private set; }
+
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// if the specified object is equal to the current object; otherwise, .
+ ///
+ public bool Equals(TypeFormattingOptions other)
+ {
+ if (ReferenceEquals(null, other))
+ {
+ return false;
+ }
+ if (ReferenceEquals(this, other))
+ {
+ return true;
+ }
+ return this.IncludeNamespace == other.IncludeNamespace
+ && this.IncludeTypeParameters == other.IncludeTypeParameters
+ && this.IncludeGenericTypeParameters == other.IncludeGenericTypeParameters
+ && this.NestedTypeSeparator == other.NestedTypeSeparator
+ && string.Equals(this.NameSuffix, other.NameSuffix) && this.IncludeGlobal == other.IncludeGlobal;
+ }
+
+ ///
+ /// Determines whether the specified object is equal to the current object.
+ ///
+ /// The object to compare with the current object.
+ ///
+ /// if the specified object is equal to the current object; otherwise, .
+ ///
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj))
+ {
+ return false;
+ }
+ if (ReferenceEquals(this, obj))
+ {
+ return true;
+ }
+ if (obj.GetType() != this.GetType())
+ {
+ return false;
+ }
+ return Equals((TypeFormattingOptions)obj);
+ }
+
+ ///
+ /// Serves as a hash function for a particular type.
+ ///
+ ///
+ /// A hash code for the current object.
+ ///
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = this.IncludeNamespace.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.IncludeTypeParameters.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.IncludeGenericTypeParameters.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.NestedTypeSeparator.GetHashCode();
+ hashCode = (hashCode * 397) ^ (this.NameSuffix != null ? this.NameSuffix.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ this.IncludeGlobal.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ public static bool operator ==(TypeFormattingOptions left, TypeFormattingOptions right)
+ {
+ return Equals(left, right);
+ }
+
+ public static bool operator !=(TypeFormattingOptions left, TypeFormattingOptions right)
+ {
+ return !Equals(left, right);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orleans/CodeGeneration/TypeUtils.cs b/src/Orleans/CodeGeneration/TypeUtils.cs
index 9aa060a40c..2c70c55137 100644
--- a/src/Orleans/CodeGeneration/TypeUtils.cs
+++ b/src/Orleans/CodeGeneration/TypeUtils.cs
@@ -42,7 +42,7 @@ internal static class TypeUtils
///
private static readonly string OrleansCoreAssembly = typeof(IGrain).Assembly.GetName().FullName;
- private static readonly ConcurrentDictionary, string> ParseableNameCache = new ConcurrentDictionary, string>();
+ private static readonly ConcurrentDictionary, string> ParseableNameCache = new ConcurrentDictionary, string>();
private static readonly ConcurrentDictionary, List> ReferencedTypes = new ConcurrentDictionary, List>();
@@ -60,8 +60,15 @@ public static string GetSimpleTypeName(Type t, Func fullName=null, L
if (typeInfo.IsNestedPublic || typeInfo.IsNestedPrivate)
{
if (typeInfo.DeclaringType.IsGenericType)
- return GetTemplatedName(GetUntemplatedTypeName(typeInfo.DeclaringType.Name), typeInfo.DeclaringType, typeInfo.GetGenericArguments(), _ => true, language) + "." + GetUntemplatedTypeName(typeInfo.Name);
-
+ {
+ return GetTemplatedName(
+ GetUntemplatedTypeName(typeInfo.DeclaringType.Name),
+ typeInfo.DeclaringType,
+ typeInfo.GetGenericArguments(),
+ _ => true,
+ language) + "." + GetUntemplatedTypeName(typeInfo.Name);
+ }
+
return GetTemplatedName(typeInfo.DeclaringType, language: language) + "." + GetUntemplatedTypeName(typeInfo.Name);
}
@@ -618,25 +625,25 @@ public static string GetUnadornedMethodName(this MethodInfo method)
///
/// A string representation of the .
///
- public static string GetParseableName(this Type type, string nameSuffix = null, bool includeNamespace = true, bool includeGenericParameters = true)
+ public static string GetParseableName(this Type type, TypeFormattingOptions options = null)
{
- return
- ParseableNameCache.GetOrAdd(
- Tuple.Create(type, nameSuffix, includeNamespace, includeGenericParameters),
- _ =>
- {
- var builder = new StringBuilder();
- var typeInfo = type.GetTypeInfo();
- GetParseableName(
- type,
- nameSuffix ?? string.Empty,
- builder,
- new Queue(
- typeInfo.IsGenericTypeDefinition ? typeInfo.GetGenericArguments() : typeInfo.GenericTypeArguments),
- includeNamespace,
- includeGenericParameters);
- return builder.ToString();
- });
+ options = options ?? new TypeFormattingOptions();
+ return ParseableNameCache.GetOrAdd(
+ Tuple.Create(type, options),
+ _ =>
+ {
+ var builder = new StringBuilder();
+ var typeInfo = type.GetTypeInfo();
+ GetParseableName(
+ type,
+ builder,
+ new Queue(
+ typeInfo.IsGenericTypeDefinition
+ ? typeInfo.GetGenericArguments()
+ : typeInfo.GenericTypeArguments),
+ options);
+ return builder.ToString();
+ });
}
///
@@ -651,33 +658,28 @@ public static string GetParseableName(this Type type, string nameSuffix = null,
///
/// The type arguments of .
///
- ///
- /// A value indicating whether or not to include the namespace name.
+ ///
+ /// The type formatting options.
///
private static void GetParseableName(
Type type,
- string nameSuffix,
StringBuilder builder,
Queue typeArguments,
- bool includeNamespace = true,
- bool includeGenericParameters = true)
+ TypeFormattingOptions options)
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsArray)
{
builder.AppendFormat(
"{0}[{1}]",
- typeInfo.GetElementType()
- .GetParseableName(
- includeNamespace: includeNamespace,
- includeGenericParameters: includeGenericParameters),
+ typeInfo.GetElementType().GetParseableName(options),
string.Concat(Enumerable.Range(0, type.GetArrayRank() - 1).Select(_ => ',')));
return;
}
if (typeInfo.IsGenericParameter)
{
- if (includeGenericParameters)
+ if (options.IncludeGenericTypeParameters)
{
builder.Append(typeInfo.GetUnadornedTypeName());
}
@@ -688,57 +690,63 @@ private static void GetParseableName(
if (typeInfo.DeclaringType != null)
{
// This is not the root type.
- GetParseableName(typeInfo.DeclaringType, string.Empty, builder, typeArguments, includeNamespace, includeGenericParameters);
- builder.Append('.');
+ GetParseableName(typeInfo.DeclaringType, builder, typeArguments, options);
+ builder.Append(options.NestedTypeSeparator);
}
- else if (!string.IsNullOrWhiteSpace(type.Namespace) && includeNamespace)
+ else if (!string.IsNullOrWhiteSpace(type.Namespace) && options.IncludeNamespace)
{
- // This is the root type.
- builder.AppendFormat("global::{0}.", type.Namespace);
+ // 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.AppendFormat("global::");
+ }
+
+ builder.AppendFormat("{0}{1}", namespaceName, options.NestedTypeSeparator);
}
if (typeInfo.IsConstructedGenericType)
{
// Get the unadorned name, the generic parameters, and add them together.
- var unadornedTypeName = typeInfo.GetUnadornedTypeName() + nameSuffix;
+ var unadornedTypeName = typeInfo.GetUnadornedTypeName() + options.NameSuffix;
builder.Append(EscapeIdentifier(unadornedTypeName));
var generics =
Enumerable.Range(0, Math.Min(typeInfo.GetGenericArguments().Count(), typeArguments.Count))
.Select(_ => typeArguments.Dequeue())
.ToList();
- if (generics.Count > 0)
+ if (generics.Count > 0 && options.IncludeTypeParameters)
{
var genericParameters = string.Join(
",",
- generics.Select(
- generic =>
- GetParseableName(
- generic,
- includeNamespace: includeNamespace,
- includeGenericParameters: includeGenericParameters)));
+ generics.Select(generic => GetParseableName(generic, options)));
builder.AppendFormat("<{0}>", genericParameters);
}
}
else if (typeInfo.IsGenericTypeDefinition)
{
// Get the unadorned name, the generic parameters, and add them together.
- var unadornedTypeName = type.GetUnadornedTypeName() + nameSuffix;
+ var unadornedTypeName = type.GetUnadornedTypeName() + options.NameSuffix;
builder.Append(EscapeIdentifier(unadornedTypeName));
var generics =
Enumerable.Range(0, Math.Min(type.GetGenericArguments().Count(), typeArguments.Count))
.Select(_ => typeArguments.Dequeue())
.ToList();
- if (generics.Count > 0)
+ if (generics.Count > 0 && options.IncludeTypeParameters)
{
var genericParameters = string.Join(
",",
- generics.Select(_ => includeGenericParameters ? _.ToString() : string.Empty));
+ generics.Select(_ => options.IncludeGenericTypeParameters ? _.ToString() : string.Empty));
builder.AppendFormat("<{0}>", genericParameters);
}
}
else
{
- builder.Append(EscapeIdentifier(type.GetUnadornedTypeName() + nameSuffix));
+ builder.Append(EscapeIdentifier(type.GetUnadornedTypeName() + options.NameSuffix));
}
}
diff --git a/src/Orleans/Configuration/ClusterConfiguration.cs b/src/Orleans/Configuration/ClusterConfiguration.cs
index e4d1ebc225..c64c813d16 100644
--- a/src/Orleans/Configuration/ClusterConfiguration.cs
+++ b/src/Orleans/Configuration/ClusterConfiguration.cs
@@ -535,7 +535,7 @@ internal static IPAddress GetLocalIPAddress(AddressFamily family = AddressFamily
if (!string.IsNullOrWhiteSpace(interfaceName) &&
!netInterface.Name.StartsWith(interfaceName, StringComparison.Ordinal)) continue;
- bool isLoopbackInterface = (i == NetworkInterface.LoopbackInterfaceIndex);
+ bool isLoopbackInterface = (netInterface.NetworkInterfaceType == NetworkInterfaceType.Loopback);
// get list of all unicast IPs from current interface
UnicastIPAddressInformationCollection ipAddresses = netInterface.GetIPProperties().UnicastAddresses;
diff --git a/src/Orleans/Core/GrainAttributes.cs b/src/Orleans/Core/GrainAttributes.cs
index 1dc12df6e8..2a81fb3c19 100644
--- a/src/Orleans/Core/GrainAttributes.cs
+++ b/src/Orleans/Core/GrainAttributes.cs
@@ -302,8 +302,8 @@ public static FactoryTypes CollectFactoryTypesSpecified()
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
public sealed class ImplicitStreamSubscriptionAttribute : Attribute
{
- internal string Namespace { get; private set; }
-
+ public string Namespace { get; private set; }
+
// We have not yet come to an agreement whether the provider should be specified as well.
public ImplicitStreamSubscriptionAttribute(string streamNamespace)
{
diff --git a/src/Orleans/Core/GrainClient.cs b/src/Orleans/Core/GrainClient.cs
index 353b036f44..98167bc090 100644
--- a/src/Orleans/Core/GrainClient.cs
+++ b/src/Orleans/Core/GrainClient.cs
@@ -35,6 +35,8 @@ The above copyright notice and this permission notice shall be included in all c
namespace Orleans
{
+ using System.Runtime.ExceptionServices;
+
///
/// Client runtime for connecting to Orleans system
///
@@ -225,9 +227,24 @@ private static void InternalInitialize(ClientConfiguration config, OutsideRuntim
tcs.SetException(exc); // Break promise
}
};
+
// Queue Init call to thread pool thread
ThreadPool.QueueUserWorkItem(doInit, null);
- CurrentConfig = tcs.Task.Result; // Wait for Init to finish
+ try
+ {
+ CurrentConfig = tcs.Task.Result; // Wait for Init to finish
+ }
+ catch (AggregateException ae)
+ {
+ // Flatten the aggregate exception, which can be deeply nested.
+ ae = ae.Flatten();
+
+ // If there is just one exception in the aggregate exception, throw that, otherwise throw the entire
+ // flattened aggregate exception.
+ var innerExceptions = ae.InnerExceptions;
+ var exceptionToThrow = innerExceptions.Count == 1 ? innerExceptions[0] : ae;
+ ExceptionDispatchInfo.Capture(exceptionToThrow).Throw();
+ }
}
///
diff --git a/src/Orleans/Orleans.csproj b/src/Orleans/Orleans.csproj
index 79f29a7f82..26ce350bca 100644
--- a/src/Orleans/Orleans.csproj
+++ b/src/Orleans/Orleans.csproj
@@ -89,6 +89,7 @@
+
diff --git a/src/Orleans/Serialization/OrleansJsonSerializer.cs b/src/Orleans/Serialization/OrleansJsonSerializer.cs
index 5160047467..31850993b9 100644
--- a/src/Orleans/Serialization/OrleansJsonSerializer.cs
+++ b/src/Orleans/Serialization/OrleansJsonSerializer.cs
@@ -1,10 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Net;
-using System.Runtime.Serialization.Formatters.Binary;
-using System.Text;
-using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Orleans.Runtime;
@@ -34,6 +29,7 @@ static OrleansJsonSerializer()
settings.Converters.Add(new GrainIdConverter());
settings.Converters.Add(new SiloAddressConverter());
settings.Converters.Add(new UniqueKeyConverter());
+ settings.Converters.Add(new GuidJsonConverter());
}
///
@@ -235,5 +231,93 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
}
}
+ ///
+ /// JSON converter for .
+ ///
+ class GuidJsonConverter : JsonConverter
+ {
+ ///
+ /// Gets a value indicating whether this can read JSON.
+ ///
+ /// if this can read JSON; otherwise, .
+ ///
+ public override bool CanRead { get { return true; } }
+
+ ///
+ /// Gets a value indicating whether this can write JSON.
+ ///
+ /// if this can write JSON; otherwise, .
+ ///
+ public override bool CanWrite { get { return true; } }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ ///
+ /// Kind of the object.
+ ///
+ ///
+ /// if this instance can convert the specified object type; otherwise,
+ /// .
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType.IsAssignableFrom(typeof(Guid)) || objectType.IsAssignableFrom(typeof(Guid?));
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ ///
+ /// The to write to.
+ ///
+ ///
+ /// The value.
+ ///
+ ///
+ /// The calling serializer.
+ ///
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteValue(default(string));
+ }
+ else if (value is Guid)
+ {
+ var guid = (Guid)value;
+ writer.WriteValue(guid.ToString("N"));
+ }
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ ///
+ /// The to read from.
+ ///
+ ///
+ /// Kind of the object.
+ ///
+ ///
+ /// The existing value of object being read.
+ ///
+ ///
+ /// The calling serializer.
+ ///
+ ///
+ /// The object value.
+ ///
+ public override object ReadJson(
+ JsonReader reader,
+ Type objectType,
+ object existingValue,
+ JsonSerializer serializer)
+ {
+ var str = reader.Value as string;
+ return str != null ? Guid.Parse(str) : default(Guid);
+ }
+ }
+
#endregion
}
diff --git a/src/Orleans/Serialization/TypeUtilities.cs b/src/Orleans/Serialization/TypeUtilities.cs
index f50ef42580..376860705d 100644
--- a/src/Orleans/Serialization/TypeUtilities.cs
+++ b/src/Orleans/Serialization/TypeUtilities.cs
@@ -238,11 +238,11 @@ public static bool IsTypeIsInaccessibleForSerialization(Type type, Module fromMo
return true;
}
}
-
- return IsTypeIsInaccessibleForSerialization(
- typeInfo.GetGenericTypeDefinition(),
- fromModule,
- fromAssembly);
+
+ if (IsTypeIsInaccessibleForSerialization(typeInfo.GetGenericTypeDefinition(), fromModule, fromAssembly))
+ {
+ return true;
+ }
}
if ((typeInfo.IsNotPublic || !typeInfo.IsVisible) && !AreInternalsVisibleTo(typeInfo.Assembly, fromAssembly))
@@ -260,14 +260,25 @@ public static bool IsTypeIsInaccessibleForSerialization(Type type, Module fromMo
}
}
+ // For arrays, check the element type.
if (typeInfo.IsArray)
{
- return IsTypeIsInaccessibleForSerialization(typeInfo.GetElementType(), fromModule, fromAssembly);
+ if (IsTypeIsInaccessibleForSerialization(typeInfo.GetElementType(), fromModule, fromAssembly))
+ {
+ return true;
+ }
+ }
+
+ // For nested types, check that the declaring type is accessible.
+ if (typeInfo.IsNested)
+ {
+ if (IsTypeIsInaccessibleForSerialization(typeInfo.DeclaringType, fromModule, fromAssembly))
+ {
+ return true;
+ }
}
- var result = typeInfo.IsNestedPrivate || typeInfo.IsNestedFamily || type.IsPointer;
-
- return result;
+ return typeInfo.IsNestedPrivate || typeInfo.IsNestedFamily || type.IsPointer;
}
///
@@ -289,12 +300,7 @@ private static bool AreInternalsVisibleTo(Assembly fromAssembly, Assembly toAsse
// Check InternalsVisibleTo attributes on the from-assembly, pointing to the to-assembly.
var serializationAssemblyName = toAssembly.GetName().FullName;
var internalsVisibleTo = fromAssembly.GetCustomAttributes();
- if (internalsVisibleTo.All(_ => _.AssemblyName != serializationAssemblyName))
- {
- return true;
- }
-
- return false;
+ return internalsVisibleTo.Any(_ => _.AssemblyName == serializationAssemblyName);
}
}
}
\ No newline at end of file
diff --git a/src/Orleans/Streams/Internal/StreamConsumer.cs b/src/Orleans/Streams/Internal/StreamConsumer.cs
index 99cef24ae1..e00ca4eb60 100644
--- a/src/Orleans/Streams/Internal/StreamConsumer.cs
+++ b/src/Orleans/Streams/Internal/StreamConsumer.cs
@@ -88,9 +88,30 @@ public async Task> SubscribeAsync(
pubSub, myGrainReference, token);
GuidId subscriptionId = pubSub.CreateSubscriptionId(stream.StreamId, myGrainReference);
- await pubSub.RegisterConsumer(subscriptionId, stream.StreamId, streamProviderName, myGrainReference, filterWrapper);
- return myExtension.SetObserver(subscriptionId, stream, observer, token, filterWrapper);
+ // Optimistic Concurrency:
+ // In general, we should first register the subsription with the pubsub (pubSub.RegisterConsumer)
+ // and only if it succeeds store it locally (myExtension.SetObserver).
+ // Basicaly, those 2 operations should be done as one atomic transaction - either both or none and isolated from concurrent reads.
+ // BUT: there is a distributed race here: the first msg may arrive before the call is awaited
+ // (since the pubsub notifies the producer that may immideately produce)
+ // and will thus not find the subriptionHandle in the extension, basically violating "isolation".
+ // Therefore, we employ Optimistic Concurrency Control here to guarantee isolation:
+ // we optimisticaly store subscriptionId in the handle first before calling pubSub.RegisterConsumer
+ // and undo it in the case of failure.
+ // There is no problem with that we call myExtension.SetObserver too early before the handle is registered in pub sub,
+ // since this subscriptionId is unique (random Guid) and no one knows it anyway, unless successfully subscribed in the pubsub.
+ var subriptionHandle = myExtension.SetObserver(subscriptionId, stream, observer, token, filterWrapper);
+ try
+ {
+ await pubSub.RegisterConsumer(subscriptionId, stream.StreamId, streamProviderName, myGrainReference, filterWrapper);
+ return subriptionHandle;
+ } catch(Exception)
+ {
+ // Undo the previous call myExtension.SetObserver.
+ myExtension.RemoveObserver(subscriptionId);
+ throw;
+ }
}
public async Task> ResumeAsync(
diff --git a/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProducer.cs b/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProducer.cs
index 3375a0f608..dd78b760a6 100644
--- a/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProducer.cs
+++ b/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProducer.cs
@@ -51,12 +51,13 @@ internal class SimpleMessageStreamProducer : IInternalAsyncBatchObserver
internal bool IsRewindable { get; private set; }
- internal SimpleMessageStreamProducer(StreamImpl stream, string streamProviderName, IStreamProviderRuntime providerUtilities, bool fireAndForgetDelivery, bool isRewindable)
+ internal SimpleMessageStreamProducer(StreamImpl stream, string streamProviderName,
+ IStreamProviderRuntime providerUtilities, bool fireAndForgetDelivery, IStreamPubSub pubSub, bool isRewindable)
{
this.stream = stream;
this.streamProviderName = streamProviderName;
providerRuntime = providerUtilities;
- pubSub = providerRuntime.PubSub(SimpleMessageStreamProvider.DEFAULT_STREAM_PUBSUB_TYPE);
+ this.pubSub = pubSub;
connectedToRendezvous = false;
this.fireAndForgetDelivery = fireAndForgetDelivery;
IsRewindable = isRewindable;
diff --git a/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProvider.cs b/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProvider.cs
index 6477d8214d..cf5ecec74b 100644
--- a/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProvider.cs
+++ b/src/Orleans/Streams/SimpleMessageStream/SimpleMessageStreamProvider.cs
@@ -35,8 +35,11 @@ public class SimpleMessageStreamProvider : IInternalStreamProvider
private Logger logger;
private IStreamProviderRuntime providerRuntime;
private bool fireAndForgetDelivery;
- internal const string FIRE_AND_FORGET_DELIVERY = "FireAndForgetDelivery";
- internal const StreamPubSubType DEFAULT_STREAM_PUBSUB_TYPE = StreamPubSubType.ExplicitGrainBasedAndImplicit;
+ private StreamPubSubType pubSubType;
+
+ private const string STREAM_PUBSUB_TYPE = "PubSubType";
+ internal const string FIRE_AND_FORGET_DELIVERY = "FireAndForgetDelivery";
+ private const StreamPubSubType DEFAULT_STREAM_PUBSUB_TYPE = StreamPubSubType.ExplicitGrainBasedAndImplicit;
public bool IsRewindable { get { return false; } }
@@ -47,8 +50,14 @@ public Task Init(string name, IProviderRuntime providerUtilitiesManager, IProvid
string fireAndForgetDeliveryStr;
fireAndForgetDelivery = config.Properties.TryGetValue(FIRE_AND_FORGET_DELIVERY, out fireAndForgetDeliveryStr) && Boolean.Parse(fireAndForgetDeliveryStr);
+ string pubSubTypeString;
+ pubSubType = !config.Properties.TryGetValue(STREAM_PUBSUB_TYPE, out pubSubTypeString)
+ ? DEFAULT_STREAM_PUBSUB_TYPE
+ : (StreamPubSubType)Enum.Parse(typeof(StreamPubSubType), pubSubTypeString);
+
logger = providerRuntime.GetLogger(this.GetType().Name);
- logger.Info("Initialized SimpleMessageStreamProvider with name {0} and with property FireAndForgetDelivery: {1}.", Name, fireAndForgetDelivery);
+ logger.Info("Initialized SimpleMessageStreamProvider with name {0} and with property FireAndForgetDelivery: {1} " +
+ "and PubSubType: {2}", Name, fireAndForgetDelivery, pubSubType);
return TaskDone.Done;
}
@@ -72,7 +81,8 @@ public IAsyncStream GetStream(Guid id, string streamNamespace)
IInternalAsyncBatchObserver IInternalStreamProvider.GetProducerInterface(IAsyncStream stream)
{
- return new SimpleMessageStreamProducer((StreamImpl)stream, Name, providerRuntime, fireAndForgetDelivery, IsRewindable);
+ return new SimpleMessageStreamProducer((StreamImpl)stream, Name, providerRuntime,
+ fireAndForgetDelivery, providerRuntime.PubSub(pubSubType), IsRewindable);
}
IInternalAsyncObservable IInternalStreamProvider.GetConsumerInterface(IAsyncStream streamId)
@@ -82,7 +92,8 @@ IInternalAsyncObservable IInternalStreamProvider.GetConsumerInterface(IAsy
private IInternalAsyncObservable GetConsumerInterfaceImpl(IAsyncStream stream)
{
- return new StreamConsumer((StreamImpl)stream, Name, providerRuntime, providerRuntime.PubSub(DEFAULT_STREAM_PUBSUB_TYPE), IsRewindable);
+ return new StreamConsumer((StreamImpl)stream, Name, providerRuntime,
+ providerRuntime.PubSub(pubSubType), IsRewindable);
}
}
}
diff --git a/src/Orleans/Telemetry/Consumers/ConsoleTelemetryConsumer.cs b/src/Orleans/Telemetry/Consumers/ConsoleTelemetryConsumer.cs
index 039ddf2fa9..1a5b3bd638 100644
--- a/src/Orleans/Telemetry/Consumers/ConsoleTelemetryConsumer.cs
+++ b/src/Orleans/Telemetry/Consumers/ConsoleTelemetryConsumer.cs
@@ -40,9 +40,10 @@ public void TrackTrace(string message, Severity severity)
break;
case Severity.Off:
return;
+ default:
+ TrackTrace(message);
+ break;
}
-
- TrackTrace(message);
}
public void TrackTrace(string message, Severity severityLevel, IDictionary properties = null)
diff --git a/src/OrleansAzureUtils/OrleansAzureUtils.csproj b/src/OrleansAzureUtils/OrleansAzureUtils.csproj
index ef060396c6..cdff78a1ec 100644
--- a/src/OrleansAzureUtils/OrleansAzureUtils.csproj
+++ b/src/OrleansAzureUtils/OrleansAzureUtils.csproj
@@ -60,7 +60,7 @@
True
- $(SolutionDir)packages\WindowsAzure.Storage.5.0.0\lib\net40\Microsoft.WindowsAzure.Storage.dll
+ $(SolutionDir)packages\WindowsAzure.Storage.5.0.2\lib\net40\Microsoft.WindowsAzure.Storage.dllTrue
diff --git a/src/OrleansAzureUtils/packages.config b/src/OrleansAzureUtils/packages.config
index dae4581a1d..eb7cc0d85d 100644
--- a/src/OrleansAzureUtils/packages.config
+++ b/src/OrleansAzureUtils/packages.config
@@ -6,5 +6,5 @@
-
+
\ No newline at end of file
diff --git a/src/OrleansCodeGenerator/GrainMethodInvokerGenerator.cs b/src/OrleansCodeGenerator/GrainMethodInvokerGenerator.cs
index 5fe79d0825..e7015380dc 100644
--- a/src/OrleansCodeGenerator/GrainMethodInvokerGenerator.cs
+++ b/src/OrleansCodeGenerator/GrainMethodInvokerGenerator.cs
@@ -31,6 +31,7 @@ namespace Orleans.CodeGenerator
using System.Reflection;
using System.Threading.Tasks;
+ using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -105,6 +106,7 @@ internal static TypeDeclarationSyntax GenerateClass(Type grainType)
CodeGeneratorCommon.ClassPrefix + TypeUtils.GetSuitableClassName(grainType) + ClassSuffix)
.AddModifiers(SF.Token(SyntaxKind.InternalKeyword))
.AddBaseListTypes(baseTypes.ToArray())
+ .AddConstraintClauses(grainType.GetTypeConstraintSyntax())
.AddMembers(members.ToArray())
.AddAttributeLists(SF.AttributeList().AddAttributes(attributes.ToArray()));
if (genericTypes.Length > 0)
diff --git a/src/OrleansCodeGenerator/GrainReferenceGenerator.cs b/src/OrleansCodeGenerator/GrainReferenceGenerator.cs
index f349dda0df..35faf81e61 100644
--- a/src/OrleansCodeGenerator/GrainReferenceGenerator.cs
+++ b/src/OrleansCodeGenerator/GrainReferenceGenerator.cs
@@ -98,6 +98,7 @@ internal static TypeDeclarationSyntax GenerateClass(Type grainType, Action
.AddBaseListTypes(
SF.SimpleBaseType(typeof(GrainReference).GetTypeSyntax()),
SF.SimpleBaseType(grainType.GetTypeSyntax()))
+ .AddConstraintClauses(grainType.GetTypeConstraintSyntax())
.AddMembers(GenerateConstructors(className))
.AddMembers(
GenerateInterfaceIdProperty(grainType),
diff --git a/src/OrleansCodeGenerator/RoslynCodeGenerator.cs b/src/OrleansCodeGenerator/RoslynCodeGenerator.cs
index 3e2cd854b9..fbf0c63d16 100644
--- a/src/OrleansCodeGenerator/RoslynCodeGenerator.cs
+++ b/src/OrleansCodeGenerator/RoslynCodeGenerator.cs
@@ -1,26 +1,4 @@
-/*
-Project Orleans Cloud Service SDK ver. 1.0
-
-Copyright (c) Microsoft Corporation
-
-All rights reserved.
-
-MIT License
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
-associated documentation files (the ""Software""), to deal in the Software without restriction,
-including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
+
namespace Orleans.CodeGenerator
{
using System;
@@ -470,6 +448,24 @@ private static void ConsiderType(
}
}
+ private static void RecordType(Type type, Module module, Assembly targetAssembly, ISet includedTypes)
+ {
+ if (SerializerGenerationManager.RecordTypeToGenerate(type, module, targetAssembly))
+ includedTypes.Add(type);
+ }
+
+ private static bool IsPersistentGrain(TypeInfo typeInfo, out Type stateType)
+ {
+ stateType = null;
+
+ if (typeInfo.BaseType == null) return false;
+ if (!typeInfo.BaseType.IsGenericType) return false;
+ if (typeof(Grain<>) != typeInfo.BaseType.GetGenericTypeDefinition()) return false;
+
+ stateType = typeInfo.BaseType.GetGenericArguments()[0];
+ return true;
+ }
+
///
/// Returns a value indicating whether or not code should be generated for the provided assembly.
///
diff --git a/src/OrleansCodeGenerator/SerializerGenerationManager.cs b/src/OrleansCodeGenerator/SerializerGenerationManager.cs
index 0d62da95a2..6b10373c97 100644
--- a/src/OrleansCodeGenerator/SerializerGenerationManager.cs
+++ b/src/OrleansCodeGenerator/SerializerGenerationManager.cs
@@ -75,7 +75,8 @@ internal static bool RecordTypeToGenerate(Type t, Module module, Assembly target
var typeInfo = t.GetTypeInfo();
if (typeInfo.IsGenericParameter || ProcessedTypes.Contains(t) || TypesToProcess.Contains(t)
- || typeof(Exception).GetTypeInfo().IsAssignableFrom(t)) return false;
+ || typeof(Exception).GetTypeInfo().IsAssignableFrom(t)
+ || typeof(Delegate).GetTypeInfo().IsAssignableFrom(t)) return false;
if (typeInfo.IsArray)
{
@@ -83,7 +84,7 @@ internal static bool RecordTypeToGenerate(Type t, Module module, Assembly target
return false;
}
- if (typeInfo.IsNestedPublic || typeInfo.IsNestedFamily || typeInfo.IsNestedPrivate)
+ if (typeInfo.IsNestedFamily || typeInfo.IsNestedPrivate)
{
Log.Warn(
ErrorCode.CodeGenIgnoringTypes,
diff --git a/src/OrleansCodeGenerator/SerializerGenerator.cs b/src/OrleansCodeGenerator/SerializerGenerator.cs
index fce9cb67a2..f4b978c9fb 100644
--- a/src/OrleansCodeGenerator/SerializerGenerator.cs
+++ b/src/OrleansCodeGenerator/SerializerGenerator.cs
@@ -48,6 +48,13 @@ namespace Orleans.CodeGenerator
///
public static class SerializerGenerator
{
+ private static readonly TypeFormattingOptions GeneratedTypeNameOptions = new TypeFormattingOptions(
+ ClassSuffix,
+ includeGenericParameters: false,
+ includeTypeParameters: false,
+ nestedClassSeparator: '_',
+ includeGlobal: false);
+
///
/// The suffix appended to the name of generated classes.
///
@@ -84,9 +91,7 @@ internal static IEnumerable GenerateClass(Type type, Acti
SF.AttributeArgument(SF.TypeOfExpression(type.GetTypeSyntax(includeGenericParameters: false))))
};
- var className = CodeGeneratorCommon.ClassPrefix
- + TypeUtils.GetSimpleTypeName(type, _ => !_.IsGenericParameter).Replace('.', '_')
- + ClassSuffix;
+ var className = CodeGeneratorCommon.ClassPrefix + type.GetParseableName(GeneratedTypeNameOptions);
var fields = GetFields(type);
// Mark each field type for generation
@@ -567,7 +572,7 @@ private static List GetFields(Type type)
{
var result =
type.GetAllFields()
- .Where(field => field.GetCustomAttribute() == null)
+ .Where(field => !field.IsNotSerialized)
.Select((info, i) => new FieldInfoMember { FieldInfo = info, FieldNumber = i })
.ToList();
result.Sort(FieldInfoMember.Comparer.Instance);
@@ -624,26 +629,25 @@ public string SetterFieldName
}
}
-
///
- /// Gets a value indicating whether or not this field represents a property with an accessible getter.
+ /// Gets a value indicating whether or not this field represents a property with an accessible, non-obsolete getter.
///
public bool IsGettableProperty
{
get
{
- return this.PropertyInfo != null && this.PropertyInfo.GetGetMethod() != null;
+ return this.PropertyInfo != null && this.PropertyInfo.GetGetMethod() != null && !this.IsObsolete;
}
}
///
- /// Gets a value indicating whether or not this field represents a property with an accessible setter.
+ /// Gets a value indicating whether or not this field represents a property with an accessible, non-obsolete setter.
///
public bool IsSettableProperty
{
get
{
- return this.PropertyInfo != null && this.PropertyInfo.GetSetMethod() != null;
+ return this.PropertyInfo != null && this.PropertyInfo.GetSetMethod() != null && !this.IsObsolete;
}
}
@@ -683,35 +687,48 @@ private PropertyInfo PropertyInfo
}
///
- /// Returns syntax for retrieving the value of this field.
+ /// Gets a value indicating whether or not this field is obsolete.
+ ///
+ private bool IsObsolete
+ {
+ get
+ {
+ var obsoleteAttr = this.FieldInfo.GetCustomAttribute();
+
+ // Get the attribute from the property, if present.
+ if (this.property != null && obsoleteAttr == null)
+ {
+ obsoleteAttr = this.property.GetCustomAttribute();
+ }
+
+ return obsoleteAttr != null;
+ }
+ }
+
+ ///
+ /// Returns syntax for retrieving the value of this field, deep copying it if neccessary.
///
/// The instance of the containing type.
/// Whether or not to ensure that no copy of the field is made.
/// Syntax for retrieving the value of this field.
public ExpressionSyntax GetGetter(ExpressionSyntax instance, bool forceAvoidCopy = false)
{
- var typeSyntax = this.FieldInfo.FieldType.GetTypeSyntax();
- var getFieldExpression =
- SF.InvocationExpression(SF.IdentifierName(this.GetterFieldName))
- .AddArgumentListArguments(SF.Argument(instance));
-
- // If the field is the backing field for an auto-property, try to use the property directly.
- if (this.PropertyInfo != null && this.PropertyInfo.GetGetMethod() != null)
- {
- return instance.Member(this.PropertyInfo.Name);
- }
+ // Retrieve the value of the field.
+ var getValueExpression = this.GetValueExpression(instance);
+ // Avoid deep-copying the field if possible.
if (forceAvoidCopy || this.FieldInfo.FieldType.IsOrleansShallowCopyable())
{
- // Shallow-copy the field.
- return getFieldExpression;
+ // Return the value without deep-copying it.
+ return getValueExpression;
}
- // Deep-copy the field.
+ // Deep-copy the value.
Expression deepCopyInner = () => SerializationManager.DeepCopyInner(default(object));
+ var typeSyntax = this.FieldInfo.FieldType.GetTypeSyntax();
return SF.CastExpression(
typeSyntax,
- deepCopyInner.Invoke().AddArgumentListArguments(SF.Argument(getFieldExpression)));
+ deepCopyInner.Invoke().AddArgumentListArguments(SF.Argument(getValueExpression)));
}
///
@@ -722,8 +739,8 @@ public ExpressionSyntax GetGetter(ExpressionSyntax instance, bool forceAvoidCopy
/// Syntax for setting the value of this field.
public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value)
{
- // If the field is the backing field for an auto-property, try to use the property directly.
- if (this.PropertyInfo != null && this.PropertyInfo.GetSetMethod() != null)
+ // If the field is the backing field for an accessible auto-property use the property directly.
+ if (this.PropertyInfo != null && this.PropertyInfo.GetSetMethod() != null && !this.IsObsolete)
{
return SF.AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
@@ -742,6 +759,30 @@ public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax va
.AddArgumentListArguments(instanceArg, SF.Argument(value));
}
+ ///
+ /// Returns syntax for retrieving the value of this field.
+ ///
+ /// The instance of the containing type.
+ /// Syntax for retrieving the value of this field.
+ private ExpressionSyntax GetValueExpression(ExpressionSyntax instance)
+ {
+ // If the field is the backing field for an accessible auto-property use the property directly.
+ ExpressionSyntax result;
+ if (this.PropertyInfo != null && this.PropertyInfo.GetGetMethod() != null && !this.IsObsolete)
+ {
+ result = instance.Member(this.PropertyInfo.Name);
+ }
+ else
+ {
+ // Retrieve the field using the generated getter.
+ result =
+ SF.InvocationExpression(SF.IdentifierName(this.GetterFieldName))
+ .AddArgumentListArguments(SF.Argument(instance));
+ }
+
+ return result;
+ }
+
///
/// A comparer for which compares by name.
///
@@ -752,11 +793,6 @@ public class Comparer : IComparer
///
private static readonly Comparer Singleton = new Comparer();
- public int Compare(FieldInfoMember x, FieldInfoMember y)
- {
- return string.Compare(x.FieldInfo.Name, y.FieldInfo.Name, StringComparison.Ordinal);
- }
-
///
/// Gets the singleton instance of this class.
///
@@ -767,6 +803,11 @@ public static Comparer Instance
return Singleton;
}
}
+
+ public int Compare(FieldInfoMember x, FieldInfoMember y)
+ {
+ return string.Compare(x.FieldInfo.Name, y.FieldInfo.Name, StringComparison.Ordinal);
+ }
}
}
}
diff --git a/src/OrleansCodeGenerator/Utilities/SyntaxFactoryExtensions.cs b/src/OrleansCodeGenerator/Utilities/SyntaxFactoryExtensions.cs
index 8637a076fa..2a1c8d209d 100644
--- a/src/OrleansCodeGenerator/Utilities/SyntaxFactoryExtensions.cs
+++ b/src/OrleansCodeGenerator/Utilities/SyntaxFactoryExtensions.cs
@@ -67,8 +67,9 @@ public static TypeSyntax GetTypeSyntax(
return
SyntaxFactory.ParseTypeName(
type.GetParseableName(
- includeNamespace: includeNamespace,
- includeGenericParameters: includeGenericParameters));
+ new TypeFormattingOptions(
+ includeNamespace: includeNamespace,
+ includeGenericParameters: includeGenericParameters)));
}
///
@@ -85,7 +86,9 @@ public static TypeSyntax GetTypeSyntax(
///
public static NameSyntax GetNameSyntax(this Type type, bool includeNamespace = true)
{
- return SyntaxFactory.ParseName(type.GetParseableName(includeNamespace: includeNamespace));
+ return
+ SyntaxFactory.ParseName(
+ type.GetParseableName(new TypeFormattingOptions(includeNamespace: includeNamespace)));
}
///
@@ -124,7 +127,9 @@ public static SimpleNameSyntax GetNameSyntax(this MethodInfo method)
public static ArrayTypeSyntax GetArrayTypeSyntax(this Type type, bool includeNamespace = true)
{
return
- SyntaxFactory.ArrayType(SyntaxFactory.ParseTypeName(type.GetParseableName(includeNamespace: includeNamespace)))
+ SyntaxFactory.ArrayType(
+ SyntaxFactory.ParseTypeName(
+ type.GetParseableName(new TypeFormattingOptions(includeNamespace: includeNamespace))))
.AddRankSpecifiers(
SyntaxFactory.ArrayRankSpecifier().AddSizes(SyntaxFactory.OmittedArraySizeExpression()));
}
@@ -235,15 +240,15 @@ public static ParameterSyntax[] GetParameterListSyntax(this ConstructorInfo cons
///
/// Returns type constraint syntax for the provided generic type argument.
///
- ///
+ ///
/// The type.
///
///
/// Type constraint syntax for the provided generic type argument.
///
- public static TypeParameterConstraintClauseSyntax[] GetTypeConstraintSyntax(this Type genericTypeArgument)
+ public static TypeParameterConstraintClauseSyntax[] GetTypeConstraintSyntax(this Type type)
{
- var typeInfo = genericTypeArgument.GetTypeInfo();
+ var typeInfo = type.GetTypeInfo();
if (typeInfo.IsGenericTypeDefinition)
{
var constraints = new List();
@@ -251,6 +256,8 @@ public static TypeParameterConstraintClauseSyntax[] GetTypeConstraintSyntax(this
{
var parameterConstraints = new List();
var attributes = genericParameter.GenericParameterAttributes;
+
+ // The "class" or "struct" constraints must come first.
if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
{
parameterConstraints.Add(SyntaxFactory.ClassOrStructConstraint(SyntaxKind.ClassConstraint));
@@ -260,12 +267,21 @@ public static TypeParameterConstraintClauseSyntax[] GetTypeConstraintSyntax(this
parameterConstraints.Add(SyntaxFactory.ClassOrStructConstraint(SyntaxKind.StructConstraint));
}
+ // Follow with the base class or interface constraints.
foreach (var genericType in genericParameter.GetGenericParameterConstraints())
{
+ // If the "struct" constraint was specified, skip the corresponding "ValueType" constraint.
+ if (genericType == typeof(ValueType))
+ {
+ continue;
+ }
+
parameterConstraints.Add(SyntaxFactory.TypeConstraint(genericType.GetTypeSyntax()));
}
- if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
+ // The "new()" constraint must be the last constraint in the sequence.
+ if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint)
+ && !attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
{
parameterConstraints.Add(SyntaxFactory.ConstructorConstraint());
}
diff --git a/src/OrleansRuntime/ReminderService/InMemoryRemindersTable.cs b/src/OrleansRuntime/ReminderService/InMemoryRemindersTable.cs
index 27ac8b2b06..284f3757ce 100644
--- a/src/OrleansRuntime/ReminderService/InMemoryRemindersTable.cs
+++ b/src/OrleansRuntime/ReminderService/InMemoryRemindersTable.cs
@@ -25,7 +25,6 @@ The above copyright notice and this permission notice shall be included in all c
using System.Collections.Generic;
using System.Linq;
-
namespace Orleans.Runtime.ReminderService
{
[Serializable]
@@ -41,8 +40,8 @@ internal class InMemoryRemindersTable
// enable after adding updates ... even then, you will probably only need etags per row, not the whole
// table version, as each read/insert/update should touch & depend on only one row at a time
//internal TableVersion TableVersion;
-
- [NonSerialized]
+
+ [NonSerialized]
private readonly TraceLogger logger = TraceLogger.GetLogger("InMemoryReminderTable", TraceLogger.LoggerType.Runtime);
public InMemoryRemindersTable()
@@ -54,10 +53,10 @@ public ReminderTableData ReadRows(GrainReference grainRef)
{
Dictionary reminders;
reminderTable.TryGetValue(grainRef, out reminders);
- return reminders == null ? new ReminderTableData() :
+ return reminders == null ? new ReminderTableData() :
new ReminderTableData(reminders.Values.ToList());
}
-
+
///
/// Return all rows that have their GrainReference's.GetUniformHashCode() in the range (start, end]
///
@@ -68,18 +67,18 @@ public ReminderTableData ReadRows(uint begin, uint end)
{
var range = RangeFactory.CreateRange(begin, end);
IEnumerable keys = reminderTable.Keys.Where(range.InRange);
-
+
// is there a sleaker way of doing this in C#?
var list = new List();
foreach (GrainReference k in keys)
list.AddRange(reminderTable[k].Values);
-
- if (logger.IsVerbose3) logger.Verbose3("Selected {0} out of {1} reminders from memory for {2}. List is: {3}{4}", list.Count, reminderTable.Count, range.ToString(),
+
+ if (logger.IsVerbose3) logger.Verbose3("Selected {0} out of {1} reminders from memory for {2}. List is: {3}{4}", list.Count, reminderTable.Count, range.ToString(),
Environment.NewLine, Utils.EnumerableToString(list, e => e.ToString()));
return new ReminderTableData(list);
}
-
+
///
/// Return all rows that have their GrainReference's.GetUniformHashCode() in the range (start, end]
///
@@ -88,9 +87,21 @@ public ReminderTableData ReadRows(uint begin, uint end)
///
public ReminderEntry ReadRow(GrainReference grainRef, string reminderName)
{
- ReminderEntry r = reminderTable[grainRef][reminderName];
- if (logger.IsVerbose3) logger.Verbose3("Read for grain {0} reminder {1} row {2}", grainRef, reminderName, r.ToString());
- return r;
+ ReminderEntry result = null;
+ Dictionary reminders;
+ if (reminderTable.TryGetValue(grainRef, out reminders))
+ {
+ reminders.TryGetValue(reminderName, out result);
+ }
+
+ if (logger.IsVerbose3)
+ {
+ if (result == null)
+ logger.Verbose3("Reminder not found for grain {0} reminder {1} ", grainRef, reminderName);
+ else
+ logger.Verbose3("Read for grain {0} reminder {1} row {2}", grainRef, reminderName, result.ToString());
+ }
+ return result;
}
public string UpsertRow(ReminderEntry entry)
@@ -111,7 +122,7 @@ public string UpsertRow(ReminderEntry entry)
if (logger.IsVerbose3) logger.Verbose3("Upserted entry {0}, replaced {1}", entry, old);
return entry.ETag;
}
-
+
///
/// Remove a row from the table
///
@@ -124,7 +135,7 @@ public bool RemoveRow(GrainReference grainRef, string reminderName, string eTag)
Dictionary data = null;
ReminderEntry e = null;
- // assuming the calling grain executes one call at a time, so no need to lock
+ // assuming the calling grain executes one call at a time, so no need to lock
if (!reminderTable.TryGetValue(grainRef, out data))
{
logger.Info("1");
@@ -160,7 +171,7 @@ public ReminderTableData ReadAll()
foreach (GrainReference k in reminderTable.Keys)
{
list.AddRange(reminderTable[k].Values);
- }
+ }
return new ReminderTableData(list);
}
diff --git a/src/OrleansRuntime/ReminderService/LocalReminderService.cs b/src/OrleansRuntime/ReminderService/LocalReminderService.cs
index 9646d6cb0c..3c5edfdb83 100644
--- a/src/OrleansRuntime/ReminderService/LocalReminderService.cs
+++ b/src/OrleansRuntime/ReminderService/LocalReminderService.cs
@@ -59,10 +59,10 @@ private enum ReminderServiceStatus
private readonly TimeSpan initTimeout;
internal LocalReminderService(
- SiloAddress addr,
- GrainId id,
- IConsistentRingProvider ring,
- OrleansTaskScheduler localScheduler,
+ SiloAddress addr,
+ GrainId id,
+ IConsistentRingProvider ring,
+ OrleansTaskScheduler localScheduler,
IReminderTable reminderTable,
GlobalConfiguration config,
TimeSpan initTimeout)
@@ -128,7 +128,7 @@ public Task Stop()
}
foreach (LocalReminderData r in localReminders.Values)
r.StopReminder(logger);
-
+
// for a graceful shutdown, also handover reminder responsibilities to new owner, and update the ReminderTable
// currently, this is taken care of by periodically reading the reminder table
return TaskDone.Done;
@@ -178,7 +178,7 @@ public async Task UnregisterReminder(IGrainReminder reminder)
await DoResponsibilitySanityCheck(grainRef, "RemoveReminder");
- // it may happen that we dont have this reminder locally ... even then, we attempt to remove the reminder from the reminder
+ // it may happen that we dont have this reminder locally ... even then, we attempt to remove the reminder from the reminder
// table ... the periodic mechanism will stop this reminder at any silo's LocalReminderService that might have this reminder locally
// remove from persistent/memory store
@@ -209,7 +209,7 @@ public async Task GetReminder(GrainReference grainRef, string re
{
if(logger.IsVerbose) logger.Verbose(ErrorCode.RS_GetReminder,"GetReminder: GrainReference={0} ReminderName={1}", grainRef.ToDetailedString(), reminderName);
var entry = await reminderTable.ReadRow(grainRef, reminderName);
- return entry.ToIGrainReminder();
+ return entry == null ? null : entry.ToIGrainReminder();
}
public async Task> GetReminders(GrainReference grainRef)
@@ -278,7 +278,7 @@ private async Task ReadTableAndStartTimers(IRingRange range)
ReminderTableData table = await reminderTable.ReadRows(srange.Begin, srange.End); // get all reminders, even the ones we already have
// if null is a valid value, it means that there's nothing to do.
- if (null == table && reminderTable is MockReminderTable) return;
+ if (null == table && reminderTable is MockReminderTable) return;
var remindersNotInTable = new Dictionary(localReminders); // shallow copy
if (logger.IsVerbose) logger.Verbose("For range {0}, I read in {1} reminders from table. LocalTableSequence {2}, CachedSequence {3}", range.ToString(), table.Reminders.Count, localTableSequence, cachedSequence);
@@ -411,7 +411,7 @@ private async Task AsyncTimerCallback(object rem)
{
var reminder = (LocalReminderData)rem;
- if (!localReminders.ContainsKey(reminder.Identity) // we have already stopped this timer
+ if (!localReminders.ContainsKey(reminder.Identity) // we have already stopped this timer
|| reminder.Timer == null) // this timer was unregistered, and is waiting to be gc-ied
return;
@@ -425,7 +425,7 @@ private async Task DoResponsibilitySanityCheck(GrainReference grainRef, string d
{
if (status != ReminderServiceStatus.Started)
await startedTask.Task;
-
+
if (!myRange.InRange(grainRef))
{
logger.Warn(ErrorCode.RS_NotResponsible, "I shouldn't have received request '{0}' for {1}. It is not in my responsibility range: {2}",
@@ -455,12 +455,12 @@ private class LocalReminderData
private readonly TimeSpan period;
private GrainReference GrainRef { get { return Identity.GrainRef; } }
private string ReminderName { get { return Identity.ReminderName; } }
-
+
internal ReminderIdentity Identity { get; private set; }
internal string ETag;
internal GrainTimer Timer;
internal long LocalSequenceNumber; // locally, we use this for resolving races between the periodic table reader, and any concurrent local register/unregister requests
-
+
internal LocalReminderData(ReminderEntry entry)
{
Identity = new ReminderIdentity(entry.GrainRef, entry.ReminderName);
@@ -484,7 +484,7 @@ public void StopReminder(TraceLogger logger)
{
if (Timer != null)
Timer.Dispose();
-
+
Timer = null;
}
@@ -536,8 +536,8 @@ public async Task OnTimerTick(AverageTimeSpanStatistic tardinessStat, TraceLogge
stopwatch.Restart();
var after = DateTime.UtcNow;
- if (logger.IsVerbose2)
- logger.Verbose2("Tick triggered for {0}, dt {1} sec, next@~ {2}", this.ToString(), (after - before).TotalSeconds,
+ if (logger.IsVerbose2)
+ logger.Verbose2("Tick triggered for {0}, dt {1} sec, next@~ {2}", this.ToString(), (after - before).TotalSeconds,
// the next tick isn't actually scheduled until we return control to
// AsyncSafeTimer but we can approximate it by adding the period of the reminder
// to the after time.
@@ -547,7 +547,7 @@ public async Task OnTimerTick(AverageTimeSpanStatistic tardinessStat, TraceLogge
{
var after = DateTime.UtcNow;
logger.Error(
- ErrorCode.RS_Tick_Delivery_Error,
+ ErrorCode.RS_Tick_Delivery_Error,
String.Format("Could not deliver reminder tick for {0}, next {1}.", this.ToString(), after + period),
exc);
// What to do with repeated failures to deliver a reminder's ticks?
diff --git a/src/TestGrainInterfaces/CodegenTestInterfaces.cs b/src/TestGrainInterfaces/CodegenTestInterfaces.cs
index ffe99c7219..791475b93e 100644
--- a/src/TestGrainInterfaces/CodegenTestInterfaces.cs
+++ b/src/TestGrainInterfaces/CodegenTestInterfaces.cs
@@ -45,6 +45,7 @@ public interface ISomeGrainWithInvocationOptions : IGrainWithIntegerKey
public interface ISerializationGenerationGrain : IGrainWithIntegerKey
{
+ Task