Skip to content

Commit

Permalink
Support concurrent insertion and splitting in Tree (#709)
Browse files Browse the repository at this point in the history
Unlike text, which is split based on value, the number of nodes that
can be created by splitting an element is not determined, so it was
not possible to use ID by only changing the offset of the original NodeID.

To solve this problem, a new TimeTicket is issued during Element Split
to create a NodeID, but because of this, it was not possible to
guarantee that the real parent of TreePos.Left was TreePos.Parent.

TreePos.Parent is only used to represent the leftmost position by
setting the values ​​of TreePos.Left and TreePos.Parent to be the same.

This commit uses TreePos.Parent only to determine whether the pos is
left-most and to directly use the parent of the actual node.
  • Loading branch information
sejongk authored Dec 14, 2023
1 parent 42fb01c commit bd5cd55
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 6 deletions.
16 changes: 11 additions & 5 deletions src/document/crdt/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,19 +687,25 @@ export class CRDTTree extends CRDTGCElement {
const [parent, leftSibling] = pos.toTreeNodes(this);
let leftNode = leftSibling;

// 02. Split text node if the left node is a text node.
// 02. Determine whether the position is left-most and the exact parent
// in the current tree.
const isLeftMost = parent === leftNode;
const realParent =
leftNode.parent && !isLeftMost ? leftNode.parent : parent;

// 03. Split text node if the left node is a text node.
if (leftNode.isText) {
leftNode.split(
this,
pos.getLeftSiblingID().getOffset() - leftNode.id.getOffset(),
);
}

// 03. Find the appropriate left node. If some nodes are inserted at the
// 04. Find the appropriate left node. If some nodes are inserted at the
// same position concurrently, then we need to find the appropriate left
// node. This is similar to RGA.
const allChildren = parent.allChildren;
const index = parent === leftNode ? 0 : allChildren.indexOf(leftNode) + 1;
const allChildren = realParent.allChildren;
const index = isLeftMost ? 0 : allChildren.indexOf(leftNode) + 1;

for (let i = index; i < parent.allChildren.length; i++) {
const next = allChildren[i];
Expand All @@ -710,7 +716,7 @@ export class CRDTTree extends CRDTGCElement {
leftNode = next;
}

return [parent, leftNode];
return [realParent, leftNode];
}

/**
Expand Down
2 changes: 1 addition & 1 deletion test/integration/tree_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2774,7 +2774,7 @@ describe('testing edge cases', () => {
}, task.name);
});

it.skip('Can concurrently split and insert into split node', async function ({
it('Can concurrently split and insert into split node', async function ({
task,
}) {
await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => {
Expand Down

0 comments on commit bd5cd55

Please sign in to comment.