private async Task ReadEventStreamAsync(Func <IBinlogEvent, Task> handleEvent, CancellationToken cancellationToken = default) { var eventStreamReader = new EventStreamReader(_databaseProvider.Deserializer); var channel = new EventStreamChannel(eventStreamReader, _channel.Stream, cancellationToken); var timeout = _options.HeartbeatInterval.Add(TimeSpan.FromMilliseconds(TimeoutConstants.Delta)); while (!cancellationToken.IsCancellationRequested) { var packet = await channel.ReadPacketAsync(cancellationToken).WithTimeout(timeout, TimeoutConstants.Message); if (packet is IBinlogEvent binlogEvent) { // We stop replication if client code throws an exception // As a derived database may end up in an inconsistent state. await handleEvent(binlogEvent); // Commit replication state if there is no exception. UpdateGtidPosition(binlogEvent); UpdateBinlogPosition(binlogEvent); } else if (packet is ErrorPacket error) { throw new InvalidOperationException($"Event stream error. {error.ToString()}"); } else if (packet is EndOfFilePacket && !_options.Blocking) { return; } else { throw new InvalidOperationException($"Event stream unexpected error."); } } }
public async Task Test_LargeSplitPacket_Combined() { using var stream = new MemoryStream(); int lastPacketLength = 150; var packetBody = CreateLargePacket(stream, PacketConstants.MaxBodyLength * 4 + lastPacketLength); stream.Position = 0; var channel = new EventStreamChannel(new TestEventStreamReader(), stream); var packet = await channel.ReadPacketAsync(); Assert.IsType <TestPacket>(packet); Assert.Equal(packetBody, ((TestPacket)packet).Body); }
public async Task Test_PacketExactly16MbWithEmptyPacket_Combined() { using var stream = new MemoryStream(); var packetBody = CreateLargePacket(stream, PacketConstants.MaxBodyLength); WriteHeader(stream, 1, 0); // empty packet stream.Position = 0; var channel = new EventStreamChannel(new TestEventStreamReader(), stream); var packet = await channel.ReadPacketAsync(); Assert.IsType <TestPacket>(packet); Assert.Equal(packetBody, ((TestPacket)packet).Body); }
/// <summary> /// Replicates binlog events from the server /// </summary> /// <param name="cancellationToken">Cancellation token</param> /// <returns>Task completed when last event is read in non-blocking mode</returns> public async IAsyncEnumerable <IBinlogEvent> Replicate([EnumeratorCancellation] CancellationToken cancellationToken = default) { await ConnectAsync(cancellationToken); // Clear on reconnect _gtid = null; _transaction = false; await AdjustStartingPosition(cancellationToken); await SetMasterHeartbeat(cancellationToken); await SetMasterBinlogChecksum(cancellationToken); await _databaseProvider.DumpBinlogAsync(_channel, _options, cancellationToken); var eventStreamReader = new EventStreamReader(_databaseProvider.Deserializer); var channel = new EventStreamChannel(eventStreamReader, _channel.Stream); var timeout = _options.HeartbeatInterval.Add(TimeSpan.FromMilliseconds(TimeoutConstants.Delta)); await foreach (var packet in channel.ReadPacketAsync(timeout, cancellationToken).WithCancellation(cancellationToken)) { if (packet is IBinlogEvent binlogEvent) { // We stop replication if client code throws an exception // As a derived database may end up in an inconsistent state. yield return(binlogEvent); // Commit replication state if there is no exception. UpdateGtidPosition(binlogEvent); UpdateBinlogPosition(binlogEvent); } else if (packet is EndOfFilePacket && !_options.Blocking) { yield break; } else if (packet is ErrorPacket error) { throw new InvalidOperationException($"Event stream error. {error.ToString()}"); } else { throw new InvalidOperationException($"Event stream unexpected error."); } } }
public async Task Test_PacketExactly16MbWithEmptyPacket_Combined() { using var stream = new MemoryStream(); var packetBody = CreateLargePacket(stream, PacketConstants.MaxBodyLength); WriteHeader(stream, 1, 0); // empty packet stream.Position = 0; var channel = new EventStreamChannel(new TestEventStreamReader(), stream); var packets = new List <IPacket>(); await foreach (var packet in channel.ReadPacketAsync(TimeSpan.FromSeconds(30))) { packets.Add(packet); } Assert.Equal(1, packets.Count); Assert.IsType <TestPacket>(packets[0]); Assert.Equal(packetBody, ((TestPacket)packets[0]).Body); }