From ce0e70a105990c27e14999019b77c8b50594603b Mon Sep 17 00:00:00 2001 From: Zp Bappi Date: Tue, 27 Nov 2018 22:28:55 +1100 Subject: [PATCH] ported root level classes --- .../ActorEnvironmentTest.cs | 2 +- src/Vlingo.Actors.Tests/ActorLifecycleTest.cs | 4 +- src/Vlingo.Actors.Tests/ActorStopTest.cs | 4 +- .../Supervision/FailureControlActor.cs | 10 +- src/Vlingo.Actors/Actor.cs | 66 +++-- src/Vlingo.Actors/ActorFactory.cs | 64 ++++- src/Vlingo.Actors/ActorProxy.cs | 44 ++-- src/Vlingo.Actors/Address.cs | 65 ----- src/Vlingo.Actors/AddressFactory.cs | 43 ---- src/Vlingo.Actors/AssemblyInfo.cs | 10 - src/Vlingo.Actors/BasicAddress.cs | 53 ++++ src/Vlingo.Actors/BasicAddressFactory.cs | 46 ++++ src/Vlingo.Actors/BasicCompletes.cs | 226 ------------------ ...Outcome.cs => BroadcastRoutingStrategy.cs} | 11 +- src/Vlingo.Actors/Cancellable__Proxy.cs | 10 +- src/Vlingo.Actors/Characters.cs | 42 ++++ src/Vlingo.Actors/CompletesEventuallyActor.cs | 2 +- .../CompletesEventuallyProviderKeeper.cs | 66 ----- .../CompletesEventually__Proxy.cs | 26 +- src/Vlingo.Actors/DeadLettersActor.cs | 8 +- .../DeadLettersListener__Proxy.cs | 9 +- src/Vlingo.Actors/DeadLetters__Proxy.cs | 27 ++- src/Vlingo.Actors/Directory.cs | 31 +-- src/Vlingo.Actors/DirectoryScannerActor.cs | 8 +- src/Vlingo.Actors/DirectoryScanner__Proxy.cs | 13 +- src/Vlingo.Actors/Environment.cs | 32 ++- src/Vlingo.Actors/{Outcome.cs => IAddress.cs} | 39 +-- src/Vlingo.Actors/IAddressFactory.cs | 26 ++ src/Vlingo.Actors/ICompletes.cs | 41 ---- .../ICompletesEventuallyProvider.cs | 3 +- ... => ICompletesEventuallyProviderKeeper.cs} | 9 +- src/Vlingo.Actors/IDirectoryScanner.cs | 4 +- ...fulOutcome.cs => ILoggerProviderKeeper.cs} | 11 +- src/Vlingo.Actors/IMailbox.cs | 11 +- ...eInterest.cs => IMailboxProviderKeeper.cs} | 11 +- src/Vlingo.Actors/IMessage.cs | 4 + src/Vlingo.Actors/IOutcomeAware.cs | 15 -- src/Vlingo.Actors/IRegistrar.cs | 3 + src/Vlingo.Actors/IRoutingStrategy.cs | 20 ++ src/Vlingo.Actors/ISupervised.cs | 2 +- src/Vlingo.Actors/LifeCycle.cs | 31 ++- src/Vlingo.Actors/LocalMessage.cs | 79 +++--- src/Vlingo.Actors/LoggerProviderKeeper.cs | 89 ------- src/Vlingo.Actors/Logger__Proxy.cs | 29 ++- src/Vlingo.Actors/MailboxProviderKeeper.cs | 97 -------- src/Vlingo.Actors/OutcomeAware__Proxy.cs | 52 ---- .../OutcomeInterestActorProxy.cs | 33 --- src/Vlingo.Actors/OutcomeInterest__Proxy.cs | 54 ----- src/Vlingo.Actors/PooledCompletes.cs | 8 +- src/Vlingo.Actors/PrivateRootActor.cs | 6 +- src/Vlingo.Actors/ProxyGenerator.cs | 23 +- src/Vlingo.Actors/PublicRootActor.cs | 2 +- src/Vlingo.Actors/RandomRoutingStrategy.cs | 28 +++ src/Vlingo.Actors/Routee.cs | 32 +++ src/Vlingo.Actors/Router.cs | 62 +++++ src/Vlingo.Actors/RouterSpecification.cs | 35 +++ src/Vlingo.Actors/Routing.cs | 56 +++++ src/Vlingo.Actors/RoutingStrategyAdapter.cs | 31 +++ src/Vlingo.Actors/Scheduled__Proxy.cs | 10 +- src/Vlingo.Actors/Scheduler.cs | 101 -------- .../SmallestMailboxRoutingStrategy.cs | 36 +++ src/Vlingo.Actors/Stage.cs | 39 +-- src/Vlingo.Actors/StageSupervisedActor.cs | 2 +- src/Vlingo.Actors/Startable__Proxy.cs | 9 +- src/Vlingo.Actors/Stoppable__Proxy.cs | 9 +- src/Vlingo.Actors/Stowage.cs | 68 ++++-- src/Vlingo.Actors/StowedLocalMessage.cs | 5 +- src/Vlingo.Actors/Supervisor__Proxy.cs | 9 +- src/Vlingo.Actors/TestKit/TestActor.cs | 4 +- src/Vlingo.Actors/TestKit/TestWorld.cs | 2 +- src/Vlingo.Actors/World.cs | 101 +++++--- 71 files changed, 1089 insertions(+), 1174 deletions(-) delete mode 100644 src/Vlingo.Actors/Address.cs delete mode 100644 src/Vlingo.Actors/AddressFactory.cs delete mode 100644 src/Vlingo.Actors/AssemblyInfo.cs create mode 100644 src/Vlingo.Actors/BasicAddress.cs create mode 100644 src/Vlingo.Actors/BasicAddressFactory.cs delete mode 100644 src/Vlingo.Actors/BasicCompletes.cs rename src/Vlingo.Actors/{FailureOutcome.cs => BroadcastRoutingStrategy.cs} (53%) create mode 100644 src/Vlingo.Actors/Characters.cs delete mode 100644 src/Vlingo.Actors/CompletesEventuallyProviderKeeper.cs rename src/Vlingo.Actors/{Outcome.cs => IAddress.cs} (52%) create mode 100644 src/Vlingo.Actors/IAddressFactory.cs delete mode 100644 src/Vlingo.Actors/ICompletes.cs rename src/Vlingo.Actors/{IScheduled.cs => ICompletesEventuallyProviderKeeper.cs} (51%) rename src/Vlingo.Actors/{SuccessfulOutcome.cs => ILoggerProviderKeeper.cs} (57%) rename src/Vlingo.Actors/{IOutcomeInterest.cs => IMailboxProviderKeeper.cs} (51%) delete mode 100644 src/Vlingo.Actors/IOutcomeAware.cs create mode 100644 src/Vlingo.Actors/IRoutingStrategy.cs delete mode 100644 src/Vlingo.Actors/LoggerProviderKeeper.cs delete mode 100644 src/Vlingo.Actors/MailboxProviderKeeper.cs delete mode 100644 src/Vlingo.Actors/OutcomeAware__Proxy.cs delete mode 100644 src/Vlingo.Actors/OutcomeInterestActorProxy.cs delete mode 100644 src/Vlingo.Actors/OutcomeInterest__Proxy.cs create mode 100644 src/Vlingo.Actors/RandomRoutingStrategy.cs create mode 100644 src/Vlingo.Actors/Routee.cs create mode 100644 src/Vlingo.Actors/Router.cs create mode 100644 src/Vlingo.Actors/RouterSpecification.cs create mode 100644 src/Vlingo.Actors/Routing.cs create mode 100644 src/Vlingo.Actors/RoutingStrategyAdapter.cs delete mode 100644 src/Vlingo.Actors/Scheduler.cs create mode 100644 src/Vlingo.Actors/SmallestMailboxRoutingStrategy.cs diff --git a/src/Vlingo.Actors.Tests/ActorEnvironmentTest.cs b/src/Vlingo.Actors.Tests/ActorEnvironmentTest.cs index 714d88fb..7dd6a70b 100644 --- a/src/Vlingo.Actors.Tests/ActorEnvironmentTest.cs +++ b/src/Vlingo.Actors.Tests/ActorEnvironmentTest.cs @@ -22,7 +22,7 @@ public void TestExpectedEnvironment() var actorDefinition = state.ValueOf("definition"); Assert.Empty(TestWorld.AllMessagesFor(env.Address)); - Assert.Equal(TestWorld.World.AddressFactory.TestNextIdValue() - 1, state.ValueOf
("address").Id); + Assert.Equal(TestWorld.World.AddressFactory.TestNextIdValue() - 1, state.ValueOf("address").Id); Assert.Equal(definition.ActorName, actorDefinition.ActorName); Assert.Equal(definition.Parameters(), actorDefinition.Parameters()); Assert.Equal(TestWorld.World.DefaultParent, state.ValueOf("parent")); diff --git a/src/Vlingo.Actors.Tests/ActorLifecycleTest.cs b/src/Vlingo.Actors.Tests/ActorLifecycleTest.cs index c4fdae33..dd2ed998 100644 --- a/src/Vlingo.Actors.Tests/ActorLifecycleTest.cs +++ b/src/Vlingo.Actors.Tests/ActorLifecycleTest.cs @@ -42,13 +42,13 @@ public LifecycleActor(TestResults testResults) this.testResults = testResults; } - internal protected override void BeforeStart() + protected internal override void BeforeStart() { testResults.receivedBeforeStart.Set(true); testResults.until.Happened(); } - internal protected override void AfterStop() + protected internal override void AfterStop() { testResults.receivedAfterStop.Set(true); testResults.until.Happened(); diff --git a/src/Vlingo.Actors.Tests/ActorStopTest.cs b/src/Vlingo.Actors.Tests/ActorStopTest.cs index 6e851185..6e4eebb5 100644 --- a/src/Vlingo.Actors.Tests/ActorStopTest.cs +++ b/src/Vlingo.Actors.Tests/ActorStopTest.cs @@ -95,7 +95,7 @@ public void CreateChildren() ChildActorFor(Definition.Has(Definition.Parameters(testResults), $"{pre}.3")); } - internal protected override void BeforeStart() + protected internal override void BeforeStart() { base.BeforeStart(); if (testResults.untilStart != null) @@ -105,7 +105,7 @@ internal protected override void BeforeStart() } private static readonly object afterStopMutex = new object(); - internal protected override void AfterStop() + protected internal override void AfterStop() { lock (afterStopMutex) { diff --git a/src/Vlingo.Actors.Tests/Supervision/FailureControlActor.cs b/src/Vlingo.Actors.Tests/Supervision/FailureControlActor.cs index c542091f..356d67bb 100644 --- a/src/Vlingo.Actors.Tests/Supervision/FailureControlActor.cs +++ b/src/Vlingo.Actors.Tests/Supervision/FailureControlActor.cs @@ -42,35 +42,35 @@ public void FailNow() throw new ApplicationException("Intended failure."); } - internal protected override void BeforeStart() + protected internal override void BeforeStart() { testResults.BeforeStartCount.IncrementAndGet(); testResults.UntilFailNow.Happened(); base.BeforeStart(); } - internal protected override void AfterStop() + protected internal override void AfterStop() { testResults.AfterStopCount.IncrementAndGet(); testResults.UntilFailNow.Happened(); base.AfterStop(); } - internal protected override void BeforeRestart(Exception reason) + protected internal override void BeforeRestart(Exception reason) { testResults.BeforeRestartCount.IncrementAndGet(); testResults.UntilFailNow.Happened(); base.BeforeRestart(reason); } - internal protected override void AfterRestart(Exception reason) + protected internal override void AfterRestart(Exception reason) { base.AfterRestart(reason); testResults.AfterRestartCount.IncrementAndGet(); testResults.UntilAfterRestart.Happened(); } - internal protected override void BeforeResume(Exception reason) + protected internal override void BeforeResume(Exception reason) { testResults.BeforeResume.IncrementAndGet(); testResults.UntilBeforeResume.Happened(); diff --git a/src/Vlingo.Actors/Actor.cs b/src/Vlingo.Actors/Actor.cs index ded75509..01a1cbf1 100644 --- a/src/Vlingo.Actors/Actor.cs +++ b/src/Vlingo.Actors/Actor.cs @@ -7,15 +7,16 @@ using System; using Vlingo.Actors.TestKit; +using Vlingo.Common; namespace Vlingo.Actors { public abstract class Actor : IStartable, IStoppable, ITestStateView { - internal ICompletes completes; + internal ResultCompletes completes; internal LifeCycle LifeCycle { get; } - public virtual Address Address => LifeCycle.Address; + public virtual IAddress Address => LifeCycle.Address; public virtual IDeadLetters DeadLetters => LifeCycle.Environment.Stage.World.DeadLetters; @@ -33,6 +34,7 @@ public virtual void Stop() { if (LifeCycle.Address.Id != World.DeadLettersId) { + // TODO: remove this actor as a child on parent LifeCycle.Stop(this); } } @@ -54,7 +56,7 @@ public override bool Equals(object other) public override string ToString() => $"Actor[type={GetType().Name} address={Address}]"; - internal Actor Parent + internal virtual Actor Parent { get { @@ -72,9 +74,10 @@ protected Actor() var maybeEnvironment = ActorFactory.ThreadLocalEnvironment.Value; LifeCycle = new LifeCycle(maybeEnvironment ?? new TestEnvironment()); ActorFactory.ThreadLocalEnvironment.Value = null; + completes = new ResultCompletes(); } - protected T ChildActorFor(Definition definition) + protected internal virtual T ChildActorFor(Definition definition) { if (definition.Supervisor != null) { @@ -98,7 +101,7 @@ protected T ChildActorFor(Definition definition) } } - internal protected ICompletes Completes() + protected internal virtual ICompletes Completes() { if(completes == null) { @@ -108,11 +111,14 @@ internal protected ICompletes Completes() return (ICompletes)completes; } - protected Definition Definition => LifeCycle.Definition; + protected internal virtual ICompletesEventually CompletesEventually() + => LifeCycle.Environment.Stage.World.CompletesFor(completes.ClientCompletes()); - internal protected ILogger Logger => LifeCycle.Environment.Logger; + protected internal virtual Definition Definition => LifeCycle.Definition; - protected T ParentAs() + protected internal virtual ILogger Logger => LifeCycle.Environment.Logger; + + protected internal virtual T ParentAs() { if (LifeCycle.Environment.IsSecured) { @@ -123,26 +129,17 @@ protected T ParentAs() return LifeCycle.Environment.Stage.ActorProxyFor(parent, parent.LifeCycle.Environment.Mailbox); } - protected void Secure() + protected virtual void Secure() { LifeCycle.Secure(); } - internal protected T SelfAs() + protected internal virtual T SelfAs() { return LifeCycle.Environment.Stage.ActorProxyFor(this, LifeCycle.Environment.Mailbox); } - protected IOutcomeInterest SelfAsOutcomeInterest(TRef reference) - { - var outcomeAware = LifeCycle.Environment.Stage.ActorProxyFor>( - this, - LifeCycle.Environment.Mailbox); - - return new OutcomeInterestActorProxy(outcomeAware, reference); - } - - internal protected Stage Stage + protected internal Stage Stage { get { @@ -155,7 +152,7 @@ internal protected Stage Stage } } - internal protected Stage StageNamed(string name) + protected internal virtual Stage StageNamed(string name) { return LifeCycle.Environment.Stage.World.StageNamed(name); } @@ -164,51 +161,52 @@ internal protected Stage StageNamed(string name) // stowing/dispersing //======================================= - internal protected virtual bool IsDispersing => - LifeCycle.Environment.Stowage.IsDispersing; + protected internal virtual bool IsDispersing => + LifeCycle.IsDispersing; - internal protected virtual void DisperseStowedMessages() + protected internal virtual void DisperseStowedMessages() { - LifeCycle.Environment.Stowage.DispersingMode(); + LifeCycle.DisperseStowedMessages(); } - internal protected virtual bool IsStowing => - LifeCycle.Environment.Stowage.IsStowing; + protected internal virtual bool IsStowing => + LifeCycle.IsStowing; - internal protected virtual void StowMessages() + protected internal virtual void StowMessages(params Type[] stowageOverrides) { - LifeCycle.Environment.Stowage.StowingMode(); + LifeCycle.StowMessages(); + LifeCycle.Environment.StowageOverrides(stowageOverrides); } //======================================= // life cycle overrides //======================================= - internal protected virtual void BeforeStart() + protected internal virtual void BeforeStart() { // override } - internal protected virtual void AfterStop() + protected internal virtual void AfterStop() { // override } - internal protected virtual void BeforeRestart(Exception reason) + protected internal virtual void BeforeRestart(Exception reason) { // override LifeCycle.AfterStop(this); } - internal protected virtual void AfterRestart(Exception reason) + protected internal virtual void AfterRestart(Exception reason) { // override LifeCycle.BeforeStart(this); } - internal protected virtual void BeforeResume(Exception reason) + protected internal virtual void BeforeResume(Exception reason) { // override } diff --git a/src/Vlingo.Actors/ActorFactory.cs b/src/Vlingo.Actors/ActorFactory.cs index a656e7af..30fb177e 100644 --- a/src/Vlingo.Actors/ActorFactory.cs +++ b/src/Vlingo.Actors/ActorFactory.cs @@ -10,15 +10,59 @@ namespace Vlingo.Actors { - internal class ActorFactory + internal static class ActorFactory { internal static readonly ThreadLocal ThreadLocalEnvironment = new ThreadLocal(false); + public static Type ActorClassWithProtocol(string actorClassname) where TProtocol : Actor + => ActorClassWithProtocol(actorClassname, typeof(TProtocol)); + + public static Type ActorClassWithProtocol(string actorClassname, Type protocolClass) + { + try + { + var actorClass = Type.GetType(actorClassname); + AssertActorWithProtocol(actorClass, protocolClass); + return actorClass; + } + catch (Exception e) + { + throw new ArgumentException($"The class {actorClassname} cannot be loaded because: {e.Message}", e); + } + } + + private static void AssertActorWithProtocol(Type candidateActorClass, Type protocolClass) + { + var superclass = candidateActorClass.BaseType; + while (superclass != null) + { + if (superclass == typeof(Actor)) + { + break; + } + superclass = superclass.BaseType; + } + + if (superclass == null) + { + throw new ArgumentException($"Class must extend Vlingo.Actors.Actor: {candidateActorClass.FullName}"); + } + + foreach (var protocolInterfaceClass in candidateActorClass.GetInterfaces()) + { + if (protocolClass == protocolInterfaceClass) + { + return; + } + } + throw new ArgumentException($"Actor class {candidateActorClass.FullName} must implement: {protocolClass.FullName}"); + } + internal static Actor ActorFor( Stage stage, Actor parent, Definition definition, - Address address, + IAddress address, IMailbox mailbox, ISupervisor supervisor, ILogger logger) @@ -54,10 +98,18 @@ internal static Actor ActorFor( actor = (Actor)ctor.Invoke(definition.InternalParameters().ToArray()); actor.LifeCycle.SendStart(actor); } - catch(Exception ex) + catch (Exception ex) { - logger.Log($"vlingo-net/actors: ActorFactory: failed because: {ex.Message}", ex); - Console.WriteLine(ex.StackTrace); + var cause = ex.InnerException ?? ex; + logger.Log("ActorFactory: failed actor creation. " + + "This is sometimes cause be the constructor parameter types not matching " + + "the types in the Definition.parameters(). Often it is caused by a " + + "failure in the actor constructor. We have attempted to uncover " + + "the root cause here, but that may not be available in some cases.\n" + + "The root cause may be: " + cause.Message + "\n" + + "See stacktrace for more information. We strongly recommend reviewing your " + + "constructor for possible failures in dependencies that it creates.", + cause); } break; } @@ -78,7 +130,7 @@ internal static Actor ActorFor( internal static IMailbox ActorMailbox( Stage stage, - Address address, + IAddress address, Definition definition) { var mailboxName = stage.World.MailboxNameFrom(definition.MailboxName); diff --git a/src/Vlingo.Actors/ActorProxy.cs b/src/Vlingo.Actors/ActorProxy.cs index bc0bbd1a..fdbd2e10 100644 --- a/src/Vlingo.Actors/ActorProxy.cs +++ b/src/Vlingo.Actors/ActorProxy.cs @@ -13,36 +13,40 @@ namespace Vlingo.Actors { internal static class ActorProxy { - private static readonly DynaClassLoader classLoader = new DynaClassLoader(typeof(ActorProxy).GetAssemblyLoadContext()); + private static readonly DynaClassLoader classLoader = new DynaClassLoader(); private static readonly DynaCompiler proxyCompiler = new DynaCompiler(); + private static readonly object _createForMutex = new object(); public static T CreateFor(Actor actor, IMailbox mailbox) => (T)CreateFor(typeof(T), actor, mailbox); public static object CreateFor(Type protocol, Actor actor, IMailbox mailbox) { - var proxyClassName = FullyQualifiedClassNameFor(protocol, "__Proxy"); + lock (_createForMutex) + { + var proxyClassName = FullyQualifiedClassNameFor(protocol, "__Proxy"); - var maybeProxy = actor.LifeCycle.Environment.LookUpProxy(protocol); + var maybeProxy = actor.LifeCycle.Environment.LookUpProxy(protocol); - if(maybeProxy != null) - { - return maybeProxy; - } + if (maybeProxy != null) + { + return maybeProxy; + } - object newProxy; - try - { - newProxy = TryCreate(actor, mailbox, proxyClassName); - } - catch (Exception) - { - newProxy = TryGenerateCreate(protocol, actor, mailbox, proxyClassName); - } + object newProxy; + try + { + newProxy = TryCreate(actor, mailbox, proxyClassName); + } + catch (Exception) + { + newProxy = TryGenerateCreate(protocol, actor, mailbox, proxyClassName); + } - actor.LifeCycle.Environment.CacheProxy(protocol, newProxy); + actor.LifeCycle.Environment.CacheProxy(protocol, newProxy); - return newProxy; + return newProxy; + } } private static object TryCreate(Actor actor, IMailbox mailbox, string targetClassName) @@ -61,14 +65,14 @@ private static object TryGenerateCreate(Type protocol, Actor actor, IMailbox mai var generator = ProxyGenerator.ForMain(true); return TryGenerateCreate(protocol, actor, mailbox, generator, targetClassName); } - catch(Exception) + catch (Exception) { try { var generator = ProxyGenerator.ForTest(true); return TryGenerateCreate(protocol, actor, mailbox, generator, targetClassName); } - catch(Exception etest) + catch (Exception etest) { throw new ArgumentException($"Actor proxy {protocol.Name} not created for main or test: {etest.Message}", etest); } diff --git a/src/Vlingo.Actors/Address.cs b/src/Vlingo.Actors/Address.cs deleted file mode 100644 index 4abcfb99..00000000 --- a/src/Vlingo.Actors/Address.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; -using Vlingo.Common; - -namespace Vlingo.Actors -{ - public sealed class Address : IComparable
- { - internal static readonly Address None = new Address(0, "None"); - - public int Id { get; } - public string Name { get; } - - internal Address(int reservedId) - : this(reservedId, null) - { } - - internal Address(int reservedId, string name) - : this(reservedId, name, false) - { } - - internal Address(int reservedId, string name, bool prefixName) - { - Id = reservedId; - Name = name == null ? - reservedId.ToString() : - ( - prefixName ? - $"{name}{reservedId}" : - name - ); - } - - public override bool Equals(object obj) - { - if(obj == null || obj.GetType() != typeof(Address)) - { - return false; - } - - return Id == ((Address)obj).Id; - } - - public override int GetHashCode() - { - return Id; - } - - public override string ToString() - { - return $"Address[{Id}, Name={Name ?? "(none)"}]"; - } - - public int CompareTo(Address other) - { - return Id.CompareTo(other.Id); - } - } -} \ No newline at end of file diff --git a/src/Vlingo.Actors/AddressFactory.cs b/src/Vlingo.Actors/AddressFactory.cs deleted file mode 100644 index f5b31c8f..00000000 --- a/src/Vlingo.Actors/AddressFactory.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using Vlingo.Common; - -namespace Vlingo.Actors -{ - public sealed class AddressFactory - { - private readonly AtomicInteger highId; - private readonly AtomicInteger nextId; - - internal AddressFactory() - { - nextId = new AtomicInteger(1); - highId = new AtomicInteger(World.HighRootId); - } - - public Address FindableBy(int id) => new Address(id, id.ToString()); - - public Address From(int reservedId, string name) => new Address(reservedId, name); - - public Address Unique() => new Address(nextId.GetAndIncrement()); - - public Address UniquePrefixedWith(string prefixedWith) - => new Address(nextId.GetAndIncrement(), prefixedWith, true); - - public Address UniqueWith(string name) => new Address(nextId.GetAndIncrement(), name); - - public Address WithHighId(string name) => new Address(highId.DecrementAndGet(), name); - - public Address WithHighId() => WithHighId(null); - - public override string ToString() - => $"AddressFactory[highId={highId.Get()}, nextId={nextId.Get()}]"; - - internal int TestNextIdValue() => nextId.Get(); - } -} diff --git a/src/Vlingo.Actors/AssemblyInfo.cs b/src/Vlingo.Actors/AssemblyInfo.cs deleted file mode 100644 index c78280d7..00000000 --- a/src/Vlingo.Actors/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System.Runtime.CompilerServices; - -[assembly:InternalsVisibleTo("Vlingo.Actors.Tests")] \ No newline at end of file diff --git a/src/Vlingo.Actors/BasicAddress.cs b/src/Vlingo.Actors/BasicAddress.cs new file mode 100644 index 00000000..22c24660 --- /dev/null +++ b/src/Vlingo.Actors/BasicAddress.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +namespace Vlingo.Actors +{ + public sealed class BasicAddress : IAddress + { + private readonly long id; + private readonly string name; + + public long Id => id; + + public long IdSequence => Id; + + public string IdSequenceString => IdString; + + public string IdString => $"{id}"; + + public string Name => name ?? id.ToString(); + + public bool IsDistributable => false; + + public int CompareTo(IAddress other) + { + if (other == null || other.GetType() != typeof(BasicAddress)) + { + return 1; + } + return id.CompareTo(((BasicAddress)other).id); + } + + public T IdTyped() + => (T)(object)IdString; + + internal BasicAddress(long reservedId) : this(reservedId, null) + { + } + + internal BasicAddress(long reservedId, string name) : this(reservedId, name, false) + { + } + + internal BasicAddress(long reservedId, string name, bool prefixName) + { + this.id = reservedId; + this.name = name == null ? null : (prefixName ? (name + id) : name); + } + } +} diff --git a/src/Vlingo.Actors/BasicAddressFactory.cs b/src/Vlingo.Actors/BasicAddressFactory.cs new file mode 100644 index 00000000..957436a8 --- /dev/null +++ b/src/Vlingo.Actors/BasicAddressFactory.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using Vlingo.Common; + +namespace Vlingo.Actors +{ + internal sealed class BasicAddressFactory : IAddressFactory + { + internal readonly static IAddress None = new BasicAddress(0, "(none)"); + private readonly AtomicLong highId; + private readonly AtomicLong nextId; + + internal BasicAddressFactory() + { + this.highId = new AtomicLong(World.HighRootId); + this.nextId = new AtomicLong(1); + } + + public IAddress FindableBy(T id) => new BasicAddress(long.Parse(id.ToString())); + + public IAddress From(long reservedId, string name) => new BasicAddress(reservedId, name); + + public IAddress From(string idString) => new BasicAddress(long.Parse(idString)); + + public IAddress From(string idString, string name) => new BasicAddress(long.Parse(idString), name); + + public long TestNextIdValue() => nextId.Get(); // for test only + + public IAddress Unique() => new BasicAddress(nextId.GetAndIncrement()); + + public IAddress UniquePrefixedWith(string prefixedWith) => new BasicAddress(nextId.GetAndIncrement(), prefixedWith, true); + + public IAddress UniqueWith(string name) => new BasicAddress(nextId.GetAndIncrement(), name); + + public IAddress WithHighId() => WithHighId(null); + + public IAddress WithHighId(string name) => new BasicAddress(highId.DecrementAndGet(), name); + + IAddress IAddressFactory.None() => None; + } +} diff --git a/src/Vlingo.Actors/BasicCompletes.cs b/src/Vlingo.Actors/BasicCompletes.cs deleted file mode 100644 index bf9aea74..00000000 --- a/src/Vlingo.Actors/BasicCompletes.cs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; -using System.Collections.Concurrent; -using Vlingo.Common; - -namespace Vlingo.Actors -{ - public class BasicCompletes : ICompletes, IScheduled - { - private readonly AtomicReference outcome; - private readonly State state; - - public BasicCompletes(Scheduler scheduler) - { - outcome = new AtomicReference(null); - state = new State(scheduler); - } - - public BasicCompletes(T outcome) - { - this.outcome = new AtomicReference(new OutcomeData(outcome)); - state = new State(); - } - - public ICompletes After(Func supplier) => After(supplier, -1L, default(T)); - - public ICompletes After(Func supplier, long timeout) => After(supplier, timeout, default(T)); - - public ICompletes After(Func supplier, long timeout, T timedOutValue) - { - state.timedOutValue = timedOutValue; - state.actions.Enqueue(supplier); - if (state.IsCompleted && outcome.Get() != null) - { - ExecuteActions(); - } - else - { - StartTimer(timeout); - } - return this; - } - - public ICompletes After(Action consumer) => After(consumer, -1L, default(T)); - - public ICompletes After(Action consumer, long timeout) => After(consumer, timeout, default(T)); - - public ICompletes After(Action consumer, long timeout, T timedOutValue) - { - state.timedOutValue = timedOutValue; - state.actions.Enqueue(consumer); - if (state.IsCompleted && outcome.Get() != null) - { - ExecuteActions(); - } - else - { - StartTimer(timeout); - } - return this; - } - - public ICompletes AndThen(Action consumer) - { - state.actions.Enqueue(consumer); - if (state.IsCompleted && outcome.Get() != null) - { - ExecuteActions(); - } - return this; - } - - public ICompletes AtLast(Func supplier) - { - state.actions.Enqueue(supplier); - if(state.IsCompleted && outcome.Get() != null) - { - ExecuteActions(); - outcome.Set(new OutcomeData(supplier.Invoke())); - } - return this; - } - - public ICompletes AtLast(Action consumer) - { - state.actions.Enqueue(consumer); - if(state.IsCompleted && outcome.Get() != null) - { - consumer.Invoke(outcome.Get().data); - } - return this; - } - - public bool HasOutcome => outcome.Get() != null; - - public virtual T Outcome => outcome.Get().data; - - object ICompletes.Outcome => outcome.Get().data; - - public virtual ICompletes With(TOutcome outcome) - { - if(state == null) - { - this.outcome.Set(new OutcomeData((T)(object)outcome)); - } - else - { - CompletedWith(false, (T)(object)outcome); - } - - return (ICompletes)this; - } - - public ICompletes With(object outcome) => With(outcome); - - public void IntervalSignal(IScheduled scheduled, object data) - { - CompletedWith(true, default(T)); - } - - internal BasicCompletes() - { - outcome = new AtomicReference(null); - state = null; - } - - internal void ClearOutcome() - { - outcome.Set(null); - } - - private void CompletedWith(bool timedOut, T outcome) - { - if (state.completed.CompareAndSet(false, true)) - { - this.outcome.Set(new OutcomeData(outcome)); - - state.CancelTimer(); - - if (timedOut) - { - this.outcome.Set(new OutcomeData(state.timedOutValue)); - } - - ExecuteActions(); - } - } - - private void ExecuteActions() - { - while (!state.executingActions.CompareAndSet(false, true)) ; - - while (!state.actions.IsEmpty) - { - if(state.actions.TryDequeue(out object action)) - { - if(action is Func) - { - outcome.Set(new OutcomeData((action as Func).Invoke())); - } - else if(action is Action) - { - (action as Action).Invoke(outcome.Get().data); - } - } - } - state.executingActions.Set(false); - } - - private void StartTimer(long timeout) - { - if (timeout > 0) - { - // 2L delayBefore prevents timeout until after return from here - state.cancellable = state.scheduler.ScheduleOnce(this, null, 2L, timeout); - } - } - - private class OutcomeData - { - internal T data; - - internal OutcomeData(T data) - { - this.data = data; - } - } - - private class State - { - internal ConcurrentQueue actions; - internal ICancellable cancellable; - internal AtomicBoolean completed; - internal Scheduler scheduler; - internal T timedOutValue; - internal AtomicBoolean executingActions; - internal State(Scheduler scheduler) - { - this.scheduler = scheduler; - this.actions = new ConcurrentQueue(); - this.completed = new AtomicBoolean(false); - this.executingActions = new AtomicBoolean(false); - } - - internal State() : this(null) { } - - internal void CancelTimer() - { - if (cancellable != null) - { - cancellable.Cancel(); - cancellable = null; - } - } - - - internal bool IsCompleted => completed.Get(); - } - } -} diff --git a/src/Vlingo.Actors/FailureOutcome.cs b/src/Vlingo.Actors/BroadcastRoutingStrategy.cs similarity index 53% rename from src/Vlingo.Actors/FailureOutcome.cs rename to src/Vlingo.Actors/BroadcastRoutingStrategy.cs index a8e0b1d6..521876e2 100644 --- a/src/Vlingo.Actors/FailureOutcome.cs +++ b/src/Vlingo.Actors/BroadcastRoutingStrategy.cs @@ -5,12 +5,19 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using System.Collections.Generic; + namespace Vlingo.Actors { - public class FailureOutcome : Outcome + public class BroadcastRoutingStrategy : RoutingStrategyAdapter { - public FailureOutcome(T value) : base(value) + public BroadcastRoutingStrategy() + { + } + + protected override IRouting ChooseRouteFor(IEnumerable routees) { + return Routing.With(routees); } } } diff --git a/src/Vlingo.Actors/Cancellable__Proxy.cs b/src/Vlingo.Actors/Cancellable__Proxy.cs index fd926a56..f763027d 100644 --- a/src/Vlingo.Actors/Cancellable__Proxy.cs +++ b/src/Vlingo.Actors/Cancellable__Proxy.cs @@ -24,7 +24,15 @@ public bool Cancel() if (!actor.IsStopped) { Action consumer = actor => actor.Cancel(); - mailbox.Send(new LocalMessage(actor, consumer, "Cancel()")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "Cancel()"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "Cancel()")); + } + return true; } diff --git a/src/Vlingo.Actors/Characters.cs b/src/Vlingo.Actors/Characters.cs new file mode 100644 index 00000000..d10a9d8c --- /dev/null +++ b/src/Vlingo.Actors/Characters.cs @@ -0,0 +1,42 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Vlingo.Actors +{ + public class Characters + { + private int current; + private readonly T[] states; + + public Characters(IList states) + { + this.states = states.ToArray(); + this.current = 0; + } + + public int Become(int which) + { + if (which < 0 || which >= states.Length) + { + throw new ArgumentOutOfRangeException("Invalid state."); + } + if (states[which] == null) + { + throw new ArgumentOutOfRangeException($"The state {which} is null."); + } + var previous = this.current; + this.current = which; + return previous; + } + + public T Current => states[current]; + } +} diff --git a/src/Vlingo.Actors/CompletesEventuallyActor.cs b/src/Vlingo.Actors/CompletesEventuallyActor.cs index 5d87ae8f..48265658 100644 --- a/src/Vlingo.Actors/CompletesEventuallyActor.cs +++ b/src/Vlingo.Actors/CompletesEventuallyActor.cs @@ -11,7 +11,7 @@ namespace Vlingo.Actors { public class CompletesEventuallyActor : Actor, ICompletesEventually { - public void With(object outcome) + public virtual void With(object outcome) { try { diff --git a/src/Vlingo.Actors/CompletesEventuallyProviderKeeper.cs b/src/Vlingo.Actors/CompletesEventuallyProviderKeeper.cs deleted file mode 100644 index 39d7dedb..00000000 --- a/src/Vlingo.Actors/CompletesEventuallyProviderKeeper.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; - -namespace Vlingo.Actors -{ - internal sealed class CompletesEventuallyProviderKeeper - { - private CompletesEventuallyProviderInfo completesEventuallyProviderInfo; - - internal CompletesEventuallyProviderKeeper() { } - - internal ICompletesEventuallyProvider ProviderFor(string name) - { - if (completesEventuallyProviderInfo == null) - { - throw new InvalidOperationException($"No registered CompletesEventuallyProvider named {name}"); - } - return completesEventuallyProviderInfo.CompletesEventuallyProvider; - } - - internal void Close() - { - if (completesEventuallyProviderInfo != null) - { - completesEventuallyProviderInfo.CompletesEventuallyProvider.Close(); - } - } - - internal ICompletesEventuallyProvider FindDefault() - { - if (completesEventuallyProviderInfo == null) - { - throw new InvalidOperationException("No registered default CompletesEventuallyProvider."); - } - return completesEventuallyProviderInfo.CompletesEventuallyProvider; - } - - internal void Keep(string name, ICompletesEventuallyProvider completesEventuallyProvider) - { - completesEventuallyProviderInfo = new CompletesEventuallyProviderInfo(name, completesEventuallyProvider, true); - } - } - - internal sealed class CompletesEventuallyProviderInfo - { - internal CompletesEventuallyProviderInfo( - string name, - ICompletesEventuallyProvider completesEventuallyProvider, - bool isDefault) - { - Name = name; - CompletesEventuallyProvider = completesEventuallyProvider; - IsDefault = isDefault; - } - - internal string Name { get; } - internal ICompletesEventuallyProvider CompletesEventuallyProvider { get; } - internal bool IsDefault { get; } - } -} diff --git a/src/Vlingo.Actors/CompletesEventually__Proxy.cs b/src/Vlingo.Actors/CompletesEventually__Proxy.cs index e0c6512b..e375f1d5 100644 --- a/src/Vlingo.Actors/CompletesEventually__Proxy.cs +++ b/src/Vlingo.Actors/CompletesEventually__Proxy.cs @@ -11,8 +11,8 @@ namespace Vlingo.Actors { public class CompletesEventually__Proxy : ICompletesEventually { - private const string RepresentationStop1 = "Stop()"; - private const string RepresentationWith2 = "With(object)"; + private const string RepresentationStop = "Stop()"; + private const string RepresentationWith = "With(object)"; private readonly Actor actor; private readonly IMailbox mailbox; @@ -30,11 +30,18 @@ public void Stop() if (!actor.IsStopped) { Action consumer = actor => actor.Stop(); - mailbox.Send(new LocalMessage(actor, consumer, RepresentationStop1)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, RepresentationStop); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, RepresentationStop)); + } } else { - actor.DeadLetters.FailedDelivery(new DeadLetter(actor, RepresentationStop1)); + actor.DeadLetters.FailedDelivery(new DeadLetter(actor, RepresentationStop)); } } @@ -43,11 +50,18 @@ public void With(object outcome) if (!actor.IsStopped) { Action consumer = actor => actor.With(outcome); - mailbox.Send(new LocalMessage(actor, consumer, RepresentationWith2)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, RepresentationWith); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, RepresentationWith)); + } } else { - actor.DeadLetters.FailedDelivery(new DeadLetter(actor, RepresentationWith2)); + actor.DeadLetters.FailedDelivery(new DeadLetter(actor, RepresentationWith)); } } } diff --git a/src/Vlingo.Actors/DeadLettersActor.cs b/src/Vlingo.Actors/DeadLettersActor.cs index c6f5a8a8..78e8a7b4 100644 --- a/src/Vlingo.Actors/DeadLettersActor.cs +++ b/src/Vlingo.Actors/DeadLettersActor.cs @@ -20,9 +20,9 @@ public DeadLettersActor() Stage.World.DeadLetters = SelfAs(); } - public void FailedDelivery(DeadLetter deadLetter) + public virtual void FailedDelivery(DeadLetter deadLetter) { - Logger.Log($"vlingo-dotnet/actors: {deadLetter}"); + Logger.Log(deadLetter.ToString()); foreach (var listener in listeners) { @@ -38,12 +38,12 @@ public void FailedDelivery(DeadLetter deadLetter) } } - public void RegisterListener(IDeadLettersListener listener) + public virtual void RegisterListener(IDeadLettersListener listener) { listeners.Add(listener); } - internal protected override void AfterStop() + protected internal override void AfterStop() { Stage.World.DeadLetters = null; base.AfterStop(); diff --git a/src/Vlingo.Actors/DeadLettersListener__Proxy.cs b/src/Vlingo.Actors/DeadLettersListener__Proxy.cs index 9ad0e789..2361a6ad 100644 --- a/src/Vlingo.Actors/DeadLettersListener__Proxy.cs +++ b/src/Vlingo.Actors/DeadLettersListener__Proxy.cs @@ -25,7 +25,14 @@ public void Handle(DeadLetter deadLetter) if (!actor.IsStopped) { Action consumer = actor => actor.Handle(deadLetter); - mailbox.Send(new LocalMessage(actor, consumer, "Handle(DeadLetter)")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "Handle(DeadLetter)"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "Handle(DeadLetter)")); + } } else { diff --git a/src/Vlingo.Actors/DeadLetters__Proxy.cs b/src/Vlingo.Actors/DeadLetters__Proxy.cs index 0d8fc077..d12a950f 100644 --- a/src/Vlingo.Actors/DeadLetters__Proxy.cs +++ b/src/Vlingo.Actors/DeadLetters__Proxy.cs @@ -27,7 +27,14 @@ public void Stop() if (!actor.IsStopped) { Action consumer = actor => actor.Stop(); - mailbox.Send(new LocalMessage(actor, consumer, "Stop()")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "Stop()"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "Stop()")); + } } else { @@ -40,7 +47,14 @@ public void FailedDelivery(DeadLetter deadLetter) if (!actor.IsStopped) { Action consumer = actor => actor.FailedDelivery(deadLetter); - mailbox.Send(new LocalMessage(actor, consumer, "FailedDelivery(DeadLetter)")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "FailedDelivery(DeadLetter)"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "FailedDelivery(DeadLetter)")); + } } else { @@ -53,7 +67,14 @@ public void RegisterListener(IDeadLettersListener listener) if (!actor.IsStopped) { Action consumer = actor => actor.RegisterListener(listener); - mailbox.Send(new LocalMessage(actor, consumer, "RegisterListener(DeadLettersListener)")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "RegisterListener(DeadLettersListener)"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "RegisterListener(DeadLettersListener)")); + } } else { diff --git a/src/Vlingo.Actors/Directory.cs b/src/Vlingo.Actors/Directory.cs index efead695..e09ff135 100644 --- a/src/Vlingo.Actors/Directory.cs +++ b/src/Vlingo.Actors/Directory.cs @@ -7,23 +7,24 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Linq; namespace Vlingo.Actors { internal sealed class Directory { - private readonly ConcurrentDictionary[] maps; + private readonly IAddress none; + private readonly ConcurrentDictionary[] maps; - internal Directory() + internal Directory(IAddress none) { + this.none = none; maps = Build(); } - internal Actor ActorOf(Address address) + internal Actor ActorOf(IAddress address) { - if(maps[MapIndex(address)].TryGetValue(address, out var actor)) + if (maps[MapIndex(address)].TryGetValue(address, out var actor)) { return actor; } @@ -37,9 +38,9 @@ internal void Dump(ILogger logger) { if (logger.IsEnabled) { - Address GetParentAddress(Actor actor) => + IAddress GetParentAddress(Actor actor) => actor.LifeCycle.Environment.Parent == null ? - Address.None : + none : actor.LifeCycle.Environment.Parent.Address; maps @@ -50,9 +51,9 @@ Address GetParentAddress(Actor actor) => } } - internal bool IsRegistered(Address address) => maps[MapIndex(address)].ContainsKey(address); + internal bool IsRegistered(IAddress address) => maps[MapIndex(address)].ContainsKey(address); - internal void Register(Address address, Actor actor) + internal void Register(IAddress address, Actor actor) { if (IsRegistered(address)) { @@ -62,9 +63,9 @@ internal void Register(Address address, Actor actor) maps[MapIndex(address)].TryAdd(address, actor); // TODO: throw if can't add? } - internal Actor Remove(Address address) + internal Actor Remove(IAddress address) { - if(maps[MapIndex(address)].TryRemove(address, out Actor actor)) + if (maps[MapIndex(address)].TryRemove(address, out Actor actor)) { return actor; } @@ -74,7 +75,7 @@ internal Actor Remove(Address address) } } - private ConcurrentDictionary[] Build() + private ConcurrentDictionary[] Build() { // This particular tuning is based on relatively few actors being spread // across 32 buckets with only 32 pre-allocated elements, for a total of @@ -93,15 +94,15 @@ private ConcurrentDictionary[] Build() // This will support 2 million actors with an average of a few hundred // less than 16K actors in each bucket. - var tempMaps = new ConcurrentDictionary[32]; + var tempMaps = new ConcurrentDictionary[32]; for (int idx = 0; idx < tempMaps.Length; ++idx) { - tempMaps[idx] = new ConcurrentDictionary(16, 32); // TODO: base this on scheduler/dispatcher + tempMaps[idx] = new ConcurrentDictionary(16, 32); // TODO: base this on scheduler/dispatcher } return tempMaps; } - private int MapIndex(Address address) => Math.Abs(address.GetHashCode() % maps.Length); + private int MapIndex(IAddress address) => Math.Abs(address.GetHashCode() % maps.Length); } } diff --git a/src/Vlingo.Actors/DirectoryScannerActor.cs b/src/Vlingo.Actors/DirectoryScannerActor.cs index 2c55359e..0acc376a 100644 --- a/src/Vlingo.Actors/DirectoryScannerActor.cs +++ b/src/Vlingo.Actors/DirectoryScannerActor.cs @@ -5,6 +5,8 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using Vlingo.Common; + namespace Vlingo.Actors { internal class DirectoryScannerActor : Actor, IDirectoryScanner @@ -16,15 +18,15 @@ public DirectoryScannerActor(Directory directory) this.directory = directory; } - public ICompletes ActorOf(Address address) + public ICompletes ActorOf(IAddress address) { var actor = directory.ActorOf(address); if(actor != null) { - return Completes().With(Stage.ActorAs(actor)); + return Completes().With(Stage.ActorAs(actor)); } - return Completes().With(default(T)); + return Completes().With(default(T)); } } } diff --git a/src/Vlingo.Actors/DirectoryScanner__Proxy.cs b/src/Vlingo.Actors/DirectoryScanner__Proxy.cs index e399b510..822bacf0 100644 --- a/src/Vlingo.Actors/DirectoryScanner__Proxy.cs +++ b/src/Vlingo.Actors/DirectoryScanner__Proxy.cs @@ -6,6 +6,7 @@ // one at https://mozilla.org/MPL/2.0/. using System; +using Vlingo.Common; namespace Vlingo.Actors { @@ -22,13 +23,21 @@ public DirectoryScanner__Proxy(Actor actor, IMailbox mailbox) this.mailbox = mailbox; } - public ICompletes ActorOf(Address address) + public ICompletes ActorOf(IAddress address) { if (!actor.IsStopped) { Action consumer = actor => actor.ActorOf(address); var completes = new BasicCompletes(actor.Scheduler); - mailbox.Send(new LocalMessage(actor, consumer, completes, ActorOfRepresentation1)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, completes, ActorOfRepresentation1); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, completes, ActorOfRepresentation1)); + } + return completes; } else diff --git a/src/Vlingo.Actors/Environment.cs b/src/Vlingo.Actors/Environment.cs index b91cc936..caff1021 100644 --- a/src/Vlingo.Actors/Environment.cs +++ b/src/Vlingo.Actors/Environment.cs @@ -7,17 +7,18 @@ using System; using System.Collections.Generic; +using System.Linq; using Vlingo.Common; namespace Vlingo.Actors { - internal class Environment + public class Environment { - internal Address Address { get; } + internal IAddress Address { get; } internal List Children { get; } internal Definition Definition { get; } internal FailureMark FailureMark { get; } - + internal ILogger Logger { get; } internal IMailbox Mailbox { get; } internal ISupervisor MaybeSupervisor { get; } @@ -29,10 +30,11 @@ internal class Environment private readonly AtomicBoolean secured; private readonly AtomicBoolean stopped; + private Type[] stowageOverrides; - internal Environment( + protected internal Environment( Stage stage, - Address address, + IAddress address, Definition definition, Actor parent, IMailbox mailbox, @@ -57,6 +59,7 @@ internal Environment( Children = new List(0); ProxyCache = new Dictionary(); Stowage = new Stowage(); + stowageOverrides = null; Suspended = new Stowage(); secured = new AtomicBoolean(false); @@ -94,7 +97,7 @@ internal void SetSecured() internal void Stop() { - if(stopped.CompareAndSet(false, true)) + if (stopped.CompareAndSet(false, true)) { StopChildren(); Suspended.Reset(); @@ -102,7 +105,22 @@ internal void Stop() Mailbox.Close(); } } - + + internal bool IsStowageOverride(Type protocol) + { + if (stowageOverrides != null) + { + return stowageOverrides.Contains(protocol); + } + + return false; + } + + internal void StowageOverrides(params Type[] overrides) + { + stowageOverrides = overrides; + } + private void StopChildren() { Children.ForEach(c => c.Stop()); diff --git a/src/Vlingo.Actors/Outcome.cs b/src/Vlingo.Actors/IAddress.cs similarity index 52% rename from src/Vlingo.Actors/Outcome.cs rename to src/Vlingo.Actors/IAddress.cs index c752a69a..92e7ab2b 100644 --- a/src/Vlingo.Actors/Outcome.cs +++ b/src/Vlingo.Actors/IAddress.cs @@ -1,19 +1,22 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -namespace Vlingo.Actors -{ - public abstract class Outcome - { - protected Outcome(TOutcome value) - { - Value = value; - } - - public TOutcome Value { get; } - } +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System; + +namespace Vlingo.Actors +{ + public interface IAddress : IComparable + { + long Id { get; } + long IdSequence { get; } + string IdSequenceString { get; } + string IdString { get; } + T IdTyped(); + string Name { get; } + bool IsDistributable { get; } + } } \ No newline at end of file diff --git a/src/Vlingo.Actors/IAddressFactory.cs b/src/Vlingo.Actors/IAddressFactory.cs new file mode 100644 index 00000000..1055ca92 --- /dev/null +++ b/src/Vlingo.Actors/IAddressFactory.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using Vlingo.Common; + +namespace Vlingo.Actors +{ + public interface IAddressFactory + { + IAddress FindableBy(T id); + IAddress From(long reservedId, string name); + IAddress From(string idString); + IAddress From(string idString, string name); + IAddress None(); + IAddress Unique(); + IAddress UniquePrefixedWith(string prefixedWith); + IAddress UniqueWith(string name); + IAddress WithHighId(); + IAddress WithHighId(string name); + long TestNextIdValue(); + } +} diff --git a/src/Vlingo.Actors/ICompletes.cs b/src/Vlingo.Actors/ICompletes.cs deleted file mode 100644 index c52505be..00000000 --- a/src/Vlingo.Actors/ICompletes.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; - -namespace Vlingo.Actors -{ - public interface ICompletes - { - bool HasOutcome { get; } - object Outcome { get; } - ICompletes With(object outcome); - } - - public interface ICompletes : ICompletes - { - ICompletes After(Func supplier); - ICompletes After(Func supplier, long timeout); - ICompletes After(Func supplier, long timeout, T timedOutValue); - ICompletes After(Action consumer); - ICompletes After(Action consumer, long timeout); - ICompletes After(Action consumer, long timeout, T timedOutValue); - ICompletes AndThen(Action consumer); - ICompletes AtLast(Action consumer); - ICompletes AtLast(Func supplier); - new T Outcome { get; } - ICompletes With(TOutcome outcome); - } - - public static class Completes - { - public static ICompletes Using(Scheduler scheduler) => new BasicCompletes(scheduler); - public static ICompletes WithSuccess(T outcome) => new BasicCompletes(outcome); - public static ICompletes WithFailure(T outcome) => new BasicCompletes(outcome); - public static ICompletes WithFailure() => new BasicCompletes(default(T)); - } -} diff --git a/src/Vlingo.Actors/ICompletesEventuallyProvider.cs b/src/Vlingo.Actors/ICompletesEventuallyProvider.cs index aebc4ee8..585d94f8 100644 --- a/src/Vlingo.Actors/ICompletesEventuallyProvider.cs +++ b/src/Vlingo.Actors/ICompletesEventuallyProvider.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Text; +using Vlingo.Common; namespace Vlingo.Actors { @@ -16,6 +17,6 @@ public interface ICompletesEventuallyProvider void Close(); ICompletesEventually CompletesEventually { get; } void InitializeUsing(Stage stage); - ICompletesEventually ProvideCompletesFor(ICompletes clientCompletes); + ICompletesEventually ProvideCompletesFor(ICompletes clientCompletes); } } diff --git a/src/Vlingo.Actors/IScheduled.cs b/src/Vlingo.Actors/ICompletesEventuallyProviderKeeper.cs similarity index 51% rename from src/Vlingo.Actors/IScheduled.cs rename to src/Vlingo.Actors/ICompletesEventuallyProviderKeeper.cs index 7c97ec8f..cca54c08 100644 --- a/src/Vlingo.Actors/IScheduled.cs +++ b/src/Vlingo.Actors/ICompletesEventuallyProviderKeeper.cs @@ -5,10 +5,15 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using System; + namespace Vlingo.Actors { - public interface IScheduled + public interface ICompletesEventuallyProviderKeeper { - void IntervalSignal(IScheduled scheduled, object data); + ICompletesEventuallyProvider ProviderFor(string name); + void Close(); + ICompletesEventuallyProvider FindDefault(); + void Keep(string name, ICompletesEventuallyProvider completesEventuallyProvider); } } diff --git a/src/Vlingo.Actors/IDirectoryScanner.cs b/src/Vlingo.Actors/IDirectoryScanner.cs index ad282f63..38d34647 100644 --- a/src/Vlingo.Actors/IDirectoryScanner.cs +++ b/src/Vlingo.Actors/IDirectoryScanner.cs @@ -5,10 +5,12 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using Vlingo.Common; + namespace Vlingo.Actors { public interface IDirectoryScanner { - ICompletes ActorOf(Address address); + ICompletes ActorOf(IAddress address); } } diff --git a/src/Vlingo.Actors/SuccessfulOutcome.cs b/src/Vlingo.Actors/ILoggerProviderKeeper.cs similarity index 57% rename from src/Vlingo.Actors/SuccessfulOutcome.cs rename to src/Vlingo.Actors/ILoggerProviderKeeper.cs index b96b9d94..08c143f2 100644 --- a/src/Vlingo.Actors/SuccessfulOutcome.cs +++ b/src/Vlingo.Actors/ILoggerProviderKeeper.cs @@ -7,11 +7,12 @@ namespace Vlingo.Actors { - public class SuccessfulOutcome : Outcome + public interface ILoggerProviderKeeper { - public SuccessfulOutcome(TOutcome value) - : base(value) - { - } + void Close(); + ILoggerProvider FindDefault(); + ILoggerProvider FindNamed(string name); + void Keep(string name, bool isDefault, ILoggerProvider loggerProvider); + } } diff --git a/src/Vlingo.Actors/IMailbox.cs b/src/Vlingo.Actors/IMailbox.cs index c9cf4826..bed279a5 100644 --- a/src/Vlingo.Actors/IMailbox.cs +++ b/src/Vlingo.Actors/IMailbox.cs @@ -5,6 +5,9 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using System; +using Vlingo.Common; + namespace Vlingo.Actors { // TODO: implement as a thread @@ -15,11 +18,9 @@ public interface IMailbox : IRunnable bool IsDelivering { get; } bool Delivering(bool flag); void Send(IMessage message); + void Send(Actor actor, Action consumer, ICompletes completes, string representation); IMessage Receive(); - } - - public interface IRunnable - { - void Run(); + bool IsPreallocated { get; } + int PendingMessages { get; } } } \ No newline at end of file diff --git a/src/Vlingo.Actors/IOutcomeInterest.cs b/src/Vlingo.Actors/IMailboxProviderKeeper.cs similarity index 51% rename from src/Vlingo.Actors/IOutcomeInterest.cs rename to src/Vlingo.Actors/IMailboxProviderKeeper.cs index 2d0f1190..617072ee 100644 --- a/src/Vlingo.Actors/IOutcomeInterest.cs +++ b/src/Vlingo.Actors/IMailboxProviderKeeper.cs @@ -7,9 +7,12 @@ namespace Vlingo.Actors { - public interface IOutcomeInterest + public interface IMailboxProviderKeeper { - void FailureOutcome(Outcome outcome); - void SuccessfulOutcome(Outcome outcome); + IMailbox AssignMailbox(string name, int hashCode); + void Close(); + string FindDefault(); + void Keep(string name, bool isDefault, IMailboxProvider mailboxProvider); + bool IsValidMailboxName(string candidateMailboxName); } -} \ No newline at end of file +} diff --git a/src/Vlingo.Actors/IMessage.cs b/src/Vlingo.Actors/IMessage.cs index 04226f72..09ffa758 100644 --- a/src/Vlingo.Actors/IMessage.cs +++ b/src/Vlingo.Actors/IMessage.cs @@ -5,6 +5,9 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using System; +using Vlingo.Common; + namespace Vlingo.Actors { public interface IMessage @@ -13,5 +16,6 @@ public interface IMessage void Deliver(); string Representation { get; } bool IsStowed { get; } + void Set(Actor actor, Action consumer, ICompletes completes, string representation); } } diff --git a/src/Vlingo.Actors/IOutcomeAware.cs b/src/Vlingo.Actors/IOutcomeAware.cs deleted file mode 100644 index d8aa9f00..00000000 --- a/src/Vlingo.Actors/IOutcomeAware.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -namespace Vlingo.Actors -{ - public interface IOutcomeAware - { - void FailureOutcome(Outcome outcome, TRef reference); - void SuccessfulOutcome(Outcome outcome, TRef reference); - } -} \ No newline at end of file diff --git a/src/Vlingo.Actors/IRegistrar.cs b/src/Vlingo.Actors/IRegistrar.cs index 4fd53fe0..a4ea0b44 100644 --- a/src/Vlingo.Actors/IRegistrar.cs +++ b/src/Vlingo.Actors/IRegistrar.cs @@ -16,6 +16,9 @@ public interface IRegistrar void Register(string name, bool isDefault, IMailboxProvider mailboxProvider); void RegisterCommonSupervisor(string stageName, string name, Type supervisedProtocol, Type supervisorClass); void RegisterDefaultSupervisor(string stageName, string name, Type supervisorClass); + void RegisterCompletesEventuallyProviderKeeper(ICompletesEventuallyProviderKeeper keeper); + void RegisterLoggerProviderKeeper(ILoggerProviderKeeper keeper); + void RegisterMailboxProviderKeeper(IMailboxProviderKeeper keeper); World World { get; } } } diff --git a/src/Vlingo.Actors/IRoutingStrategy.cs b/src/Vlingo.Actors/IRoutingStrategy.cs new file mode 100644 index 00000000..dd7908cb --- /dev/null +++ b/src/Vlingo.Actors/IRoutingStrategy.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System.Collections.Generic; + +namespace Vlingo.Actors +{ + public interface IRoutingStrategy + { + Routing ChooseRouteFor(T1 routable1, IList routees); + Routing ChooseRouteFor(T1 routable1, T2 routable2, IList routees); + Routing ChooseRouteFor(T1 routable1, T2 routable2, T3 routable3, IList routees); + Routing ChooseRouteFor(T1 routable1, T2 routable2, T3 routable3, T4 routable4, IList routees); + Routing ChooseRouteFor(T1 routable1, T2 routable2, T3 routable3, T4 routable4, T5 routable5, IList routees); + } +} diff --git a/src/Vlingo.Actors/ISupervised.cs b/src/Vlingo.Actors/ISupervised.cs index e966354a..3f572d37 100644 --- a/src/Vlingo.Actors/ISupervised.cs +++ b/src/Vlingo.Actors/ISupervised.cs @@ -12,7 +12,7 @@ namespace Vlingo.Actors { public interface ISupervised { - Address Address { get; } + IAddress Address { get; } void Escalate(); void RestartWithin(long period, int intensity, Scope scope); void Resume(); diff --git a/src/Vlingo.Actors/LifeCycle.cs b/src/Vlingo.Actors/LifeCycle.cs index 5031f37f..378580a0 100644 --- a/src/Vlingo.Actors/LifeCycle.cs +++ b/src/Vlingo.Actors/LifeCycle.cs @@ -13,7 +13,7 @@ internal sealed class LifeCycle { internal Environment Environment { get; set; } - + internal LifeCycle(Environment environment) { Environment = environment; @@ -21,7 +21,7 @@ internal LifeCycle(Environment environment) public override int GetHashCode() => Address.GetHashCode(); - internal Address Address => Environment.Address; + internal IAddress Address => Environment.Address; internal Definition Definition { @@ -124,8 +124,15 @@ internal void SendStart(Actor targetActor) try { Action consumer = actor => actor.Start(); - var message = new LocalMessage(targetActor, consumer, "Start()"); - Environment.Mailbox.Send(message); + if (!Environment.Mailbox.IsPreallocated) + { + var message = new LocalMessage(targetActor, consumer, "Start()"); + Environment.Mailbox.Send(message); + } + else + { + Environment.Mailbox.Send(targetActor, consumer, null, "Start()"); + } } catch (Exception ex) { @@ -146,13 +153,26 @@ internal void DisperseStowedMessages() SendFirstIn(Environment.Stowage); } - private void SendFirstIn(Stowage stowage) + internal void NextDispersing() + { + if (IsDispersing) + { + if (!SendFirstIn(Environment.Stowage)) + { + Environment.Stowage.Reset(); + } + } + } + + internal bool SendFirstIn(Stowage stowage) { var maybeMessage = stowage.Head; if (maybeMessage != null) { Environment.Mailbox.Send(maybeMessage); + return true; } + return falase; } internal bool IsStowing => Environment.Stowage.IsStowing; @@ -187,6 +207,7 @@ internal void Resume() internal void Suspend() { Environment.Suspended.StowingMode(); + Environment.Stowage.Restow(Environment.Suspended); } internal ISupervisor Supervisor() diff --git a/src/Vlingo.Actors/LocalMessage.cs b/src/Vlingo.Actors/LocalMessage.cs index 8e0b9c7b..ba3e645a 100644 --- a/src/Vlingo.Actors/LocalMessage.cs +++ b/src/Vlingo.Actors/LocalMessage.cs @@ -6,18 +6,22 @@ // one at https://mozilla.org/MPL/2.0/. using System; +using Vlingo.Common; namespace Vlingo.Actors { public class LocalMessage : IMessage { - private readonly ICompletes completes; + private Actor actor; + private ICompletes completes; + private Action consumer; + private string representation; - public LocalMessage(Actor actor, Action consumer, ICompletes completes, string representation) + public LocalMessage(Actor actor, Action consumer, ICompletes completes, string representation) { - Actor = actor; - Consumer = consumer; - Representation = representation; + this.actor = actor; + this.consumer = consumer; + this.representation = representation; this.completes = completes; } @@ -27,17 +31,19 @@ public LocalMessage(Actor actor, Action consumer, string representation) } public LocalMessage(LocalMessage message) - : this(message.Actor, message.Consumer, null, message.Representation) + : this(message.actor, message.consumer, message.completes, message.representation) { } - public Actor Actor { get; } + public LocalMessage(IMailbox mailbox) + { + } - private Action Consumer { get; } + public virtual Actor Actor => actor; public virtual void Deliver() { - if (Actor.LifeCycle.IsResuming) + if (actor.LifeCycle.IsResuming) { if (IsStowed) { @@ -45,13 +51,14 @@ public virtual void Deliver() } else { - InternalDeliver(Actor.LifeCycle.Environment.Suspended.SwapWith(this)); + InternalDeliver(actor.LifeCycle.Environment.Suspended.SwapWith(this)); } - Actor.LifeCycle.NextResuming(); + actor.LifeCycle.NextResuming(); } - else if (Actor.IsDispersing) + else if (actor.IsDispersing) { - InternalDeliver(Actor.LifeCycle.Environment.Stowage.SwapWith(this)); + InternalDeliver(this); + actor.LifeCycle.NextDispersing(); } else { @@ -59,56 +66,66 @@ public virtual void Deliver() } } - public virtual string Representation { get; } - public virtual bool IsStowed => false; - public override string ToString() => $"LocalMessage[{Representation}]"; + public virtual string Representation => representation; + + public void Set(Actor actor, Action consumer, ICompletes completes, string representation) + { + this.actor = actor; + this.consumer = (Action)(object)consumer; + this.representation = representation; + this.completes = completes; + } + + public override string ToString() => $"LocalMessage[{representation}]"; private void DeadLetter() { - var deadLetter = new DeadLetter(Actor, Representation); - var deadLetters = Actor.DeadLetters; + var deadLetter = new DeadLetter(actor, representation); + var deadLetters = actor.DeadLetters; if(deadLetters != null) { deadLetters.FailedDelivery(deadLetter); } else { - Actor.Logger.Log($"vlingo-dotnet/actors: MISSING DEAD LETTERS FOR: {deadLetter}"); + actor.Logger.Log($"vlingo-dotnet/actors: MISSING DEAD LETTERS FOR: {deadLetter}"); } } private void InternalDeliver(IMessage message) { - if (Actor.IsStopped) + var protocol = typeof(T); + + if (actor.IsStopped) { DeadLetter(); } - else if (Actor.LifeCycle.IsSuspended) + else if (actor.LifeCycle.IsSuspended) { - Actor.LifeCycle.Environment.Suspended.Stow(message); + actor.LifeCycle.Environment.Suspended.Stow(message); } - else if (Actor.IsStowing) + else if (actor.IsStowing && !actor.LifeCycle.Environment.IsStowageOverride(protocol)) { - Actor.LifeCycle.Environment.Stowage.Stow(message); + actor.LifeCycle.Environment.Stowage.Stow(message); } else { try { - Actor.completes = completes; - Consumer.Invoke((T)(object)Actor); - if (Actor.completes != null && Actor.completes.HasOutcome) + actor.completes.Reset(completes); + consumer.Invoke(actor); + if (actor.completes.__internal__outcomeSet) { - var outcome = Actor.completes.Outcome; - Actor.LifeCycle.Environment.Stage.World.CompletesFor(completes).With(outcome); + var outcome = actor.completes.Outcome; + actor.LifeCycle.Environment.Stage.World.CompletesFor(completes).With(actor.completes.__internal__outcome); } } catch(Exception ex) { - Actor.Logger.Log($"Message#Deliver(): Exception: {ex.Message} for Actor: {Actor} sending: {Representation}", ex); - Actor.Stage.HandleFailureOf(new StageSupervisedActor(Actor, ex)); + actor.Logger.Log($"Message#Deliver(): Exception: {ex.Message} for Actor: {actor} sending: {representation}", ex); + actor.Stage.HandleFailureOf(new StageSupervisedActor(actor, ex)); } } } diff --git a/src/Vlingo.Actors/LoggerProviderKeeper.cs b/src/Vlingo.Actors/LoggerProviderKeeper.cs deleted file mode 100644 index 8391f80a..00000000 --- a/src/Vlingo.Actors/LoggerProviderKeeper.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System.Collections.Generic; -using System.Linq; - -namespace Vlingo.Actors -{ - internal sealed class LoggerProviderKeeper - { - private readonly IDictionary loggerProviderInfos; - - internal LoggerProviderKeeper() - { - loggerProviderInfos = new Dictionary(); - } - - internal void Close() - { - foreach (var info in loggerProviderInfos.Values) - { - info.LoggerProvider.Close(); - } - } - - internal ILoggerProvider FindDefault() => - loggerProviderInfos - .Where(x => x.Value.IsDefault) - .Select(x => x.Value.LoggerProvider) - .FirstOrDefault(); - - internal ILoggerProvider FindNamed(string name) - { - if (!loggerProviderInfos.ContainsKey(name)) - { - throw new KeyNotFoundException($"No registered LoggerProvider named: {name}"); - } - - return loggerProviderInfos[name]?.LoggerProvider; - } - - internal void Keep(string name, bool isDefault, ILoggerProvider loggerProvider) - { - if (loggerProviderInfos.Count == 0 || FindDefault() == null) - { - isDefault = true; - } - else if (isDefault) - { - UndefaultCurrentDefault(); - } - - loggerProviderInfos[name] = new LoggerProviderInfo(name, loggerProvider, isDefault); - } - - - private void UndefaultCurrentDefault() - { - var currentDefaults = loggerProviderInfos - .Where(x => x.Value != null && x.Value.IsDefault) - .Select(x => new { x.Key, Info = x.Value }) - .ToList(); - - foreach(var item in currentDefaults) - { - loggerProviderInfos[item.Key] = new LoggerProviderInfo(item.Info.Name, item.Info.LoggerProvider, false); - } - } - } - - - internal sealed class LoggerProviderInfo - { - internal bool IsDefault { get; } - internal ILoggerProvider LoggerProvider { get; } - internal string Name { get; } - - internal LoggerProviderInfo(string name, ILoggerProvider loggerProvider, bool isDefault) - { - Name = name; - LoggerProvider = loggerProvider; - IsDefault = isDefault; - } - } -} diff --git a/src/Vlingo.Actors/Logger__Proxy.cs b/src/Vlingo.Actors/Logger__Proxy.cs index 2ca99aea..89cab5f0 100644 --- a/src/Vlingo.Actors/Logger__Proxy.cs +++ b/src/Vlingo.Actors/Logger__Proxy.cs @@ -23,7 +23,9 @@ public Logger__Proxy(Actor actor, IMailbox mailbox) this.actor = actor; this.mailbox = mailbox; } + public bool IsEnabled => false; + public string Name => null; public void Log(string message) @@ -31,7 +33,14 @@ public void Log(string message) if (!actor.IsStopped) { Action consumer = actor => actor.Log(message); - mailbox.Send(new LocalMessage(actor, consumer, LogRepresentation1)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, LogRepresentation1); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, LogRepresentation1)); + } } else { @@ -43,7 +52,14 @@ public void Log(string message, Exception ex) if (!actor.IsStopped) { Action consumer = actor => actor.Log(message, ex); - mailbox.Send(new LocalMessage(actor, consumer, LogRepresentation2)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, LogRepresentation2); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, LogRepresentation2)); + } } else { @@ -55,7 +71,14 @@ public void Close() if (!actor.IsStopped) { Action consumer = actor => actor.Close(); - mailbox.Send(new LocalMessage(actor, consumer, CloseRepresentation3)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, CloseRepresentation3); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, CloseRepresentation3)); + } } else { diff --git a/src/Vlingo.Actors/MailboxProviderKeeper.cs b/src/Vlingo.Actors/MailboxProviderKeeper.cs deleted file mode 100644 index df73aa8f..00000000 --- a/src/Vlingo.Actors/MailboxProviderKeeper.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Vlingo.Actors -{ - internal sealed class MailboxProviderKeeper - { - private readonly IDictionary mailboxProviderInfos; - - public MailboxProviderKeeper() - { - mailboxProviderInfos = new Dictionary(); - } - - internal IMailbox AssignMailbox(string name, int hashCode) - { - if (!mailboxProviderInfos.ContainsKey(name)) - { - throw new KeyNotFoundException($"No registered MailboxProvider named: {name}"); - } - - return mailboxProviderInfos[name]?.MailboxProvider?.ProvideMailboxFor(hashCode); - } - - internal void Close() - { - foreach(var info in mailboxProviderInfos.Values) - { - info.MailboxProvider.Close(); - } - } - - internal string FindDefault() - { - foreach(var info in mailboxProviderInfos.Values) - { - if (info.IsDefault) - { - return info.Name; - } - } - - throw new InvalidOperationException("No registered default MailboxProvider."); - } - - internal void Keep(string name, bool isDefault, IMailboxProvider mailboxProvider) - { - if (mailboxProviderInfos.Count == 0) - { - isDefault = true; - } - else if (isDefault) - { - UndefaultCurrentDefault(); - } - - mailboxProviderInfos[name] = new MailboxProviderInfo(name, mailboxProvider, isDefault); - } - - private void UndefaultCurrentDefault() - { - var currentDefaults = mailboxProviderInfos - .Where(x => x.Value.IsDefault) - .Select(x => new { x.Key, Info = x.Value }) - .ToList(); - - foreach (var item in currentDefaults) - { - mailboxProviderInfos[item.Key] = new MailboxProviderInfo(item.Info.Name, item.Info.MailboxProvider, false); - } - } - - internal bool IsValidMailboxName(string candidateMailboxName) => mailboxProviderInfos.ContainsKey(candidateMailboxName); - } - - internal sealed class MailboxProviderInfo - { - internal bool IsDefault { get; } - internal IMailboxProvider MailboxProvider { get; } - internal string Name { get; } - - internal MailboxProviderInfo(string name, IMailboxProvider mailboxProvider, bool isDefault) - { - Name = name; - MailboxProvider = mailboxProvider; - IsDefault = isDefault; - } - } -} diff --git a/src/Vlingo.Actors/OutcomeAware__Proxy.cs b/src/Vlingo.Actors/OutcomeAware__Proxy.cs deleted file mode 100644 index 0eb3eadb..00000000 --- a/src/Vlingo.Actors/OutcomeAware__Proxy.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; - -namespace Vlingo.Actors -{ - public class OutcomeAware__Proxy : IOutcomeAware - { - private const string FailureOutcomeRepesentation1 = "failureOutcome(Outcome, R)"; - private const string SuccessfulOutcomeRepesentation2 = "successfulOutcome(Outcome, R)"; - - private readonly Actor actor; - private readonly IMailbox mailbox; - - public OutcomeAware__Proxy(Actor actor, IMailbox mailbox) - { - this.actor = actor; - this.mailbox = mailbox; - } - - public void FailureOutcome(Outcome outcome, TRef reference) - { - if (!actor.IsStopped) - { - Action> consumer = actor => actor.FailureOutcome(outcome, reference); - mailbox.Send(new LocalMessage>(actor, consumer, FailureOutcomeRepesentation1)); - } - else - { - actor.DeadLetters.FailedDelivery(new DeadLetter(actor, FailureOutcomeRepesentation1)); - } - } - - public void SuccessfulOutcome(Outcome outcome, TRef reference) - { - if (!actor.IsStopped) - { - Action> consumer = actor => actor.SuccessfulOutcome(outcome, reference); - mailbox.Send(new LocalMessage>(actor, consumer, SuccessfulOutcomeRepesentation2)); - } - else - { - actor.DeadLetters.FailedDelivery(new DeadLetter(actor, SuccessfulOutcomeRepesentation2)); - } - } - } -} diff --git a/src/Vlingo.Actors/OutcomeInterestActorProxy.cs b/src/Vlingo.Actors/OutcomeInterestActorProxy.cs deleted file mode 100644 index 2beabf74..00000000 --- a/src/Vlingo.Actors/OutcomeInterestActorProxy.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -namespace Vlingo.Actors -{ - public class OutcomeInterestActorProxy : IOutcomeInterest - { - private readonly IOutcomeAware outcomeAware; - private readonly TRef reference; - - public OutcomeInterestActorProxy( - IOutcomeAware outcomeAware, - TRef reference) - { - this.outcomeAware = outcomeAware; - this.reference = reference; - } - - public virtual void FailureOutcome(Outcome outcome) - { - outcomeAware.FailureOutcome(outcome, reference); - } - - public virtual void SuccessfulOutcome(Outcome outcome) - { - outcomeAware.SuccessfulOutcome(outcome, reference); - } - } -} diff --git a/src/Vlingo.Actors/OutcomeInterest__Proxy.cs b/src/Vlingo.Actors/OutcomeInterest__Proxy.cs deleted file mode 100644 index aafda408..00000000 --- a/src/Vlingo.Actors/OutcomeInterest__Proxy.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; - -namespace Vlingo.Actors -{ - public class OutcomeInterest__Proxy : IOutcomeInterest - { - private const string FailureOutcomeRepesentation1 = "failureOutcome(Outcome)"; - private const string SuccessfulOutcomeRepesentation2 = "successfulOutcome(Outcome)"; - - private readonly Actor actor; - private readonly IMailbox mailbox; - - public OutcomeInterest__Proxy(Actor actor, IMailbox mailbox) - { - this.actor = actor; - this.mailbox = mailbox; - } - - public void FailureOutcome(Outcome outcome) - { - if (!actor.IsStopped) - { - Action> consumer = actor => actor.FailureOutcome(outcome); - mailbox.Send(new LocalMessage>(actor, consumer, FailureOutcomeRepesentation1)); - // TODO: please confirm the implementation above. it differs from java version - } - else - { - actor.DeadLetters.FailedDelivery(new DeadLetter(actor, FailureOutcomeRepesentation1)); - } - } - - public void SuccessfulOutcome(Outcome outcome) - { - if (!actor.IsStopped) - { - Action> consumer = actor => actor.SuccessfulOutcome(outcome); - mailbox.Send(new LocalMessage>(actor, consumer, SuccessfulOutcomeRepesentation2)); - // TODO: please confirm the implementation above. it differs from java version - } - else - { - actor.DeadLetters.FailedDelivery(new DeadLetter(actor, SuccessfulOutcomeRepesentation2)); - } - } - } -} diff --git a/src/Vlingo.Actors/PooledCompletes.cs b/src/Vlingo.Actors/PooledCompletes.cs index 0d373493..1a74d0dc 100644 --- a/src/Vlingo.Actors/PooledCompletes.cs +++ b/src/Vlingo.Actors/PooledCompletes.cs @@ -5,19 +5,21 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. +using Vlingo.Common; + namespace Vlingo.Actors { public class PooledCompletes : ICompletesEventually { public long Id { get; } - public ICompletes ClientCompletes { get; } + public ICompletes ClientCompletes { get; } public ICompletesEventually CompletesEventually { get; } public PooledCompletes( long id, - ICompletes clientCompletes, + ICompletes clientCompletes, ICompletesEventually completesEventually) { Id = id; @@ -25,7 +27,7 @@ public PooledCompletes( CompletesEventually = completesEventually; } - public object Outcome { get; private set; } + public virtual object Outcome { get; private set; } public virtual void With(object outcome) { diff --git a/src/Vlingo.Actors/PrivateRootActor.cs b/src/Vlingo.Actors/PrivateRootActor.cs index ae34d7fa..a56e3e24 100644 --- a/src/Vlingo.Actors/PrivateRootActor.cs +++ b/src/Vlingo.Actors/PrivateRootActor.cs @@ -24,7 +24,7 @@ public PrivateRootActor() Stage.ActorProtocolFor( Definition.Has(Definition.NoParameters, World.PublicRootName), this, - new Address(World.PublicRootId, World.PublicRootName), + Stage.World.AddressFactory.From(World.PublicRootId, World.PublicRootName), null, null, Logger); @@ -32,13 +32,13 @@ public PrivateRootActor() Stage.ActorProtocolFor( Definition.Has(Definition.NoParameters, World.DeadLettersName), this, - new Address(World.DeadLettersId, World.DeadLettersName), + Stage.World.AddressFactory.From(World.DeadLettersId, World.DeadLettersName), null, null, Logger); } - internal protected override void AfterStop() + protected internal override void AfterStop() { Stage.World.SetPrivateRoot(null); base.AfterStop(); diff --git a/src/Vlingo.Actors/ProxyGenerator.cs b/src/Vlingo.Actors/ProxyGenerator.cs index c9abf683..4314e8a2 100644 --- a/src/Vlingo.Actors/ProxyGenerator.cs +++ b/src/Vlingo.Actors/ProxyGenerator.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Reflection; using System.Text; +using Vlingo.Common; using Vlingo.Common.Compiler; using static Vlingo.Common.Compiler.DynaFile; @@ -122,6 +123,7 @@ private string ImportStatements( namespaces.Add("System"); namespaces.Add("System.Collections.Generic"); namespaces.Add(typeof(Actor).Namespace); + namespaces.Add(typeof(ResultCompletes).Namespace); // Vlingo.Common namespaces.Add(protocolInterface.Namespace); @@ -239,7 +241,7 @@ private string PropertyDefinitions(IEnumerable properties) private string GetMethodDefinition(Type protocolInterface, MethodInfo method, int count) { - var completes = DoesImplementICompletes(method.ReturnType); + var isACompletes = DoesImplementICompletes(method.ReturnType); var methodParamSignature = string.Join(", ", method.GetParameters().Select(p => $"{GetSimpleTypeName(p.ParameterType)} {p.Name}")); var methodSignature = string.Format(" public {0} {1}({2})", @@ -252,13 +254,22 @@ private string GetMethodDefinition(Type protocolInterface, MethodInfo method, in GetSimpleTypeName(protocolInterface), method.Name, string.Join(", ", method.GetParameters().Select(p => p.Name))); - var completesStatement = completes ? string.Format(" var completes = new BasicCompletes<{0}>(actor.Scheduler);\n", GetSimpleTypeName(method.ReturnType.GetGenericArguments().First())) : ""; + var completesStatement = isACompletes ? string.Format(" var completes = new BasicCompletes<{0}>(actor.Scheduler);\n", GetSimpleTypeName(method.ReturnType.GetGenericArguments().First())) : ""; var representationName = string.Format("{0}Representation{1}", method.Name, count); - var mailboxSendStatement = string.Format(" mailbox.Send(new LocalMessage<{0}>(actor, consumer, {1}{2}));", + var mailboxSendStatement = string.Format( + " if(mailbox.IsPreallocated)\n" + + " {\n" + + " mailbox.Send(actor, consumer, {0}, {1});\n" + + " }\n" + + " else\n" + + " {\n" + + " mailbox.Send(new LocalMessage<{2}>(actor, consumer, {3}{1}));\n" + + " }", + isACompletes ? "completes" : "null", + representationName, GetSimpleTypeName(protocolInterface), - completes ? "completes, " : "", - representationName); - var completesReturnStatement = completes ? " return completes;\n" : ""; + isACompletes ? "completes, " : ""); + var completesReturnStatement = isACompletes ? " return completes;\n" : ""; var elseDead = string.Format(" actor.DeadLetters.FailedDelivery(new DeadLetter(actor, {0}));", representationName); var returnValue = DefaultReturnValueString(method.ReturnType); var returnStatement = string.IsNullOrEmpty(returnValue) ? "" : string.Format(" return {0};\n", returnValue); diff --git a/src/Vlingo.Actors/PublicRootActor.cs b/src/Vlingo.Actors/PublicRootActor.cs index e823b7d3..6a304b32 100644 --- a/src/Vlingo.Actors/PublicRootActor.cs +++ b/src/Vlingo.Actors/PublicRootActor.cs @@ -30,7 +30,7 @@ public void Inform(Exception error, ISupervised supervised) supervised.RestartWithin(SupervisionStrategy.Period, SupervisionStrategy.Intensity, SupervisionStrategy.Scope); } - internal protected override void AfterStop() + protected internal override void AfterStop() { Stage.World.SetDefaultParent(null); Stage.World.SetPublicRoot(null); diff --git a/src/Vlingo.Actors/RandomRoutingStrategy.cs b/src/Vlingo.Actors/RandomRoutingStrategy.cs new file mode 100644 index 00000000..db059fbc --- /dev/null +++ b/src/Vlingo.Actors/RandomRoutingStrategy.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System; +using System.Collections.Generic; + +namespace Vlingo.Actors +{ + public class RandomRoutingStrategy : RoutingStrategyAdapter + { + private readonly Random random; + + public RandomRoutingStrategy() : base() + { + random = new Random(); + } + + protected override Routing ChooseRouteFor(IList routees) + { + int index = random.Next(routees.Count); + return Routing.With(routees[index]); + } + } +} diff --git a/src/Vlingo.Actors/Routee.cs b/src/Vlingo.Actors/Routee.cs new file mode 100644 index 00000000..4ca0f9bf --- /dev/null +++ b/src/Vlingo.Actors/Routee.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System.Collections.Generic; +using System.Linq; + +namespace Vlingo.Actors +{ + public class Routee + { + private readonly Actor actor; + + internal static IList ForAll(IList children) + => children + .Select(x => new Routee(x)) + .ToList(); + + internal Routee(Actor actor) : base() + { + this.actor = actor; + } + + public virtual int PendingMessages + => actor.LifeCycle.Environment.Mailbox.PendingMessages; + + public virtual T As() => actor.SelfAs(); + } +} diff --git a/src/Vlingo.Actors/Router.cs b/src/Vlingo.Actors/Router.cs new file mode 100644 index 00000000..68429d44 --- /dev/null +++ b/src/Vlingo.Actors/Router.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System.Collections.Generic; + +namespace Vlingo.Actors +{ + public abstract class Router : Actor + { + private readonly IList routees; + private readonly IRoutingStrategy routingStrategy; + + protected internal Router(RouterSpecification specification, IRoutingStrategy routingStrategy) + { + for (int i = 0; i < specification.poolSize(); i++) + { + ChildActorFor(specification.RouterDefinition, specification.RouterProtocol); + } + this.routees = Routee.ForAll(LifeCycle.Environment.Children); + this.routingStrategy = routingStrategy; + } + + protected internal virtual Routing ComputeRouting(T1 routable1) + { + var routing = routingStrategy.ChooseRouteFor(routable1, routees); + routing.Validate(); + return routing; + } + + protected internal virtual Routing ComputeRouting(T1 routable1, T2 routable2) + { + var routing = routingStrategy.ChooseRouteFor(routable1, routable2, routees); + routing.Validate(); + return routing; + } + + protected internal virtual Routing ComputeRouting(T1 routable1, T2 routable2, T3 routable3) + { + var routing = routingStrategy.ChooseRouteFor(routable1, routable2, routable3, routees); + routing.Validate(); + return routing; + } + + protected internal virtual Routing ComputeRouting(T1 routable1, T2 routable2, T3 routable3, T4 routable4) + { + var routing = routingStrategy.ChooseRouteFor(routable1, routable2, routable3, routable4, routees); + routing.Validate(); + return routing; + } + + protected internal virtual Routing ComputeRouting(T1 routable1, T2 routable2, T3 routable3, T4 routable4, T5 routable5) + { + var routing = routingStrategy.ChooseRouteFor(routable1, routable2, routable3, routable4, routable5, routees); + routing.Validate(); + return routing; + } + } +} diff --git a/src/Vlingo.Actors/RouterSpecification.cs b/src/Vlingo.Actors/RouterSpecification.cs new file mode 100644 index 00000000..376b7efb --- /dev/null +++ b/src/Vlingo.Actors/RouterSpecification.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System; + +namespace Vlingo.Actors +{ + public class RouterSpecification + { + private readonly int poolSize; //TODO: refactor towards resizable pool + private readonly Definition routerDefinition; + private readonly Type routerProtocol; + + public RouterSpecification(int poolSize, Definition routerDefinition, Type routerProtocol) + { + if (poolSize <= 0) + { + throw new ArgumentException("poolSize must be 1 or greater"); + } + this.poolSize = poolSize; + this.routerDefinition = routerDefinition; + this.routerProtocol = routerProtocol; + } + + public virtual int PoolSize => poolSize; + + public virtual Definition RouterDefinition => routerDefinition; + + public virtual Type RouterProtocol => routerProtocol; + } +} diff --git a/src/Vlingo.Actors/Routing.cs b/src/Vlingo.Actors/Routing.cs new file mode 100644 index 00000000..2a602d19 --- /dev/null +++ b/src/Vlingo.Actors/Routing.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System; +using System.Collections.Generic; +using System.Linq; +using Vlingo.Common; + +namespace Vlingo.Actors +{ + public class Routing + { + public static Routing Empty() => new Routing(); + public static Routing With(Routee routee) => new Routing(new List { routee }); + + public static Routing With(Optional routeeOrNull) + => routeeOrNull.IsPresent ? + With(routeeOrNull.Get()) : + Empty(); + + public static Routing With(IList routees) => new Routing(routees); + + private readonly ArraySegment routees; + + internal Routing() : this(null) + { + } + + internal Routing(IList routees) + { + var routeesCollection = routees ?? new List(); + this.routees = new ArraySegment(routeesCollection.ToArray()); + } + + public virtual IReadOnlyList Routees => routees; + + public virtual IList RouteesAs() + => routees.Select(r => r.As()).ToList(); + + public virtual bool IsEmpty => routees.Count > 0; + + public override string ToString() => $"Routing[routees={routees}]"; + + public virtual void Validate() + { + if (IsEmpty) + { + throw new InvalidOperationException("routees may not be empty"); + } + } + } +} diff --git a/src/Vlingo.Actors/RoutingStrategyAdapter.cs b/src/Vlingo.Actors/RoutingStrategyAdapter.cs new file mode 100644 index 00000000..08de386a --- /dev/null +++ b/src/Vlingo.Actors/RoutingStrategyAdapter.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System.Collections.Generic; + +namespace Vlingo.Actors +{ + public abstract class RoutingStrategyAdapter : IRoutingStrategy + { + public virtual Routing ChooseRouteFor(T1 routable1, IList routees) + => ChooseRouteFor(routees); + + public virtual Routing ChooseRouteFor(T1 routable1, T2 routable2, IList routees) + => ChooseRouteFor(routees); + + public virtual Routing ChooseRouteFor(T1 routable1, T2 routable2, T3 routable3, IList routees) + => ChooseRouteFor(routees); + + public virtual Routing ChooseRouteFor(T1 routable1, T2 routable2, T3 routable3, T4 routable4, IList routees) + => ChooseRouteFor(routees); + + public virtual Routing ChooseRouteFor(T1 routable1, T2 routable2, T3 routable3, T4 routable4, T5 routable5, IList routees) + => ChooseRouteFor(routees); + + protected abstract Routing ChooseRouteFor(IList routees); + } +} diff --git a/src/Vlingo.Actors/Scheduled__Proxy.cs b/src/Vlingo.Actors/Scheduled__Proxy.cs index 42f55389..584fe39f 100644 --- a/src/Vlingo.Actors/Scheduled__Proxy.cs +++ b/src/Vlingo.Actors/Scheduled__Proxy.cs @@ -6,6 +6,7 @@ // one at https://mozilla.org/MPL/2.0/. using System; +using Vlingo.Common; namespace Vlingo.Actors { @@ -26,7 +27,14 @@ public void IntervalSignal(IScheduled scheduled, object data) if (!actor.IsStopped) { Action consumer = actor => actor.IntervalSignal(scheduled, data); - mailbox.Send(new LocalMessage(actor, consumer, RepresentationIntervalSignal1)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, RepresentationIntervalSignal1); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, RepresentationIntervalSignal1)); + } } else { diff --git a/src/Vlingo.Actors/Scheduler.cs b/src/Vlingo.Actors/Scheduler.cs deleted file mode 100644 index d04f1c7c..00000000 --- a/src/Vlingo.Actors/Scheduler.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. -// -// This Source Code Form is subject to the terms of the -// Mozilla Public License, v. 2.0. If a copy of the MPL -// was not distributed with this file, You can obtain -// one at https://mozilla.org/MPL/2.0/. - -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Vlingo.Actors -{ - public class Scheduler - { - private readonly ConcurrentBag tasks; - - public ICancellable Schedule(IScheduled scheduled, object data, long delayBefore, long interval) - => CreateAndStore( - scheduled, - data, - TimeSpan.FromMilliseconds(delayBefore), - TimeSpan.FromMilliseconds(interval), - true); - - public ICancellable ScheduleOnce(IScheduled scheduled, object data, long delayBefore, long interval) - => CreateAndStore( - scheduled, - data, - TimeSpan.FromMilliseconds(delayBefore + interval), - TimeSpan.FromMilliseconds(Timeout.Infinite), - false); - - - internal Scheduler() - { - tasks = new ConcurrentBag(); - } - - internal void Close() - { - foreach(var task in tasks) - { - task.Cancel(); - } - } - - private SchedulerTask CreateAndStore( - IScheduled scheduled, - object data, - TimeSpan delayBefore, - TimeSpan interval, - bool repeats) - { - var task = new SchedulerTask(scheduled, data, delayBefore, interval, repeats); - tasks.Add(task); - return task; - } - - private class SchedulerTask : ICancellable - { - private readonly IScheduled scheduled; - private readonly bool repeats; - private Timer timer; - private bool hasRun; - - public SchedulerTask(IScheduled scheduled, object data, TimeSpan delayBefore, TimeSpan interval, bool repeats) - { - this.scheduled = scheduled; - this.repeats = repeats; - hasRun = false; - timer = new Timer(new TimerCallback(Tick), data, delayBefore, interval); - } - - private void Tick(object data) - { - hasRun = true; - scheduled.IntervalSignal(scheduled, data); - - if (!repeats) - { - Cancel(); - } - } - - public bool Cancel() - { - if (timer != null) - { - using (timer) - { - timer.Change(-1, -1); - } - timer = null; - } - - return repeats || !hasRun; - } - } - } -} diff --git a/src/Vlingo.Actors/SmallestMailboxRoutingStrategy.cs b/src/Vlingo.Actors/SmallestMailboxRoutingStrategy.cs new file mode 100644 index 00000000..1b089fcd --- /dev/null +++ b/src/Vlingo.Actors/SmallestMailboxRoutingStrategy.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2012-2018 Vaughn Vernon. All rights reserved. +// +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v. 2.0. If a copy of the MPL +// was not distributed with this file, You can obtain +// one at https://mozilla.org/MPL/2.0/. + +using System.Collections.Generic; + +namespace Vlingo.Actors +{ + public class SmallestMailboxRoutingStrategy : RoutingStrategyAdapter + { + protected override Routing ChooseRouteFor(IList routees) + { + Routee least = null; + int leastCount = int.MaxValue; + foreach (var routee in routees) + { + var count = routee.PendingMessages; + if (count == 0) + { + least = routee; + break; + } + else if (count < leastCount) + { + least = routee; + leastCount = count; + } + } + + return least == null ? Routing.Empty() : Routing.With(least); + } + } +} diff --git a/src/Vlingo.Actors/Stage.cs b/src/Vlingo.Actors/Stage.cs index 1cde88a9..1fd5ab53 100644 --- a/src/Vlingo.Actors/Stage.cs +++ b/src/Vlingo.Actors/Stage.cs @@ -26,7 +26,7 @@ public Stage(World world, string name) { World = world; Name = name; - directory = new Directory(); + directory = new Directory(world.AddressFactory.None()); commonSupervisors = new Dictionary(); scheduler = new Scheduler(); stopped = new AtomicBoolean(false); @@ -42,13 +42,16 @@ public T ActorFor(Definition definition) definition.Supervisor, definition.LoggerOr(World.DefaultLogger)); - public T ActorFor(Definition definition, Address address, ILogger logger) + public T ActorFor(Definition definition, IAddress address, ILogger logger) { + var actorAddress = AllocateAddress(definition, address); + var actorMailbox = AllocateMailbox(definition, actorAddress, null); + var actor = ActorProtocolFor( definition, definition.ParentOr(World.DefaultParent), - address, - null, + actorAddress, + actorMailbox, definition.Supervisor, logger); @@ -62,13 +65,16 @@ public T ActorFor(Definition definition, ILogger logger) definition.Supervisor, logger); - public T ActorFor(Definition definition, Address address) + public T ActorFor(Definition definition, IAddress address) { + var actorAddress = AllocateAddress(definition, address); + var actorMailbox = AllocateMailbox(definition, actorAddress, null); + var actor = ActorProtocolFor( definition, definition.ParentOr(World.DefaultParent), - address, - null, + actorAddress, + actorMailbox, definition.Supervisor, definition.LoggerOr(World.DefaultLogger)); @@ -84,7 +90,7 @@ public Protocols ActorFor(Definition definition, Type[] protocols) definition.Supervisor, definition.LoggerOr(World.DefaultLogger))); - public ICompletes ActorOf(Address address) => directoryScanner.ActorOf(address); + public ICompletes ActorOf(IAddress address) => directoryScanner.ActorOf(address); public TestActor TestActorFor(Definition definition) { @@ -189,7 +195,7 @@ internal ActorProtocolActor[] ActorProtocolFor(Definition definition, Ty internal ActorProtocolActor ActorProtocolFor( Definition definition, Actor parent, - Address maybeAddress, + IAddress maybeAddress, IMailbox maybeMailbox, ISupervisor maybeSupervisor, ILogger logger) @@ -213,7 +219,7 @@ internal ActorProtocolActor[] ActorProtocolFor( Definition definition, Type[] protocols, Actor parent, - Address maybeAddress, + IAddress maybeAddress, IMailbox maybeMailbox, ISupervisor maybeSupervisor, ILogger logger) @@ -284,10 +290,16 @@ internal void Stop(Actor actor) } } + private IAddress AllocateAddress(Definition definition, IAddress maybeAddress) + => maybeAddress ?? World.AddressFactory.UniqueWith(definition.ActorName); + + private IMailbox AllocateMailbox(Definition definition, IAddress address, IMailbox maybeMailbox) + => maybeMailbox ?? ActorFactory.ActorMailbox(this, address, definition); + private Actor CreateRawActor( Definition definition, Actor parent, - Address maybeAddress, + IAddress maybeAddress, IMailbox maybeMailbox, ISupervisor maybeSupervisor, ILogger logger) @@ -313,9 +325,8 @@ private Actor CreateRawActor( } catch(Exception e) { - logger.Log($"Actor instantiation failed because: {e.Message}"); - Console.WriteLine(e.Message); - Console.WriteLine(e.StackTrace); + logger.Log($"Actor instantiation failed because: {e.Message}", e); + throw new InvalidOperationException($"Actor instantiation failed because: {e.Message}", e); } diff --git a/src/Vlingo.Actors/StageSupervisedActor.cs b/src/Vlingo.Actors/StageSupervisedActor.cs index 662d13fc..734842cb 100644 --- a/src/Vlingo.Actors/StageSupervisedActor.cs +++ b/src/Vlingo.Actors/StageSupervisedActor.cs @@ -21,7 +21,7 @@ protected internal StageSupervisedActor(Actor actor, Exception error) Error = error; } - public virtual Address Address => actor.Address; + public virtual IAddress Address => actor.Address; public virtual void Escalate() => Supervisor.Supervisor.Inform(Error, this); diff --git a/src/Vlingo.Actors/Startable__Proxy.cs b/src/Vlingo.Actors/Startable__Proxy.cs index 35130806..b017b407 100644 --- a/src/Vlingo.Actors/Startable__Proxy.cs +++ b/src/Vlingo.Actors/Startable__Proxy.cs @@ -23,7 +23,14 @@ public Startable__Proxy(Actor actor, IMailbox mailbox) public void Start() { Action consumer = actor => actor.Start(); - mailbox.Send(new LocalMessage(actor, consumer, "Start()")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "Start()"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "Start()")); + } } } } diff --git a/src/Vlingo.Actors/Stoppable__Proxy.cs b/src/Vlingo.Actors/Stoppable__Proxy.cs index 230851f5..df87fab3 100644 --- a/src/Vlingo.Actors/Stoppable__Proxy.cs +++ b/src/Vlingo.Actors/Stoppable__Proxy.cs @@ -27,7 +27,14 @@ public void Stop() if (!actor.IsStopped) { Action consumer = actor => actor.Stop(); - mailbox.Send(new LocalMessage(actor, consumer, "Stop()")); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, "Stop()"); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, "Stop()")); + } } else { diff --git a/src/Vlingo.Actors/Stowage.cs b/src/Vlingo.Actors/Stowage.cs index 73e591ad..bf9f1ffe 100644 --- a/src/Vlingo.Actors/Stowage.cs +++ b/src/Vlingo.Actors/Stowage.cs @@ -5,7 +5,6 @@ // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. -using System; using System.Collections.Generic; using Vlingo.Common; @@ -14,19 +13,22 @@ namespace Vlingo.Actors internal class Stowage { private Queue stowedMessages; - private AtomicBoolean dispersing; - private AtomicBoolean stowing; + private bool dispersing; + private bool stowing; public Stowage() { - dispersing = new AtomicBoolean(false); - stowing = new AtomicBoolean(false); + dispersing = false; + stowing = false; Reset(); } - protected internal int Count => stowedMessages.Count; + public override string ToString() + => $"Stowage[stowing={stowing}, dispersing={dispersing}, messages={stowedMessages}]"; - protected internal void Dump(ILogger logger) + internal int Count => stowedMessages.Count; + + internal void Dump(ILogger logger) { foreach (var message in stowedMessages) { @@ -34,9 +36,9 @@ protected internal void Dump(ILogger logger) } } - protected internal bool HasMessages => stowedMessages.Count > 0; + internal bool HasMessages => stowedMessages.Count > 0; - protected internal IMessage Head + internal IMessage Head { get { @@ -50,38 +52,58 @@ protected internal IMessage Head } } - protected internal void Reset() + internal void Reset() { stowedMessages = new Queue(); - stowing.Set(false); - dispersing.Set(false); + stowing = false; + dispersing = false; } - protected internal bool IsStowing => stowing.Get(); + internal bool IsStowing => stowing; - public void StowingMode() + internal void StowingMode() { - stowing.Set(true); - dispersing.Set(false); + stowing = true; + dispersing = false; } - protected internal bool IsDispersing => dispersing.Get(); + internal bool IsDispersing => dispersing; + + internal void DispersingMode() + { + stowing = false; + dispersing = true; + } - protected internal void DispersingMode() + void Restow(Stowage other) { - stowing.Set(false); - dispersing.Set(true); + var message = Head; + while (message != null) + { + other.Stow(message); + message = Head; + } } - protected internal void Stow(IMessage message) + internal void Stow(IMessage message) { if (IsStowing) { - stowedMessages.Enqueue(new StowedLocalMessage((LocalMessage)message)); + IMessage toStow = null; + if (message.IsStowed) + { + toStow = message; + } + else + { + toStow = new StowedLocalMessage((LocalMessage)message); + } + + stowedMessages.Enqueue(toStow); } } - protected internal IMessage SwapWith(IMessage newerMessage) + internal IMessage SwapWith(IMessage newerMessage) { if (!HasMessages) { diff --git a/src/Vlingo.Actors/StowedLocalMessage.cs b/src/Vlingo.Actors/StowedLocalMessage.cs index d98d28af..ad81f89b 100644 --- a/src/Vlingo.Actors/StowedLocalMessage.cs +++ b/src/Vlingo.Actors/StowedLocalMessage.cs @@ -6,13 +6,14 @@ // one at https://mozilla.org/MPL/2.0/. using System; +using Vlingo.Common; namespace Vlingo.Actors { public class StowedLocalMessage : LocalMessage { - public StowedLocalMessage(Actor actor, Action consumer, string representation) - : base(actor, consumer, representation) + public StowedLocalMessage(Actor actor, Action consumer, ICompletes completes, string representation) + : base(actor, consumer, completes, representation) { } diff --git a/src/Vlingo.Actors/Supervisor__Proxy.cs b/src/Vlingo.Actors/Supervisor__Proxy.cs index 0cc7eef0..2fa84e9a 100644 --- a/src/Vlingo.Actors/Supervisor__Proxy.cs +++ b/src/Vlingo.Actors/Supervisor__Proxy.cs @@ -31,7 +31,14 @@ public void Inform(Exception error, ISupervised supervised) if (!actor.IsStopped) { Action consumer = actor => actor.Inform(error, supervised); - mailbox.Send(new LocalMessage(actor, consumer, RepresentationInform1)); + if (mailbox.IsPreallocated) + { + mailbox.Send(actor, consumer, null, RepresentationInform1); + } + else + { + mailbox.Send(new LocalMessage(actor, consumer, RepresentationInform1)); + } } else { diff --git a/src/Vlingo.Actors/TestKit/TestActor.cs b/src/Vlingo.Actors/TestKit/TestActor.cs index 43d205d0..ac9e787c 100644 --- a/src/Vlingo.Actors/TestKit/TestActor.cs +++ b/src/Vlingo.Actors/TestKit/TestActor.cs @@ -9,7 +9,7 @@ namespace Vlingo.Actors.TestKit { public class TestActor : ITestStateView { - public TestActor(Actor actor, T protocol, Address address) + public TestActor(Actor actor, T protocol, IAddress address) { ActorInside = actor; Actor = protocol; @@ -17,7 +17,7 @@ public TestActor(Actor actor, T protocol, Address address) } public T Actor { get; } - public Address Address { get; } + public IAddress Address { get; } public Actor ActorInside { get; } public TestState ViewTestState() => ActorInside.ViewTestState(); diff --git a/src/Vlingo.Actors/TestKit/TestWorld.cs b/src/Vlingo.Actors/TestKit/TestWorld.cs index 48925e9f..a9da4bc1 100644 --- a/src/Vlingo.Actors/TestKit/TestWorld.cs +++ b/src/Vlingo.Actors/TestKit/TestWorld.cs @@ -29,7 +29,7 @@ internal static TestWorld Instance private readonly IDictionary> actorMessages = new Dictionary>(); - public IList AllMessagesFor(Address address) + public IList AllMessagesFor(IAddress address) => actorMessages.ContainsKey(address.Id) ? actorMessages[address.Id] : new List(); public static TestWorld Start(string name) diff --git a/src/Vlingo.Actors/World.cs b/src/Vlingo.Actors/World.cs index 3c479afd..abcecf91 100644 --- a/src/Vlingo.Actors/World.cs +++ b/src/Vlingo.Actors/World.cs @@ -7,44 +7,45 @@ using System; using System.Collections.Generic; +using Vlingo.Common; using Vlingo.Common.Compiler; namespace Vlingo.Actors { - public class World : IRegistrar + public sealed class World : IRegistrar { - internal const int PrivateRootId = int.MaxValue; + internal const long PrivateRootId = long.MaxValue; internal const string PrivateRootName = "#private"; - internal const int PublicRootId = PrivateRootId - 1; + internal const long PublicRootId = PrivateRootId - 1; internal const string PublicRootName = "#public"; - internal const int DeadLettersId = PublicRootId - 1; + internal const long DeadLettersId = PublicRootId - 1; internal const string DeadLettersName = "#deadLetters"; - internal const int HighRootId = DeadLettersId - 1; + public const long HighRootId = DeadLettersId - 1; internal const string DefaultStage = "__defaultStage"; - private readonly CompletesEventuallyProviderKeeper completesProviderKeeper; - private readonly LoggerProviderKeeper loggerProviderKeeper; - private readonly MailboxProviderKeeper mailboxProviderKeeper; + private readonly IDictionary dynamicDependencies; + private readonly IDictionary stages; + + private ICompletesEventuallyProviderKeeper completesProviderKeeper; + private ILoggerProviderKeeper loggerProviderKeeper; + private IMailboxProviderKeeper mailboxProviderKeeper; - private IDictionary stages; private ILogger defaultLogger; private ISupervisor defaultSupervisor; - private readonly DynaClassLoader classLoader; private World(string name, Configuration configuration) { Name = name; Configuration = configuration; - classLoader = new DynaClassLoader(GetType().GetAssemblyLoadContext()); - completesProviderKeeper = new CompletesEventuallyProviderKeeper(); - loggerProviderKeeper = new LoggerProviderKeeper(); - mailboxProviderKeeper = new MailboxProviderKeeper(); + AddressFactory = new BasicAddressFactory(); + completesProviderKeeper = new DefaultCompletesEventuallyProviderKeeper(); + loggerProviderKeeper = new DefaultLoggerProviderKeeper(); + mailboxProviderKeeper = new DefaultMailboxProviderKeeper(); stages = new Dictionary(); - AddressFactory = new AddressFactory(); - var defaultStage = StageNamed(DefaultStage); + configuration.StartPlugins(this, 0); configuration.StartPlugins(this, 1); StartRootFor(defaultStage, DefaultLogger); @@ -53,7 +54,7 @@ private World(string name, Configuration configuration) defaultStage.StartDirectoryScanner(); } - public AddressFactory AddressFactory { get; } + public IAddressFactory AddressFactory { get; } public Configuration Configuration { get; } @@ -108,7 +109,7 @@ public Protocols ActorFor(Definition definition, Type[] protocols) public IDeadLetters DeadLetters { get; internal set; } - public ICompletesEventually CompletesFor(ICompletes clientCompletes) + public ICompletesEventually CompletesFor(ICompletes clientCompletes) => completesProviderKeeper.FindDefault().ProvideCompletesFor(clientCompletes); public ILogger DefaultLogger @@ -143,7 +144,7 @@ public ISupervisor DefaultSupervisor { get { - if(defaultSupervisor == null) + if (defaultSupervisor == null) { defaultSupervisor = DefaultParent.SelfAs(); } @@ -156,23 +157,23 @@ public ISupervisor DefaultSupervisor public string Name { get; } - public virtual void Register(string name, ICompletesEventuallyProvider completesEventuallyProvider) + public void Register(string name, ICompletesEventuallyProvider completesEventuallyProvider) { completesEventuallyProvider.InitializeUsing(Stage); completesProviderKeeper.Keep(name, completesEventuallyProvider); } - public virtual void Register(string name, bool isDefault, ILoggerProvider loggerProvider) + public void Register(string name, bool isDefault, ILoggerProvider loggerProvider) { var actualDefault = loggerProviderKeeper.FindDefault() == null ? true : isDefault; loggerProviderKeeper.Keep(name, actualDefault, loggerProvider); defaultLogger = loggerProviderKeeper.FindDefault().Logger; } - public virtual void Register(string name, bool isDefault, IMailboxProvider mailboxProvider) + public void Register(string name, bool isDefault, IMailboxProvider mailboxProvider) => mailboxProviderKeeper.Keep(name, isDefault, mailboxProvider); - public virtual void RegisterCommonSupervisor(string stageName, string name, Type supervisedProtocol, Type supervisorClass) + public void RegisterCommonSupervisor(string stageName, string name, Type supervisedProtocol, Type supervisorClass) { try { @@ -187,7 +188,7 @@ public virtual void RegisterCommonSupervisor(string stageName, string name, Type } } - public virtual void RegisterDefaultSupervisor(string stageName, string name, Type supervisorClass) + public void RegisterDefaultSupervisor(string stageName, string name, Type supervisorClass) { try { @@ -203,6 +204,44 @@ public virtual void RegisterDefaultSupervisor(string stageName, string name, Typ } } + public void RegisterCompletesEventuallyProviderKeeper(ICompletesEventuallyProviderKeeper keeper) + { + if (this.completesProviderKeeper != null) + { + this.completesProviderKeeper.Close(); + } + + this.completesProviderKeeper = keeper; + } + + public void RegisterLoggerProviderKeeper(ILoggerProviderKeeper keeper) + { + if (this.loggerProviderKeeper != null) + { + this.loggerProviderKeeper.Close(); + } + this.loggerProviderKeeper = keeper; + } + + public void RegisterMailboxProviderKeeper(IMailboxProviderKeeper keeper) + { + if (this.mailboxProviderKeeper != null) + { + this.mailboxProviderKeeper.Close(); + } + this.mailboxProviderKeeper = keeper; + } + + public void RegisterDynamic(string name, object dep) + { + this.dynamicDependencies[name] = dep; + } + + public TDependency ResolveDynamic(string name) + { + return (TDependency)this.dynamicDependencies[name]; + } + public Stage Stage => StageNamed(DefaultStage); private readonly object stageNamedMutex = new object(); @@ -210,10 +249,10 @@ public Stage StageNamed(string name) { lock (stageNamedMutex) { - if(!stages.TryGetValue(name, out Stage stage)) + if (!stages.TryGetValue(name, out Stage stage)) { stage = new Stage(this, name); - if(!string.Equals(name, DefaultStage)) + if (!string.Equals(name, DefaultStage)) { stage.StartDirectoryScanner(); } @@ -224,9 +263,9 @@ public Stage StageNamed(string name) } } - public virtual bool IsTerminated => Stage.IsStopped; + public bool IsTerminated => Stage.IsStopped; - public virtual void Terminate() + public void Terminate() { if (!IsTerminated) { @@ -272,7 +311,7 @@ internal void SetDefaultParent(Actor defaultParent) { lock (defaultParentMutex) { - if(defaultParent != null && DefaultParent != null) + if (defaultParent != null && DefaultParent != null) { throw new InvalidOperationException("Default parent already exists."); } @@ -286,7 +325,7 @@ internal void SetDeadLetters(IDeadLetters deadLetters) { lock (deadLettersMutex) { - if(deadLetters != null && DeadLetters != null) + if (deadLetters != null && DeadLetters != null) { deadLetters.Stop(); throw new InvalidOperationException("Dead letters already exists."); @@ -309,7 +348,7 @@ internal void SetPrivateRoot(IStoppable privateRoot) throw new InvalidOperationException("Private root already exists."); } - PrivateRoot = privateRoot; + PrivateRoot = privateRoot; } }