/// <summary> /// Read and process all the table changes from the provided tables. /// /// Table changes are first read from lower priority to higher priority tables, and subsequently processed /// from higher priority tables to lower priority ones. This is made in order to prevent processing changes /// from dependent entities that haven't yet been processed (keeping consistency with dependent entities and /// the generated events). /// For instance, assuming we are processing player wallets and player wallet transactions (wallets have higher /// priority than transactions), to prevent reading player wallet transactions from wallets that have not yet been /// read we first read changes in player wallet transactions, then we read changes in wallets, then we process the /// changes in wallets and finally we process the change in transactions. /// </summary> /// <param name="conn">The database connection.</param> /// <param name="ChangeTrackingContextHandler">Context handler</param> private IEnumerable <Change> GetChanges(IDbConnection conn, ChangeTrackingContextHandler contextHandler) { Stack <IEnumerable <Change> > tableChanges = new Stack <IEnumerable <Change> >(); IEnumerable <TrackedTableInformation> changeTrackingTableInfos = Repository.GetTrackedTablesInformation(conn); var currentApplicationOffset = contextHandler.GetContext().ApplicationOffset; var dbOffset = contextHandler.GetContext().DatabaseOffset; foreach (var changeTrackingTableInfo in changeTrackingTableInfos.OrderBy(x => x.Priority)) { if (!contextHandler.IsMinimalOffsetSupportedHigher(changeTrackingTableInfo.MinValidVersion)) { var changes = Repository.GetOffsetChanges(conn, changeTrackingTableInfo, currentApplicationOffset, dbOffset); if (changes.Count() != 0) { tableChanges.Push(changes); ContextHandler.RegisterPendingChanges(changes.Count()); } } } if (!tableChanges.Any()) { yield return new Change { } } ; // SYNC else { while (tableChanges.Any()) { foreach (var change in tableChanges.Pop()) { yield return(change); ContextHandler.RegisterPendingChanges(-1); } } } }
public void Subscribe(ChangeTrackingContextHandler provider) { Cancellation = provider.Subscribe(this); }
/// <summary> /// Change tracking stream constructor /// </summary> /// <param name="configuration">Change tracking configuration</param> /// <param name="stateStorage">Change tracking state storage</param> public ChangeTrackingStreamSource(ChangeTrackingConfiguration configuration, StateStorage stateStorage = null) { this.Repository = new ChangeTrackingRepository(configuration); this.PollingInterval = TimeSpan.FromMilliseconds(configuration.PollIntervalMilliseconds); this.ContextHandler = new ChangeTrackingContextHandler(configuration.ApplicationName, stateStorage ?? new MemoryStateStorage()); }