Skip to content

Commit

Permalink
* Fixed issue: #7; * Minor refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
NimaAra committed Sep 19, 2017
1 parent bcbdbec commit 26b97e6
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
<None Remove="Easy.MessageHub.Benchmarker.Core.v3.ncrunchproject" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Easy.MessageHub\Easy.MessageHub.csproj" />
</ItemGroup>
Expand Down
14 changes: 7 additions & 7 deletions Easy.MessageHub.Tests.Unit/Easy.MessageHub.Tests.Unit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=3.6.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="Shouldly, Version=2.8.2.0, Culture=neutral, PublicKeyToken=6042cbcb05cbc941, processorArchitecture=MSIL">
<HintPath>..\packages\Shouldly.2.8.2\lib\net451\Shouldly.dll</HintPath>
<Reference Include="Shouldly, Version=2.8.3.0, Culture=neutral, PublicKeyToken=6042cbcb05cbc941, processorArchitecture=MSIL">
<HintPath>..\packages\Shouldly.2.8.3\lib\net451\Shouldly.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand All @@ -46,14 +46,14 @@
<Compile Include="SubscriptionsTests.cs" />
<Compile Include="SubscriptionTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Easy.MessageHub\Easy.MessageHub.csproj">
<Project>{833AB5AD-A0C5-4F41-A4BD-1EC011AD8677}</Project>
<Name>Easy.MessageHub</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
7 changes: 4 additions & 3 deletions Easy.MessageHub.Tests.Unit/MessageHubTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ private static void UsageExamples()
var commandsQueue = new Queue<Command>();
var ordersQueue = new Queue<Order>();

Action<Type, object> auditHandler = (type, msg) =>

void AuditHandler(Type type, object msg)
{
// ReSharper disable once AccessToModifiedClosure
if (!isUsageExampleRunning) { return; }

msg.ShouldBeAssignableTo<MessageBase>();
auditQueue.Enqueue((MessageBase) msg);
};
}

hub.RegisterGlobalHandler(auditHandler);
hub.RegisterGlobalHandler(AuditHandler);

hub.Publish(new MessageBase { Name = "Base" });

Expand Down
12 changes: 6 additions & 6 deletions Easy.MessageHub.Tests.Unit/SubscriptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,28 @@ public void When_subscribing_value_type()
Subscriptions.Clear();
Subscriptions.IsRegistered(newKey).ShouldBeFalse();

var subscriptionsSnapshotMain = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var subscriptionsSnapshotMain = Subscriptions.GetTheLatestSubscriptions();
subscriptionsSnapshotMain.Length.ShouldBe(0);

var keyA = Subscriptions.Register(TimeSpan.Zero, action);
var subscriptionsSnapshotA = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var subscriptionsSnapshotA = Subscriptions.GetTheLatestSubscriptions();
subscriptionsSnapshotA.Length.ShouldBe(1);

var keyB = Subscriptions.Register(TimeSpan.Zero, action);
var subscriptionsSnapshotB = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var subscriptionsSnapshotB = Subscriptions.GetTheLatestSubscriptions();
subscriptionsSnapshotB.Length.ShouldBe(2);

Subscriptions.IsRegistered(keyA).ShouldBeTrue();
var subscriptionsSnapshotC = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var subscriptionsSnapshotC = Subscriptions.GetTheLatestSubscriptions();
subscriptionsSnapshotC.Length.ShouldBe(2);
subscriptionsSnapshotC.ShouldBeSameAs(subscriptionsSnapshotB);

Subscriptions.UnRegister(keyB);
var subscriptionsSnapshotD = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var subscriptionsSnapshotD = Subscriptions.GetTheLatestSubscriptions();
subscriptionsSnapshotD.Length.ShouldBe(1);

Subscriptions.Clear();
var subscriptionsSnapshotE = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var subscriptionsSnapshotE = Subscriptions.GetTheLatestSubscriptions();
subscriptionsSnapshotE.Length.ShouldBe(0);
}
}
Expand Down
4 changes: 2 additions & 2 deletions Easy.MessageHub.Tests.Unit/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="3.6.1" targetFramework="net452" />
<package id="Shouldly" version="2.8.2" targetFramework="net452" />
<package id="NUnit" version="3.8.1" targetFramework="net452" />
<package id="Shouldly" version="2.8.3" targetFramework="net452" />
</packages>
7 changes: 2 additions & 5 deletions Easy.MessageHub/MessageHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void RegisterGlobalHandler(Action<Type, object> onMessage)
/// <param name="message">The message to published</param>
public void Publish<T>(T message)
{
var localSubscriptions = Subscriptions.GetTheLatestRevisionOfSubscriptions();
var localSubscriptions = Subscriptions.GetTheLatestSubscriptions();

var msgType = typeof(T);

Expand Down Expand Up @@ -93,10 +93,7 @@ public void Publish<T>(T message)
/// <typeparam name="T">The type of message to subscribe to</typeparam>
/// <param name="action">The callback to be invoked once the message is published on the <see cref="MessageHub"/></param>
/// <returns>The token representing the subscription</returns>
public Guid Subscribe<T>(Action<T> action)
{
return Subscribe(action, TimeSpan.Zero);
}
public Guid Subscribe<T>(Action<T> action) => Subscribe(action, TimeSpan.Zero);

/// <summary>
/// Subscribes a callback against the <see cref="MessageHub"/> for a specific type of message.
Expand Down
53 changes: 34 additions & 19 deletions Easy.MessageHub/Subscriptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ namespace Easy.MessageHub
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

internal static class Subscriptions
{
private static readonly List<Subscription> AllSubscriptions = new List<Subscription>();
private static int _subscriptionRevision;
private static int _subscriptionsChangeCounter;

[ThreadStatic]
private static int _localSubscriptionRevision;
Expand All @@ -24,7 +25,7 @@ internal static Guid Register<T>(TimeSpan throttleBy, Action<T> action)
lock (AllSubscriptions)
{
AllSubscriptions.Add(subscription);
_subscriptionRevision++;
_subscriptionsChangeCounter++;
}

return key;
Expand All @@ -34,10 +35,19 @@ internal static void UnRegister(Guid token)
{
lock (AllSubscriptions)
{
var subscription = AllSubscriptions.FirstOrDefault(s => s.Token == token);
var subscription = AllSubscriptions.Find(s => s.Token == token);
if (subscription == null) { return; }

var removed = AllSubscriptions.Remove(subscription);
if (!removed) { return; }

var localIdx = Array.IndexOf(_localSubscriptions, subscription);
if (localIdx >= 0)
{
_localSubscriptions = RemoveAt(_localSubscriptions, localIdx);
}

if (removed) { _subscriptionRevision++; }
_subscriptionsChangeCounter++;
}
}

Expand All @@ -46,7 +56,8 @@ internal static void Clear()
lock (AllSubscriptions)
{
AllSubscriptions.Clear();
_subscriptionRevision++;
Array.Clear(_localSubscriptions, 0, _localSubscriptions.Length);
_subscriptionsChangeCounter++;
}
}

Expand All @@ -55,33 +66,37 @@ internal static bool IsRegistered(Guid token)
lock (AllSubscriptions) { return AllSubscriptions.Any(s => s.Token == token); }
}

internal static Subscription[] GetTheLatestRevisionOfSubscriptions()
internal static Subscription[] GetTheLatestSubscriptions()
{
if (_localSubscriptions == null)
{
_localSubscriptions = new Subscription[0];
}
if (_localSubscriptions == null) { _localSubscriptions = new Subscription[0]; }

if (_localSubscriptionRevision == _subscriptionRevision)
{
return _localSubscriptions;
}
var changeCounterLatestCopy = Interlocked.CompareExchange(ref _subscriptionsChangeCounter, 0, 0);
if (_localSubscriptionRevision == changeCounterLatestCopy) { return _localSubscriptions; }

Subscription[] latestSubscriptions;
lock (AllSubscriptions)
{
latestSubscriptions = AllSubscriptions.ToArray();
_localSubscriptionRevision = _subscriptionRevision;
}

_localSubscriptionRevision = changeCounterLatestCopy;
_localSubscriptions = latestSubscriptions;

return latestSubscriptions;
return _localSubscriptions;
}

internal static void Dispose()
internal static void Dispose() => Clear();

private static T[] RemoveAt<T>(T[] source, int index)
{
Clear();
var dest = new T[source.Length - 1];
if (index > 0) { Array.Copy(source, 0, dest, 0, index); }

if (index < source.Length - 1)
{
Array.Copy(source, index + 1, dest, index, source.Length - index - 1);
}

return dest;
}
}
}

0 comments on commit 26b97e6

Please sign in to comment.