예제 #1
0
 public async Task <ChangeBatch> GetChangeBatchAsync(TableSchema tableSchema, byte[] fromLsn, byte[] fromSeqVal, byte[] toLsn, int batchSize)
 {
     return(await _cdcRepository.GetChangeBatchAsync(tableSchema, fromLsn, fromSeqVal, toLsn, batchSize));
 }
예제 #2
0
        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);
            }
        }