/// <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}"))); } }
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)); }
/// <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); }
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()); }
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); } }
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)); }); }