Example #1
0
 public EntityContainer(
     Synchronizer <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity, TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity> context,
     ITotalProgressLogger totalProgress,
     ILoadEntityLogger logger)
 {
     _context       = context;
     _totalProgress = totalProgress;
     _logger        = logger;
 }
 public EntityContainer(
     Synchronizer <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity, TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity, TContext> context,
     ITotalProgressLogger totalProgress,
     ILoadEntityLogger aLogger,
     ILoadEntityLogger bLogger)
 {
     _context       = context;
     _totalProgress = totalProgress;
     _aLogger       = aLogger;
     _bLogger       = bLogger;
 }
Example #3
0
            public EntityContainer(
                Synchronizer <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity, TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity, TContext> context,
                ITotalProgressLogger totalProgress,
                ILoadEntityLogger aLogger,
                ILoadEntityLogger bLogger)
            {
                _context       = context;
                _totalProgress = totalProgress;
                _aLogger       = aLogger;
                _bLogger       = bLogger;

                _loadedAEntities = new Dictionary <TAtypeEntityId, TAtypeEntity>(context._atypeIdComparer);
                _loadedBEntities = new Dictionary <TBtypeEntityId, TBtypeEntity>(context._btypeIdComparer);
            }
        public void NotifyLoadCount(int aLoadCount, int bLoadCount)
        {
            if (_logger != null)
            return;

              try
              {
            if (aLoadCount + bLoadCount > _loadOperationThresholdForProgressDisplay)
              _logger = new TotalProgressLogger (_progressUiFactory, _exceptionLogger);
            else
              _logger = NullTotalProgressLogger.Instance;
              }
              catch (Exception x)
              {
            _exceptionLogger.LogException (x, s_logger);
            _logger = NullTotalProgressLogger.Instance;
              }
        }
        public void NotifyWork(int totalEntitiesBeingLoaded, int chunkCount)
        {
            if (_logger != null)
            {
                return;
            }

            try
            {
                if (totalEntitiesBeingLoaded >= _loadOperationThresholdForProgressDisplay)
                {
                    _logger = new TotalProgressLogger(_progressUiFactory, _exceptionLogger, chunkCount);
                }
                else
                {
                    _logger = NullTotalProgressLogger.Instance;
                }
            }
            catch (Exception x)
            {
                _exceptionLogger.LogException(x, s_logger);
                _logger = NullTotalProgressLogger.Instance;
            }
        }
Example #6
0
        public void NotifyLoadCount(int aLoadCount, int bLoadCount)
        {
            if (_logger != null)
            {
                return;
            }

            try
            {
                if (aLoadCount + bLoadCount > _loadOperationThresholdForProgressDisplay)
                {
                    _logger = new TotalProgressLogger(_progressUiFactory, _exceptionLogger);
                }
                else
                {
                    _logger = NullTotalProgressLogger.Instance;
                }
            }
            catch (Exception x)
            {
                _exceptionLogger.LogException(x, s_logger);
                _logger = NullTotalProgressLogger.Instance;
            }
        }
        private async Task <List <IEntityRelationData <TAtypeEntityId, TAtypeEntityVersion, TBtypeEntityId, TBtypeEntityVersion> > > Synchronize(
            ITotalProgressLogger totalProgress,
            IEnumerable <IEntityRelationData <TAtypeEntityId, TAtypeEntityVersion, TBtypeEntityId, TBtypeEntityVersion> > knownEntityRelations,
            Dictionary <TAtypeEntityId, TAtypeEntityVersion> newAVersions,
            Dictionary <TBtypeEntityId, TBtypeEntityVersion> newBVersions,
            EntityContainer entityContainer,
            ISynchronizationLogger logger,
            TContext synchronizationContext)
        {
            var entitySyncStates = new EntitySyncStateContainer <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity, TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity>();

            var aDeltaLogInfo = new VersionDeltaLoginInformation();
            var bDeltaLogInfo = new VersionDeltaLoginInformation();

            foreach (var knownEntityRelationData in knownEntityRelations)
            {
                TAtypeEntityVersion newAVersion;
                TBtypeEntityVersion newBVersion;

                var newAVersionAvailable = newAVersions.TryGetValue(knownEntityRelationData.AtypeId, out newAVersion);
                var newBVersionAvailable = newBVersions.TryGetValue(knownEntityRelationData.BtypeId, out newBVersion);

                if (newAVersionAvailable)
                {
                    newAVersions.Remove(knownEntityRelationData.AtypeId);
                }

                if (newBVersionAvailable)
                {
                    newBVersions.Remove(knownEntityRelationData.BtypeId);
                }

                var entitySyncState = CreateInitialSyncState(knownEntityRelationData, newAVersionAvailable, newAVersion, newBVersionAvailable, newBVersion, aDeltaLogInfo, bDeltaLogInfo);

                entitySyncStates.Add(entitySyncState);
            }

            HashSet <TAtypeEntityId> aEntitesToLoad = new HashSet <TAtypeEntityId>();
            HashSet <TBtypeEntityId> bEntitesToLoad = new HashSet <TBtypeEntityId>();

            entitySyncStates.Execute(s => s.AddRequiredEntitiesToLoad(aEntitesToLoad.Add, bEntitesToLoad.Add));

            if (newAVersions.Count > 0 && newBVersions.Count > 0)
            {
                foreach (var newA in newAVersions)
                {
                    aEntitesToLoad.Add(newA.Key);
                }

                foreach (var newB in newBVersions)
                {
                    bEntitesToLoad.Add(newB.Key);
                }

                await entityContainer.FillIfEmpty(aEntitesToLoad, bEntitesToLoad, synchronizationContext);

                var newAtypeEntities = GetSubSet(entityContainer.AEntities, newAVersions.Keys, _atypeIdComparer);
                var newBtypeEntities = GetSubSet(entityContainer.BEntities, newBVersions.Keys, _btypeIdComparer);

                var matchingEntites = _initialEntityMatcher.FindMatchingEntities(
                    _entityRelationDataFactory,
                    newAtypeEntities,
                    newBtypeEntities,
                    newAVersions,
                    newBVersions);

                foreach (var knownEntityRelationData in matchingEntites)
                {
                    newAVersions.Remove(knownEntityRelationData.AtypeId);
                    newBVersions.Remove(knownEntityRelationData.BtypeId);
                    var entitySyncState = _initialSyncStateCreationStrategy.CreateFor_Unchanged_Unchanged(knownEntityRelationData);
                    entitySyncStates.Add(entitySyncState);
                }

                foreach (var newA in newAVersions)
                {
                    var syncState = _initialSyncStateCreationStrategy.CreateFor_Added_NotExisting(newA.Key, newA.Value);
                    entitySyncStates.Add(syncState);
                }

                foreach (var newB in newBVersions)
                {
                    var syncState = _initialSyncStateCreationStrategy.CreateFor_NotExisting_Added(newB.Key, newB.Value);
                    entitySyncStates.Add(syncState);
                }
            }
            else
            {
                foreach (var newA in newAVersions)
                {
                    var syncState = _initialSyncStateCreationStrategy.CreateFor_Added_NotExisting(newA.Key, newA.Value);
                    syncState.AddRequiredEntitiesToLoad(aEntitesToLoad.Add, bEntitesToLoad.Add);
                    entitySyncStates.Add(syncState);
                }

                foreach (var newB in newBVersions)
                {
                    var syncState = _initialSyncStateCreationStrategy.CreateFor_NotExisting_Added(newB.Key, newB.Value);
                    syncState.AddRequiredEntitiesToLoad(aEntitesToLoad.Add, bEntitesToLoad.Add);
                    entitySyncStates.Add(syncState);
                }

                await entityContainer.FillIfEmpty(aEntitesToLoad, bEntitesToLoad, synchronizationContext);
            }

            // all the leftovers in newAVersions and newBVersions must be the added ones
            aDeltaLogInfo.IncAdded(newAVersions.Count);
            bDeltaLogInfo.IncAdded(newBVersions.Count);
            s_logger.InfoFormat("Atype delta: {0}", aDeltaLogInfo);
            s_logger.InfoFormat("Btype delta: {0}", bDeltaLogInfo);
            logger.LogDeltas(aDeltaLogInfo, bDeltaLogInfo);


            entitySyncStates.DoTransition(s => s.FetchRequiredEntities(entityContainer.AEntities, entityContainer.BEntities));
            entitySyncStates.DoTransition(s => s.Resolve());

            // since resolve may change to an new state, required entities have to be fetched again.
            // an state is allowed only to resolve to another state, if the following states requires equal or less entities!
            entitySyncStates.DoTransition(s => s.FetchRequiredEntities(entityContainer.AEntities, entityContainer.BEntities));

            var aJobs = new JobList <TAtypeEntity, TAtypeEntityId, TAtypeEntityVersion>();
            var bJobs = new JobList <TBtypeEntity, TBtypeEntityId, TBtypeEntityVersion>();

            entitySyncStates.Execute(s => s.AddSyncronizationJob(aJobs, bJobs, logger.CreateEntitySynchronizationLogger()));

            using (var progress = totalProgress.StartProcessing(aJobs.TotalJobCount + bJobs.TotalJobCount))
            {
                await _atypeWriteRepository.PerformOperations(aJobs.CreateJobs, aJobs.UpdateJobs, aJobs.DeleteJobs, progress, synchronizationContext);

                await _btypeWriteRepository.PerformOperations(bJobs.CreateJobs, bJobs.UpdateJobs, bJobs.DeleteJobs, progress, synchronizationContext);
            }

            entitySyncStates.DoTransition(s => s.NotifyJobExecuted());

            var newEntityRelations = new List <IEntityRelationData <TAtypeEntityId, TAtypeEntityVersion, TBtypeEntityId, TBtypeEntityVersion> >();

            entitySyncStates.Execute(s => s.AddNewRelationNoThrow(newEntityRelations.Add));

            entitySyncStates.Dispose();


            return(newEntityRelations);
        }
        private async Task Synchronize(
            ITotalProgressLogger totalProgress,
            IEnumerable <IEntityRelationData <TAtypeEntityId, TAtypeEntityVersion, TBtypeEntityId, TBtypeEntityVersion> > knownEntityRelations,
            IEntityStateCollection <TAtypeEntityId, TAtypeEntityVersion> aStates,
            IEntityStateCollection <TBtypeEntityId, TBtypeEntityVersion> bStates,
            ISynchronizationLogger logger,
            TContext synchronizationContext,
            ISynchronizationInterceptor <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity, TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity, TContext> interceptor,
            Action <List <IEntityRelationData <TAtypeEntityId, TAtypeEntityVersion, TBtypeEntityId, TBtypeEntityVersion> > > saveNewRelations)
        {
            var entitySynchronizationLoggerFactory = new SynchronizationLoggerBoundEntitySynchronizationLoggerFactory <TAtypeEntity, TBtypeEntity>(logger, _fullEntitySynchronizationLoggerFactory);

            using (IEntityContainer <TAtypeEntityId, TAtypeEntity, TContext> aEntities = new EntityContainer <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity, TContext>(_atypeRepository, _atypeIdComparer, _chunkSize, _chunkedExecutor))
                using (IEntityContainer <TBtypeEntityId, TBtypeEntity, TContext> bEntities = new EntityContainer <TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity, TContext>(_btypeRepository, _btypeIdComparer, _chunkSize, _chunkedExecutor))
                {
                    var entitySynchronizationContexts = await CreateEntitySyncStateContexts(aEntities, bEntities, knownEntityRelations, aStates, bStates, logger, synchronizationContext, interceptor);

                    var totalAJobs = new JobCount();
                    var totalBJobs = new JobCount();

                    try
                    {
                        var chunks = _entitySyncStateChunkCreator.CreateChunks(entitySynchronizationContexts, _atypeIdComparer, _btypeIdComparer).ToArray();


                        totalProgress.NotifyWork(chunks.Aggregate(0, (acc, c) => acc + c.AEntitesToLoad.Count + c.BEntitesToLoad.Count), chunks.Length);

                        foreach ((var aEntitesToLoad, var bEntitesToLoad, var currentBatch) in chunks)
                        {
                            var chunkLogger = totalProgress.StartChunk();

                            IReadOnlyDictionary <TAtypeEntityId, TAtypeEntity> aEntitiesById;
                            using (chunkLogger.StartARepositoryLoad(aEntitesToLoad.Count))
                            {
                                aEntitiesById = await aEntities.GetEntities(aEntitesToLoad, logger.ALoadEntityLogger, synchronizationContext);
                            }

                            IReadOnlyDictionary <TBtypeEntityId, TBtypeEntity> bEntitiesById;
                            using (chunkLogger.StartBRepositoryLoad(bEntitesToLoad.Count))
                            {
                                bEntitiesById = await bEntities.GetEntities(bEntitesToLoad, logger.BLoadEntityLogger, synchronizationContext);
                            }

                            currentBatch.ForEach(s => s.FetchRequiredEntities(aEntitiesById, bEntitiesById));
                            currentBatch.ForEach(s => s.Resolve());

                            // since resolve may change to an new state, required entities have to be fetched again.
                            // an state is allowed only to resolve to another state, if the following states requires equal or less entities!
                            currentBatch.ForEach(s => s.FetchRequiredEntities(aEntitiesById, bEntitiesById));

                            var aJobs = new JobList <TAtypeEntityId, TAtypeEntityVersion, TAtypeEntity>();
                            var bJobs = new JobList <TBtypeEntityId, TBtypeEntityVersion, TBtypeEntity>();

                            currentBatch.ForEach(s => s.AddSyncronizationJob(aJobs, bJobs, entitySynchronizationLoggerFactory, synchronizationContext));

                            totalAJobs = totalAJobs.Add(aJobs.Count);
                            totalBJobs = totalBJobs.Add(bJobs.Count);

                            try
                            {
                                using (var progress = chunkLogger.StartProcessing(aJobs.TotalJobCount + bJobs.TotalJobCount))
                                {
                                    await _atypeWriteRepository.PerformOperations(aJobs.CreateJobs, aJobs.UpdateJobs, aJobs.DeleteJobs, progress, synchronizationContext);

                                    await _btypeWriteRepository.PerformOperations(bJobs.CreateJobs, bJobs.UpdateJobs, bJobs.DeleteJobs, progress, synchronizationContext);
                                }

                                currentBatch.ForEach(s => s.NotifyJobExecuted());
                            }
                            catch (Exception x)
                            {
                                if (_exceptionHandlingStrategy.DoesGracefullyAbortSynchronization(x))
                                {
                                    entitySynchronizationContexts.ForEach(s => s.Abort());
                                    SaveNewRelations(entitySynchronizationContexts, saveNewRelations);
                                }
                                throw;
                            }
                        }
                    }
                    finally
                    {
                        s_logger.InfoFormat($"A repository jobs: {totalAJobs}");
                        s_logger.InfoFormat($"B repository jobs: {totalBJobs}");
                        logger.LogJobs(totalAJobs.ToString(), totalBJobs.ToString());
                    }

                    SaveNewRelations(entitySynchronizationContexts, saveNewRelations);
                }
        }