From df169ef1bba2e302272fedb4394021d3adf7c07d Mon Sep 17 00:00:00 2001 From: Lawrence Forooghian Date: Mon, 26 Jan 2026 10:29:55 -0300 Subject: [PATCH] Remove the createOperationIsMerged flag This flag served as an idempotency mechanism from the time when we were applying *_CREATE ops on ACK in createMap() and createCounter(). Since the removal of these methods in 0dc0ce6, we no longer perform these ops locally, so this flag isn't needed. Discussion in [1]. Resolves AIT-318. [1] https://ably-real-time.slack.com/archives/C09SY1AQGK0/p1769195388456439 --- src/plugins/liveobjects/livecounter.ts | 15 --------------- src/plugins/liveobjects/livemap.ts | 16 ---------------- src/plugins/liveobjects/liveobject.ts | 2 -- 3 files changed, 33 deletions(-) diff --git a/src/plugins/liveobjects/livecounter.ts b/src/plugins/liveobjects/livecounter.ts index 255ec9215..631d907d2 100644 --- a/src/plugins/liveobjects/livecounter.ts +++ b/src/plugins/liveobjects/livecounter.ts @@ -212,7 +212,6 @@ export class LiveCounter extends LiveObject update = this.tombstone(objectMessage); } else { // otherwise override data for this object with data from the object state - this._createOperationIsMerged = false; // RTLC6b this._dataRef = { data: objectState.counter?.count ?? 0 }; // RTLC6c // RTLC6d if (!this._client.Utils.isNil(objectState.createOp)) { @@ -254,7 +253,6 @@ export class LiveCounter extends LiveObject // if we got here, it means that current counter instance is missing the initial value in its data reference, // which we're going to add now. this._dataRef.data += objectOperation.counter?.count ?? 0; // RTLC6d1 - this._createOperationIsMerged = true; // RTLC6d2 return { update: { amount: objectOperation.counter?.count ?? 0 }, @@ -275,19 +273,6 @@ export class LiveCounter extends LiveObject op: ObjectOperation, msg: ObjectMessage, ): LiveCounterUpdate | LiveObjectUpdateNoop { - if (this._createOperationIsMerged) { - // There can't be two different create operation for the same object id, because the object id - // fully encodes that operation. This means we can safely ignore any new incoming create operations - // if we already merged it once. - this._client.Logger.logAction( - this._client.logger, - this._client.Logger.LOG_MICRO, - 'LiveCounter._applyCounterCreate()', - `skipping applying COUNTER_CREATE op on a counter instance as it was already applied before; objectId=${this.getObjectId()}`, - ); - return { noop: true }; - } - return this._mergeInitialDataFromCreateOperation(op, msg); } diff --git a/src/plugins/liveobjects/livemap.ts b/src/plugins/liveobjects/livemap.ts index d4d502a25..c9670fef0 100644 --- a/src/plugins/liveobjects/livemap.ts +++ b/src/plugins/liveobjects/livemap.ts @@ -435,7 +435,6 @@ export class LiveMap = Record> update = this.tombstone(objectMessage); } else { // otherwise override data for this object with data from the object state - this._createOperationIsMerged = false; // RTLM6b this._dataRef = this._liveMapDataFromMapEntries(objectState.map?.entries ?? {}); // RTLM6c // RTLM6d if (!this._client.Utils.isNil(objectState.createOp)) { @@ -678,8 +677,6 @@ export class LiveMap = Record> Object.assign(aggregatedUpdate.update, update.update); }); - this._createOperationIsMerged = true; // RTLM6d2 - return aggregatedUpdate; } @@ -695,19 +692,6 @@ export class LiveMap = Record> op: ObjectOperation, msg: ObjectMessage, ): LiveMapUpdate | LiveObjectUpdateNoop { - if (this._createOperationIsMerged) { - // There can't be two different create operation for the same object id, because the object id - // fully encodes that operation. This means we can safely ignore any new incoming create operations - // if we already merged it once. - this._client.Logger.logAction( - this._client.logger, - this._client.Logger.LOG_MICRO, - 'LiveMap._applyMapCreate()', - `skipping applying MAP_CREATE op on a map instance as it was already applied before; objectId=${this.getObjectId()}`, - ); - return { noop: true }; - } - if (this._semantics !== op.map?.semantics) { throw new this._client.ErrorInfo( `Cannot apply MAP_CREATE op on LiveMap objectId=${this.getObjectId()}; map's semantics=${this._semantics}, but op expected ${op.map?.semantics}`, diff --git a/src/plugins/liveobjects/liveobject.ts b/src/plugins/liveobjects/liveobject.ts index 55858d973..31df25c71 100644 --- a/src/plugins/liveobjects/liveobject.ts +++ b/src/plugins/liveobjects/liveobject.ts @@ -44,7 +44,6 @@ export abstract class LiveObject< */ protected _dataRef: TData; protected _siteTimeserials: Record; - protected _createOperationIsMerged: boolean; private _tombstone: boolean; private _tombstonedAt: number | undefined; /** @@ -63,7 +62,6 @@ export abstract class LiveObject< this._dataRef = this._getZeroValueData(); // use empty map of serials by default, so any future operation can be applied to this object this._siteTimeserials = {}; - this._createOperationIsMerged = false; this._tombstone = false; this._parentReferences = new Map>(); }