Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RemoteActorRefProvider address paring, caching and resolving improvements #5273

Merged
merged 41 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f25de15
refactor remote-actorref-provider and add tests for cache entries
Zetanova Sep 7, 2021
3fc0168
replace address-cache with actorpath-cache
Zetanova Sep 7, 2021
9a67f1c
refactor resolve with local address
Zetanova Sep 7, 2021
746f76b
refactor and cleanup
Zetanova Sep 7, 2021
bff01bb
remove volatile from fields
Zetanova Sep 7, 2021
d0f232e
Merge branch 'dev' into perf-remote-actorref-provider
Zetanova Sep 7, 2021
3dc67a5
merge upstream
Zetanova Sep 8, 2021
b458ae4
Merge branch 'perf-remote-actorref-provider' of https://github.com/Ze…
Zetanova Sep 8, 2021
2a55502
remove double equals
Zetanova Sep 8, 2021
14e88e2
cleanup
Zetanova Sep 9, 2021
762ec30
refactor to base
Zetanova Sep 9, 2021
aea2166
optimize elements list
Zetanova Sep 9, 2021
a36170f
improve actor path join
Zetanova Sep 10, 2021
aa211c7
improve actor path equals and compare
Zetanova Sep 10, 2021
1842505
cleanup
Zetanova Sep 10, 2021
f388cef
protect stack and use moveto of arraybuilder
Zetanova Sep 11, 2021
baaeea2
update api spec
Zetanova Sep 11, 2021
f86dc4b
test for jumbo actor path name support
Zetanova Sep 11, 2021
4427087
small refactors
Zetanova Sep 12, 2021
93f5d9c
add ActorPath.ParentOf(depth)
Zetanova Sep 12, 2021
d74deaa
dont copy actorpath
Zetanova Sep 12, 2021
a7a525e
use actorpath-cache and remove cache entry test
Zetanova Sep 12, 2021
d3c33e8
refactor fill array
Zetanova Sep 12, 2021
4512aec
prepair actor path cache for better deduplication
Zetanova Sep 12, 2021
ad3ca76
update api
Zetanova Sep 12, 2021
026a6fc
cache root actor path
Zetanova Sep 15, 2021
b29e242
update api
Zetanova Sep 15, 2021
9d9a2d7
remove obsolete code
Zetanova Sep 15, 2021
29eaff2
cleanup code
Zetanova Sep 15, 2021
f33929e
Merge branch 'dev' into perf-remote-actorref-provider
Aaronontheweb Sep 15, 2021
1051ed3
Merge remote-tracking branch 'upstream/dev' into perf-remote-actorref…
Zetanova Sep 15, 2021
2564415
Merge branch 'perf-remote-actorref-provider' of https://github.com/Ze…
Zetanova Sep 15, 2021
d3a0ae0
removed commented cache tests
Zetanova Sep 15, 2021
217485c
refactor span to string bulder
Zetanova Sep 15, 2021
409485f
use internal fields and ref equals
Zetanova Sep 17, 2021
9eba407
add rebase path test
Zetanova Sep 17, 2021
cc30aa1
fix possible NRE
Zetanova Sep 18, 2021
73d26ff
extend and test address parsing
Zetanova Sep 18, 2021
c13ad50
update api
Zetanova Sep 18, 2021
793b8b5
Merge branch 'dev' into perf-remote-actorref-provider
Zetanova Sep 29, 2021
8dd6e0c
Merge branch 'dev' into perf-remote-actorref-provider
Aaronontheweb Oct 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 16 additions & 21 deletions src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,21 @@ namespace Akka.Actor
protected ActorPath(Akka.Actor.Address address, string name) { }
protected ActorPath(Akka.Actor.ActorPath parentPath, string name, long uid) { }
public Akka.Actor.Address Address { get; }
public abstract System.Collections.Generic.IReadOnlyList<string> Elements { get; }
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved
public int Depth { get; }
public System.Collections.Generic.IReadOnlyList<string> Elements { get; }
public string Name { get; }
public abstract Akka.Actor.ActorPath Parent { get; }
public abstract Akka.Actor.ActorPath Root { get; }
public Akka.Actor.ActorPath Parent { get; }
[Newtonsoft.Json.JsonIgnoreAttribute()]
public Akka.Actor.ActorPath Root { get; }
public long Uid { get; }
public Akka.Actor.ActorPath Child(string childName) { }
public abstract int CompareTo(Akka.Actor.ActorPath other);
public int CompareTo(Akka.Actor.ActorPath other) { }
public bool Equals(Akka.Actor.ActorPath other) { }
public override bool Equals(object obj) { }
public static string FormatPathElements(System.Collections.Generic.IEnumerable<string> pathElements) { }
public override int GetHashCode() { }
public static bool IsValidPathElement(string s) { }
public Akka.Actor.ActorPath ParentOf(int depth) { }
public static Akka.Actor.ActorPath Parse(string path) { }
public string ToSerializationFormat() { }
public string ToSerializationFormatWithAddress(Akka.Actor.Address address) { }
Expand All @@ -199,13 +202,16 @@ namespace Akka.Actor
public string ToStringWithoutAddress() { }
public Akka.Util.ISurrogate ToSurrogate(Akka.Actor.ActorSystem system) { }
public static bool TryParse(string path, out Akka.Actor.ActorPath actorPath) { }
public static bool TryParse(Akka.Actor.ActorPath basePath, System.ReadOnlySpan<char> absoluteUri, out Akka.Actor.ActorPath actorPath) { }
public static bool TryParseAddress(string path, out Akka.Actor.Address address) { }
public abstract Akka.Actor.ActorPath WithUid(long uid);
public static bool TryParseAddress(string path, out Akka.Actor.Address address, out System.ReadOnlySpan<char> absoluteUri) { }
public static bool TryParseParts(System.ReadOnlySpan<char> path, out System.ReadOnlySpan<char> address, out System.ReadOnlySpan<char> absoluteUri) { }
public Akka.Actor.ActorPath WithUid(long uid) { }
public static Akka.Actor.ActorPath /(Akka.Actor.ActorPath path, string name) { }
public static Akka.Actor.ActorPath /(Akka.Actor.ActorPath path, System.Collections.Generic.IEnumerable<string> name) { }
public static bool ==(Akka.Actor.ActorPath left, Akka.Actor.ActorPath right) { }
public static bool !=(Akka.Actor.ActorPath left, Akka.Actor.ActorPath right) { }
public class Surrogate : Akka.Util.ISurrogate, System.IEquatable<Akka.Actor.ActorPath.Surrogate>, System.IEquatable<Akka.Actor.ActorPath>
public sealed class Surrogate : Akka.Util.ISurrogate, System.IEquatable<Akka.Actor.ActorPath.Surrogate>, System.IEquatable<Akka.Actor.ActorPath>
{
public Surrogate(string path) { }
public string Path { get; }
Expand Down Expand Up @@ -408,13 +414,14 @@ namespace Akka.Actor
public static Akka.Actor.Address Parse(string address) { }
public override string ToString() { }
public Akka.Util.ISurrogate ToSurrogate(Akka.Actor.ActorSystem system) { }
public static bool TryParse(System.ReadOnlySpan<char> span, out Akka.Actor.Address address) { }
public Akka.Actor.Address WithHost(string host = null) { }
public Akka.Actor.Address WithPort(System.Nullable<int> port = null) { }
public Akka.Actor.Address WithProtocol(string protocol) { }
public Akka.Actor.Address WithSystem(string system) { }
public static bool ==(Akka.Actor.Address left, Akka.Actor.Address right) { }
public static bool !=(Akka.Actor.Address left, Akka.Actor.Address right) { }
public class AddressSurrogate : Akka.Util.ISurrogate
public sealed class AddressSurrogate : Akka.Util.ISurrogate
{
public AddressSurrogate() { }
public string Host { get; set; }
Expand Down Expand Up @@ -497,15 +504,9 @@ namespace Akka.Actor
{
public static void CancelIfNotNull(this Akka.Actor.ICancelable cancelable) { }
}
public class ChildActorPath : Akka.Actor.ActorPath
public sealed class ChildActorPath : Akka.Actor.ActorPath
{
public ChildActorPath(Akka.Actor.ActorPath parentPath, string name, long uid) { }
public override System.Collections.Generic.IReadOnlyList<string> Elements { get; }
public override Akka.Actor.ActorPath Parent { get; }
public override Akka.Actor.ActorPath Root { get; }
public override int CompareTo(Akka.Actor.ActorPath other) { }
public override int GetHashCode() { }
public override Akka.Actor.ActorPath WithUid(long uid) { }
}
public sealed class CoordinatedShutdown : Akka.Actor.IExtension
{
Expand Down Expand Up @@ -1544,15 +1545,9 @@ namespace Akka.Actor
public void SwapUnderlying(Akka.Actor.ICell cell) { }
protected override void TellInternal(object message, Akka.Actor.IActorRef sender) { }
}
public class RootActorPath : Akka.Actor.ActorPath
public sealed class RootActorPath : Akka.Actor.ActorPath
{
public RootActorPath(Akka.Actor.Address address, string name = "") { }
public override System.Collections.Generic.IReadOnlyList<string> Elements { get; }
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved
public override Akka.Actor.ActorPath Parent { get; }
[Newtonsoft.Json.JsonIgnoreAttribute()]
public override Akka.Actor.ActorPath Root { get; }
public override int CompareTo(Akka.Actor.ActorPath other) { }
public override Akka.Actor.ActorPath WithUid(long uid) { }
}
[Akka.Annotations.InternalApiAttribute()]
public class RootGuardianActorRef : Akka.Actor.LocalActorRef
Expand Down
29 changes: 29 additions & 0 deletions src/core/Akka.Remote.Tests/RemotingSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using Xunit.Abstractions;
using Nito.AsyncEx;
using ThreadLocalRandom = Akka.Util.ThreadLocalRandom;
using Akka.Remote.Serialization;

namespace Akka.Remote.Tests
{
Expand Down Expand Up @@ -177,6 +178,34 @@ public async Task Remoting_must_support_Ask()
Assert.IsType<FutureActorRef<(string, IActorRef)>>(actorRef);
}

//[Fact]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to uncomment these @Zetanova ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this can be let here or deleted.

The thing with ThreadLocal.Values does not really work in the current Cache implementation,
it would produce a memory leak in production.

I did not an easy way to test the cache contains from outside.
It should be tested in one point in the feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it, we would need to refactor the cache infrastructure.

Optimal place and a very easy thing to do,
would to move the ActorPathCache from TreadLocal to context based.

To create an instance of ActorPathCache in EndpointReader and passing it down to decode-messages would be an optimal place with the best cache-hit-rate.

Because ActorResolveCache is used by both writing/reader,
we would there something else.

//public async Task Remoting_should_not_cache_ref_of_local_ask()
//{
// var localActorRefResolveCache = ActorRefResolveThreadLocalCache.For(Sys);
// var localActorPathCache = ActorPathThreadLocalCache.For(Sys);

// var (msg, actorRef) = await _here.Ask<(string, IActorRef)>("ping", DefaultTimeout);
// Assert.Equal("pong", msg);
// Assert.IsType<FutureActorRef<(string, IActorRef)>>(actorRef);

// Assert.Equal(0, localActorRefResolveCache.All.Sum(n => n.Stats.Entries));
// Assert.Equal(2, localActorPathCache.All.Sum(n => n.Stats.Entries));
//}

//[Fact]
//public async Task Remoting_should_not_cache_ref_of_remote_ask()
//{
// var remoteActorRefResolveCache = ActorRefResolveThreadLocalCache.For(_remoteSystem);
// var remoteActorPathCache = ActorPathThreadLocalCache.For(_remoteSystem);

// var (msg, actorRef) = await _here.Ask<(string, IActorRef)>("ping", DefaultTimeout);
// Assert.Equal("pong", msg);
// Assert.IsType<FutureActorRef<(string, IActorRef)>>(actorRef);

// Assert.Equal(0, remoteActorRefResolveCache.All.Sum(n => n.Stats.Entries));
// Assert.Equal(2, remoteActorPathCache.All.Sum(n => n.Stats.Entries)); //should be 1
//}

[Fact(Skip = "Racy")]
public async Task Ask_does_not_deadlock()
{
Expand Down
73 changes: 60 additions & 13 deletions src/core/Akka.Remote.Tests/Serialization/LruBoundedCacheSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Akka.Remote.Serialization;
Expand All @@ -14,22 +16,55 @@

namespace Akka.Remote.Tests.Serialization
{
sealed class FastHashTestComparer : IEqualityComparer<string>
{
private readonly string _hashSeed;

public FastHashTestComparer(string hashSeed = "")
{
_hashSeed = hashSeed;
}

public bool Equals(string x, string y)
{
return StringComparer.Ordinal.Equals(x, y);
}

public int GetHashCode(string k)
{
return FastHash.OfStringFast(_hashSeed != string.Empty
? _hashSeed + k + _hashSeed : k);
}
}

sealed class BrokenTestComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return StringComparer.Ordinal.Equals(x, y);
}

public int GetHashCode(string k)
{
return 0;
}
}

public class LruBoundedCacheSpec
{
private class TestCache : LruBoundedCache<string, string> {
public TestCache(int capacity, int evictAgeThreshold, string hashSeed = "") : base(capacity, evictAgeThreshold)
public TestCache(int capacity, int evictAgeThreshold, IEqualityComparer<string> comparer)
: base(capacity, evictAgeThreshold, comparer)
{
_hashSeed = hashSeed;
}

private readonly string _hashSeed;
private int _cntr = 0;

protected override int Hash(string k)
public TestCache(int capacity, int evictAgeThreshold, string hashSeed = "")
: base(capacity, evictAgeThreshold, new FastHashTestComparer(hashSeed))
{
return FastHash.OfStringFast(_hashSeed + k + _hashSeed);
}

private int _cntr = 0;

protected override string Compute(string k)
{
var id = _cntr;
Expand Down Expand Up @@ -71,20 +106,17 @@ public void ExpectComputedOnly(string key, string value)

private sealed class BrokenHashFunctionTestCache : TestCache
{
public BrokenHashFunctionTestCache(int capacity, int evictAgeThreshold, string hashSeed = "") : base(capacity, evictAgeThreshold, hashSeed)
public BrokenHashFunctionTestCache(int capacity, int evictAgeThreshold) :
base(capacity, evictAgeThreshold, new BrokenTestComparer())
{
}

protected override int Hash(string k)
{
return 0;
}
}

[Fact]
public void LruBoundedCache_must_work_in_the_happy_case()
{
var cache = new TestCache(4,4);
var cache = new TestCache(4, 4);

cache.ExpectComputed("A", "A:0");
cache.ExpectComputed("B", "B:1");
Expand All @@ -97,6 +129,19 @@ public void LruBoundedCache_must_work_in_the_happy_case()
cache.ExpectCached("D", "D:3");
}

[Fact]
public void LruBoundedCache_must_handle_explict_set()
{
var cache = new TestCache(4, 4);

cache.ExpectComputed("A", "A:0");
cache.TrySet("A", "A:1").Should().Be(true);
cache.Get("A").Should().Be("A:1");

cache.TrySet("B", "B:X").Should().Be(true);
cache.Get("B").Should().Be("B:X");
}

[Fact]
public void LruBoundedCache_must_evict_oldest_when_full()
{
Expand Down Expand Up @@ -237,6 +282,8 @@ public void LruBoundedCache_must_not_cache_noncacheable_values()
cache.ExpectCached("C", "C:6");
cache.ExpectCached("D", "D:7");
cache.ExpectCached("E", "E:8");

cache.TrySet("#X", "#X:13").Should().BeFalse();
}

[Fact]
Expand Down
Loading