Beispiel #1
0
        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);
        }
Beispiel #4
0
        /// <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);
        }