Update lengths before delta event in rollback (#22818)

During rollback of delete from string, the delta callback is invoked
before the lengths are updated, which results in the callback code
seeing messed up string content. This fix swaps the order and adds
testing for the events.
This commit is contained in:
Scarlett Lee 2024-10-15 16:05:22 -07:00 коммит произвёл GitHub
Родитель 0334d003b0
Коммит 027f5985df
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 49 добавлений и 10 удалений

Просмотреть файл

@ -2296,16 +2296,6 @@ export class MergeTree {
segment.removedSeq = undefined;
segment.localRemovedSeq = undefined;
// Note: optional chaining short-circuits:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining#short-circuiting
this.mergeTreeDeltaCallback?.(
{ op: createInsertSegmentOp(this.findRollbackPosition(segment), segment) },
{
operation: MergeTreeDeltaType.INSERT,
deltaSegments: [{ segment }],
},
);
for (
let updateNode = segment.parent;
updateNode !== undefined;
@ -2317,6 +2307,16 @@ export class MergeTree {
this.collabWindow.clientId,
);
}
// Note: optional chaining short-circuits:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining#short-circuiting
this.mergeTreeDeltaCallback?.(
{ op: createInsertSegmentOp(this.findRollbackPosition(segment), segment) },
{
operation: MergeTreeDeltaType.INSERT,
deltaSegments: [{ segment }],
},
);
});
} else if (
op.type === MergeTreeDeltaType.INSERT ||

Просмотреть файл

@ -330,17 +330,56 @@ describe("client.rollback", () => {
it("Should rollback delete which causes split segments", () => {
client.insertTextLocal(0, "abcde");
client.removeRangeLocal(1, 4);
let deltaEvent = false;
client.on("delta", () => {
assert.equal(client.getText(), "abcde");
deltaEvent = true;
});
client.rollback?.({ type: MergeTreeDeltaType.REMOVE }, client.peekPendingSegmentGroups());
assert.equal(client.getText(), "abcde");
assert.equal(deltaEvent, true);
});
it("Should rollback delete across split segments", () => {
client.insertTextLocal(0, "abcde");
client.annotateRangeLocal(2, 3, { foo: "bar" });
client.removeRangeLocal(1, 4);
let deltaCount = 0;
let bFound = false;
let cFound = false;
let dFound = false;
client.on("delta", (_opArgs, delta) => {
deltaCount++;
assert.equal(client.getText().length, 2 + deltaCount);
assert.equal(delta.deltaSegments.length, 1);
assert.equal(delta.deltaSegments[0].segment.type, TextSegment.type);
const text = (delta.deltaSegments[0].segment as TextSegment).toString();
switch (text) {
case "b": {
bFound = true;
break;
}
case "c": {
cFound = true;
break;
}
case "d": {
dFound = true;
break;
}
default: {
assert(false, `Unexpected text segment: ${text}`);
}
}
});
client.rollback?.({ type: MergeTreeDeltaType.REMOVE }, client.peekPendingSegmentGroups());
assert.equal(client.getText(), "abcde");
assert.equal(deltaCount, 3);
assert(bFound);
assert(cFound);
assert(dFound);
});
it("Should rollback delete and update blocks", () => {
const text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()";