From 6466e1e12183986bbdcf7bbdac38192956ecc499 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Thu, 11 Jul 2024 10:43:35 +0900 Subject: [PATCH] Handle local changes correctly when receiving snapshot --- src/document/document.ts | 8 ++++++++ test/integration/client_test.ts | 25 +++++++++++++++++++++++++ test/integration/snapshot_test.ts | 4 ++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/document/document.ts b/src/document/document.ts index c1aaaec34..0ebf79ece 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -1072,6 +1072,14 @@ export class Document { this.localChanges.shift(); } + // NOTE(hackerwins): If the document has local changes, we need to apply + // them after applying the snapshot. We need to treat the local changes + // as remote changes because the application should apply the local + // changes to their own document. + if (pack.hasSnapshot()) { + this.applyChanges(this.localChanges, OpSource.Remote); + } + // 03. Update the checkpoint. this.checkpoint = this.checkpoint.forward(pack.getCheckpoint()); diff --git a/test/integration/client_test.ts b/test/integration/client_test.ts index ba3202825..c56997f10 100644 --- a/test/integration/client_test.ts +++ b/test/integration/client_test.ts @@ -838,4 +838,29 @@ describe.sequential('Client', function () { vi.unstubAllGlobals(); }); + + it('Should handle local changes correctly when receiving snapshot', async ({ + task, + }) => { + type TestDoc = { counter: Counter }; + await withTwoClientsAndDocuments(async (c1, d1, c2, d2) => { + d1.update((r) => (r.counter = new Counter(yorkie.IntType, 0))); + await c1.sync(); + await c2.sync(); + + // 01. c1 increases the counter for creating snapshot. + for (let i = 0; i < 500; i++) { + d1.update((r) => r.counter.increase(1)); + } + await c1.sync(); + + // 02. c2 receives the snapshot and increases the counter simultaneously. + c2.sync(); + d2.update((r) => r.counter.increase(1)); + + await c2.sync(); + await c1.sync(); + assert.equal(d1.toSortedJSON(), d2.toSortedJSON()); + }, task.name); + }); }); diff --git a/test/integration/snapshot_test.ts b/test/integration/snapshot_test.ts index 49d16e4e1..686fa83ae 100644 --- a/test/integration/snapshot_test.ts +++ b/test/integration/snapshot_test.ts @@ -38,8 +38,8 @@ describe('Snapshot', function () { await c1.sync(); await c2.sync(); - // 01. Updates 700 changes over snapshot threshold by c1. - for (let idx = 0; idx < 700; idx++) { + // 01. Updates 500 changes over snapshot threshold by c1. + for (let idx = 0; idx < 500; idx++) { d1.update((root) => { root.k1.edit(idx, idx, 'x'); });