Repository navigation
Milestone 3.5: widen system/address UID int32 -> int64 (Artery prerequisite) #8317
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
Changes from all commits
1f3018f
6044662
259a94e
25f7c56
c7a2cd2
36b255e
e955723
12b8146
3fa4f53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,47 @@ | ||
| ## 1. Core type + generation | ||
|
|
||
| - [ ] 1.1 Widen `AddressUid.Uid` (field) + `AddressUidExtension.Uid(ActorSystem)` `int → long` | ||
| - [ ] 1.2 Add a netstandard2.0-safe 64-bit RNG; default generation stays in `[0, int.MaxValue]` | ||
| - [ ] 1.3 Config switch to enable full 64-bit uid generation (default off; documented "all nodes v1.6 first" precondition) | ||
| - [x] 1.1 Widen `AddressUid.Uid` (field) + `AddressUidExtension.Uid(ActorSystem)` `int → long` | ||
| - [x] 1.2 Add a netstandard2.0-safe 64-bit RNG; default generation stays in `[0, int.MaxValue]` | ||
| - [x] 1.3 Config switch to enable full 64-bit uid generation (default off; documented "all nodes v1.6 first" precondition) — `akka.remote.use-64bit-system-uids` | ||
|
|
||
| ## 2. Cluster | ||
|
|
||
| - [ ] 2.1 `UniqueAddress(Address, long uid)` + `long Uid`; fix identity/sort/hash (`Member`) | ||
| - [ ] 2.2 Verify gossip vector-clock node name (`VclockName` = address + "-" + uid decimal string) — behavior unchanged | ||
| - [ ] 2.3 `ClusterDaemon` `Quarantined(new UniqueAddress(addr, long uid))` | ||
| - [x] 2.1 `UniqueAddress(Address, long uid)` + `long Uid`; fix identity/sort/hash (`Member`) | ||
| - [x] 2.2 Verify gossip vector-clock node name (`VclockName` = address + "-" + uid decimal string) — behavior unchanged (string-only, `ClusterDaemon.VclockName`; hash also value-identical for int-range uids) | ||
| - [x] 2.3 `ClusterDaemon` `Quarantined(new UniqueAddress(addr, long uid))` | ||
|
|
||
| ## 3. Remoting state machine (internal `int → long`) | ||
|
|
||
| - [ ] 3.1 `HandshakeInfo` ctor + `Uid`; `AkkaProtocolTransport` refuseUid path | ||
| - [ ] 3.2 `EndpointRegistry` (register/quarantine/refuseUid) | ||
| - [ ] 3.3 `Endpoint.cs`: `HopelessAssociation`, `ReliableDeliverySupervisor`, `GotUid`, `EndpointWriter` uid fields/params | ||
| - [ ] 3.4 `EndpointManager` messages: `Pass`, `Quarantined`, `Quarantine`, `ResendState` | ||
| - [x] 3.1 `HandshakeInfo` ctor + `Uid`; `AkkaProtocolTransport` refuseUid path | ||
| - [x] 3.2 `EndpointRegistry` (register/quarantine/refuseUid) | ||
| - [x] 3.3 `Endpoint.cs`: `HopelessAssociation`, `ReliableDeliverySupervisor`, `GotUid`, `EndpointWriter` uid fields/params | ||
| - [x] 3.4 `EndpointManager` messages: `Pass`, `Quarantined`, `Quarantine`, `ResendState` | ||
|
|
||
| ## 4. RemoteWatcher | ||
|
|
||
| - [ ] 4.1 `HeartbeatRsp(long addressUid)` + `long AddressUid`; `_addressUids: Dictionary<Address,long>`; `ReceiveHeartbeatRsp` | ||
| - [ ] 4.2 `Quarantine(Address, long? addressUid)` | ||
| - [x] 4.1 `HeartbeatRsp(long addressUid)` + `long AddressUid`; `_addressUids: Dictionary<Address,long>`; `ReceiveHeartbeatRsp` | ||
| - [x] 4.2 `Quarantine(Address, long? addressUid)` | ||
|
|
||
| ## 5. Quarantine API (hard re-type) | ||
|
|
||
| - [ ] 5.1 `IRemoteActorRefProvider.Quarantine(Address, long? uid)` | ||
| - [ ] 5.2 `RemoteActorRefProvider.Quarantine`, `RemoteTransport.Quarantine`, `Remoting.Quarantine` | ||
| - [ ] 5.3 `QuarantinedEvent(Address, long uid)` + `long Uid` | ||
| - [x] 5.1 `IRemoteActorRefProvider.Quarantine(Address, long? uid)` | ||
| - [x] 5.2 `RemoteActorRefProvider.Quarantine`, `RemoteTransport.Quarantine`, `Remoting.Quarantine` | ||
| - [x] 5.3 `QuarantinedEvent(Address, long uid)` + `long Uid` | ||
|
|
||
| ## 6. Wire + serializers | ||
|
|
||
| - [ ] 6.1 `ClusterMessages.proto` `UniqueAddress.uid` `uint32 → uint64`; regenerate | ||
| - [ ] 6.2 Remove narrowing casts: `ClusterMessageSerializer`, `MiscMessageSerializer`, `AkkaPduCodec`, DData `SerializationSupport.UniqueAddressFromProto` | ||
| - [ ] 6.3 Coordinate `serializer-v2` schema to emit/read 64-bit uid | ||
| - [x] 6.1 `ClusterMessages.proto` `UniqueAddress.uid` `uint32 → uint64`; regenerate (Grpc.Tools at build time) | ||
| - [x] 6.2 Remove narrowing casts: `ClusterMessageSerializer`, `MiscMessageSerializer`, `AkkaPduCodec`, DData `SerializationSupport.UniqueAddressFromProto` | ||
| - [x] 6.3 Coordinate `serializer-v2` schema to emit/read 64-bit uid (Decision 11 in serializer-v2 design.md) | ||
|
|
||
| ## 7. API approval + build | ||
|
|
||
| - [ ] 7.1 Update `Akka.API.Tests` approved files (`ApproveRemote.*`, `ApproveCluster.*`) for the hard break | ||
| - [ ] 7.2 `dotnet build -warnaserror` clean | ||
| - [ ] 7.3 Akka.Remote + Akka.Cluster + DistributedData tests green | ||
| - [x] 7.1 Update `Akka.API.Tests` approved files (`ApproveRemote.*`, `ApproveCluster.*`) for the hard break | ||
| - [x] 7.2 `dotnet build -warnaserror` clean | ||
| - [x] 7.3 Akka.Remote + Akka.Cluster + DistributedData tests green (391 / 376 / 190 passed, 0 failed, net10.0 Release) | ||
|
|
||
| ## 8. Compatibility + docs | ||
|
|
||
| - [ ] 8.1 Rolling-upgrade test: v1.5 ↔ v1.6 gossip with int-range uids — no truncation, cluster forms | ||
| - [ ] 8.2 Full-range generation test (all-v1.6) — >32-bit uids round-trip | ||
| - [ ] 8.3 Add `BREAKING_CHANGES_V1.6.md` entry (API + Wire rows) | ||
| - [x] 8.1 Rolling-upgrade test: v1.5 ↔ v1.6 gossip with int-range uids — no truncation, cluster forms (wire-level simulation via uint32/uint64 varint cross-parse in `UniqueAddressWireCompatSpec`; a live mixed-version cluster cannot be exercised in-repo) | ||
| - [x] 8.2 Full-range generation test (all-v1.6) — >32-bit uids round-trip (gossip, heartbeat, handshake PDU, DData; generation range tests in `AddressUidExtensionSpecs`) | ||
| - [x] 8.3 Add `BREAKING_CHANGES_V1.6.md` entry (API + Wire rows) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| //----------------------------------------------------------------------- | ||
| // <copyright file="UniqueAddressSerializationSupportSpec.cs" company="Akka.NET Project"> | ||
| // Copyright (C) 2009-2022 Lightbend Inc. <http://www.lightbend.com> | ||
| // Copyright (C) 2013-2025 .NET Foundation <https://github.com/akkadotnet/akka.net> | ||
| // </copyright> | ||
| //----------------------------------------------------------------------- | ||
|
|
||
| using Akka.Actor; | ||
| using Akka.Configuration; | ||
| using Akka.DistributedData.Serialization; | ||
| using FluentAssertions; | ||
| using Xunit; | ||
| using Address = Akka.Actor.Address; | ||
| using UniqueAddress = Akka.Cluster.UniqueAddress; | ||
|
|
||
| namespace Akka.DistributedData.Tests.Serialization | ||
| { | ||
| /// <summary> | ||
| /// Task 8.2: DData's <see cref="Proto.Msg.UniqueAddress"/> wire field was already <c>int64</c> | ||
| /// (ReplicatorMessages.proto) before the widen-system-uid-to-64bit change - only the C# narrowing cast in | ||
| /// <see cref="SerializationSupport.UniqueAddressFromProto"/> was removed. This verifies >32-bit uids | ||
| /// round-trip cleanly through <see cref="SerializationSupport.UniqueAddressToProto"/> / | ||
| /// <see cref="SerializationSupport.UniqueAddressFromProto"/>. | ||
| /// </summary> | ||
| [Collection("DistributedDataSpec")] | ||
| public class UniqueAddressSerializationSupportSpec : TestKit.Xunit.TestKit | ||
| { | ||
| private static readonly Config BaseConfig = ConfigurationFactory.ParseString(@" | ||
| akka.actor { | ||
| provider=""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"" | ||
| } | ||
| akka.remote.dot-netty.tcp.port = 0").WithFallback(DistributedData.DefaultConfig()); | ||
|
|
||
| private readonly SerializationSupport _support; | ||
|
|
||
| public UniqueAddressSerializationSupportSpec(ITestOutputHelper output) | ||
| : base(BaseConfig, "UniqueAddressSerializationSupportSpec", output) | ||
| { | ||
| _support = new SerializationSupport((ExtendedActorSystem)Sys); | ||
| } | ||
|
|
||
| [Theory(DisplayName = "Should_round_trip_unchanged_When_SerializationSupport_converts_a_64_bit_uid")] | ||
| [InlineData(12345L)] | ||
| [InlineData(long.MaxValue)] | ||
| [InlineData(unchecked((long)0x8000_0000_0000_0001))] // negative | ||
| [InlineData(1L << 40)] | ||
| public void Should_round_trip_unchanged_When_SerializationSupport_converts_a_64_bit_uid(long uid) | ||
| { | ||
| var address = new UniqueAddress(new Address("akka.tcp", Sys.Name, "some.host.org", 4711), uid); | ||
|
|
||
| var proto = SerializationSupport.UniqueAddressToProto(address); | ||
| var roundTripped = _support.UniqueAddressFromProto(proto); | ||
|
|
||
| roundTripped.Should().Be(address); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,14 +23,14 @@ namespace Akka.Remote | |
| { | ||
| public class AddressUid : Akka.Actor.IExtension | ||
| { | ||
| public readonly int Uid; | ||
| public readonly long Uid; | ||
| public AddressUid() { } | ||
| } | ||
| public class AddressUidExtension : Akka.Actor.ExtensionIdProvider<Akka.Remote.AddressUid> | ||
| { | ||
| public AddressUidExtension() { } | ||
| public override Akka.Remote.AddressUid CreateExtension(Akka.Actor.ExtendedActorSystem system) { } | ||
| public static int Uid(Akka.Actor.ActorSystem system) { } | ||
| public static long Uid(Akka.Actor.ActorSystem system) { } | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fastest way to check the public-surface blast radius. The approved-file delta is only the uid members: |
||
| } | ||
| public class AkkaProtocolSettings | ||
| { | ||
|
|
@@ -143,7 +143,7 @@ namespace Akka.Remote | |
| bool HasAddress(Akka.Actor.Address address); | ||
| Akka.Actor.IActorRef InternalResolveActorRef(string path); | ||
| Akka.Actor.Deploy LookUpRemotes(System.Collections.Generic.IEnumerable<string> p); | ||
| void Quarantine(Akka.Actor.Address address, int? uid); | ||
| void Quarantine(Akka.Actor.Address address, long? uid); | ||
| Akka.Actor.IInternalActorRef ResolveActorRefWithLocalAddress(string path, Akka.Actor.Address localAddress); | ||
| void UseActorOnNode(Akka.Remote.RemoteActorRef actor, Akka.Actor.Props props, Akka.Actor.Deploy deploy, Akka.Actor.IInternalActorRef supervisor); | ||
| } | ||
|
|
@@ -161,9 +161,9 @@ namespace Akka.Remote | |
| } | ||
| public sealed class QuarantinedEvent : Akka.Remote.RemotingLifecycleEvent | ||
| { | ||
| public QuarantinedEvent(Akka.Actor.Address address, int uid) { } | ||
| public QuarantinedEvent(Akka.Actor.Address address, long uid) { } | ||
| public Akka.Actor.Address Address { get; } | ||
| public int Uid { get; } | ||
| public long Uid { get; } | ||
| public override Akka.Event.LogLevel LogLevel() { } | ||
| public override string ToString() { } | ||
| } | ||
|
|
@@ -219,7 +219,7 @@ namespace Akka.Remote | |
| public virtual void Init(Akka.Actor.Internal.ActorSystemImpl system) { } | ||
| public Akka.Actor.IActorRef InternalResolveActorRef(string path) { } | ||
| public Akka.Actor.Deploy LookUpRemotes(System.Collections.Generic.IEnumerable<string> p) { } | ||
| public void Quarantine(Akka.Actor.Address address, int? uid) { } | ||
| public void Quarantine(Akka.Actor.Address address, long? uid) { } | ||
| public void RegisterTempActor(Akka.Actor.IInternalActorRef actorRef, Akka.Actor.ActorPath path) { } | ||
| public Akka.Actor.IActorRef ResolveActorRef(Akka.Actor.ActorPath actorPath) { } | ||
| public Akka.Actor.IActorRef ResolveActorRef(string path) { } | ||
|
|
@@ -286,7 +286,7 @@ namespace Akka.Remote | |
| public abstract Akka.Actor.Address LocalAddressForRemote(Akka.Actor.Address remote); | ||
| public abstract System.Threading.Tasks.Task<bool> ManagementCommand(object cmd); | ||
| public abstract System.Threading.Tasks.Task<bool> ManagementCommand(object cmd, System.Threading.CancellationToken cancellationToken); | ||
| public abstract void Quarantine(Akka.Actor.Address address, int? uid); | ||
| public abstract void Quarantine(Akka.Actor.Address address, long? uid); | ||
| public abstract void Send(object message, Akka.Actor.IActorRef sender, Akka.Remote.RemoteActorRef recipient); | ||
| public abstract System.Threading.Tasks.Task Shutdown(); | ||
| public abstract void Start(); | ||
|
|
@@ -308,7 +308,7 @@ namespace Akka.Remote | |
| protected override void OnReceive(object message) { } | ||
| protected override void PostStop() { } | ||
| protected virtual void PublishAddressTerminated(Akka.Actor.Address address) { } | ||
| protected virtual void Quarantine(Akka.Actor.Address address, int? addressUid) { } | ||
| protected virtual void Quarantine(Akka.Actor.Address address, long? addressUid) { } | ||
| protected void RemoveWatch(Akka.Actor.IInternalActorRef watchee, Akka.Actor.IInternalActorRef watcher) { } | ||
| protected void RemoveWatchee(Akka.Actor.IInternalActorRef watchee) { } | ||
| protected void UnwatchNode(Akka.Actor.Address watcheeAddress) { } | ||
|
|
@@ -325,8 +325,8 @@ namespace Akka.Remote | |
| } | ||
| public class HeartbeatRsp | ||
| { | ||
| public HeartbeatRsp(int addressUid) { } | ||
| public int AddressUid { get; } | ||
| public HeartbeatRsp(long addressUid) { } | ||
| public long AddressUid { get; } | ||
| } | ||
| public class HeartbeatTick | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DData's
UniqueAddress.uidinReplicatorMessages.protowas alreadyint64before this change, so this is just the C#(int)narrowing coming off.UniqueAddressSerializationSupportSpecadds a >32-bit round-trip overUniqueAddressToProto/UniqueAddressFromPrototo lock that in.