Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

walker: Use memdb for queued paths #839

Merged
merged 4 commits into from
Apr 6, 2022
Merged

walker: Use memdb for queued paths #839

merged 4 commits into from
Apr 6, 2022

Conversation

radeksimko
Copy link
Member

@radeksimko radeksimko commented Mar 22, 2022

Fixes #838

The bug was originally introduced in #502 - i.e. has been around since introduction of workspace support, for about 9 months. I am therefore leaning towards just slotting this into a regular release schedule (as opposed to cutting patch release).


Previously we stored queued paths in a priority queue implemented via container/heap. To allow a more efficient synchronization (which is needed in tests) and a little more readable code (at least the walker code), the data was moved into a new memdb table. This means we can leverage memdb watch channels to do the synchronization and entirely avoid a separate "SyncWalker" implementation just for tests.

New walker_paths memdb table

Each entry within the new table is represented as WalkerPath:

type WalkerPath struct {
Dir document.DirHandle
IsDirOpen bool
State PathState
}

WalkerCollector

A new WalkerCollector is introduced to collect job IDs and errors as part of walking, such that we can block & wait for completion of all these async jobs in tests and also fail tests if errors occur during walking.

type WalkerCollector struct {
errors *multierror.Error
errorsMu *sync.RWMutex
jobIds job.IDs
jobIdsMu *sync.RWMutex
}

Synchronization in tests

A new helper function is introduced to block and wait for:

  1. walker to finish walking a given path
  2. jobs scheduled from that walk to finish

and also to flag up any errors occurred during the walk as test failures.

func waitForWalkerPath(t *testing.T, ss *state.StateStore, wc *module.WalkerCollector, dir document.DirHandle) {
ctx := context.Background()
err := ss.WalkerPaths.WaitForDirs(ctx, []document.DirHandle{dir})
if err != nil {
t.Fatal(err)
}
err = ss.JobStore.WaitForJobs(ctx, wc.JobIds()...)
if err != nil {
t.Fatal(err)
}
err = wc.ErrorOrNil()
if err != nil {
t.Fatal(err)
}
}

This replaces the clunkier sync mode of the walker where StartWalk() would optionally block under test.


Future - General Purpose Walker?

As noted with the // TODO inline comment, I see an opportunity to further cleanup the Walker code and make it more general-purpose by extracting the logic that runs for every module found. That would likely allow us to remove most of the arguments from NewWalker. I just didn't want to do it in this PR which already got quite big.

@radeksimko radeksimko added the bug Something isn't working label Mar 22, 2022
@radeksimko radeksimko marked this pull request as ready for review March 22, 2022 18:13
@radeksimko radeksimko requested a review from a team March 22, 2022 18:13
@radeksimko radeksimko removed the request for review from a team April 1, 2022 06:28
@radeksimko radeksimko marked this pull request as draft April 1, 2022 06:29
@radeksimko
Copy link
Member Author

Converting to draft as there is still ongoing issue with the channel being filled up due to the fact that we only consume from the channel on a certain occasion.

if w.queue.Len() == 0 {
w.queueMu.Unlock()
select {
case <-w.pushChan:
// block to avoid infinite loop
continue
case <-w.doneCh:
return
}
}
nextPath := heap.Pop(w.queue)
w.queueMu.Unlock()
path := nextPath.(string)
nextPathToWalk <- path

This would suggest that walker is basically capped 50 paths all the time.

I want to explore the possibility of moving the path queue into memdb as well since the problem we have here is basically the same as in the job scheduler and it might allow us to get rid of most sync logic within the walker.

@radeksimko
Copy link
Member Author

radeksimko commented Apr 1, 2022

I have a draft of a solution (pushed to branch) but it's not fully finished and it looks like it would be best to first tackle #515

@radeksimko radeksimko self-assigned this Apr 1, 2022
@radeksimko radeksimko changed the title fix: queue paths for walking in a go routine to avoid blocking walker: Use memdb for queued paths Apr 1, 2022
@radeksimko radeksimko force-pushed the fix-walker-queueing branch 7 times, most recently from b563a34 to a30349f Compare April 5, 2022 13:18
Makes use of the new WalkerCollector allowing us to pass around a single *Walker instance.
This also allows us to move synchronization from within StartWalking() to tests themselves, reducing the difference between "code under test" and "code in prod".
@radeksimko radeksimko marked this pull request as ready for review April 5, 2022 13:42
@radeksimko radeksimko requested a review from a team April 5, 2022 13:57
Copy link
Member

@dbanck dbanck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks for the helpful PR description!

I've only a small suggestion, but that isn't a blocker

@radeksimko radeksimko merged commit 07ee6c4 into main Apr 6, 2022
@radeksimko radeksimko deleted the fix-walker-queueing branch April 6, 2022 08:09
@github-actions
Copy link

This functionality has been released in v0.27.0 of the language server.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Many-root workspaces cause server to hang
2 participants