Skip to content

Commit 88bb0a4

Browse files
committed
[ECO-5426] Refactored spec comments for LiveObject, LiveCounter and LiveMap classes
1 parent b91412d commit 88bb0a4

5 files changed

Lines changed: 55 additions & 73 deletions

File tree

live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ internal class DefaultLiveObjects(private val channelName: String, private val a
304304
continue
305305
}
306306

307-
val objectState = objectMessage.objectState!!
307+
val objectState: ObjectState = objectMessage.objectState
308308
syncObjectsDataPool[objectState.objectId] = objectState
309309
}
310310
}

live-objects/src/main/kotlin/io/ably/lib/objects/LiveCounter.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import io.ably.lib.util.Log
66
* Implementation of LiveObject for LiveCounter.
77
* Similar to JavaScript LiveCounter class.
88
*
9-
* @spec RTLC1 - LiveCounter implementation
10-
* @spec RTLC2 - LiveCounter extends LiveObject
9+
* @spec RTLC1/RTLC2 - LiveCounter implementation extends LiveObject
1110
*/
1211
internal class LiveCounter(
1312
objectId: String,
@@ -23,7 +22,7 @@ internal class LiveCounter(
2322
/**
2423
* @spec RTLC6 - Overrides counter data with state from sync
2524
*/
26-
override fun overrideWithObjectState(objectState: ObjectState): Any {
25+
override fun overrideWithObjectState(objectState: ObjectState): Map<String, Long> {
2726
if (objectState.objectId != objectId) {
2827
throw objectError("Invalid object state: object state objectId=${objectState.objectId}; LiveCounter objectId=$objectId")
2928
}
@@ -93,7 +92,7 @@ internal class LiveCounter(
9392
notifyUpdated(update)
9493
}
9594

96-
override fun clearData(): Any {
95+
override fun clearData(): Map<String, Long> {
9796
val previousData = data
9897
data = 0
9998
return mapOf("amount" to -previousData)
@@ -102,7 +101,7 @@ internal class LiveCounter(
102101
/**
103102
* @spec RTLC6d - Merges initial data from create operation
104103
*/
105-
private fun applyCounterCreate(operation: ObjectOperation): Any {
104+
private fun applyCounterCreate(operation: ObjectOperation): Map<String, Long> {
106105
if (createOperationIsMerged) {
107106
Log.v(
108107
tag,
@@ -117,7 +116,7 @@ internal class LiveCounter(
117116
/**
118117
* @spec RTLC8 - Applies counter increment operation
119118
*/
120-
private fun applyCounterInc(counterOp: ObjectCounterOp): Any {
119+
private fun applyCounterInc(counterOp: ObjectCounterOp): Map<String, Long> {
121120
val amount = counterOp.amount?.toLong() ?: 0
122121
data += amount
123122
return mapOf("amount" to amount)
@@ -126,7 +125,7 @@ internal class LiveCounter(
126125
/**
127126
* @spec RTLC6d - Merges initial data from create operation
128127
*/
129-
private fun mergeInitialDataFromCreateOperation(operation: ObjectOperation): Any {
128+
private fun mergeInitialDataFromCreateOperation(operation: ObjectOperation): Map<String, Long> {
130129
// if a counter object is missing for the COUNTER_CREATE op, the initial value is implicitly 0 in this case.
131130
// note that it is intentional to SUM the incoming count from the create op.
132131
// if we got here, it means that current counter instance is missing the initial value in its data reference,

live-objects/src/main/kotlin/io/ably/lib/objects/LiveMap.kt

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import io.ably.lib.util.Log
66
* Implementation of LiveObject for LiveMap.
77
* Similar to JavaScript LiveMap class.
88
*
9-
* @spec RTLM1 - LiveMap implementation
10-
* @spec RTLM2 - LiveMap extends LiveObject
9+
* @spec RTLM1/RTLM2 - LiveMap implementation extends LiveObject
1110
*/
1211
internal class LiveMap(
1312
objectId: String,
@@ -20,19 +19,19 @@ internal class LiveMap(
2019
/**
2120
* @spec RTLM3 - Map data structure storing entries
2221
*/
23-
private data class MapEntry(
22+
private data class LiveMapEntry(
2423
var tombstone: Boolean = false,
2524
var tombstonedAt: Long? = null,
2625
var timeserial: String? = null,
2726
var data: ObjectData? = null
2827
)
2928

30-
private val data = mutableMapOf<String, MapEntry>()
29+
private val data = mutableMapOf<String, LiveMapEntry>()
3130

3231
/**
3332
* @spec RTLM6 - Overrides object data with state from sync
3433
*/
35-
override fun overrideWithObjectState(objectState: ObjectState): Any {
34+
override fun overrideWithObjectState(objectState: ObjectState): Map<String, String> {
3635
if (objectState.objectId != objectId) {
3736
throw objectError("Invalid object state: object state objectId=${objectState.objectId}; LiveMap objectId=$objectId")
3837
}
@@ -62,8 +61,8 @@ internal class LiveMap(
6261
createOperationIsMerged = false // RTLM6b
6362
data.clear()
6463

65-
objectState.map?.entries?.forEach { (key, entry) ->
66-
data[key] = MapEntry(
64+
objectState.map.entries?.forEach { (key, entry) ->
65+
data[key] = LiveMapEntry(
6766
tombstone = entry.tombstone ?: false,
6867
tombstonedAt = if (entry.tombstone == true) System.currentTimeMillis() else null,
6968
timeserial = entry.timeserial,
@@ -119,7 +118,7 @@ internal class LiveMap(
119118
notifyUpdated(update)
120119
}
121120

122-
override fun clearData(): Any {
121+
override fun clearData(): Map<String, String> {
123122
val previousData = data.toMap()
124123
data.clear()
125124
return calculateUpdateFromDataDiff(previousData, emptyMap())
@@ -128,13 +127,13 @@ internal class LiveMap(
128127
/**
129128
* @spec RTLM6d - Merges initial data from create operation
130129
*/
131-
private fun applyMapCreate(operation: ObjectOperation): Any {
130+
private fun applyMapCreate(operation: ObjectOperation): Map<String, String> {
132131
if (createOperationIsMerged) {
133132
Log.v(
134133
tag,
135134
"Skipping applying MAP_CREATE op on a map instance as it was already applied before; objectId=$objectId"
136135
)
137-
return mapOf<String, String>()
136+
return mapOf()
138137
}
139138

140139
if (semantics != operation.map?.semantics) {
@@ -149,7 +148,7 @@ internal class LiveMap(
149148
/**
150149
* @spec RTLM7 - Applies MAP_SET operation to LiveMap
151150
*/
152-
private fun applyMapSet(mapOp: ObjectMapOp, opSerial: String?): Any {
151+
private fun applyMapSet(mapOp: ObjectMapOp, opSerial: String?): Map<String, String> {
153152
val existingEntry = data[mapOp.key]
154153

155154
// RTLM7a
@@ -159,7 +158,7 @@ internal class LiveMap(
159158
tag,
160159
"Skipping update for key=\"${mapOp.key}\": op serial $opSerial <= entry serial ${existingEntry.timeserial}; objectId=$objectId"
161160
)
162-
return mapOf<String, String>()
161+
return mapOf()
163162
}
164163

165164
if (existingEntry != null) {
@@ -170,7 +169,7 @@ internal class LiveMap(
170169
existingEntry.data = mapOp.data // RTLM7a2a
171170
} else {
172171
// RTLM7b, RTLM7b1
173-
data[mapOp.key] = MapEntry(
172+
data[mapOp.key] = LiveMapEntry(
174173
tombstone = false, // RTLM7b2
175174
timeserial = opSerial,
176175
data = mapOp.data
@@ -183,7 +182,7 @@ internal class LiveMap(
183182
/**
184183
* @spec RTLM8 - Applies MAP_REMOVE operation to LiveMap
185184
*/
186-
private fun applyMapRemove(mapOp: ObjectMapOp, opSerial: String?): Any {
185+
private fun applyMapRemove(mapOp: ObjectMapOp, opSerial: String?): Map<String, String> {
187186
val existingEntry = data[mapOp.key]
188187

189188
// RTLM8a
@@ -193,7 +192,7 @@ internal class LiveMap(
193192
tag,
194193
"Skipping remove for key=\"${mapOp.key}\": op serial $opSerial <= entry serial ${existingEntry.timeserial}; objectId=$objectId"
195194
)
196-
return mapOf<String, String>()
195+
return mapOf()
197196
}
198197

199198
if (existingEntry != null) {
@@ -204,7 +203,7 @@ internal class LiveMap(
204203
existingEntry.data = null // RTLM8a2a
205204
} else {
206205
// RTLM8b, RTLM8b1
207-
data[mapOp.key] = MapEntry(
206+
data[mapOp.key] = LiveMapEntry(
208207
tombstone = true, // RTLM8b2
209208
tombstonedAt = System.currentTimeMillis(),
210209
timeserial = opSerial
@@ -215,38 +214,29 @@ internal class LiveMap(
215214
}
216215

217216
/**
217+
* For Lww CRDT semantics (the only supported LiveMap semantic) an operation
218+
* Should only be applied if incoming serial is strictly greater than existing entry's serial.
218219
* @spec RTLM9 - Serial comparison logic for map operations
219220
*/
220-
private fun canApplyMapOperation(mapEntrySerial: String?, opSerial: String?): Boolean {
221-
// for Lww CRDT semantics (the only supported LiveMap semantic) an operation
222-
// should only be applied if its serial is strictly greater ("after") than an entry's serial.
223-
224-
if (mapEntrySerial.isNullOrEmpty() && opSerial.isNullOrEmpty()) {
225-
// RTLM9b - if both serials are nullish or empty strings, we treat them as the "earliest possible" serials,
226-
// in which case they are "equal", so the operation should not be applied
221+
private fun canApplyMapOperation(existingMapEntrySerial: String?, opSerial: String?): Boolean {
222+
if (existingMapEntrySerial.isNullOrEmpty() && opSerial.isNullOrEmpty()) { // RTLM9b
227223
return false
228224
}
229-
230-
if (mapEntrySerial.isNullOrEmpty()) {
231-
// RTLM9d - any operation serial is greater than non-existing entry serial
225+
if (existingMapEntrySerial.isNullOrEmpty()) { // RTLM9d - If true, means opSerial is not empty based on previous checks
232226
return true
233227
}
234-
235-
if (opSerial.isNullOrEmpty()) {
236-
// RTLM9c - non-existing operation serial is lower than any entry serial
228+
if (opSerial.isNullOrEmpty()) { // RTLM9c - Check reached here means existingMapEntrySerial is not empty
237229
return false
238230
}
239-
240-
// RTLM9e - if both serials exist, compare them lexicographically
241-
return opSerial > mapEntrySerial
231+
return opSerial > existingMapEntrySerial // RTLM9e - both are not empty
242232
}
243233

244234
/**
245235
* @spec RTLM6d - Merges initial data from create operation
246236
*/
247-
private fun mergeInitialDataFromCreateOperation(operation: ObjectOperation): Any {
237+
private fun mergeInitialDataFromCreateOperation(operation: ObjectOperation): Map<String, String> {
248238
if (operation.map?.entries.isNullOrEmpty()) { // no map entries in MAP_CREATE op
249-
return mapOf<String, String>()
239+
return mapOf()
250240
}
251241

252242
val aggregatedUpdate = mutableMapOf<String, String>()
@@ -275,7 +265,7 @@ internal class LiveMap(
275265
return aggregatedUpdate
276266
}
277267

278-
private fun calculateUpdateFromDataDiff(prevData: Map<String, MapEntry>, newData: Map<String, MapEntry>): Map<String, String> {
268+
private fun calculateUpdateFromDataDiff(prevData: Map<String, LiveMapEntry>, newData: Map<String, LiveMapEntry>): Map<String, String> {
279269
val update = mutableMapOf<String, String>()
280270

281271
// Check for removed entries

live-objects/src/main/kotlin/io/ably/lib/objects/LiveObject.kt

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import io.ably.lib.util.Log
66
* Base implementation of LiveObject interface.
77
* Provides common functionality for all live objects.
88
*
9-
* @spec RTLM1 - Base class for LiveMap objects
10-
* @spec RTLC1 - Base class for LiveCounter objects
9+
* @spec RTLM1/RTLC1 - Base class for LiveMap/LiveCounter objects
1110
*/
1211
internal abstract class BaseLiveObject(
1312
protected val objectId: String,
@@ -17,14 +16,14 @@ internal abstract class BaseLiveObject(
1716
protected open val tag = "BaseLiveObject"
1817
protected var isTombstoned = false
1918
protected var tombstonedAt: Long? = null
19+
2020
/**
21-
* @spec RTLM6 - Map of serials keyed by site code for LiveMap
22-
* @spec RTLC6 - Map of serials keyed by site code for LiveCounter
21+
* @spec RTLM6/RTLC6 - Map of serials keyed by site code for LiveMap/LiveCounter
2322
*/
2423
protected val siteTimeserials = mutableMapOf<String, String>()
24+
2525
/**
26-
* @spec RTLM6 - Flag to track if create operation has been merged for LiveMap
27-
* @spec RTLC6 - Flag to track if create operation has been merged for LiveCounter
26+
* @spec RTLM6/RTLC6 - Flag to track if create operation has been merged for LiveMap/LiveCounter
2827
*/
2928
protected var createOperationIsMerged = false
3029

@@ -37,24 +36,20 @@ internal abstract class BaseLiveObject(
3736
* Checks if an operation can be applied based on serial comparison.
3837
* Similar to JavaScript _canApplyOperation method.
3938
*
40-
* @spec RTLM9 - Serial comparison logic for LiveMap operations
41-
* @spec RTLC9 - Serial comparison logic for LiveCounter operations
39+
* @spec RTLM9/RTLC9 - Serial comparison logic for LiveMap/LiveCounter operations
4240
*/
43-
protected fun canApplyOperation(opSiteCode: String?, opSerial: String?): Boolean {
44-
if (isTombstoned) {
45-
// this object is tombstoned so the operation cannot be applied
41+
protected fun canApplyOperation(siteCode: String?, serial: String?): Boolean {
42+
if (isTombstoned) { // this object is tombstoned so the operation cannot be applied
4643
return false
4744
}
48-
49-
if (opSerial.isNullOrEmpty()) {
50-
throw objectError("Invalid serial: $opSerial")
45+
if (serial.isNullOrEmpty()) {
46+
throw objectError("Invalid serial: $serial")
5147
}
52-
if (opSiteCode.isNullOrEmpty()) {
53-
throw objectError("Invalid site code: $opSiteCode")
48+
if (siteCode.isNullOrEmpty()) {
49+
throw objectError("Invalid site code: $siteCode")
5450
}
55-
56-
val siteSerial = siteTimeserials[opSiteCode]
57-
return siteSerial == null || opSerial > siteSerial
51+
val existingSiteSerial = siteTimeserials[siteCode]
52+
return existingSiteSerial == null || serial > existingSiteSerial
5853
}
5954

6055
/**
@@ -68,8 +63,7 @@ internal abstract class BaseLiveObject(
6863
* Applies object delete operation.
6964
* Similar to JavaScript _applyObjectDelete method.
7065
*
71-
* @spec RTLM10 - Object deletion for LiveMap
72-
* @spec RTLC10 - Object deletion for LiveCounter
66+
* @spec RTLM10/RTLC10 - Object deletion for LiveMap/LiveCounter
7367
*/
7468
protected fun applyObjectDelete(): Any {
7569
return tombstone()
@@ -79,8 +73,7 @@ internal abstract class BaseLiveObject(
7973
* Marks the object as tombstoned.
8074
* Similar to JavaScript tombstone method.
8175
*
82-
* @spec RTLM11 - Tombstone functionality for LiveMap
83-
* @spec RTLC11 - Tombstone functionality for LiveCounter
76+
* @spec RTLM11/RTLC11 - Tombstone functionality for LiveMap/LiveCounter
8477
*/
8578
protected fun tombstone(): Any {
8679
isTombstoned = true
@@ -94,7 +87,7 @@ internal abstract class BaseLiveObject(
9487
* Clears the object's data.
9588
* Similar to JavaScript clearData method.
9689
*/
97-
protected abstract fun clearData(): Any
90+
protected abstract fun clearData(): Map<String, Any>
9891

9992
/**
10093
* Gets the timestamp when the object was tombstoned.
@@ -110,14 +103,12 @@ internal abstract class BaseLiveObject(
110103
*/
111104
internal interface LiveObject {
112105
/**
113-
* @spec RTLM6 - Overrides object data with state from sync
114-
* @spec RTLC6 - Overrides counter data with state from sync
106+
* @spec RTLM6/RTLC6 - Overrides object data with state from sync for LiveMap/LiveCounter
115107
*/
116108
fun overrideWithObjectState(objectState: ObjectState): Any
117109

118110
/**
119-
* @spec RTLM7 - Applies operations to LiveMap
120-
* @spec RTLC7 - Applies operations to LiveCounter
111+
* @spec RTLM7/RTLC7 - Applies operations to LiveMap/LiveCounter
121112
*/
122113
fun applyOperation(operation: ObjectOperation, message: ObjectMessage)
123114

live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ internal data class ObjectMapEntry(
117117
val tombstone: Boolean? = null,
118118

119119
/**
120-
* The serial value of the last operation that was applied to the map entry.
121-
* It is optional in a MAP_CREATE operation and might be missing, in which case the client should use a nullish value for it
120+
* The serial value of the latest operation that was applied to the map entry.
121+
* It is optional in a MAP_CREATE operation and might be missing, in which case the client should use a null value for it
122122
* and treat it as the "earliest possible" serial for comparison purposes.
123123
* Spec: OME2b
124124
*/
@@ -180,12 +180,14 @@ internal data class ObjectOperation(
180180

181181
/**
182182
* The payload for the operation if it is an operation on a Map object type.
183+
* i.e. MAP_SET, MAP_REMOVE.
183184
* Spec: OOP3c
184185
*/
185186
val mapOp: ObjectMapOp? = null,
186187

187188
/**
188189
* The payload for the operation if it is an operation on a Counter object type.
190+
* i.e. COUNTER_INC.
189191
* Spec: OOP3d
190192
*/
191193
val counterOp: ObjectCounterOp? = null,

0 commit comments

Comments
 (0)