Even for objects that support true concurrent modification, there are still cases where we want to enforce turn-taking. In particularly, activities that present the same objects to a large number of users can be problematic because of performance issues (and related usability problems as the UI slows down). See, for example, the notes on moo-workspace integration.
The distributed nature of the CORK architecture makes this somewhat tricky. Local replicas are modified optimistically (with the assumption that the modification will be accepted) and then corrected if a conflict is detected later. Exclusivity requires (real or synthensized) central control.
Ideally, the token-management mechanism would have the following properties:
- Support for queuing
- And queue retrieval, for presentation in the UI
- Support for time limits
- Automatic de-queuing of logged-out users
- Messages describing queue changes should only be sent to clients in a given queue
Note that, unless we integrate token-management with the permissions mechanism, it will not be particularly useful to expend extra complexity to make token-management secure. It is reasonable to assume that it will simply be used to enable/disable parts of the client interface, rather than fundamentally restricting modification to shared data.
Possible approaches:
- SessionData-based managment. The BRIDGE SessionData mechanism provides management of arbitrary per-user/session information. This could be used as a basis for token management:
- To request the token, the session data for all users currently viewing the object could be examined. For users already in the queue, an element would be present that contained the object id of the object whose access was controlled by the token, along with a ticket number. The highest ticket number found would be incremented and used as the ticket number for the new user, who would add an entry to their own session data. (In practice, the list of queued users would probably be continuously maintained so that it could be presented in the UI. Hence actual re-inspection of the session data objects would not be needed.)
- When the current low-ticket holder is finished with the object, the entry would be removed from his session data. Each other session would then determine who was next in line. User id, login time, or some other fixed value could be used to resolve ticket number ties.
- Logouts could be handled by the same mechanism: A disappearing SessionData could be handled in the same way as a SessionData's ticket element being cleared.
- Timeouts would be trickier, particularly given the absence of a centralized notion of time. A solution to this would be have each interested client note the (local) time at which the token-holder acquired the token. The token-holder's client would have primary responsibility for releasing the token on completion, but after a small (fixed or relative?) grace period, other clients would be able to enforce the timeout.
- The grace period could be adjusted relative to order in the list, e.g., the 2nd person in line could clear the token after 30 sec, the next after 1 min, etc...
- Uncontested tokens could effectively be held indefinitely
- This approach:
- requires no centralized service
- requires no new replicated objects
- is "object-agnostic" and can be used to control access to any type of object
- but would not be readily adaptable to a more secure mechanism that actually enforced editing restrictions
- but may require excessive messaging. At present, each client retrieves the SessionData object for every other user in the system in order to show login time, status, etc... in the user list. We could introduce another object, linked to by the SessionData, that would contain token information and be retrieved and released as needed. Not sure whether the net result would be more or less network traffic.
- Add a ResourceQueue replicated object, with logic similar to that of the SessionData-based approach.
- These would have to be explicitly created and associated with the object(s) that they were controlling access to, but would allow better management of retrieval and release, reducing network traffic. (Messages would only be sent to clients that had retrieved the queue object.)
- Traffic could be further reduced (in apps where appropriate) by deferring retrieval until the first attempt to acquire the token.
- Centralized mechanism for managing ResourceQueue objects, similar to the way SessionData objects are managed by the server.
- would allow easier transition to a more rigidly enforced token management scheme, since it would not rely on clients managing up the queue themselves.
- but would introduce (yet) more server-side complexity, further limiting future options for federated configurations
Option (2) seems preferable, particularly given that we know that (in WebPals-ish activities), messaging load will be an issue.
ResourceQueue Design
ResourceQueue could be based on SharedList, but given the simpler set of operations (e.g., we need not support replacement of items) it may make sense to create a new implementation based on a LinkedList (since most operations will be Queue-ish).
- LinkedList of QueueEntries, where QueueEntry records contain:
- User id
- Client id, for use with
isClientAlive(...),
- we should probably rely on local user list lookups instead, as
isClientAlive(...) calls result in messaging and will pose problems in a more distributed configuration
- client id will also allow us to distinguish multiple logins from the same user
- Ticket number, computed from max ticket number in list
- Long field for (optional) time limit
- Transient long field for local time of last change of token owner
- add and remove methods must be synchronized
- Each client should be responsible for removing itself (either manually or on timeout) and the entry ahead of it. This should minimize network traffic.
- Most of the management logic should be moved to ComponentView so that it can be automatically detached on UI disposal.
- Need ListModel methods for UI
|