/// <summary> /// Adds a gtid value to the GtidSet. /// </summary> public bool AddGtid(IGtid value) { var gtid = (Gtid)value; UuidSet uuidSet; if (!UuidSets.TryGetValue(gtid.SourceId, out uuidSet)) { uuidSet = new UuidSet(gtid.SourceId, new List <Interval>()); UuidSets[gtid.SourceId] = uuidSet; } return(uuidSet.AddGtid(gtid)); }
/// <summary> /// Replicates binlog events from the server /// </summary> /// <param name="handleEvent">Client callback function</param> /// <param name="cancellationToken">Cancellation token</param> /// <returns>Task completed when last event is read in non-blocking mode</returns> public async Task ReplicateAsync(Func <IBinlogEvent, Task> handleEvent, 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); await ReadEventStreamAsync(handleEvent, cancellationToken); }
/// <summary> /// Adds a gtid value to the GtidList. /// </summary> public bool AddGtid(IGtid gtidRaw) { var gtid = (Gtid)gtidRaw; for (int i = 0; i < Gtids.Count; i++) { if (Gtids[i].DomainId == gtid.DomainId) { Gtids[i] = gtid; return(false); } } Gtids.Add(gtid); return(true); }
/// <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."); } } }
private void UpdateGtidPosition(IBinlogEvent binlogEvent) { if (_options.Binlog.StartingStrategy != StartingStrategy.FromGtid) { return; } if (binlogEvent is GtidEvent gtidEvent) { _gtid = gtidEvent.Gtid; } else if (binlogEvent is XidEvent xidEvent) { CommitGtid(); } else if (binlogEvent is QueryEvent queryEvent) { if (string.IsNullOrWhiteSpace(queryEvent.SqlStatement)) { return; } if (queryEvent.SqlStatement == "BEGIN") { _transaction = true; } else if (queryEvent.SqlStatement == "COMMIT" || queryEvent.SqlStatement == "ROLLBACK") { CommitGtid(); } else if (!_transaction) { // Auto-commit query like DDL CommitGtid(); } } }
/// <summary> /// Creates a new <see cref="GtidEvent"/>. /// </summary> public GtidEvent(EventHeader header, IGtid gtid, int flags) : base(header) { Gtid = gtid; Flags = flags; }