コード例 #1
0
        public void Nested()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal   = new ManualResetEventSlim();
                var listener = new Listener();

                var outerDone   = false;
                var innerDone   = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task        = new Task(() =>
                {
                    signal.Set();
                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                    using (listener.BeginAsyncOperation("Test"))
                    {
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        innerDone = true;
                    }

                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                    outerDone = true;
                });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start(TaskScheduler.Default);

                Wait(listener, signal);

                Assert.True(innerDone, "Should have completed the inner task");
                Assert.True(outerDone, "Should have completed the outer task");
            }
        }
コード例 #2
0
        public void Cancel()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal   = new ManualResetEventSlim();
                var listener = new Listener();

                var done        = false;
                var continued   = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task        = new Task(() =>
                {
                    signal.Set();
                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                    var asyncToken2 = listener.BeginAsyncOperation("Test");
                    var queuedTask  = new Task(() =>
                    {
                        sleepHelper.Sleep(TimeSpan.FromSeconds(5));
                        continued = true;
                    });
                    asyncToken2.Dispose();
                    queuedTask.Start(TaskScheduler.Default);
                    done = true;
                });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start(TaskScheduler.Default);

                Wait(listener, signal);

                Assert.True(done, "Cancelling should have completed the current task.");
                Assert.False(continued, "Continued Task when it shouldn't have.");
            }
        }
コード例 #3
0
        public void QueuedOperation()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal   = new ManualResetEventSlim();
                var listener = new Listener();

                var done        = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task        = new Task(() =>
                {
                    signal.Set();
                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                    var asyncToken2 = listener.BeginAsyncOperation("Test");
                    var queuedTask  = new Task(() =>
                    {
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        done = true;
                    });
                    queuedTask.CompletesAsyncOperation(asyncToken2);
                    queuedTask.Start(TaskScheduler.Default);
                });

                task.CompletesAsyncOperation(asyncToken1);
                task.Start(TaskScheduler.Default);

                Wait(listener, signal);

                Assert.True(done, "Should have waited for the queued operation to finish!");
            }
        }
コード例 #4
0
        public void IgnoredCancel()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal   = new ManualResetEventSlim();
                var listener = new Listener();

                var done              = false;
                var queuedFinished    = false;
                var cancelledFinished = false;
                var asyncToken1       = listener.BeginAsyncOperation("Test");
                var task              = new Task(() =>
                {
                    using (listener.BeginAsyncOperation("Test"))
                    {
                        var cancelledTask = new Task(() =>
                        {
                            sleepHelper.Sleep(TimeSpan.FromSeconds(10));
                            cancelledFinished = true;
                        });

                        signal.Set();
                        cancelledTask.Start(TaskScheduler.Default);
                    }

                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                    // Now that we've cancelled the first request, queue another one to make sure we wait for it.
                    var asyncToken2 = listener.BeginAsyncOperation("Test");
                    var queuedTask  = new Task(() =>
                    {
                        sleepHelper.Sleep(TimeSpan.FromSeconds(1));
                        queuedFinished = true;
                    });
                    queuedTask.CompletesAsyncOperation(asyncToken2);
                    queuedTask.Start(TaskScheduler.Default);
                    done = true;
                });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start(TaskScheduler.Default);

                Wait(listener, signal);

                Assert.True(done, "Cancelling should have completed the current task.");
                Assert.True(queuedFinished, "Continued didn't run, but it was supposed to ignore the cancel.");
                Assert.False(cancelledFinished, "We waited for the cancelled task to finish.");
            }
        }
コード例 #5
0
                    public void Enqueue(ProjectId projectId, bool needDependencyTracking = false)
                    {
                        UpdateLastAccessTime();

                        using (_workGate.DisposableWait(CancellationToken))
                        {
                            // the project is already in the queue. nothing needs to be done
                            if (_pendingWork.ContainsKey(projectId))
                            {
                                return;
                            }

                            var data = new Data(
                                projectId,
                                needDependencyTracking,
                                Listener.BeginAsyncOperation(
                                    nameof(Enqueue),
                                    tag: _registration.Workspace
                                    )
                                );

                            _pendingWork.Add(projectId, data);
                            _gate.Release();
                        }

                        Logger.Log(
                            FunctionId.WorkCoordinator_Project_Enqueue,
                            s_enqueueLogger,
                            Environment.TickCount,
                            projectId
                            );
                    }
コード例 #6
0
                    public void Enqueue(WorkItem item)
                    {
                        Contract.ThrowIfFalse(item.DocumentId != null, "can only enqueue a document work item");

                        // Don't enqueue item if we don't have any high priority analyzers
                        if (Analyzers.IsEmpty)
                        {
                            return;
                        }

                        // we only put workitem in high priority queue if there is a text change.
                        // this is to prevent things like opening a file, changing in other files keep enqueuing
                        // expensive high priority work.
                        if (!item.InvocationReasons.Contains(PredefinedInvocationReasons.SyntaxChanged))
                        {
                            return;
                        }

                        if (!_processor._documentTracker.SupportsDocumentTracking &&
                            _processor._registration.Workspace.Kind is WorkspaceKind.RemoteWorkspace)
                        {
                            Debug.Fail($"Unexpected use of '{nameof(ExportIncrementalAnalyzerProviderAttribute.HighPriorityForActiveFile)}' in workspace kind '{_processor._registration.Workspace.Kind}' that cannot support active file tracking.");
                        }

                        // check whether given item is for active document, otherwise, nothing to do here
                        if (_processor._documentTracker.TryGetActiveDocument() != item.DocumentId)
                        {
                            return;
                        }

                        // we need to clone due to waiter
                        EnqueueActiveFileItem(item.WithAsyncToken(Listener.BeginAsyncOperation("ActiveFile")));
                    }
コード例 #7
0
                    public async Task EnqueueWorkItemAsync(Document document)
                    {
                        // we are shutting down
                        CancellationToken.ThrowIfCancellationRequested();

                        // call to this method is serialized. and only this method does the writing.
                        var priorityService =
                            document.GetLanguageService <IWorkCoordinatorPriorityService>();
                        var isLowPriority =
                            priorityService != null &&
                            await priorityService
                            .IsLowPriorityAsync(document, CancellationToken)
                            .ConfigureAwait(false);

                        _processor.Enqueue(
                            new WorkItem(
                                document.Id,
                                document.Project.Language,
                                InvocationReasons.SemanticChanged,
                                isLowPriority,
                                activeMember: null,
                                Listener.BeginAsyncOperation(
                                    nameof(EnqueueWorkItemAsync),
                                    tag: EnqueueItem
                                    )
                                )
                            );
                    }
コード例 #8
0
                    public void Enqueue(WorkItem item)
                    {
                        Contract.ThrowIfFalse(item.DocumentId != null, "can only enqueue a document work item");

                        // Don't enqueue item if we don't have any high priority analyzers
                        if (this.Analyzers.IsEmpty)
                        {
                            return;
                        }

                        // we only put workitem in high priority queue if there is a text change.
                        // this is to prevent things like opening a file, changing in other files keep enqueuing
                        // expensive high priority work.
                        if (!item.InvocationReasons.Contains(PredefinedInvocationReasons.SyntaxChanged))
                        {
                            return;
                        }

                        // check whether given item is for active document, otherwise, nothing to do here
                        if (_processor._documentTracker == null ||
                            _processor._documentTracker.TryGetActiveDocument() != item.DocumentId)
                        {
                            return;
                        }

                        // we need to clone due to waiter
                        EnqueueActiveFileItem(item.WithAsyncToken(Listener.BeginAsyncOperation("ActiveFile")));
                    }
            private void PushTextChanges(Document oldDocument, Document newDocument)
            {
                // this pushes text changes to the remote side if it can.
                // this is purely perf optimization. whether this pushing text change
                // worked or not doesn't affect feature's functionality.
                //
                // this basically see whether it can cheaply find out text changes
                // between 2 snapshots, if it can, it will send out that text changes to
                // remote side.
                //
                // the remote side, once got the text change, will again see whether
                // it can use that text change information without any high cost and
                // create new snapshot from it.
                //
                // otherwise, it will do the normal behavior of getting full text from
                // VS side. this optimization saves times we need to do full text
                // synchronization for typing scenario.

                if ((oldDocument.TryGetText(out var oldText) == false) ||
                    (newDocument.TryGetText(out var newText) == false))
                {
                    // we only support case where text already exist
                    return;
                }

                // get text changes
                var textChanges = newText.GetTextChanges(oldText);

                if (textChanges.Count == 0)
                {
                    // no changes
                    return;
                }

                // whole document case
                if (textChanges.Count == 1 && textChanges[0].Span.Length == oldText.Length)
                {
                    // no benefit here. pulling from remote host is more efficient
                    return;
                }

                // only cancelled when remote host gets shutdown
                var token = Listener.BeginAsyncOperation(nameof(PushTextChanges));

                _textChangeQueue.ScheduleTask(async() =>
                {
                    var client = await _service.Workspace.TryGetRemoteHostClientAsync(CancellationToken).ConfigureAwait(false);
                    if (client == null)
                    {
                        return;
                    }

                    var state = await oldDocument.State.GetStateChecksumsAsync(CancellationToken).ConfigureAwait(false);

                    await client.TryRunRemoteAsync(
                        WellKnownRemoteHostServices.RemoteHostService, nameof(IRemoteHostService.SynchronizeTextAsync),
                        new object[] { oldDocument.Id, state.Text, textChanges }, CancellationToken).ConfigureAwait(false);
                }, CancellationToken).CompletesAsyncOperation(token);
            }
コード例 #10
0
        public void MultipleEnqueues()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal   = new ManualResetEventSlim();
                var listener = new Listener();

                var outerDone        = false;
                var firstQueuedDone  = false;
                var secondQueuedDone = false;

                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task        = new Task(() =>
                {
                    signal.Set();
                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                    var asyncToken2    = listener.BeginAsyncOperation("Test");
                    var firstQueueTask = new Task(() =>
                    {
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        var asyncToken3     = listener.BeginAsyncOperation("Test");
                        var secondQueueTask = new Task(() =>
                        {
                            sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                            secondQueuedDone = true;
                        });
                        secondQueueTask.CompletesAsyncOperation(asyncToken3);
                        secondQueueTask.Start(TaskScheduler.Default);
                        firstQueuedDone = true;
                    });
                    firstQueueTask.CompletesAsyncOperation(asyncToken2);
                    firstQueueTask.Start(TaskScheduler.Default);
                    outerDone = true;
                });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start(TaskScheduler.Default);

                Wait(listener, signal);

                Assert.True(outerDone, "The outer task should have finished!");
                Assert.True(firstQueuedDone, "The first queued task should have finished");
                Assert.True(secondQueuedDone, "The second queued task should have finished");
            }
        }
コード例 #11
0
        private void EnqueueChecksumUpdate()
        {
            // event will raised sequencially. no concurrency on this handler
            if (_workQueue.TryPeek(out _))
            {
                return;
            }

            _workQueue.Enqueue(Listener.BeginAsyncOperation(nameof(SolutionChecksumUpdater)));
        }
コード例 #12
0
        internal void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args)
        {
            // all diagnostics events are serialized.
            var ev = _eventMap.GetEventHandlers <EventHandler <DiagnosticsUpdatedArgs> >(DiagnosticsUpdatedEventName);

            if (ev.HasHandlers)
            {
                var asyncToken = Listener.BeginAsyncOperation(nameof(RaiseDiagnosticsUpdated));
                _eventQueue.ScheduleTask(() => ev.RaiseEvent(handler => handler(this, args))).CompletesAsyncOperation(asyncToken);
            }
        }
コード例 #13
0
        public void SecondCompletion()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal1  = new ManualResetEventSlim();
                var signal2  = new ManualResetEventSlim();
                var listener = new Listener();

                var firstDone  = false;
                var secondDone = false;

                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var firstTask   = Task.Factory.StartNew(() =>
                {
                    signal1.Set();
                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                    firstDone = true;
                }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                firstTask.CompletesAsyncOperation(asyncToken1);
                firstTask.Wait();

                var asyncToken2 = listener.BeginAsyncOperation("Test");
                var secondTask  = Task.Factory.StartNew(() =>
                {
                    signal2.Set();
                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                    secondDone = true;
                }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                secondTask.CompletesAsyncOperation(asyncToken2);

                // give it two signals since second one might not have started when WaitTask.Wait is called - race condition
                Wait(listener, signal1, signal2);

                Assert.True(firstDone, "First didn't finish");
                Assert.True(secondDone, "Should have waited for the second task");
            }
        }
コード例 #14
0
                    private async Task ProcessDocumentAsync(Solution solution, ImmutableArray <IIncrementalAnalyzer> analyzers, WorkItem workItem, CancellationToken cancellationToken)
                    {
                        Contract.ThrowIfNull(workItem.DocumentId);

                        if (CancellationToken.IsCancellationRequested)
                        {
                            return;
                        }

                        var processedEverything = false;
                        var documentId          = workItem.DocumentId;

                        try
                        {
                            using (Logger.LogBlock(FunctionId.WorkCoordinator_ProcessDocumentAsync, w => w.ToString(), workItem, cancellationToken))
                            {
                                var document = solution.GetDocument(documentId);
                                if (document != null)
                                {
                                    await _processor.ProcessDocumentAnalyzersAsync(document, analyzers, workItem, cancellationToken).ConfigureAwait(false);
                                }

                                if (!cancellationToken.IsCancellationRequested)
                                {
                                    processedEverything = true;
                                }
                            }
                        }
                        catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
                        {
                            throw ExceptionUtilities.Unreachable;
                        }
                        finally
                        {
                            // we got cancelled in the middle of processing the document.
                            // let's make sure newly enqueued work item has all the flag needed.
                            // Avoid retry attempts after cancellation is requested, since work will not be processed
                            // after that point.
                            if (!processedEverything && !CancellationToken.IsCancellationRequested)
                            {
                                _workItemQueue.AddOrReplace(workItem.Retry(Listener.BeginAsyncOperation("ReenqueueWorkItem")));
                            }

                            SolutionCrawlerLogger.LogProcessActiveFileDocument(_processor._logAggregator, documentId.Id, processedEverything);

                            // remove one that is finished running
                            _workItemQueue.MarkWorkItemDoneFor(workItem.DocumentId);
                        }
                    }
コード例 #15
0
            private void EnqueueChecksumUpdate()
            {
                // event will raised sequencially. no concurrency on this handler
                if (_event.CurrentCount > 0)
                {
                    return;
                }

                lock (_gate)
                {
                    _lastToken = _lastToken ?? Listener.BeginAsyncOperation(nameof(SolutionChecksumUpdater));
                }

                _event.Release();
            }
コード例 #16
0
        internal void RaiseBulkDiagnosticsUpdated(Func <Action <DiagnosticsUpdatedArgs>, Task> eventActionAsync)
        {
            // all diagnostics events are serialized.
            var ev = _eventMap.GetEventHandlers <EventHandler <DiagnosticsUpdatedArgs> >(DiagnosticsUpdatedEventName);

            if (ev.HasHandlers)
            {
                // we do this bulk update to reduce number of tasks (with captured data) enqueued.
                // we saw some "out of memory" due to us having long list of pending tasks in memory.
                // this is to reduce for such case to happen.
                Action <DiagnosticsUpdatedArgs> raiseEvents = args => ev.RaiseEvent(handler => handler(this, args));

                var asyncToken = Listener.BeginAsyncOperation(nameof(RaiseDiagnosticsUpdated));
                _eventQueue.ScheduleTask(() => eventActionAsync(raiseEvents)).CompletesAsyncOperation(asyncToken);
            }
        }
コード例 #17
0
                public void Enqueue(Document document, SyntaxPath?changedMember)
                {
                    UpdateLastAccessTime();

                    using (_workGate.DisposableWait(CancellationToken))
                    {
                        if (_pendingWork.TryGetValue(document.Id, out var data))
                        {
                            // create new async token and dispose old one.
                            var newAsyncToken = Listener.BeginAsyncOperation(
                                nameof(Enqueue),
                                tag: _registration.Workspace
                                );
                            data.AsyncToken.Dispose();

                            _pendingWork[document.Id] = new Data(
                                document,
                                data.ChangedMember == changedMember ? changedMember : null,
                                newAsyncToken
                                );
                            return;
                        }

                        _pendingWork.Add(
                            document.Id,
                            new Data(
                                document,
                                changedMember,
                                Listener.BeginAsyncOperation(
                                    nameof(Enqueue),
                                    tag: _registration.Workspace
                                    )
                                )
                            );
                        _gate.Release();
                    }

                    Logger.Log(
                        FunctionId.WorkCoordinator_SemanticChange_Enqueue,
                        s_enqueueLogger,
                        Environment.TickCount,
                        document.Id,
                        changedMember != null
                        );
                }
コード例 #18
0
        public void Operation()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal = new ManualResetEventSlim();
                var listener = new Listener();

                var done = false;
                var asyncToken = listener.BeginAsyncOperation("Test");
                var task = new Task(() =>
                    {
                        signal.Set();
                        sleepHelper.Sleep(TimeSpan.FromSeconds(1));
                        done = true;
                    });
                task.CompletesAsyncOperation(asyncToken);
                task.Start();

                Wait(listener, signal);
                Assert.True(done, "The operation should have completed");
            }
        }
コード例 #19
0
        public void Operation()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal   = new ManualResetEventSlim();
                var listener = new Listener();

                var done       = false;
                var asyncToken = listener.BeginAsyncOperation("Test");
                var task       = new Task(() =>
                {
                    signal.Set();
                    sleepHelper.Sleep(TimeSpan.FromSeconds(1));
                    done = true;
                });
                task.CompletesAsyncOperation(asyncToken);
                task.Start(TaskScheduler.Default);

                Wait(listener, signal);
                Assert.True(done, "The operation should have completed");
            }
        }
コード例 #20
0
                    private async Task ProcessProjectAsync(ImmutableArray <IIncrementalAnalyzer> analyzers, WorkItem workItem, CancellationToken cancellationToken)
                    {
                        if (CancellationToken.IsCancellationRequested)
                        {
                            return;
                        }

                        // we do have work item for this project
                        var projectId           = workItem.ProjectId;
                        var processedEverything = false;
                        var processingSolution  = Processor._registration.GetSolutionToAnalyze();

                        try
                        {
                            using (Logger.LogBlock(FunctionId.WorkCoordinator_ProcessProjectAsync, w => w.ToString(), workItem, cancellationToken))
                            {
                                var project = processingSolution.GetProject(projectId);
                                if (project != null)
                                {
                                    var reasons          = workItem.InvocationReasons;
                                    var semanticsChanged = reasons.Contains(PredefinedInvocationReasons.SemanticChanged) ||
                                                           reasons.Contains(PredefinedInvocationReasons.SolutionRemoved);

                                    using (Processor.EnableCaching(project.Id))
                                    {
                                        await Processor.RunAnalyzersAsync(analyzers, project, workItem, (a, p, c) => a.AnalyzeProjectAsync(p, semanticsChanged, reasons, c), cancellationToken).ConfigureAwait(false);
                                    }
                                }
                                else
                                {
                                    SolutionCrawlerLogger.LogProcessProjectNotExist(Processor._logAggregator);

                                    await RemoveProjectAsync(projectId, cancellationToken).ConfigureAwait(false);
                                }

                                if (!cancellationToken.IsCancellationRequested)
                                {
                                    processedEverything = true;
                                }
                            }
                        }
                        catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
                        {
                            throw ExceptionUtilities.Unreachable;
                        }
                        finally
                        {
                            // we got cancelled in the middle of processing the project.
                            // let's make sure newly enqueued work item has all the flag needed.
                            // Avoid retry attempts after cancellation is requested, since work will not be processed
                            // after that point.
                            if (!processedEverything && !CancellationToken.IsCancellationRequested)
                            {
                                _workItemQueue.AddOrReplace(workItem.Retry(Listener.BeginAsyncOperation("ReenqueueWorkItem")));
                            }

                            SolutionCrawlerLogger.LogProcessProject(Processor._logAggregator, projectId.Id, processedEverything);

                            // remove one that is finished running
                            _workItemQueue.MarkWorkItemDoneFor(projectId);
                        }
                    }
コード例 #21
0
                    private async Task ProcessDocumentAsync(ImmutableArray <IIncrementalAnalyzer> analyzers, WorkItem workItem, CancellationToken cancellationToken)
                    {
                        Contract.ThrowIfNull(workItem.DocumentId);

                        if (CancellationToken.IsCancellationRequested)
                        {
                            return;
                        }

                        var processedEverything = false;
                        var documentId          = workItem.DocumentId;

                        // we should always use solution snapshot after workitem is removed from the queue.
                        // otherwise, we can have a race such as below.
                        //
                        // 1.solution crawler picked up a solution
                        // 2.before processing the solution, an workitem got changed
                        // 3.and then the work item got picked up from the queue
                        // 4.and use the work item with the solution that got picked up in step 1
                        //
                        // step 2 is happening because solution has changed, but step 4 used old solution from step 1
                        // that doesn't have effects of the solution changes.
                        //
                        // solution crawler must remove the work item from the queue first and then pick up the soluton,
                        // so that the queue gets new work item if there is any solution changes after the work item is removed
                        // from the queue
                        //
                        // using later version of solution is always fine since, as long as there is new work item in the queue,
                        // solution crawler will eventually call the last workitem with the lastest solution
                        // making everything to catch up
                        var solution = Processor.CurrentSolution;

                        try
                        {
                            using (Logger.LogBlock(FunctionId.WorkCoordinator_ProcessDocumentAsync, w => w.ToString(), workItem, cancellationToken))
                            {
                                var document = solution.GetDocument(documentId);

                                if (document != null)
                                {
                                    // if we are called because a document is opened, we invalidate the document so that
                                    // it can be re-analyzed. otherwise, since newly opened document has same version as before
                                    // analyzer will simply return same data back
                                    if (workItem.MustRefresh && !workItem.IsRetry)
                                    {
                                        var isOpen = document.IsOpen();

                                        await ProcessOpenDocumentIfNeededAsync(analyzers, workItem, document, isOpen, cancellationToken).ConfigureAwait(false);
                                        await ProcessCloseDocumentIfNeededAsync(analyzers, workItem, document, isOpen, cancellationToken).ConfigureAwait(false);
                                    }

                                    // check whether we are having special reanalyze request
                                    await ProcessReanalyzeDocumentAsync(workItem, document, cancellationToken).ConfigureAwait(false);

                                    await Processor.ProcessDocumentAnalyzersAsync(document, analyzers, workItem, cancellationToken).ConfigureAwait(false);
                                }
                                else
                                {
                                    SolutionCrawlerLogger.LogProcessDocumentNotExist(Processor._logAggregator);

                                    await RemoveDocumentAsync(documentId, cancellationToken).ConfigureAwait(false);
                                }

                                if (!cancellationToken.IsCancellationRequested)
                                {
                                    processedEverything = true;
                                }
                            }
                        }
                        catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                        {
                            throw ExceptionUtilities.Unreachable;
                        }
                        finally
                        {
                            // we got cancelled in the middle of processing the document.
                            // let's make sure newly enqueued work item has all the flag needed.
                            // Avoid retry attempts after cancellation is requested, since work will not be processed
                            // after that point.
                            if (!processedEverything && !CancellationToken.IsCancellationRequested)
                            {
                                _workItemQueue.AddOrReplace(workItem.Retry(Listener.BeginAsyncOperation("ReenqueueWorkItem")));
                            }

                            SolutionCrawlerLogger.LogProcessDocument(Processor._logAggregator, documentId.Id, processedEverything);

                            // remove one that is finished running
                            _workItemQueue.MarkWorkItemDoneFor(workItem.DocumentId);
                        }
                    }
コード例 #22
0
        public void QueuedOperation()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal = new ManualResetEventSlim();
                var listener = new Listener();

                var done = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task = new Task(() =>
                    {
                        signal.Set();
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                        var asyncToken2 = listener.BeginAsyncOperation("Test");
                        var queuedTask = new Task(() =>
                            {
                                sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                                done = true;
                            });
                        queuedTask.CompletesAsyncOperation(asyncToken2);
                        queuedTask.Start();
                    });

                task.CompletesAsyncOperation(asyncToken1);
                task.Start();

                Wait(listener, signal);

                Assert.True(done, "Should have waited for the queued operation to finish!");
            }
        }
コード例 #23
0
        public void SecondCompletion()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal1 = new ManualResetEventSlim();
                var signal2 = new ManualResetEventSlim();
                var listener = new Listener();

                var firstDone = false;
                var secondDone = false;

                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var firstTask = Task.Factory.StartNew(() =>
                    {
                        signal1.Set();
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        firstDone = true;
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                firstTask.CompletesAsyncOperation(asyncToken1);
                firstTask.Wait();

                var asyncToken2 = listener.BeginAsyncOperation("Test");
                var secondTask = Task.Factory.StartNew(() =>
                    {
                        signal2.Set();
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        secondDone = true;
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                secondTask.CompletesAsyncOperation(asyncToken2);

                // give it two signals since second one might not have started when WaitTask.Wait is called - race condition
                Wait(listener, signal1, signal2);

                Assert.True(firstDone, "First didn't finish");
                Assert.True(secondDone, "Should have waited for the second task");
            }
        }
コード例 #24
0
        public void IgnoredCancel()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal = new ManualResetEventSlim();
                var listener = new Listener();

                var done = false;
                var queuedFinished = false;
                var cancelledFinished = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task = new Task(() =>
                {
                    using (listener.BeginAsyncOperation("Test"))
                    {
                        var cancelledTask = new Task(() =>
                        {
                            sleepHelper.Sleep(TimeSpan.FromSeconds(10));
                            cancelledFinished = true;
                        });

                        signal.Set();
                        cancelledTask.Start();
                    }

                    sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                    // Now that we've cancelled the first request, queue another one to make sure we wait for it.
                    var asyncToken2 = listener.BeginAsyncOperation("Test");
                    var queuedTask = new Task(() =>
                        {
                            sleepHelper.Sleep(TimeSpan.FromSeconds(1));
                            queuedFinished = true;
                        });
                    queuedTask.CompletesAsyncOperation(asyncToken2);
                    queuedTask.Start();
                    done = true;
                });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start();

                Wait(listener, signal);

                Assert.True(done, "Cancelling should have completed the current task.");
                Assert.True(queuedFinished, "Continued didn't run, but it was supposed to ignore the cancel.");
                Assert.False(cancelledFinished, "We waited for the cancelled task to finish.");
            }
        }
コード例 #25
0
        public void MultipleEnqueues()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal = new ManualResetEventSlim();
                var listener = new Listener();

                var outerDone = false;
                var firstQueuedDone = false;
                var secondQueuedDone = false;

                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task = new Task(() =>
                    {
                        signal.Set();
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                        var asyncToken2 = listener.BeginAsyncOperation("Test");
                        var firstQueueTask = new Task(() =>
                            {
                                sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                                var asyncToken3 = listener.BeginAsyncOperation("Test");
                                var secondQueueTask = new Task(() =>
                                    {
                                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                                        secondQueuedDone = true;
                                    });
                                secondQueueTask.CompletesAsyncOperation(asyncToken3);
                                secondQueueTask.Start();
                                firstQueuedDone = true;
                            });
                        firstQueueTask.CompletesAsyncOperation(asyncToken2);
                        firstQueueTask.Start();
                        outerDone = true;
                    });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start();

                Wait(listener, signal);

                Assert.True(outerDone, "The outer task should have finished!");
                Assert.True(firstQueuedDone, "The first queued task should have finished");
                Assert.True(secondQueuedDone, "The second queued task should have finished");
            }
        }
コード例 #26
0
        public void Nested()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal = new ManualResetEventSlim();
                var listener = new Listener();

                var outerDone = false;
                var innerDone = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task = new Task(() =>
                    {
                        signal.Set();
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));

                        using (listener.BeginAsyncOperation("Test"))
                        {
                            sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                            innerDone = true;
                        }

                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        outerDone = true;
                    });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start();

                Wait(listener, signal);

                Assert.True(innerDone, "Should have completed the inner task");
                Assert.True(outerDone, "Should have completed the outer task");
            }
        }
コード例 #27
0
        public void Cancel()
        {
            using (var sleepHelper = new SleepHelper())
            {
                var signal = new ManualResetEventSlim();
                var listener = new Listener();

                var done = false;
                var continued = false;
                var asyncToken1 = listener.BeginAsyncOperation("Test");
                var task = new Task(() =>
                    {
                        signal.Set();
                        sleepHelper.Sleep(TimeSpan.FromMilliseconds(500));
                        var asyncToken2 = listener.BeginAsyncOperation("Test");
                        var queuedTask = new Task(() =>
                            {
                                sleepHelper.Sleep(TimeSpan.FromSeconds(5));
                                continued = true;
                            });
                        asyncToken2.Dispose();
                        queuedTask.Start();
                        done = true;
                    });
                task.CompletesAsyncOperation(asyncToken1);
                task.Start();

                Wait(listener, signal);

                Assert.True(done, "Cancelling should have completed the current task.");
                Assert.False(continued, "Continued Task when it shouldn't have.");
            }
        }
コード例 #28
0
 private IAsyncToken BeginOperation(string taskName)
 => Listener.BeginAsyncOperation(taskName);