-
Notifications
You must be signed in to change notification settings - Fork 637
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make gossip available as a mem stream: $mem-gossip
Works very similarly to the $mem-node-state stream. Factored out a helper class. Both mem streams are in the same logical log because the SubscriptionsService currently supports one physical log and one inmemory log.
- Loading branch information
1 parent
a0bbea0
commit 8023d6a
Showing
14 changed files
with
255 additions
and
49 deletions.
There are no files selected for viewing
88 changes: 88 additions & 0 deletions
88
src/EventStore.Core.XUnit.Tests/Services/Storage/InMemory/GossipListenerServiceTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
using System; | ||
using System.Net; | ||
using System.Text; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
using System.Threading.Channels; | ||
using System.Threading.Tasks; | ||
using EventStore.Core.Cluster; | ||
using EventStore.Core.Messages; | ||
using EventStore.Core.Messaging; | ||
using EventStore.Core.Services; | ||
using EventStore.Core.Services.Storage.InMemory; | ||
using Xunit; | ||
|
||
namespace EventStore.Core.XUnit.Tests.Services.Storage.InMemory; | ||
|
||
public class GossipListenerServiceTests { | ||
private readonly GossipListenerService _sut; | ||
private readonly ChannelReader<Message> _channelReader; | ||
private readonly Guid _nodeId = Guid.NewGuid(); | ||
|
||
private readonly JsonSerializerOptions _options = new() { | ||
Converters = { | ||
new JsonStringEnumConverter(), | ||
}, | ||
}; | ||
|
||
public GossipListenerServiceTests() { | ||
var channel = Channel.CreateUnbounded<Message>(); | ||
_channelReader = channel.Reader; | ||
_sut = new GossipListenerService( | ||
nodeId: _nodeId, | ||
publisher: new EnvelopePublisher(new ChannelEnvelope(channel)), | ||
new InMemoryLog()); | ||
} | ||
|
||
[Fact] | ||
public async Task notify_state_change() { | ||
static int random() => Random.Shared.Next(65000); | ||
|
||
var member = MemberInfo.ForVNode( | ||
instanceId: Guid.NewGuid(), | ||
timeStamp: DateTime.Now, | ||
state: Data.VNodeState.DiscoverLeader, | ||
isAlive: true, | ||
internalTcpEndPoint: default, | ||
internalSecureTcpEndPoint: new DnsEndPoint("myhost", random()), | ||
externalTcpEndPoint: default, | ||
externalSecureTcpEndPoint: new DnsEndPoint("myhost", random()), | ||
httpEndPoint: new DnsEndPoint("myhost", random()), | ||
advertiseHostToClientAs: "advertiseHostToClientAs", | ||
advertiseHttpPortToClientAs: random(), | ||
advertiseTcpPortToClientAs: random(), | ||
lastCommitPosition: random(), | ||
writerCheckpoint: random(), | ||
chaserCheckpoint: random(), | ||
epochPosition: random(), | ||
epochNumber: random(), | ||
epochId: Guid.NewGuid(), | ||
nodePriority: random(), | ||
isReadOnlyReplica: true); | ||
|
||
// when | ||
_sut.Handle(new GossipMessage.GossipUpdated(new ClusterInfo(member))); | ||
|
||
// then | ||
var @event = Assert.IsType<StorageMessage.InMemoryEventCommitted>(await _channelReader.ReadAsync()); | ||
|
||
Assert.Equal(SystemStreams.GossipStream, @event.Event.EventStreamId); | ||
Assert.Equal(GossipListenerService.EventType, @event.Event.EventType); | ||
Assert.Equal(0, @event.Event.EventNumber); | ||
|
||
var expectedBytes = JsonSerializer.SerializeToUtf8Bytes( | ||
new { | ||
NodeId = _nodeId, | ||
Members = new[] { new ClientClusterInfo.ClientMemberInfo(member) }, | ||
}, | ||
_options); | ||
|
||
var actualBytes = @event.Event.Data; | ||
|
||
Assert.Equal( | ||
Encoding.UTF8.GetString(expectedBytes), | ||
Encoding.UTF8.GetString(actualBytes.Span)); | ||
|
||
Assert.Equal(expectedBytes, actualBytes); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
src/EventStore.Core/Services/Storage/InMemory/GossipListenerService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
using EventStore.Core.Bus; | ||
using EventStore.Core.Messages; | ||
|
||
namespace EventStore.Core.Services.Storage.InMemory; | ||
|
||
public class GossipListenerService : | ||
IInMemoryStreamReader, | ||
IHandle<GossipMessage.GossipUpdated> { | ||
|
||
private readonly SingleEventInMemoryStream _stream; | ||
private readonly Guid _nodeId; | ||
public const string EventType = "$GossipUpdated"; | ||
|
||
private readonly JsonSerializerOptions _options = new() { | ||
Converters = { | ||
new JsonStringEnumConverter(), | ||
}, | ||
}; | ||
|
||
public GossipListenerService(Guid nodeId, IPublisher publisher, InMemoryLog memLog) { | ||
_stream = new(publisher, memLog, SystemStreams.GossipStream); | ||
_nodeId = nodeId; | ||
} | ||
|
||
public void Handle(GossipMessage.GossipUpdated message) { | ||
// SystemStreams.GossipStream is a system stream so only readable by admins | ||
// we use ClientMemberInfo because plugins will consume this stream and | ||
// it is less likely to change than the internal gossip. | ||
var payload = new { | ||
NodeId = _nodeId, | ||
Members = message.ClusterInfo.Members.Select(static x => | ||
new Cluster.ClientClusterInfo.ClientMemberInfo(x)), | ||
}; | ||
|
||
var data = JsonSerializer.SerializeToUtf8Bytes(payload, _options); | ||
_stream.Write(EventType, data); | ||
} | ||
|
||
public ClientMessage.ReadStreamEventsForwardCompleted ReadForwards( | ||
ClientMessage.ReadStreamEventsForward msg) => _stream.ReadForwards(msg); | ||
|
||
public ClientMessage.ReadStreamEventsBackwardCompleted ReadBackwards( | ||
ClientMessage.ReadStreamEventsBackward msg) => _stream.ReadBackwards(msg); | ||
} |
2 changes: 1 addition & 1 deletion
2
...Services/Storage/IInMemoryStreamReader.cs → ...Storage/InMemory/IInMemoryStreamReader.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
src/EventStore.Core/Services/Storage/InMemory/InMemoryLog.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System.Threading; | ||
|
||
namespace EventStore.Core.Services.Storage.InMemory; | ||
|
||
// does not support $all style reads, but tracks the LastCommitPosition so that | ||
// the long poll mechanism works in the SubscriptionsService. | ||
// note that the SubscriptionsService currently only supports one physical log | ||
// and one inmemory log so we can't have separate inmemory logs per inmemory stream. | ||
public class InMemoryLog { | ||
long _lastCommitPosition = 0L; | ||
|
||
public long GetLastCommitPosition() => Interlocked.Read(ref _lastCommitPosition); | ||
public long GetNextCommitPosition() => Interlocked.Increment(ref _lastCommitPosition); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
src/EventStore.Core/Services/Storage/InMemory/NodeStateListenerService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
using EventStore.Core.Bus; | ||
using EventStore.Core.Messages; | ||
|
||
namespace EventStore.Core.Services.Storage.InMemory; | ||
|
||
// threading: we expect to handle one StateChangeMessage at a time, but Reads can happen concurrently | ||
// with those handlings and with other reads. | ||
public class NodeStateListenerService : | ||
IInMemoryStreamReader, | ||
IHandle<SystemMessage.StateChangeMessage> { | ||
|
||
private readonly SingleEventInMemoryStream _stream; | ||
|
||
public const string EventType = "$NodeStateChanged"; | ||
|
||
private readonly JsonSerializerOptions _options = new() { | ||
Converters = { | ||
new JsonStringEnumConverter(), | ||
}, | ||
}; | ||
|
||
public NodeStateListenerService(IPublisher publisher, InMemoryLog memLog) { | ||
_stream = new(publisher, memLog, SystemStreams.NodeStateStream); | ||
} | ||
|
||
public void Handle(SystemMessage.StateChangeMessage message) { | ||
var payload = new { message.State }; | ||
var data = JsonSerializer.SerializeToUtf8Bytes(payload, _options); | ||
_stream.Write(EventType, data); | ||
} | ||
|
||
public ClientMessage.ReadStreamEventsForwardCompleted ReadForwards( | ||
ClientMessage.ReadStreamEventsForward msg) => _stream.ReadForwards(msg); | ||
|
||
public ClientMessage.ReadStreamEventsBackwardCompleted ReadBackwards( | ||
ClientMessage.ReadStreamEventsBackward msg) => _stream.ReadBackwards(msg); | ||
} |
Oops, something went wrong.