Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RHTNode removal to converter for consistency #842

Merged
merged 3 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions src/api/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,22 @@ function toTreeNodesWhenEdit(nodes: Array<CRDTTreeNode>): Array<PbTreeNodes> {
return pbTreeNodesList;
}

/**
* `toRHT` converts the given model to Protobuf format.
*/
function toRHT(rht: RHT): { [key: string]: PbNodeAttr } {
const pbRHT: { [key: string]: PbNodeAttr } = {};
for (const node of rht) {
pbRHT[node.getKey()] = new PbNodeAttr({
value: node.getValue(),
updatedAt: toTimeTicket(node.getUpdatedAt()),
isRemoved: node.isRemoved(),
});
}

return pbRHT;
}

/**
* `toTreeNodes` converts the given model to Protobuf format.
*/
Expand Down Expand Up @@ -620,12 +636,7 @@ function toTreeNodes(node: CRDTTreeNode): Array<PbTreeNode> {
}

if (n.attrs) {
for (const attr of n.attrs) {
pbTreeNode.attributes[attr.getKey()] = new PbNodeAttr({
value: attr.getValue(),
updatedAt: toTimeTicket(attr.getUpdatedAt()),
});
}
pbTreeNode.attributes = toRHT(n.attrs);
}

pbTreeNodes.push(pbTreeNode);
Expand Down Expand Up @@ -1053,6 +1064,23 @@ function fromTreeNodes(
return CRDTTree.create(root, InitialTimeTicket).getRoot();
}

/**
* `fromRHT` converts the given Protobuf format to model format.
*/
function fromRHT(pbRHT: { [key: string]: PbNodeAttr }): RHT {
const rht = RHT.create();
for (const [key, pbRHTNode] of Object.entries(pbRHT)) {
rht.setInternal(
key,
pbRHTNode.value,
fromTimeTicket(pbRHTNode.updatedAt)!,
pbRHTNode.isRemoved,
);
}

return rht;
}

/**
* `fromTreeNode` converts the given Protobuf format to model format.
*/
Expand All @@ -1063,11 +1091,7 @@ function fromTreeNode(pbTreeNode: PbTreeNode): CRDTTreeNode {
if (node.isText) {
node.value = pbTreeNode.value;
} else if (pbAttrs.length) {
const attrs = RHT.create();
for (const [key, value] of pbAttrs) {
attrs.set(key, value.value, fromTimeTicket(value.updatedAt)!);
}
node.attrs = attrs;
node.attrs = fromRHT(pbTreeNode.attributes);
}

if (pbTreeNode.insPrevId) {
Expand Down
1 change: 1 addition & 0 deletions src/api/yorkie/v1/resources.proto
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ message RGANode {
message NodeAttr {
string value = 1;
TimeTicket updated_at = 2;
bool is_removed = 3;
}

message TextNode {
Expand Down
5 changes: 5 additions & 0 deletions src/api/yorkie/v1/resources_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,11 @@ export declare class NodeAttr extends Message<NodeAttr> {
*/
updatedAt?: TimeTicket;

/**
* @generated from field: bool is_removed = 3;
*/
isRemoved: boolean;

constructor(data?: PartialMessage<NodeAttr>);

static readonly runtime: typeof proto3;
Expand Down
1 change: 1 addition & 0 deletions src/api/yorkie/v1/resources_pb.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ const NodeAttr = proto3.makeMessageType(
() => [
{ no: 1, name: "value", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "updated_at", kind: "message", T: TimeTicket },
{ no: 3, name: "is_removed", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
],
);

Expand Down
31 changes: 30 additions & 1 deletion src/document/crdt/rht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ export class RHT {
return new RHT();
}

/**
* `getNodeMapByKey` returns the hashtable of RHT.
*/
public getNodeMapByKey(): Map<string, RHTNode> {
return this.nodeMapByKey;
}

/**
* `set` sets the value of the given key.
*/
Expand Down Expand Up @@ -149,6 +156,23 @@ export class RHT {
return [undefined, undefined];
}

/**
* SetInternal sets the value of the given key internally.
*/
public setInternal(
key: string,
value: string,
executedAt: TimeTicket,
removed: boolean,
) {
const node = RHTNode.of(key, value, executedAt, removed);
this.nodeMapByKey.set(key, node);

if (removed) {
this.numberOfRemovedElement++;
}
}
hackerwins marked this conversation as resolved.
Show resolved Hide resolved

/**
* `remove` removes the Element of the given key.
*/
Expand Down Expand Up @@ -213,7 +237,12 @@ export class RHT {
public deepcopy(): RHT {
const rht = new RHT();
for (const [, node] of this.nodeMapByKey) {
rht.set(node.getKey(), node.getValue(), node.getUpdatedAt());
rht.setInternal(
node.getKey(),
node.getValue(),
node.getUpdatedAt(),
node.isRemoved(),
);
}
return rht;
}
Expand Down
11 changes: 10 additions & 1 deletion test/unit/api/converter_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,13 @@ describe('Converter', function () {
});

root.tree.editByPath([0, 1], [1, 1]);

root.tree.style(0, 1, { b: 't', i: 't' });
assert.equal(root.tree.toXML(), '<r><p b="t" i="t">14</p></r>');

root.tree.removeStyle(0, 1, ['i']);
});
assert.equal(doc.getRoot().tree.toXML(), /*html*/ `<r><p>14</p></r>`);
assert.equal(doc.getRoot().tree.toXML(), /*html*/ `<r><p b="t">14</p></r>`);
hackerwins marked this conversation as resolved.
Show resolved Hide resolved
assert.equal(doc.getRoot().tree.getSize(), 4);

const bytes = converter.objectToBytes(doc.getRootObject());
Expand All @@ -119,5 +124,9 @@ describe('Converter', function () {
doc.getRoot().tree.getSize(),
(obj.get('tree') as unknown as Tree).getSize(),
);
assert.equal(
doc.getRoot().tree.toXML(),
(obj.get('tree') as unknown as Tree).toXML(),
);
});
});
10 changes: 10 additions & 0 deletions test/unit/document/crdt/rht_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ describe('RHT interface', function () {
assert.equal(jsonObj.testKey2, testData.testKey2);
assert.equal(jsonObj.testKey3, testData.testKey3);
});

it('should deepcopy correctly', function () {
const rht = RHT.create();
rht.set('key1', 'value1', timeT());
rht.remove('key2', timeT());

const rht2 = rht.deepcopy();
assert.equal(rht.toJSON(), rht2.toJSON());
assert.equal(rht.size(), rht2.size());
});
});

describe('RHT', () => {
Expand Down
Loading