diff --git a/packages/sdk/src/api/converter.ts b/packages/sdk/src/api/converter.ts index 94f487a57..06eeac359 100644 --- a/packages/sdk/src/api/converter.ts +++ b/packages/sdk/src/api/converter.ts @@ -396,10 +396,6 @@ function toOperation(operation: Operation): PbOperation { ); pbEditOperation.from = toTextNodePos(editOperation.getFromPos()); pbEditOperation.to = toTextNodePos(editOperation.getToPos()); - const pbCreatedAtMapByActor = pbEditOperation.createdAtMapByActor; - for (const [key, value] of editOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor[key] = toTimeTicket(value)!; - } pbEditOperation.content = editOperation.getContent(); const pbAttributes = pbEditOperation.attributes; for (const [key, value] of editOperation.getAttributes()) { @@ -416,10 +412,6 @@ function toOperation(operation: Operation): PbOperation { ); pbStyleOperation.from = toTextNodePos(styleOperation.getFromPos()); pbStyleOperation.to = toTextNodePos(styleOperation.getToPos()); - const pbCreatedAtMapByActor = pbStyleOperation.createdAtMapByActor; - for (const [key, value] of styleOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor[key] = toTimeTicket(value)!; - } const pbAttributes = pbStyleOperation.attributes; for (const [key, value] of styleOperation.getAttributes()) { pbAttributes[key] = value; @@ -442,10 +434,6 @@ function toOperation(operation: Operation): PbOperation { } else if (operation instanceof TreeEditOperation) { const treeEditOperation = operation as TreeEditOperation; const pbTreeEditOperation = new PbOperation_TreeEdit(); - const pbCreatedAtMapByActor = pbTreeEditOperation.createdAtMapByActor; - for (const [key, value] of treeEditOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor[key] = toTimeTicket(value)!; - } pbTreeEditOperation.parentCreatedAt = toTimeTicket( treeEditOperation.getParentCreatedAt(), ); @@ -469,10 +457,6 @@ function toOperation(operation: Operation): PbOperation { ); pbTreeStyleOperation.from = toTreePos(treeStyleOperation.getFromPos()); pbTreeStyleOperation.to = toTreePos(treeStyleOperation.getToPos()); - const pbCreatedAtMapByActor = pbTreeStyleOperation.createdAtMapByActor; - for (const [key, value] of treeStyleOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor[key] = toTimeTicket(value)!; - } const attributesToRemove = treeStyleOperation.getAttributesToRemove(); if (attributesToRemove.length > 0) { @@ -799,7 +783,6 @@ function toChangePack(pack: ChangePack): PbChangePack { changes: toChanges(pack.getChanges()), snapshot: pack.getSnapshot(), versionVector: toVersionVector(pack.getVersionVector()), - minSyncedTicket: toTimeTicket(pack.getMinSyncedTicket()), }); } @@ -1206,12 +1189,6 @@ function fromOperation(pbOperation: PbOperation): Operation | undefined { ); } else if (pbOperation.body.case === 'edit') { const pbEditOperation = pbOperation.body.value; - const createdAtMapByActor = new Map(); - Object.entries(pbEditOperation!.createdAtMapByActor).forEach( - ([key, value]) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }, - ); const attributes = new Map(); Object.entries(pbEditOperation!.attributes).forEach(([key, value]) => { attributes.set(key, value); @@ -1220,19 +1197,12 @@ function fromOperation(pbOperation: PbOperation): Operation | undefined { fromTimeTicket(pbEditOperation!.parentCreatedAt)!, fromTextNodePos(pbEditOperation!.from!), fromTextNodePos(pbEditOperation!.to!), - createdAtMapByActor, pbEditOperation!.content, attributes, fromTimeTicket(pbEditOperation!.executedAt)!, ); } else if (pbOperation.body.case === 'style') { const pbStyleOperation = pbOperation.body.value; - const createdAtMapByActor = new Map(); - Object.entries(pbStyleOperation!.createdAtMapByActor).forEach( - ([key, value]) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }, - ); const attributes = new Map(); Object.entries(pbStyleOperation!.attributes).forEach(([key, value]) => { attributes.set(key, value); @@ -1241,7 +1211,6 @@ function fromOperation(pbOperation: PbOperation): Operation | undefined { fromTimeTicket(pbStyleOperation!.parentCreatedAt)!, fromTextNodePos(pbStyleOperation!.from!), fromTextNodePos(pbStyleOperation!.to!), - createdAtMapByActor, attributes, fromTimeTicket(pbStyleOperation!.executedAt)!, ); @@ -1257,40 +1226,24 @@ function fromOperation(pbOperation: PbOperation): Operation | undefined { ); } else if (pbOperation.body.case === 'treeEdit') { const pbTreeEditOperation = pbOperation.body.value; - const createdAtMapByActor = new Map(); - Object.entries(pbTreeEditOperation!.createdAtMapByActor).forEach( - ([key, value]) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }, - ); return TreeEditOperation.create( fromTimeTicket(pbTreeEditOperation!.parentCreatedAt)!, fromTreePos(pbTreeEditOperation!.from!), fromTreePos(pbTreeEditOperation!.to!), fromTreeNodesWhenEdit(pbTreeEditOperation!.contents), pbTreeEditOperation!.splitLevel, - createdAtMapByActor, fromTimeTicket(pbTreeEditOperation!.executedAt)!, ); } else if (pbOperation.body.case === 'treeStyle') { const pbTreeStyleOperation = pbOperation.body.value; const attributes = new Map(); const attributesToRemove = pbTreeStyleOperation.attributesToRemove; - const createdAtMapByActor = new Map(); - if (pbTreeStyleOperation?.createdAtMapByActor) { - Object.entries(pbTreeStyleOperation!.createdAtMapByActor).forEach( - ([key, value]) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }, - ); - } if (attributesToRemove?.length > 0) { return TreeStyleOperation.createTreeRemoveStyleOperation( fromTimeTicket(pbTreeStyleOperation!.parentCreatedAt)!, fromTreePos(pbTreeStyleOperation!.from!), fromTreePos(pbTreeStyleOperation!.to!), - createdAtMapByActor, attributesToRemove, fromTimeTicket(pbTreeStyleOperation!.executedAt)!, ); @@ -1304,7 +1257,6 @@ function fromOperation(pbOperation: PbOperation): Operation | undefined { fromTimeTicket(pbTreeStyleOperation!.parentCreatedAt)!, fromTreePos(pbTreeStyleOperation!.from!), fromTreePos(pbTreeStyleOperation!.to!), - createdAtMapByActor, attributes, fromTimeTicket(pbTreeStyleOperation!.executedAt)!, ); @@ -1372,7 +1324,6 @@ function fromChangePack

( fromChanges(pbPack.changes), fromVersionVector(pbPack.versionVector), pbPack.snapshot, - fromTimeTicket(pbPack.minSyncedTicket), ); } diff --git a/packages/sdk/src/api/yorkie/v1/resources.proto b/packages/sdk/src/api/yorkie/v1/resources.proto index 547ec6c55..7ed5058fc 100644 --- a/packages/sdk/src/api/yorkie/v1/resources.proto +++ b/packages/sdk/src/api/yorkie/v1/resources.proto @@ -44,7 +44,7 @@ message ChangePack { Checkpoint checkpoint = 2; bytes snapshot = 3; repeated Change changes = 4; - TimeTicket min_synced_ticket = 5; + TimeTicket min_synced_ticket = 5; // deprecated bool is_removed = 6; VersionVector version_vector = 7; } @@ -96,7 +96,7 @@ message Operation { TimeTicket parent_created_at = 1; TextNodePos from = 2; TextNodePos to = 3; - map created_at_map_by_actor = 4; + map created_at_map_by_actor = 4; // deprecated string content = 5; TimeTicket executed_at = 6; map attributes = 7; @@ -117,7 +117,7 @@ message Operation { TextNodePos to = 3; map attributes = 4; TimeTicket executed_at = 5; - map created_at_map_by_actor = 6; + map created_at_map_by_actor = 6; // deprecated } message Increase { TimeTicket parent_created_at = 1; @@ -128,7 +128,7 @@ message Operation { TimeTicket parent_created_at = 1; TreePos from = 2; TreePos to = 3; - map created_at_map_by_actor = 4; + map created_at_map_by_actor = 4; // deprecated repeated TreeNodes contents = 5; int32 split_level = 7; TimeTicket executed_at = 6; @@ -140,7 +140,7 @@ message Operation { map attributes = 4; TimeTicket executed_at = 5; repeated string attributes_to_remove = 6; - map created_at_map_by_actor = 7; + map created_at_map_by_actor = 7; // deprecated } message ArraySet { TimeTicket parent_created_at = 1; diff --git a/packages/sdk/src/api/yorkie/v1/resources_pb.ts b/packages/sdk/src/api/yorkie/v1/resources_pb.ts index 9297e1fb0..51ea68259 100644 --- a/packages/sdk/src/api/yorkie/v1/resources_pb.ts +++ b/packages/sdk/src/api/yorkie/v1/resources_pb.ts @@ -220,6 +220,8 @@ export class ChangePack extends Message { changes: Change[] = []; /** + * deprecated + * * @generated from field: yorkie.v1.TimeTicket min_synced_ticket = 5; */ minSyncedTicket?: TimeTicket; @@ -768,6 +770,8 @@ export class Operation_Edit extends Message { to?: TextNodePos; /** + * deprecated + * * @generated from field: map created_at_map_by_actor = 4; */ createdAtMapByActor: { [key: string]: TimeTicket } = {}; @@ -911,6 +915,8 @@ export class Operation_Style extends Message { executedAt?: TimeTicket; /** + * deprecated + * * @generated from field: map created_at_map_by_actor = 6; */ createdAtMapByActor: { [key: string]: TimeTicket } = {}; @@ -1017,6 +1023,8 @@ export class Operation_TreeEdit extends Message { to?: TreePos; /** + * deprecated + * * @generated from field: map created_at_map_by_actor = 4; */ createdAtMapByActor: { [key: string]: TimeTicket } = {}; @@ -1105,6 +1113,8 @@ export class Operation_TreeStyle extends Message { attributesToRemove: string[] = []; /** + * deprecated + * * @generated from field: map created_at_map_by_actor = 7; */ createdAtMapByActor: { [key: string]: TimeTicket } = {}; diff --git a/packages/sdk/src/document/change/change_id.ts b/packages/sdk/src/document/change/change_id.ts index f30c29aeb..c6660f6e3 100644 --- a/packages/sdk/src/document/change/change_id.ts +++ b/packages/sdk/src/document/change/change_id.ts @@ -86,16 +86,7 @@ export class ChangeID { const lamport = other.lamport > this.lamport ? other.lamport + 1n : this.lamport + 1n; - // NOTE(chacha912): For changes created by legacy SDK prior to v0.5.2 that lack version - // vectors, document's version vector was not being properly accumlated. To address this, - // we generate a version vector using the lamport timestamp when no version vector exists. - let otherVV = other.versionVector; - if (otherVV.size() === 0) { - otherVV = otherVV.deepcopy(); - otherVV.set(other.actor, other.lamport); - } - - const maxVersionVector = this.versionVector.max(otherVV); + const maxVersionVector = this.versionVector.max(other.versionVector); const newID = new ChangeID( this.clientSeq, lamport, diff --git a/packages/sdk/src/document/change/change_pack.ts b/packages/sdk/src/document/change/change_pack.ts index e0cbbba7f..b382703de 100644 --- a/packages/sdk/src/document/change/change_pack.ts +++ b/packages/sdk/src/document/change/change_pack.ts @@ -17,7 +17,6 @@ import { Indexable } from '@yorkie-js/sdk/src/document/document'; import { Checkpoint } from '@yorkie-js/sdk/src/document/change/checkpoint'; import { Change } from '@yorkie-js/sdk/src/document/change/change'; -import { TimeTicket } from '@yorkie-js/sdk/src/document/time/ticket'; import { VersionVector } from '../time/version_vector'; /** @@ -46,13 +45,6 @@ export class ChangePack

{ */ private snapshot?: Uint8Array; - /** - * `minSyncedTicket` is the minimum logical time taken by clients who attach - * to the document. It is used to collect garbage on the replica on the - * client. - */ - private minSyncedTicket?: TimeTicket; - /** * `versionVector` is the version vector current document */ @@ -65,14 +57,12 @@ export class ChangePack

{ changes: Array>, versionVector?: VersionVector, snapshot?: Uint8Array, - minSyncedTicket?: TimeTicket, ) { this.documentKey = key; this.checkpoint = checkpoint; this.isRemoved = isRemoved; this.changes = changes; this.snapshot = snapshot; - this.minSyncedTicket = minSyncedTicket; this.versionVector = versionVector; } /** @@ -85,7 +75,6 @@ export class ChangePack

{ changes: Array>, versionVector?: VersionVector, snapshot?: Uint8Array, - minSyncedTicket?: TimeTicket, ): ChangePack

{ return new ChangePack

( key, @@ -94,7 +83,6 @@ export class ChangePack

{ changes, versionVector, snapshot, - minSyncedTicket, ); } @@ -154,13 +142,6 @@ export class ChangePack

{ return this.snapshot; } - /** - * `getMinSyncedTicket` returns the minimum synced ticket of this pack. - */ - public getMinSyncedTicket(): TimeTicket | undefined { - return this.minSyncedTicket; - } - /** * `getVersionVector` returns the document's version vector of this pack */ diff --git a/packages/sdk/src/document/crdt/rga_tree_split.ts b/packages/sdk/src/document/crdt/rga_tree_split.ts index 6eea6b8c3..0a17e73ab 100644 --- a/packages/sdk/src/document/crdt/rga_tree_split.ts +++ b/packages/sdk/src/document/crdt/rga_tree_split.ts @@ -444,13 +444,11 @@ export class RGATreeSplitNode */ public canDelete( editedAt: TimeTicket, - maxCreatedAt: TimeTicket | undefined, clientLamportAtChange: bigint, ): boolean { const justRemoved = !this.removedAt; - const nodeExisted = maxCreatedAt - ? !this.getCreatedAt().after(maxCreatedAt) - : this.getCreatedAt().getLamport() <= clientLamportAtChange; + const nodeExisted = + this.getCreatedAt().getLamport() <= clientLamportAtChange; if (nodeExisted && (!this.removedAt || editedAt.after(this.removedAt))) { return justRemoved; @@ -464,12 +462,10 @@ export class RGATreeSplitNode */ public canStyle( editedAt: TimeTicket, - maxCreatedAt: TimeTicket | undefined, clientLamportAtChange: bigint, ): boolean { - const nodeExisted = maxCreatedAt - ? !this.getCreatedAt().after(maxCreatedAt) - : this.getCreatedAt().getLamport() <= clientLamportAtChange; + const nodeExisted = + this.getCreatedAt().getLamport() <= clientLamportAtChange; return nodeExisted && (!this.removedAt || editedAt.after(this.removedAt)); } @@ -574,31 +570,23 @@ export class RGATreeSplit implements GCParent { * @param range - range of RGATreeSplitNode * @param editedAt - edited time * @param value - value - * @param maxCreatedAtMapByActor - maxCreatedAtMapByActor - * @returns `[RGATreeSplitPos, Map, Array, Array]` + * @returns `[RGATreeSplitPos, Array, Array]` */ public edit( range: RGATreeSplitPosRange, editedAt: TimeTicket, value?: T, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [ - RGATreeSplitPos, - Map, - Array, - Array>, - ] { + ): [RGATreeSplitPos, Array, Array>] { // 01. split nodes with from and to const [toLeft, toRight] = this.findNodeWithSplit(range[1], editedAt); const [fromLeft, fromRight] = this.findNodeWithSplit(range[0], editedAt); // 02. delete between from and to const nodesToDelete = this.findBetween(fromRight, toRight); - const [changes, maxCreatedAtMap, removedNodes] = this.deleteNodes( + const [changes, removedNodes] = this.deleteNodes( nodesToDelete, editedAt, - maxCreatedAtMapByActor, versionVector, ); @@ -637,7 +625,7 @@ export class RGATreeSplit implements GCParent { pairs.push({ parent: this, child: removedNode }); } - return [caretPos, maxCreatedAtMap, pairs, changes]; + return [caretPos, pairs, changes]; } /** @@ -909,15 +897,10 @@ export class RGATreeSplit implements GCParent { private deleteNodes( candidates: Array>, editedAt: TimeTicket, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [ - Array>, - Map, - Map>, - ] { + ): [Array>, Map>] { if (!candidates.length) { - return [[], new Map(), new Map()]; + return [[], new Map()]; } // There are 2 types of nodes in `candidates`: should delete, should not delete. @@ -926,36 +909,26 @@ export class RGATreeSplit implements GCParent { const [nodesToDelete, nodesToKeep] = this.filterNodes( candidates, editedAt, - maxCreatedAtMapByActor, versionVector, ); - const createdAtMapByActor = new Map(); const removedNodes = new Map(); // First we need to collect indexes for change. const changes = this.makeChanges(nodesToKeep, editedAt); for (const node of nodesToDelete) { // Then make nodes be tombstones and map that. - const actorID = node.getCreatedAt().getActorID(); - if ( - !createdAtMapByActor.has(actorID) || - node.getID().getCreatedAt().after(createdAtMapByActor.get(actorID)) - ) { - createdAtMapByActor.set(actorID, node.getID().getCreatedAt()); - } removedNodes.set(node.getID().toIDString(), node); node.remove(editedAt); } // Finally remove index nodes of tombstones. this.deleteIndexNodes(nodesToKeep); - return [changes, createdAtMapByActor, removedNodes]; + return [changes, removedNodes]; } private filterNodes( candidates: Array>, editedAt: TimeTicket, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, ): [Array>, Array | undefined>] { const nodesToDelete: Array> = []; @@ -966,22 +939,14 @@ export class RGATreeSplit implements GCParent { for (const node of candidates) { const actorID = node.getCreatedAt().getActorID(); - let maxCreatedAt: TimeTicket | undefined; - let clientLamportAtChange = 0n; - if (versionVector === undefined && maxCreatedAtMapByActor === undefined) { - // Local edit - use version vector comparison - clientLamportAtChange = MaxLamport; - } else if (versionVector!.size() > 0) { + let clientLamportAtChange = MaxLamport; // Local edit + if (versionVector != undefined) { clientLamportAtChange = versionVector!.get(actorID) ? versionVector!.get(actorID)! : 0n; - } else { - maxCreatedAt = maxCreatedAtMapByActor!.has(actorID) - ? maxCreatedAtMapByActor!.get(actorID) - : InitialTimeTicket; } - if (node.canDelete(editedAt, maxCreatedAt, clientLamportAtChange)) { + if (node.canDelete(editedAt, clientLamportAtChange)) { nodesToDelete.push(node); } else { nodesToKeep.push(node); diff --git a/packages/sdk/src/document/crdt/text.ts b/packages/sdk/src/document/crdt/text.ts index 9958e21fd..3c8915f4c 100644 --- a/packages/sdk/src/document/crdt/text.ts +++ b/packages/sdk/src/document/crdt/text.ts @@ -16,7 +16,6 @@ import { MaxLamport, - InitialTimeTicket, TimeTicket, } from '@yorkie-js/sdk/src/document/time/ticket'; import { VersionVector } from '@yorkie-js/sdk/src/document/time/version_vector'; @@ -241,14 +240,8 @@ export class CRDTText extends CRDTElement { content: string, editedAt: TimeTicket, attributes?: Record, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [ - Map, - Array>, - Array, - RGATreeSplitPosRange, - ] { + ): [Array>, Array, RGATreeSplitPosRange] { const crdtTextValue = content ? CRDTTextValue.create(content) : undefined; if (crdtTextValue && attributes) { for (const [k, v] of Object.entries(attributes)) { @@ -256,14 +249,12 @@ export class CRDTText extends CRDTElement { } } - const [caretPos, maxCreatedAtMap, pairs, valueChanges] = - this.rgaTreeSplit.edit( - range, - editedAt, - crdtTextValue, - maxCreatedAtMapByActor, - versionVector, - ); + const [caretPos, pairs, valueChanges] = this.rgaTreeSplit.edit( + range, + editedAt, + crdtTextValue, + versionVector, + ); const changes: Array> = valueChanges.map((change) => ({ ...change, @@ -279,7 +270,7 @@ export class CRDTText extends CRDTElement { type: TextChangeType.Content, })); - return [maxCreatedAtMap, changes, pairs, [caretPos, caretPos]]; + return [changes, pairs, [caretPos, caretPos]]; } /** @@ -290,16 +281,14 @@ export class CRDTText extends CRDTElement { * @param range - range of RGATreeSplitNode * @param attributes - style attributes * @param editedAt - edited time - * @param maxCreatedAtMapByActor - maxCreatedAtMapByActor * @internal */ public setStyle( range: RGATreeSplitPosRange, attributes: Record, editedAt: TimeTicket, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [Map, Array, Array>] { + ): [Array, Array>] { // 01. split nodes with from and to const [, toRight] = this.rgaTreeSplit.findNodeWithSplit(range[1], editedAt); const [, fromRight] = this.rgaTreeSplit.findNodeWithSplit( @@ -310,32 +299,18 @@ export class CRDTText extends CRDTElement { // 02. style nodes between from and to const changes: Array> = []; const nodes = this.rgaTreeSplit.findBetween(fromRight, toRight); - const createdAtMapByActor = new Map(); const toBeStyleds: Array> = []; for (const node of nodes) { const actorID = node.getCreatedAt().getActorID(); - let maxCreatedAt: TimeTicket | undefined; - let clientLamportAtChange = 0n; - if (versionVector === undefined && maxCreatedAtMapByActor === undefined) { - // Local edit - use version vector comparison - clientLamportAtChange = MaxLamport; - } else if (versionVector!.size() > 0) { + let clientLamportAtChange = MaxLamport; // Local edit + if (versionVector != undefined) { clientLamportAtChange = versionVector!.get(actorID) ? versionVector!.get(actorID)! : 0n; - } else { - maxCreatedAt = maxCreatedAtMapByActor!.has(actorID) - ? maxCreatedAtMapByActor!.get(actorID) - : InitialTimeTicket; } - if (node.canStyle(editedAt, maxCreatedAt, clientLamportAtChange)) { - const maxCreatedAt = createdAtMapByActor.get(actorID); - const createdAt = node.getCreatedAt(); - if (!maxCreatedAt || createdAt.after(maxCreatedAt)) { - createdAtMapByActor.set(actorID, createdAt); - } + if (node.canStyle(editedAt, clientLamportAtChange)) { toBeStyleds.push(node); } } @@ -367,7 +342,7 @@ export class CRDTText extends CRDTElement { } } - return [createdAtMapByActor, pairs, changes]; + return [pairs, changes]; } /** diff --git a/packages/sdk/src/document/crdt/tree.ts b/packages/sdk/src/document/crdt/tree.ts index a7e097a58..579c60dd7 100644 --- a/packages/sdk/src/document/crdt/tree.ts +++ b/packages/sdk/src/document/crdt/tree.ts @@ -16,7 +16,6 @@ import { TimeTicket, - InitialTimeTicket, TimeTicketStruct, MaxLamport, TimeTicketSize, @@ -635,12 +634,10 @@ export class CRDTTreeNode */ public canDelete( editedAt: TimeTicket, - maxCreatedAt: TimeTicket | undefined, clientLamportAtChange: bigint, ): boolean { - const nodeExisted = maxCreatedAt - ? !this.getCreatedAt().after(maxCreatedAt) - : this.getCreatedAt().getLamport() <= clientLamportAtChange; + const nodeExisted = + this.getCreatedAt().getLamport() <= clientLamportAtChange; return nodeExisted && (!this.removedAt || editedAt.after(this.removedAt)); } @@ -650,15 +647,13 @@ export class CRDTTreeNode */ public canStyle( editedAt: TimeTicket, - maxCreatedAt: TimeTicket | undefined, clientLamportAtChange: bigint, ): boolean { if (this.isText) { return false; } - const nodeExisted = maxCreatedAt - ? !this.getCreatedAt().after(maxCreatedAt) - : this.getCreatedAt().getLamport() <= clientLamportAtChange; + const nodeExisted = + this.getCreatedAt().getLamport() <= clientLamportAtChange; return nodeExisted && (!this.removedAt || editedAt.after(this.removedAt)); } @@ -923,9 +918,8 @@ export class CRDTTree extends CRDTElement implements GCParent { range: [CRDTTreePos, CRDTTreePos], attributes: { [key: string]: string } | undefined, editedAt: TimeTicket, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [Map, Array, Array] { + ): [Array, Array] { const [fromParent, fromLeft] = this.findNodesAndSplitText( range[0], editedAt, @@ -936,7 +930,6 @@ export class CRDTTree extends CRDTElement implements GCParent { const attrs: { [key: string]: any } = attributes ? parseObjectValues(attributes) : {}; - const createdAtMapByActor = new Map(); const pairs: Array = []; this.traverseInPosRange( fromParent, @@ -945,34 +938,14 @@ export class CRDTTree extends CRDTElement implements GCParent { toLeft, ([node]) => { const actorID = node.getCreatedAt().getActorID(); - let maxCreatedAt: TimeTicket | undefined; - let clientLamportAtChange = 0n; - if ( - versionVector === undefined && - maxCreatedAtMapByActor === undefined - ) { - // Local edit - use version vector comparison - clientLamportAtChange = MaxLamport; - } else if (versionVector!.size() > 0) { + let clientLamportAtChange = MaxLamport; // Local edit + if (versionVector != undefined) { clientLamportAtChange = versionVector!.get(actorID) ? versionVector!.get(actorID)! : 0n; - } else { - maxCreatedAt = maxCreatedAtMapByActor!.has(actorID) - ? maxCreatedAtMapByActor!.get(actorID) - : InitialTimeTicket; } - if ( - node.canStyle(editedAt, maxCreatedAt, clientLamportAtChange) && - attributes - ) { - const maxCreatedAt = createdAtMapByActor!.get(actorID); - const createdAt = node.getCreatedAt(); - if (!maxCreatedAt || createdAt.after(maxCreatedAt)) { - createdAtMapByActor.set(actorID, createdAt); - } - + if (node.canStyle(editedAt, clientLamportAtChange) && attributes) { const updatedAttrPairs = node.setAttrs(attributes, editedAt); const affectedAttrs = updatedAttrPairs.reduce( (acc: { [key: string]: string }, [, curr]) => { @@ -1010,7 +983,7 @@ export class CRDTTree extends CRDTElement implements GCParent { }, ); - return [createdAtMapByActor, pairs, changes]; + return [pairs, changes]; } /** @@ -1020,9 +993,8 @@ export class CRDTTree extends CRDTElement implements GCParent { range: [CRDTTreePos, CRDTTreePos], attributesToRemove: Array, editedAt: TimeTicket, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [Map, Array, Array] { + ): [Array, Array] { const [fromParent, fromLeft] = this.findNodesAndSplitText( range[0], editedAt, @@ -1030,7 +1002,6 @@ export class CRDTTree extends CRDTElement implements GCParent { const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); const changes: Array = []; - const createdAtMapByActor = new Map(); const pairs: Array = []; this.traverseInPosRange( fromParent, @@ -1039,34 +1010,17 @@ export class CRDTTree extends CRDTElement implements GCParent { toLeft, ([node]) => { const actorID = node.getCreatedAt().getActorID(); - let maxCreatedAt: TimeTicket | undefined; - let clientLamportAtChange = 0n; - if ( - versionVector === undefined && - maxCreatedAtMapByActor === undefined - ) { - // Local edit - use version vector comparison - clientLamportAtChange = MaxLamport; - } else if (versionVector!.size() > 0) { + let clientLamportAtChange = MaxLamport; // Local edit + if (versionVector != undefined) { clientLamportAtChange = versionVector!.get(actorID) ? versionVector!.get(actorID)! : 0n; - } else { - maxCreatedAt = maxCreatedAtMapByActor!.has(actorID) - ? maxCreatedAtMapByActor!.get(actorID) - : InitialTimeTicket; } if ( - node.canStyle(editedAt, maxCreatedAt, clientLamportAtChange) && + node.canStyle(editedAt, clientLamportAtChange) && attributesToRemove ) { - const maxCreatedAt = createdAtMapByActor!.get(actorID); - const createdAt = node.getCreatedAt(); - if (!maxCreatedAt || createdAt.after(maxCreatedAt)) { - createdAtMapByActor.set(actorID, createdAt); - } - if (!node.attrs) { node.attrs = new RHT(); } @@ -1094,7 +1048,7 @@ export class CRDTTree extends CRDTElement implements GCParent { }, ); - return [createdAtMapByActor, pairs, changes]; + return [pairs, changes]; } /** @@ -1107,9 +1061,8 @@ export class CRDTTree extends CRDTElement implements GCParent { splitLevel: number, editedAt: TimeTicket, issueTimeTicket: (() => TimeTicket) | undefined, - maxCreatedAtMapByActor?: Map, versionVector?: VersionVector, - ): [Array, Array, Map] { + ): [Array, Array] { // 01. find nodes from the given range and split nodes. const [fromParent, fromLeft] = this.findNodesAndSplitText( range[0], @@ -1123,7 +1076,6 @@ export class CRDTTree extends CRDTElement implements GCParent { const nodesToBeRemoved: Array = []; const tokensToBeRemoved: Array> = []; const toBeMovedToFromParents: Array = []; - const maxCreatedAtMap = new Map(); this.traverseInPosRange( fromParent, fromLeft, @@ -1147,37 +1099,19 @@ export class CRDTTree extends CRDTElement implements GCParent { } const actorID = node.getCreatedAt().getActorID(); - let maxCreatedAt: TimeTicket | undefined; - let clientLamportAtChange = 0n; - if ( - versionVector === undefined && - maxCreatedAtMapByActor === undefined - ) { - // Local edit - use version vector comparison - clientLamportAtChange = MaxLamport; - } else if (versionVector!.size() > 0) { + let clientLamportAtChange = MaxLamport; // Local edit + if (versionVector != undefined) { clientLamportAtChange = versionVector!.get(actorID) ? versionVector!.get(actorID)! : 0n; - } else { - maxCreatedAt = maxCreatedAtMapByActor!.has(actorID) - ? maxCreatedAtMapByActor!.get(actorID) - : InitialTimeTicket; } // NOTE(sejongk): If the node is removable or its parent is going to // be removed, then this node should be removed. if ( - node.canDelete(editedAt, maxCreatedAt, clientLamportAtChange) || + node.canDelete(editedAt, clientLamportAtChange) || nodesToBeRemoved.includes(node.parent!) ) { - const maxCreatedAt = maxCreatedAtMap.get(actorID); - const createdAt = node.getCreatedAt(); - - if (!maxCreatedAt || createdAt.after(maxCreatedAt)) { - maxCreatedAtMap.set(actorID, createdAt); - } - // NOTE(hackerwins): If the node overlaps as an end token with the // range then we need to keep the node. if (tokenType === TokenType.Text || tokenType === TokenType.Start) { @@ -1281,7 +1215,7 @@ export class CRDTTree extends CRDTElement implements GCParent { } } - return [changes, pairs, maxCreatedAtMap]; + return [changes, pairs]; } /** diff --git a/packages/sdk/src/document/json/text.ts b/packages/sdk/src/document/json/text.ts index 73d257eb5..384e10250 100644 --- a/packages/sdk/src/document/json/text.ts +++ b/packages/sdk/src/document/json/text.ts @@ -114,7 +114,7 @@ export class Text { } const attrs = attributes ? stringifyObjectValues(attributes) : undefined; const ticket = this.context.issueTimeTicket(); - const [maxCreatedAtMapByActor, , pairs, rangeAfterEdit] = this.text.edit( + const [, pairs, rangeAfterEdit] = this.text.edit( range, content, ticket, @@ -130,7 +130,6 @@ export class Text { this.text.getCreatedAt(), range[0], range[1], - maxCreatedAtMapByActor, content, attrs ? new Map(Object.entries(attrs)) : new Map(), ticket, @@ -183,11 +182,7 @@ export class Text { const attrs = stringifyObjectValues(attributes); const ticket = this.context.issueTimeTicket(); - const [maxCreatedAtMapByActor, pairs] = this.text.setStyle( - range, - attrs, - ticket, - ); + const [pairs] = this.text.setStyle(range, attrs, ticket); for (const pair of pairs) { this.context!.registerGCPair(pair); @@ -198,7 +193,6 @@ export class Text { this.text.getCreatedAt(), range[0], range[1], - maxCreatedAtMapByActor, new Map(Object.entries(attrs)), ticket, ), diff --git a/packages/sdk/src/document/json/tree.ts b/packages/sdk/src/document/json/tree.ts index 418d566b2..2a9f06a7a 100644 --- a/packages/sdk/src/document/json/tree.ts +++ b/packages/sdk/src/document/json/tree.ts @@ -516,18 +516,16 @@ export class Tree { const ticket = this.context.issueTimeTicket(); const attrs = attributes ? stringifyObjectValues(attributes) : undefined; - const [maxCreationMapByActor] = this.tree!.style( - [fromPos, toPos], - attrs, - ticket, - ); + const [pairs] = this.tree!.style([fromPos, toPos], attrs, ticket); + for (const pair of pairs) { + this.context!.registerGCPair(pair); + } this.context.push( TreeStyleOperation.create( this.tree.getCreatedAt(), fromPos, toPos, - maxCreationMapByActor, attrs ? new Map(Object.entries(attrs)) : new Map(), ticket, ), @@ -561,12 +559,7 @@ export class Tree { const ticket = this.context.issueTimeTicket(); const attrs = attributes ? stringifyObjectValues(attributes) : undefined; - const [maxCreationMapByActor, pairs] = this.tree!.style( - [fromPos, toPos], - attrs, - ticket, - ); - + const [pairs] = this.tree!.style([fromPos, toPos], attrs, ticket); for (const pair of pairs) { this.context!.registerGCPair(pair); } @@ -576,7 +569,6 @@ export class Tree { this.tree.getCreatedAt(), fromPos, toPos, - maxCreationMapByActor, attrs ? new Map(Object.entries(attrs)) : new Map(), ticket, ), @@ -609,7 +601,7 @@ export class Tree { const toPos = this.tree.findPos(toIdx); const ticket = this.context.issueTimeTicket(); - const [maxCreationMapByActor, pairs] = this.tree!.removeStyle( + const [pairs] = this.tree!.removeStyle( [fromPos, toPos], attributesToRemove, ticket, @@ -624,7 +616,6 @@ export class Tree { this.tree.getCreatedAt(), fromPos, toPos, - maxCreationMapByActor, attributesToRemove, ticket, ), @@ -669,7 +660,7 @@ export class Tree { .filter((a) => a) as Array; } - const [, pairs, maxCreatedAtMapByActor] = this.tree!.edit( + const [, pairs] = this.tree!.edit( [fromPos, toPos], crdtNodes.length ? crdtNodes.map((crdtNode) => crdtNode?.deepcopy()) @@ -690,7 +681,6 @@ export class Tree { toPos, crdtNodes.length ? crdtNodes : undefined, splitLevel, - maxCreatedAtMapByActor, ticket, ), ); diff --git a/packages/sdk/src/document/operation/edit_operation.ts b/packages/sdk/src/document/operation/edit_operation.ts index a0f769ca8..7cc43b648 100644 --- a/packages/sdk/src/document/operation/edit_operation.ts +++ b/packages/sdk/src/document/operation/edit_operation.ts @@ -35,7 +35,6 @@ import { Code, YorkieError } from '@yorkie-js/sdk/src/util/error'; export class EditOperation extends Operation { private fromPos: RGATreeSplitPos; private toPos: RGATreeSplitPos; - private maxCreatedAtMapByActor: Map; private content: string; private attributes: Map; @@ -43,7 +42,6 @@ export class EditOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: RGATreeSplitPos, toPos: RGATreeSplitPos, - maxCreatedAtMapByActor: Map, content: string, attributes: Map, executedAt: TimeTicket, @@ -51,7 +49,6 @@ export class EditOperation extends Operation { super(parentCreatedAt, executedAt); this.fromPos = fromPos; this.toPos = toPos; - this.maxCreatedAtMapByActor = maxCreatedAtMapByActor; this.content = content; this.attributes = attributes; } @@ -63,7 +60,6 @@ export class EditOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: RGATreeSplitPos, toPos: RGATreeSplitPos, - maxCreatedAtMapByActor: Map, content: string, attributes: Map, executedAt: TimeTicket, @@ -72,7 +68,6 @@ export class EditOperation extends Operation { parentCreatedAt, fromPos, toPos, - maxCreatedAtMapByActor, content, attributes, executedAt, @@ -102,12 +97,11 @@ export class EditOperation extends Operation { } const text = parentObject as CRDTText; - const [, changes, pairs] = text.edit( + const [changes, pairs] = text.edit( [this.fromPos, this.toPos], this.content, this.getExecutedAt(), Object.fromEntries(this.attributes), - this.maxCreatedAtMapByActor, versionVector, ); @@ -173,12 +167,4 @@ export class EditOperation extends Operation { public getAttributes(): Map { return this.attributes || new Map(); } - - /** - * `getMaxCreatedAtMapByActor` returns the map that stores the latest creation time - * by actor for the nodes included in the editing range. - */ - public getMaxCreatedAtMapByActor(): Map { - return this.maxCreatedAtMapByActor; - } } diff --git a/packages/sdk/src/document/operation/style_operation.ts b/packages/sdk/src/document/operation/style_operation.ts index 58ea493a2..6d764a909 100644 --- a/packages/sdk/src/document/operation/style_operation.ts +++ b/packages/sdk/src/document/operation/style_operation.ts @@ -34,21 +34,18 @@ import { Code, YorkieError } from '@yorkie-js/sdk/src/util/error'; export class StyleOperation extends Operation { private fromPos: RGATreeSplitPos; private toPos: RGATreeSplitPos; - private maxCreatedAtMapByActor: Map; private attributes: Map; constructor( parentCreatedAt: TimeTicket, fromPos: RGATreeSplitPos, toPos: RGATreeSplitPos, - maxCreatedAtMapByActor: Map, attributes: Map, executedAt: TimeTicket, ) { super(parentCreatedAt, executedAt); this.fromPos = fromPos; this.toPos = toPos; - this.maxCreatedAtMapByActor = maxCreatedAtMapByActor; this.attributes = attributes; } @@ -59,7 +56,6 @@ export class StyleOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: RGATreeSplitPos, toPos: RGATreeSplitPos, - maxCreatedAtMapByActor: Map, attributes: Map, executedAt: TimeTicket, ): StyleOperation { @@ -67,7 +63,6 @@ export class StyleOperation extends Operation { parentCreatedAt, fromPos, toPos, - maxCreatedAtMapByActor, attributes, executedAt, ); @@ -95,11 +90,10 @@ export class StyleOperation extends Operation { ); } const text = parentObject as CRDTText; - const [, pairs, changes] = text.setStyle( + const [pairs, changes] = text.setStyle( [this.fromPos, this.toPos], this.attributes ? Object.fromEntries(this.attributes) : {}, this.getExecutedAt(), - this.maxCreatedAtMapByActor, versionVector, ); @@ -158,12 +152,4 @@ export class StyleOperation extends Operation { public getAttributes(): Map { return this.attributes; } - - /** - * `getMaxCreatedAtMapByActor` returns the map that stores the latest creation time - * by actor for the nodes included in the editing range. - */ - public getMaxCreatedAtMapByActor(): Map { - return this.maxCreatedAtMapByActor; - } } diff --git a/packages/sdk/src/document/operation/tree_edit_operation.ts b/packages/sdk/src/document/operation/tree_edit_operation.ts index b345f6cde..e95e21fc3 100644 --- a/packages/sdk/src/document/operation/tree_edit_operation.ts +++ b/packages/sdk/src/document/operation/tree_edit_operation.ts @@ -39,7 +39,6 @@ export class TreeEditOperation extends Operation { private toPos: CRDTTreePos; private contents: Array | undefined; private splitLevel: number; - private maxCreatedAtMapByActor: Map; constructor( parentCreatedAt: TimeTicket, @@ -47,7 +46,6 @@ export class TreeEditOperation extends Operation { toPos: CRDTTreePos, contents: Array | undefined, splitLevel: number, - maxCreatedAtMapByActor: Map, executedAt: TimeTicket, ) { super(parentCreatedAt, executedAt); @@ -55,7 +53,6 @@ export class TreeEditOperation extends Operation { this.toPos = toPos; this.contents = contents; this.splitLevel = splitLevel; - this.maxCreatedAtMapByActor = maxCreatedAtMapByActor; } /** @@ -67,7 +64,6 @@ export class TreeEditOperation extends Operation { toPos: CRDTTreePos, contents: Array | undefined, splitLevel: number, - maxCreatedAtMapByActor: Map, executedAt: TimeTicket, ): TreeEditOperation { return new TreeEditOperation( @@ -76,7 +72,6 @@ export class TreeEditOperation extends Operation { toPos, contents, splitLevel, - maxCreatedAtMapByActor, executedAt, ); } @@ -129,7 +124,6 @@ export class TreeEditOperation extends Operation { ); return issueTimeTicket; })(), - this.maxCreatedAtMapByActor, versionVector, ); @@ -208,12 +202,4 @@ export class TreeEditOperation extends Operation { public getSplitLevel(): number { return this.splitLevel; } - - /** - * `getMaxCreatedAtMapByActor` returns the map that stores the latest creation time - * by actor for the nodes included in the editing range. - */ - public getMaxCreatedAtMapByActor(): Map { - return this.maxCreatedAtMapByActor; - } } diff --git a/packages/sdk/src/document/operation/tree_style_operation.ts b/packages/sdk/src/document/operation/tree_style_operation.ts index c746142b2..492dd267e 100644 --- a/packages/sdk/src/document/operation/tree_style_operation.ts +++ b/packages/sdk/src/document/operation/tree_style_operation.ts @@ -38,7 +38,6 @@ import { Code, YorkieError } from '@yorkie-js/sdk/src/util/error'; export class TreeStyleOperation extends Operation { private fromPos: CRDTTreePos; private toPos: CRDTTreePos; - private maxCreatedAtMapByActor: Map; private attributes: Map; private attributesToRemove: Array; @@ -46,7 +45,6 @@ export class TreeStyleOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: CRDTTreePos, toPos: CRDTTreePos, - maxCreatedAtMapByActor: Map, attributes: Map, attributesToRemove: Array, executedAt: TimeTicket, @@ -54,7 +52,6 @@ export class TreeStyleOperation extends Operation { super(parentCreatedAt, executedAt); this.fromPos = fromPos; this.toPos = toPos; - this.maxCreatedAtMapByActor = maxCreatedAtMapByActor; this.attributes = attributes; this.attributesToRemove = attributesToRemove; } @@ -66,7 +63,6 @@ export class TreeStyleOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: CRDTTreePos, toPos: CRDTTreePos, - maxCreatedAtMapByActor: Map, attributes: Map, executedAt: TimeTicket, ): TreeStyleOperation { @@ -74,7 +70,6 @@ export class TreeStyleOperation extends Operation { parentCreatedAt, fromPos, toPos, - maxCreatedAtMapByActor, attributes, [], executedAt, @@ -88,7 +83,6 @@ export class TreeStyleOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: CRDTTreePos, toPos: CRDTTreePos, - maxCreatedAtMapByActor: Map, attributesToRemove: Array, executedAt: TimeTicket, ): TreeStyleOperation { @@ -96,7 +90,6 @@ export class TreeStyleOperation extends Operation { parentCreatedAt, fromPos, toPos, - maxCreatedAtMapByActor, new Map(), attributesToRemove, executedAt, @@ -131,21 +124,19 @@ export class TreeStyleOperation extends Operation { const attributes: { [key: string]: any } = {}; [...this.attributes].forEach(([key, value]) => (attributes[key] = value)); - [, pairs, changes] = tree.style( + [pairs, changes] = tree.style( [this.fromPos, this.toPos], attributes, this.getExecutedAt(), - this.maxCreatedAtMapByActor, versionVector, ); } else { const attributesToRemove = this.attributesToRemove; - [, pairs, changes] = tree.removeStyle( + [pairs, changes] = tree.removeStyle( [this.fromPos, this.toPos], attributesToRemove, this.getExecutedAt(), - this.maxCreatedAtMapByActor, versionVector, ); } @@ -226,12 +217,4 @@ export class TreeStyleOperation extends Operation { public getAttributesToRemove(): Array { return this.attributesToRemove; } - - /** - * `getMaxCreatedAtMapByActor` returns the map that stores the latest creation time - * by actor for the nodes included in the styling range. - */ - public getMaxCreatedAtMapByActor(): Map { - return this.maxCreatedAtMapByActor; - } }