Ejemplo n.º 1
0
        /// <summary>
        /// statistic event override
        /// </summary>
        /// <param name="event"></param>
        public void Write(StatisticEvent <int> @event)
        {
            if (@event.Metric != StatisticType.WorkersLog)
            {
                return;
            }

            lock (_pipelineId)
            {
                var metric = new ActiveWorkersLogMessage
                {
                    Timestamp     = DateTime.Now,
                    PipelineId    = _pipelineId,
                    ActiveWorkers = @event.Value
                };

                _storage.Value.AddToList(new StorageKey(_pipelineId, $"log:{@event.Metric}"), metric);

                if (_dispatcherLock.IsLocked())
                {
                    return;
                }

                _dispatcherLock.Lock();

                if (_taskDispatcher == null)
                {
                    _taskDispatcher = new BackgroundTaskDispatcher(new StorageContext(_storage.Value));
                }

                _taskDispatcher.StartNew(new ActiveWorkersLogCleanupTask(_dispatcherLock, new StorageKey(_pipelineId, $"log:{@event.Metric}")));
            }
        }
Ejemplo n.º 2
0
        private void CleanupProcessors()
        {
            if (_cleanupLock.IsLocked())
            {
                return;
            }

            _cleanupLock.Lock();

            foreach (var processor in _processors.ToList())
            {
                if (processor.IsWorking)
                {
                    continue;
                }

                if (_processors.Count == _minProcessors)
                {
                    break;
                }

                _processors.Remove(processor);
                processor.Dispose();

                _logger.Write($"Remove Worker from EventBus. Workers: {_processors.Count}", Category.Log, source: "EventBus");
                _logger.WriteMetric(_processors.Count, StatisticType.WorkersLog);
            }

            _cleanupLock.Unlock();

            _metricService.SetMetric(new Metric(MetricType.ThreadCount, "Active Workers", _processors.Count));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Start processing events
        /// </summary>
        public void Start()
        {
            if (_lock.IsLocked())
            {
                return;
            }

            _lock.Lock();

            _logger.Write($"Start working on Thread {_id}", Category.Log, LogLevel.Debug, "EventBus");

            Task = Task.Factory.StartNew(() =>
            {
                try
                {
                    _worker.Execute();
                }
                catch (Exception e)
                {
                    _logger.Write(e.Message, Category.Log, LogLevel.Error, "EventProcessor");
                }
                finally
                {
                    _continuation();
                    _lock.Unlock();
                }
            }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }
Ejemplo n.º 4
0
        public void ActiveWorkersLogCleanupTask_Execute_Unlock()
        {
            var locker = new DispatcherLock();

            locker.Lock();
            var task = new ActiveWorkersLogCleanupTask(locker, new StorageKey("test"));

            task.Execute(new StorageContext(new Mock <IStorage>().Object));

            Assert.IsFalse(locker.IsLocked());
        }
Ejemplo n.º 5
0
        private async Task Initialize([NotNull] TAssetPart assetSideInstance)
        {
            var partId           = new AbsoluteId(Owner.Id.AssetId, assetSideInstance.Id);
            var gameSideInstance = await Editor.Controller.InvokeAsync(() => Editor.Controller.FindGameSidePart(partId));

            if (gameSideInstance == null)
            {
                throw new InvalidOperationException("Unable to reach the game-side instance");
            }

            using (await DispatcherLock.Lock(true, Editor.Controller, Editor.Dispatcher))
            {
                Editor.Controller.Logger.Debug($"Initial linking for part {assetSideInstance.Id}");
                var assetNode = (IAssetNode)Editor.NodeContainer.GetNode(assetSideInstance);
                var gameNode  = Editor.Controller.GameSideNodeContainer.GetOrCreateNode(gameSideInstance);
                gameObjectLinker.LinkGraph(assetNode, gameNode);
            }
        }
Ejemplo n.º 6
0
        private async Task PropagatorTask(TAssetPart assetSidePart)
        {
            // Ensure we are ready game-side before doing any operation
            await gameSideReady.Task;

            await Initialize(assetSidePart);

            var contentReferenceCollector = new ContentReferenceCollector(Owner.Asset.PropertyGraph.Definition);
            await Editor.Controller.InvokeTask(() =>
            {
                Editor.Controller.Logger.Debug($"Registering reference to: {Owner.Id}");
                return(Editor.Controller.Loader.Manager.RegisterReferencer(Owner.Id));
            });

            var rootNode = Editor.NodeContainer.GetOrCreateNode(assetSidePart);

            contentReferenceCollector.Visit(rootNode);

            await Editor.Controller.InvokeTask(async() =>
            {
                using (await Editor.Controller.Loader.LockDatabaseAsynchronously())
                {
                    foreach (var contentReference in contentReferenceCollector.ContentReferences)
                    {
                        // Ok to await inside the loop, this call should never yield because we already own the lock.
                        await Editor.Controller.Loader.Manager.PushContentReference(Owner.Id, contentReference.ContentId, contentReference.Node, contentReference.Index);
                    }
                }
            });

            initialized.SetResult(0);

            while (running)
            {
                var e = await propagatorQueue.ReceiveAsync();

                // This allow to post null when disposing so we evaluate running again to exit this task
                if (e == null)
                {
                    continue;
                }

                var assetNode    = (IAssetNode)e.Node;
                var gameSideNode = assetNode.GetContent(GameSideContentKey);
                if (gameSideNode == null)
                {
                    throw new InvalidOperationException("Unable to retrieve the game-side node");
                }

                var index = (e as ItemChangeEventArgs)?.Index ?? NodeIndex.Empty;
                if (!AssetRegistry.IsContentType(e.Node.Descriptor.GetInnerCollectionType()))
                {
                    if (e.Node.Type.IsValueType)
                    {
                        // No need to retrieve and/or duplicate the value for value type, we just propagate the change
                        await Editor.Controller.InvokeAsync(() => UpdateGameSideContent(gameSideNode, e.NewValue, e.ChangeType, index));
                    }
                    else
                    {
                        var value       = RetrieveValue(assetNode, e.NewValue, e.ChangeType, index);
                        var isReference = await PropagatePartReference(gameSideNode, value, e);

                        if (!isReference)
                        {
                            await Editor.Controller.InvokeAsync(() =>
                            {
                                var gameSideValue = CloneObjectForGameSide(value, assetNode, gameSideNode);
                                UpdateGameSideContent(gameSideNode, gameSideValue, e.ChangeType, index);
                            });
                        }
                    }
                }
                else
                {
                    await UpdateGameSideReference(Editor, gameSideNode, e.ChangeType, e.OldValue, e.NewValue, index);
                }

                // Critical section, both Asset thread and Game thread must be locked
                using (await DispatcherLock.Lock(true, Editor.Controller, Editor.Dispatcher))
                {
                    // Link nodes of the asset-side objects with the game-side objects.
                    gameObjectLinker.LinkGraph(assetNode, gameSideNode);
                    // Also collect content reference (this requires only lock on the Asset thread)
                    contentReferenceCollector.Reset();
                    // If the change is a remove, the content reference should have been cleared by UpdateGameSideReference and there's nothing to collect
                    if (e.ChangeType != ContentChangeType.CollectionRemove)
                    {
                        contentReferenceCollector.Visit(assetNode, index);
                    }
                }

                // Update the content reference list on the game-side now that we have push the change.
                await Editor.Controller.InvokeTask(async() =>
                {
                    using (await Editor.Controller.Loader.LockDatabaseAsynchronously())
                    {
                        foreach (var contentReference in contentReferenceCollector.ContentReferences)
                        {
                            // Ok to await inside the loop, this call should never yield because we already own the lock.
                            await Editor.Controller.Loader.Manager.PushContentReference(Owner.Id, contentReference.ContentId, contentReference.Node, contentReference.Index);
                        }
                    }

                    Editor.Controller.TriggerActiveRenderStageReevaluation();
                });
            }

            await Editor.Controller.InvokeTask(() =>
            {
                Editor.Controller.Logger.Debug($"Unregistering reference to: {Owner.Id}");
                return(Editor.Controller.Loader.Manager.RemoveReferencer(Owner.Id));
            });
        }