Previously, we would use `Project::serialize_buffer_for_peer` and
`Project::deserialize_buffer` respectively in the host and in the
guest to create a new buffer or just send its ID if the host thought
the buffer had already been sent.
These methods would be called as part of other methods, such as
`Project::open_buffer_by_id` or `Project::open_buffer_for_symbol`.
However, if any of the tasks driving the futures that eventually
called `Project::deserialize_buffer` were dropped after the host
responded with the buffer state but (crucially) before the guest
deserialized it and registered it, there could be a situation where
the host thought the guest had the buffer (thus sending them just the
buffer id) and the guest would wait indefinitely.
Given how crucial this interaction is, this commit switches to creating
remote buffers for peers out of band. The host will push buffers to guests,
who will always refer to buffers via IDs and wait for the host to send them,
as opposed to including the buffer's payload as part of some other operation.
Changing the frequency at which we update worktrees highlighted a
problem in the randomized tests that was causing clients to receive
a definition to a worktree *before* observing the registration of
the worktree itself. This was most likely caused by #1224 because
the scenario that pull request enabled was the following:
- Guest requests a definition pointing to a non-existant worktree
- Server forwards the request to the host
- Host sends an `UpdateProject` message
- Host sends a response to the definition request
- Server observes the `UpdateProject` message and tries to acquire
the store
- Given that we're waiting, the server goes ahead to process the
response for the definition request, responding *before*
`UpdateProject` is forwarded
- Server finally forwards `UpdateProject` to the guest
This commit ensures that, after forwarding a project request and getting a
response, we acquire a lock to the store again to ensure the project still
exists. This has the effect of ordering the forwarded request *after* any
message that was received prior to the response and for which we are still
waiting to acquire a lock to the store.
* Rename `project_activity_summary` to `top_users_activity_summary`
to make clearer the distinction between it and the per-user summary.
* Rename `user_activity_summary` to `user_activity_timeline`, since
its output is structured a bit differently than the courser-grained
"summary" returned by the top-user query.
* Rename `ActivityDuration` -> `ActivityPeriod`
This prevents deadlocks when e.g., client A performs a request to client B and
client B performs a request to client A. If both clients stop processing further
messages until their respective request completes, they won't have a chance to
respond to the other client's request and cause a deadlock.
This arrangement ensures we will attempt to process earlier messages first, but fall
back to processing messages arrived later in the spirit of making progress.
Now that we track active projects, if nothing happens to the store
during the activity timeout we would still serve some old metrics
that may not account for the staleness of a project.
This commit changes it so that we grab a mutable reference to the store
before serving the metrics, which has the side effect of updating
all the metrics.
* Make `UnregisterProject` a request. This way the client-side project can wait
to clear out its remote id until the request has completed, so that the
contacts panel can avoid showing duplicate private/public projects in the
brief time after unregistering a project, before the next UpdateCollaborators
message is received.
* Remove the `RegisterWorktree` and `UnregisterWorktree` methods and replace
them with a single `UpdateProject` method that idempotently updates the
Project's list of worktrees.
Panes now emit an event when adding the first item, so we need to flush
effects between splitting and following in order to avoid accidentally
cancelling the follow.