@@ -44,9 +44,9 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
4444 private val syncObjectsDataPool = ConcurrentHashMap <String , ObjectState >()
4545 private var currentSyncId: String? = null
4646 /* *
47- * @spec RTO5 - Buffered object operations during sync
47+ * @spec RTO7 - Buffered object operations during sync
4848 */
49- private val bufferedObjectOperations = mutableListOf<ObjectMessage >()
49+ private val bufferedObjectOperations = mutableListOf<ObjectMessage >() // RTO7a
5050
5151 /* *
5252 * @spec RTO1 - Returns the root LiveMap object with proper validation and sync waiting
@@ -130,18 +130,21 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
130130 /* *
131131 * Handles object messages (non-sync messages).
132132 *
133- * @spec RTO5 - Buffers messages if not synced, applies immediately if synced
133+ * @spec RTO8 - Buffers messages if not synced, applies immediately if synced
134134 */
135135 private fun handleObjectMessages (objectMessages : List <ObjectMessage >) {
136136 if (state != ObjectsState .SYNCED ) {
137- // Buffer messages if not synced yet
137+ // RTO7 - The client receives object messages in realtime over the channel concurrently with the sync sequence.
138+ // Some of the incoming object messages may have already been applied to the objects described in
139+ // the sync sequence, but others may not; therefore we must buffer these messages so that we can apply
140+ // them to the objects once the sync is complete.
138141 Log .v(tag, " Buffering ${objectMessages.size} object messages, state: $state " )
139- bufferedObjectOperations.addAll(objectMessages)
142+ bufferedObjectOperations.addAll(objectMessages) // RTO8a
140143 return
141144 }
142145
143146 // Apply messages immediately if synced
144- applyObjectMessages(objectMessages)
147+ applyObjectMessages(objectMessages) // RTO8b
145148 }
146149
147150 /* *
@@ -154,7 +157,7 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
154157 val newSyncSequence = currentSyncId != syncId
155158 if (newSyncSequence) {
156159 // RTO5a2 - new sync sequence started
157- startNewSync(syncId) // RTO5a2a
160+ startNewSync(syncId)
158161 }
159162
160163 // RTO5a3 - continue current sync sequence
@@ -198,8 +201,8 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
198201 Log .v(tag, " Starting new sync sequence: syncId=$syncId " )
199202
200203 // need to discard all buffered object operation messages on new sync start
201- bufferedObjectOperations.clear()
202- syncObjectsDataPool.clear()
204+ bufferedObjectOperations.clear() // RTO5a2b
205+ syncObjectsDataPool.clear() // RTO5a2a
203206 currentSyncId = syncId
204207 stateChange(ObjectsState .SYNCING , false )
205208 }
@@ -214,9 +217,9 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
214217 applySync()
215218 // should apply buffered object operations after we applied the sync.
216219 // can use regular non-sync object.operation logic
217- applyObjectMessages(bufferedObjectOperations)
220+ applyObjectMessages(bufferedObjectOperations) // RTO5c6
218221
219- bufferedObjectOperations.clear()
222+ bufferedObjectOperations.clear() // RTO5c5
220223 syncObjectsDataPool.clear() // RTO5c4
221224 currentSyncId = null // RTO5c3
222225 stateChange(ObjectsState .SYNCED , deferStateEvent)
@@ -264,19 +267,26 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
264267 /* *
265268 * Applies object messages to objects.
266269 *
267- * @spec RTO6 - Creates zero-value objects if they don't exist
270+ * @spec RTO9 - Creates zero-value objects if they don't exist
268271 */
269272 private fun applyObjectMessages (objectMessages : List <ObjectMessage >) {
273+ // RTO9a
270274 for (objectMessage in objectMessages) {
271275 if (objectMessage.operation == null ) {
276+ // RTO9a1
272277 Log .w(tag, " Object message received without operation field, skipping message: ${objectMessage.id} " )
273278 continue
274279 }
275280
276- val objectOperation: ObjectOperation = objectMessage.operation
277- // RTO6a - get or create the zero value object in the pool
278- val obj = objectsPool.createZeroValueObjectIfNotExists(objectOperation.objectId)
279- obj.applyOperation(objectOperation, objectMessage)
281+ val objectOperation: ObjectOperation = objectMessage.operation // RTO9a2
282+ // RTO9a2a - we can receive an op for an object id we don't have yet in the pool. instead of buffering such operations,
283+ // we can create a zero-value object for the provided object id and apply the operation to that zero-value object.
284+ // this also means that all objects are capable of applying the corresponding *_CREATE ops on themselves,
285+ // since they need to be able to eventually initialize themselves from that *_CREATE op.
286+ // so to simplify operations handling, we always try to create a zero-value object in the pool first,
287+ // and then we can always apply the operation on the existing object in the pool.
288+ val obj = objectsPool.createZeroValueObjectIfNotExists(objectOperation.objectId) // RTO9a2a1
289+ obj.applyOperation(objectOperation, objectMessage) // RTO9a2a2, RTO9a2a3
280290 }
281291 }
282292
0 commit comments