WIP: 'Stateful IDs' experimental redesign #44
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR (and the spec behind it) are a work in progress.
This PR basically aims to rewrite most of Rojo to drop the notion of routes almost entirely in favor of generated IDs and make the server much more stateful. The goal is to make change description completely robust in all cases, including models with many duplicated instance names.
I'll try to describe the design in this PR description before actually implementing the bulk of it.
Base Terms
Instance
on the client.Initialization
On server initialization, Rojo reads all files in each partition and runs each through our middleware stack (renamed from plugins). Middleware transform a
VfsItem
into a list ofRbxInstance
objects with these properties:String
String
Option<Id>
HashMap<String, RbxValue>
Route
(does not have to serialize)Id
Option<RbxReferent>
The server should keep these book-keeping maps:
HashMap<Id, RbxInstance
, to serve as an indexHashMap<Route, Id>
, to manage filesystem changesHashMap<Id, Route>
, to manage changes from the clientHashMap<Route, String>
, to disambiguate and debounce changes written to the filesystemHashMap<RbxReferent, Id>
, when loadingrbxmx
format models from diskOn initial sync, the client should receive:
RbxInstance
the server knows of.Id
to a Roblox route, containing an entry for every partition and where they should be mounted.File Changes
Whenever a file is changed, the server should:
Route
.VfsItem
object.Route
toString
.VfsItem
through the middleware chain to a tree ofRbxInstance
objects.RbxInstance
case should just reference children by ID, but that's super inconvenient here.Route
toId
.Id
, reuse it and replace the root'sId
.RbxReferent
value is present on the instance, attempt to map it to an existingId
, falling back to creating a newId
.(Timestamp, Id)
for the root instance into a sorted list that's client queryable.The client will then:
Id
s that have changed.Id
that has changed.If an
Id
was not previously tracked by the client, the associatedRbxInstance
'sparent
field will point to anotherId
. The client will either have knowledge of thatId
, or request it from the server if it isn't known. This can potentially continue up the tree until the client reaches a partition mount point, which should be known by the client due to the initialization process.Client Changes
The client should keep list of mutations to track any uncommitted changes to Roblox Instances tracked by Rojo.
Those changes should come in three flavors:
id
,key
, andvalue
)id
)clientId
)Every sync period, which could be around 100ms, the plugin should send a request with every Roblox Instance mutation all at once.
In order to correctly serialize changes received from the client, some care needs to be taken.
For every Changed or Deleted mutation received from the client, the server should:
RbxInstance
associated with theid
.RbxInstance
in-place.parent
property until anRbxInstance
is found that has aroute
property.VfsItem
object.VfsItem
into the server's map fromRoute
toString
, which is used by the "File Changes" process.For every Created mutation received from the client, the server should:
RbxInstance
associated with the instance'sparent
Id
Id
for the instance being created.VfsItem
objects to commit to disk.RbxInstance
into all of the server's relevant maps.Id
to the client, indexed by the request'sclientId
, which can be used for later updates in both directions.State and Session Restart
Previously, only the client had meaningful state with regards to what instances were loaded; the server in 0.3.x only tracks a list of changes by route.
Both the Rojo server and client in the Stateful IDs redesign have a significant amount of state, which requires using a field already present, but unused, in the sync protocol.
During initialization and initial sync, the server should send the client two values:
rojo.json
The client should store the server ID as connection metadata, and the project name as place metadata that it may persist.
Every request from the client should attach both the server ID and the project name. As a first validation check, the server must compare both values to its own.
If a mismatch is detected, the server should immediately abort the request and return an error containing its server ID and loaded project name.
If the client detects an error in this way, it should delete any connection metadata, including
Id
mappings -- this data is no longer relevant to any new connections.If the returned project name matches the value that the client was using before, the client should begin a session restart by reinitializing the connection to the server and creating new metadata.