vaadin / collaboration-engine

The simplest way to build real-time collaboration into web apps
https://vaadin.com/collaboration
Other
3 stars 1 forks source link

Support accessing from arbitrary threads without a session lock #46

Open Legioth opened 3 years ago

Legioth commented 3 years ago

The design of classes like TopicConnection and CollaborationMap is implicitly assuming that usage is from a thread that holds the same session lock that is also used by the associated ComponentConnectionContext. In this way, there are never any synchronization issues between actions triggered from application code and actions triggered from collaborative changes (which are delegated trough ConnectionContext::dispatchAction). There's also a per-topic lock that helps protect the integrity of the data in the topic itself, but this lock does not always provide clearly ordered operations from the application's point of view.

State in TopicConnection does currently have these characteristics:

Taken as a whole, all mutable state in TopicConnection can be concurrently accessed from three different directions: application code (which may be assumed to hold the session lock), activation handler (which holds the session lock when using ComponentConnectionContext), and topic events (which hold the topic lock but does typically not hold the (right) session lock). 💥

It seems like updating handleMapChange and handleListChange to dispatch through the connection context would address all the cases where state is accessed from the topic side, thus only leaving the paths through application code and through the activation handler.

We could ensure application code invocations are always synchronized with regards to the activation handler invocations if we would introduce a method in ConnectionContext that would assert synchronization is present (e.g. by checking that a ReentrantLock is held by the current thread) and triggering that check through all application code entry points.

Legioth commented 3 years ago

The same approach for synchronization of internal state could also be used by classes like PresenceManager (aka PresenceAdapter) that are centered around a ConnectionContext instance (once we get rid of setTopic).