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

Improve GC for deactivated client's nodes #926

Merged
merged 11 commits into from
Nov 20, 2024
21 changes: 20 additions & 1 deletion packages/sdk/src/document/time/version_vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ export class VersionVector {
return max;
}

/**
* `minLamport` returns min lamport value from vector
*/
public minLamport(): bigint {
if (this.vector.size === 0) {
return BigInt(0);
}

let min: bigint | undefined;
for (const [, lamport] of this) {
if (min === undefined || lamport < min) {
min = lamport;
}
}
return min as bigint;
}
hackerwins marked this conversation as resolved.
Show resolved Hide resolved

/**
* `max` returns new version vector which consists of max value of each vector
*/
Expand Down Expand Up @@ -96,7 +113,9 @@ export class VersionVector {
const lamport = this.vector.get(other.getActorID());

if (lamport === undefined) {
return false;
const minLamport = this.minLamport();

return !!minLamport && minLamport > other.getLamport();
hackerwins marked this conversation as resolved.
Show resolved Hide resolved
}

return lamport >= other.getLamport();
Expand Down
97 changes: 97 additions & 0 deletions packages/sdk/test/integration/gc_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1599,4 +1599,101 @@ describe('Garbage Collection', function () {
await client1.deactivate();
await client2.deactivate();
});

it('gc targeting nodes made by deactivated client', async function ({
task,
}) {
type TestDoc = { t: Text };
const docKey = toDocKey(`${task.name}-${new Date().getTime()}`);
const doc1 = new yorkie.Document<TestDoc>(docKey);
const doc2 = new yorkie.Document<TestDoc>(docKey);
const client1 = new yorkie.Client(testRPCAddr);
const client2 = new yorkie.Client(testRPCAddr);
await client1.activate();
await client2.activate();

await client1.attach(doc1, { syncMode: SyncMode.Manual });
assert.equal(
versionVectorHelper(doc1.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(1) },
]),
true,
);

await client2.attach(doc2, { syncMode: SyncMode.Manual });
assert.equal(
versionVectorHelper(doc2.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(1) },
{ actor: client2.getID()!, lamport: BigInt(2) },
]),
true,
);

doc1.update((root) => {
root.t = new Text();
root.t.edit(0, 0, 'a');
root.t.edit(1, 1, 'b');
root.t.edit(2, 2, 'c');
}, 'sets text');
assert.equal(
versionVectorHelper(doc1.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(2) },
]),
true,
);

await client1.sync();
assert.equal(
versionVectorHelper(doc1.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(3) },
{ actor: client2.getID()!, lamport: BigInt(1) },
]),
true,
);

await client2.sync();
assert.equal(
versionVectorHelper(doc2.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(2) },
{ actor: client2.getID()!, lamport: BigInt(3) },
]),
true,
);

doc2.update((root) => {
root.t.edit(2, 2, 'c');
}, 'insert c');
assert.equal(
versionVectorHelper(doc2.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(2) },
{ actor: client2.getID()!, lamport: BigInt(4) },
]),
true,
);

doc1.update((root) => {
root.t.edit(1, 3, '');
}, 'delete bd');
assert.equal(
versionVectorHelper(doc1.getVersionVector(), [
{ actor: client1.getID()!, lamport: BigInt(4) },
{ actor: client2.getID()!, lamport: BigInt(1) },
]),
true,
);

await client1.sync();
await client2.sync();

await client1.deactivate();
assert.equal(doc2.getGarbageLen(), 2);
assert.equal(doc2.getVersionVector().size(), 2);

// TODO(JOOHOJANG): remove below comments after https://github.com/yorkie-team/yorkie/issues/1058 resolved
// Due to https://github.com/yorkie-team/yorkie/issues/1058, removing deactivated client's version vector is not working properly now.

//await client2.sync();
//assert.equal(doc2.getGarbageLen(), 0);
//assert.equal(doc2.getVersionVector().size(), 1);
});
});
Loading