public async Task <ChangeBatch> GetChangeBatchAsync(TableSchema tableSchema, byte[] fromLsn, byte[] fromSeqVal, byte[] toLsn, int batchSize) { return(await _cdcRepository.GetChangeBatchAsync(tableSchema, fromLsn, fromSeqVal, toLsn, batchSize)); }
private async Task ReadTransactionsAsync(CancellationToken token, TableSchema tableSchema, int batchSize, BlockingCollection <ChangeRecord> changes, byte[] lastProcessedLsn) { byte[] toLsn = await _cdcRepository.GetMaxLsnAsync(); byte[] fromLsn = await GetInitialFromLsnAsync(tableSchema, lastProcessedLsn); try { byte[] fromSeqVal = null; bool waitingForChanges = false; // outer loop sets the upper LSN range, inner loop iteratively reads up to that LSN while (!token.IsCancellationRequested) { bool unfinishedLsn = false; bool moreOfCurrentRange = true; while (moreOfCurrentRange && !token.IsCancellationRequested) { // once we've caught up with the current target LSN, we'll exit the inner loop and go get the latest upper LSN if (GetBigInteger(fromLsn) <= GetBigInteger(toLsn)) { ChangeBatch batch = null; if (unfinishedLsn) { batch = await _cdcRepository.GetChangeBatchAsync(tableSchema, fromLsn, fromSeqVal, toLsn, batchSize); } else { batch = await _cdcRepository.GetChangeBatchAsync(tableSchema, fromLsn, toLsn, batchSize); } if (batch.Changes.Any()) { waitingForChanges = false; //Console.WriteLine($"Table {tableName} - Retrieved block #{blockCounter} with {batch.Changes.Count} changes"); var enumerator = batch.Changes.GetEnumerator(); if (!enumerator.MoveNext()) { break; } while (!token.IsCancellationRequested) { if (changes.TryAdd(enumerator.Current, 1000)) { if (!enumerator.MoveNext()) { break; } } } fromLsn = batch.Changes.Last().Lsn; fromSeqVal = batch.Changes.Last().SeqVal; moreOfCurrentRange = batch.MoreChanges; unfinishedLsn = batch.MoreOfLastTransaction; if (unfinishedLsn) { fromSeqVal = Increment(fromSeqVal); } else { fromLsn = Increment(fromLsn); } } else { moreOfCurrentRange = false; unfinishedLsn = false; //Console.WriteLine($"Table {tableName} - No changes"); } } else { moreOfCurrentRange = false; unfinishedLsn = false; //Console.WriteLine($"Table {tableName} - No changes"); } } var latestLsn = await _cdcRepository.GetMaxLsnAsync(); if (latestLsn.SequenceEqual(toLsn)) { if (!waitingForChanges) { // add a change record that signals to the Transaction Grouping Task that there are no new changes available // this is important as the Transaction Grouping Task needs to differentiate between a slow reader and no data var noDataSignalRecord = GetNoDataSignalRecord(tableSchema); changes.TryAdd(noDataSignalRecord, 5000); } waitingForChanges = true; // blocks until a new upper LSN is available // note that a new upper LSN is published every five minutes by SQL Server even when no changes have occurred toLsn = await GetLatestUpperLsnAsync(token, toLsn); } else { toLsn = latestLsn; } } } catch (Exception ex) { throw new ReaderException("Reader failure", ex, fromLsn); } }