Skip to content

Commit 515c57b

Browse files
authored
Merge pull request #478 from ably/clarify-zero-value-objects-v2
Clarify the default values for newly created LiveMap and LiveCounter
2 parents 0a96e51 + 4cec279 commit 515c57b

1 file changed

Lines changed: 18 additions & 12 deletions

File tree

specifications/objects-features.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,14 @@ Objects feature enables clients to store shared data as "objects" on a channel.
140140
- `(RTO3)` An internal `ObjectsPool` should be used to maintain the list of objects present on a channel
141141
- `(RTO3a)` `ObjectsPool` is a `Dict<String, LiveObject>` - a map of `LiveObject`s keyed by [`objectId`](../features#OST2a) string
142142
- `(RTO3b)` It must always contain a `LiveMap` object with id `root`
143-
- `(RTO3b1)` Upon initialization of the `ObjectsPool`, create a new `LiveMap` (per [RTLM4](#RTLM4)) with `objectId` set to `root` and add it to the `ObjectsPool`
143+
- `(RTO3b1)` Upon initialization of the `ObjectsPool`, create a new `LiveMap` per [RTLM4](#RTLM4) with `objectId` set to `root` and add it to the `ObjectsPool`
144144
- `(RTO4)` When a channel `ATTACHED` `ProtocolMessage` is received, the client library must perform the following actions in order. The `ProtocolMessage` may contain a `HAS_OBJECTS` bit flag (see [TR3](../features#TR3)); note that some of the following actions are conditional on this flag.
145145
- `(RTO4c)` The [RTO17](#RTO17) sync state must transition to `SYNCING` if not already `SYNCING`
146146
- `(RTO4d)` The `bufferedObjectOperations` list must be cleared without applying any buffered operations
147147
- `(RTO4a)` If the `HAS_OBJECTS` flag is 1, the server will shortly perform an `OBJECT_SYNC` sequence as described in [RTO5](#RTO5). Note that this does not imply that objects are definitely present on the channel, only that there may be; the `OBJECT_SYNC` message may be empty
148148
- `(RTO4b)` If the `HAS_OBJECTS` flag is 0 or there is no `flags` field, the sync sequence must be considered complete immediately, and the client library must perform the following actions in order:
149149
- `(RTO4b1)` All objects except the one with id `root` must be removed from the internal `ObjectsPool`
150-
- `(RTO4b2)` The data for the `LiveMap` with id `root` must be cleared by setting it to a zero-value per [RTLM4](#RTLM4). Note that the client SDK must not create a new `LiveMap` instance with id `root`; it must only clear the internal data of the existing `LiveMap` with id `root`
150+
- `(RTO4b2)` The data for the `LiveMap` with id `root` must be set to the value described in [RTLM4c](#RTLM4c). Note that the client SDK must not create a new `LiveMap` instance with id `root`; it must only clear the internal data of the existing `LiveMap` with id `root`
151151
- `(RTO4b2a)` Emit a `LiveMapUpdate` object for the `LiveMap` with ID `root`, with `LiveMapUpdate.update` consisting of entries for the keys that were removed, each set to `removed`
152152
- `(RTO4b3)` The `SyncObjectsPool` must be cleared
153153
- `(RTO4b5)` This clause has been replaced by [RTO4d](#RTO4d)
@@ -179,8 +179,8 @@ Objects feature enables clients to store shared data as "objects" on a channel.
179179
- `(RTO5c1a2)` Store the `LiveObjectUpdate` object returned by the operation, along with a reference to the updated object
180180
- `(RTO5c1b)` If an object with `ObjectState.objectId` does not exist in the internal `ObjectsPool`:
181181
- `(RTO5c1b1)` Create a new `LiveObject` using the data from `ObjectState` and add it to the internal `ObjectsPool`:
182-
- `(RTO5c1b1a)` If `ObjectState.counter` is present, create a zero-value `LiveCounter` (per [RTLC4](#RTLC4)), set its private `objectId` equal to `ObjectState.objectId` and replace its internal data using the current `ObjectState` per [RTLC6](#RTLC6)
183-
- `(RTO5c1b1b)` If `ObjectState.map` is present, create a zero-value `LiveMap` (per [RTLM4](#RTLM4)), set its private `objectId` equal to `ObjectState.objectId`, set its private `semantics` equal to `ObjectState.map.semantics` and replace its internal data using the current `ObjectState` per [RTLM6](#RTLM6)
182+
- `(RTO5c1b1a)` If `ObjectState.counter` is present, create a new `LiveCounter` per [RTLC4](#RTLC4) by passing in `ObjectState.objectId` as `objectId`, and then replace its internal data using the current `ObjectState` per [RTLC6](#RTLC6)
183+
- `(RTO5c1b1b)` If `ObjectState.map` is present, create a new `LiveMap` per [RTLM4](#RTLM4) by passing in `ObjectState.objectId` as `objectId`, `ObjectState.map.semantics` as `semantics`, and then replace its internal data using the current `ObjectState` per [RTLM6](#RTLM6)
184184
- `(RTO5c1b1c)` This clause has been deleted (redundant to [RTO5f3](#RTO5f3)).
185185
- `(RTO5c2)` Remove any objects from the internal `ObjectsPool` for which `objectId`s were not received during the sync sequence
186186
- `(RTO5c2a)` The object with ID `root` must not be removed from `ObjectsPool`, as per [RTO3b](#RTO3b)
@@ -191,12 +191,12 @@ Objects feature enables clients to store shared data as "objects" on a channel.
191191
- `(RTO5c5)` The `bufferedObjectOperations` list must be cleared
192192
- `(RTO5c9)` The `appliedOnAckSerials` set ([RTO7b](#RTO7b)) must be cleared. A state sync causes the channel's LiveObjects data to be replaced, so after a state sync the `appliedOnAckSerials` no longer accurately describes which operations have been applied to the channel's LiveObjects data
193193
- `(RTO5c8)` The [RTO17](#RTO17) sync state must transition to `SYNCED`
194-
- `(RTO6)` Certain object operations may require creating a zero-value object if one does not already exist in the internal `ObjectsPool` for the given `objectId`. This can be done as follows:
194+
- `(RTO6)` Certain object operations may require creating a new object if one does not already exist in the internal `ObjectsPool` for the given `objectId`. This can be done as follows:
195195
- `(RTO6a)` If an object with `objectId` exists in `ObjectsPool`, do not create a new object
196196
- `(RTO6b)` The expected type of the object can be inferred from the provided `objectId`:
197197
- `(RTO6b1)` Split the `objectId` (formatted as `[type]:[hash]&#64;[timestamp]`, see [RTO14c](#RTO14c)) on the separator `:` and parse the first part as the type string
198-
- `(RTO6b2)` If the parsed type is `map`, create a zero-value `LiveMap` per [RTLM4](#RTLM4) in the `ObjectsPool`
199-
- `(RTO6b3)` If the parsed type is `counter`, create a zero-value `LiveCounter` per [RTLC4](#RTLC4) in the `ObjectsPool`
198+
- `(RTO6b2)` If the parsed type is `map`, create a new `LiveMap` per [RTLM4](#RTLM4) by passing in the `objectId`, and add it to the `ObjectsPool`
199+
- `(RTO6b3)` If the parsed type is `counter`, create a new `LiveCounter` per [RTLC4](#RTLC4) by passing in the `objectId`, and add it to the `ObjectsPool`
200200
- `(RTO7)` The client library may receive `OBJECT` `ProtocolMessages` in realtime over the channel concurrently with `OBJECT_SYNC` `ProtocolMessages` during the object sync sequence ([RTO5](#RTO5)). Some of the incoming `OBJECT` messages may have already been applied to the objects described in the sync sequence, while others may not. Therefore, the client must buffer `OBJECT` messages during the sync sequence so that it can determine which of them should be applied to the objects once the sync is complete. See [RTO8](#RTO8)
201201
- `(RTO7a)` The `RealtimeObjects` instance has an internal attribute `bufferedObjectOperations`, which is an array of `ObjectMessage` instances. This is used to store the buffered `ObjectMessages`, as described in [RTO8a](#RTO8a).
202202
- `(RTO7a1)` This array is empty upon `RealtimeObjects` initialization
@@ -214,7 +214,7 @@ Objects feature enables clients to store shared data as "objects" on a channel.
214214
- `(RTO9a3)` If the `appliedOnAckSerials` set ([RTO7b](#RTO7b)) contains `ObjectMessage.serial`, log a debug or trace message indicating that the operation has already been applied upon receipt of the ACK, remove this value from the set, and discard the current `ObjectMessage` without taking any further action
215215
- `(RTO9a2)` The `ObjectMessage.operation.action` field (see [`ObjectOperationAction`](../features#OOP2)) determines the type of operation to apply:
216216
- `(RTO9a2a)` If `ObjectMessage.operation.action` is one of the following: `MAP_CREATE`, `MAP_SET`, `MAP_REMOVE`, `COUNTER_CREATE`, `COUNTER_INC`, `OBJECT_DELETE`, or `MAP_CLEAR`, then:
217-
- `(RTO9a2a1)` If it does not already exist, create a zero-value `LiveObject` in the internal `ObjectsPool` per [RTO6](#RTO6) using the `objectId` from `ObjectMessage.operation.objectId`
217+
- `(RTO9a2a1)` If it does not already exist, create a new `LiveObject` in the internal `ObjectsPool` per [RTO6](#RTO6) using the `objectId` from `ObjectMessage.operation.objectId`
218218
- `(RTO9a2a2)` Get the `LiveObject` instance from the internal `ObjectsPool` using the `objectId` from `ObjectMessage.operation.objectId`
219219
- `(RTO9a2a3)` Apply the `ObjectMessage.operation` to the `LiveObject`; see [RTLC7](#RTLC7), [RTLM15](#RTLM15), passing the `source` parameter. The operation returns a boolean indicating whether the operation was successfully applied
220220
- `(RTO9a2a4)` If `source` is `LOCAL` and [RTO9a2a3](#RTO9a2a3) returned `true`, add `ObjectMessage.serial` to the internal `appliedOnAckSerials` set ([RTO7b](#RTO7b))
@@ -350,7 +350,7 @@ Objects feature enables clients to store shared data as "objects" on a channel.
350350
- `(RTLO4e3a)` This clause has been replaced by [RTLO6a](#RTLO6a)
351351
- `(RTLO4e3b)` This clause has been replaced by [RTLO6b](#RTLO6b)
352352
- `(RTLO4e3b1)` This clause has been replaced by [RTLO6b1](#RTLO6b1)
353-
- `(RTLO4e4)` Set the data for the `LiveObject` to a zero-value, as described in [RTLC4](#RTLC4) or [RTLM4](#RTLM4) depending on the object type
353+
- `(RTLO4e4)` Set the `data` attribute of the `LiveObject` to the value described in [RTLC4b](#RTLC4b) or [RTLM4c](#RTLM4c), depending on the object type
354354
- `(RTLO5)` An `OBJECT_DELETE` operation can be applied to a `LiveObject` in the following way:
355355
- `(RTLO5a)` Expects the following arguments:
356356
- `(RTLO5a1)` `ObjectMessage`
@@ -365,7 +365,9 @@ Objects feature enables clients to store shared data as "objects" on a channel.
365365
- `(RTLC1)` The `LiveCounter` extends `LiveObject`
366366
- `(RTLC2)` Represents the counter object type for Object IDs of type `counter`
367367
- `(RTLC3)` Holds a 64-bit floating-point number as a private `data`
368-
- `(RTLC4)` The zero-value `LiveCounter` is a `LiveCounter` with `data` set to 0
368+
- `(RTLC4)` A new empty `LiveCounter` can be created with the following values:
369+
- `(RTLC4a)` `objectId` is passed into the constructor and set upon creation
370+
- `(RTLC4b)` `data` is set to 0
369371
- `(RTLC11)` Data updates for a `LiveCounter` are emitted using the `LiveCounterUpdate` object:
370372
- `(RTLC11a)` `LiveCounterUpdate` extends `LiveObjectUpdate`
371373
- `(RTLC11b)` `LiveCounterUpdate.update` has the following properties:
@@ -471,7 +473,11 @@ Objects feature enables clients to store shared data as "objects" on a channel.
471473
- `(RTLM3a)` `ObjectsMapEntry` entries in a `LiveMap` have the following attributes in addition to those defined in [OME2](../features#OME2):
472474
- `(RTLM3a1)` `tombstonedAt` (optional) Time - a timestamp indicating when this map entry was tombstoned. This property is nullable, and specification points that manipulate this value maintain the invariant that it is non-null if and only if the corresponding `ObjectsMapEntry.tombstone` is `true`
473475
- `(RTLM25)` Holds a nullable private `clearTimeserial` string, initially `null`
474-
- `(RTLM4)` The zero-value `LiveMap` is a `LiveMap` with `data` set to an empty map and `clearTimeserial` set to `null`
476+
- `(RTLM4)` A new empty `LiveMap` can be created with the following values:
477+
- `(RTLM4a)` `objectId` is passed into the constructor and set upon creation
478+
- `(RTLM4b)` `semantics` may be passed into the constructor and set upon creation; if not provided, it defaults to [`ObjectsMapSemantics.LWW`](../features#OMP2)
479+
- `(RTLM4c)` `data` is set to an empty map
480+
- `(RTLM4d)` `clearTimeserial` is set to `null`
475481
- `(RTLM18)` Data updates for a `LiveMap` are emitted using the `LiveMapUpdate` object:
476482
- `(RTLM18a)` `LiveMapUpdate` extends `LiveObjectUpdate`
477483
- `(RTLM18b)` `LiveMapUpdate.update` is of type `Dict<String, 'updated' | 'removed'>` - a map of `LiveMap` keys that were either updated or removed, with the corresponding value indicating the type of change for each key
@@ -644,7 +650,7 @@ Objects feature enables clients to store shared data as "objects" on a channel.
644650
- `(RTLM7c)` This clause has been replaced by [RTLM7g](#RTLM7g) as of specification version 6.0.0.
645651
- `(RTLM7c1)` This clause has been replaced by [RTLM7g1](#RTLM7g1) as of specification version 6.0.0.
646652
- `(RTLM7g)` If `MapSet.value.objectId` is non-empty:
647-
- `(RTLM7g1)` Create a zero-value `LiveObject` for this `objectId` in the internal `ObjectsPool` per [RTO6](#RTO6)
653+
- `(RTLM7g1)` Create a new `LiveObject` for this `objectId` in the internal `ObjectsPool` per [RTO6](#RTO6)
648654
- `(RTLM7f)` Return a `LiveMapUpdate` object with a `LiveMapUpdate.update` map containing the key used in this operation set to `updated`
649655
- `(RTLM8)` A `MAP_REMOVE` operation for a key can be applied to a `LiveMap` in the following way:
650656
- `(RTLM8c)` Expects the following arguments:

0 commit comments

Comments
 (0)