feat(y-indexeddb): cleanup (#2207)

Co-authored-by: himself65 <himself65@outlook.com>
This commit is contained in:
三咲智子 Kevin Deng
2023-05-05 04:25:58 +08:00
committed by GitHub
parent 6d7f06c1c3
commit 52b9734a7b
4 changed files with 58 additions and 11 deletions

2
.github/CLA.md vendored
View File

@@ -56,5 +56,5 @@ Example:
- Skye Sun, @skyesun, 2023/04/14 - Skye Sun, @skyesun, 2023/04/14
- Jordy Delgado, @Jdelgad8, 2023/04/17 - Jordy Delgado, @Jdelgad8, 2023/04/17
- Howard Do, @howarddo2208, 2023/04/20 - Howard Do, @howarddo2208, 2023/04/20
- Kevin Deng, @sxzz, 2023/04/21 - 三咲智子 Kevin Deng, @sxzz, 2023/04/21
- Moeyua, @moeyua, 2023/04/22 - Moeyua, @moeyua, 2023/04/22

View File

@@ -13,6 +13,7 @@ import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
import type { WorkspacePersist } from '../index'; import type { WorkspacePersist } from '../index';
import { import {
CleanupWhenConnectingError,
createIndexedDBProvider, createIndexedDBProvider,
dbVersion, dbVersion,
DEFAULT_DB_NAME, DEFAULT_DB_NAME,
@@ -59,7 +60,7 @@ describe('indexeddb provider', () => {
await provider.whenSynced; await provider.whenSynced;
const db = await openDB(rootDBName, dbVersion); const db = await openDB(rootDBName, dbVersion);
{ {
const store = await db const store = db
.transaction('workspace', 'readonly') .transaction('workspace', 'readonly')
.objectStore('workspace'); .objectStore('workspace');
const data = await store.get(id); const data = await store.get(id);
@@ -161,6 +162,43 @@ describe('indexeddb provider', () => {
expect(p1).not.toBe(p2); expect(p1).not.toBe(p2);
}); });
test('cleanup', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
provider.connect();
await provider.whenSynced;
const db = await openDB(rootDBName, dbVersion);
{
const store = db
.transaction('workspace', 'readonly')
.objectStore('workspace');
const keys = await store.getAllKeys();
expect(keys).contain(workspace.id);
}
provider.disconnect();
await provider.cleanup();
{
const store = db
.transaction('workspace', 'readonly')
.objectStore('workspace');
const keys = await store.getAllKeys();
expect(keys).not.contain(workspace.id);
}
});
test('cleanup when connecting', async () => {
const provider = createIndexedDBProvider(workspace.id, workspace.doc);
provider.connect();
expect(() => provider.cleanup()).rejects.toThrowError(
CleanupWhenConnectingError
);
await provider.whenSynced;
provider.disconnect();
await provider.cleanup();
});
test('merge', async () => { test('merge', async () => {
setMergeCount(5); setMergeCount(5);
const provider = createIndexedDBProvider( const provider = createIndexedDBProvider(

View File

@@ -90,6 +90,12 @@ export class EarlyDisconnectError extends Error {
} }
} }
export class CleanupWhenConnectingError extends Error {
constructor() {
super('Cleanup when connecting');
}
}
export const markMilestone = async ( export const markMilestone = async (
id: string, id: string,
doc: Doc, doc: Doc,
@@ -144,11 +150,11 @@ export const createIndexedDBProvider = (
let resolve: () => void; let resolve: () => void;
let reject: (reason?: unknown) => void; let reject: (reason?: unknown) => void;
let early = true; let early = true;
let connect = false; let connected = false;
async function handleUpdate(update: Uint8Array, origin: unknown) { async function handleUpdate(update: Uint8Array, origin: unknown) {
const db = await dbPromise; const db = await dbPromise;
if (!connect) { if (!connected) {
return; return;
} }
if (origin === indexeddbOrigin) { if (origin === indexeddbOrigin) {
@@ -197,7 +203,7 @@ export const createIndexedDBProvider = (
upgrade: upgradeDB, upgrade: upgradeDB,
}); });
const handleDestroy = async () => { const handleDestroy = async () => {
connect = true; connected = true;
const db = await dbPromise; const db = await dbPromise;
db.close(); db.close();
}; };
@@ -208,7 +214,7 @@ export const createIndexedDBProvider = (
resolve = _resolve; resolve = _resolve;
reject = _reject; reject = _reject;
}); });
connect = true; connected = true;
doc.on('update', handleUpdate); doc.on('update', handleUpdate);
doc.on('destroy', handleDestroy); doc.on('destroy', handleDestroy);
// only run promise below, otherwise the logic is incorrect // only run promise below, otherwise the logic is incorrect
@@ -218,7 +224,7 @@ export const createIndexedDBProvider = (
.transaction('workspace', 'readwrite') .transaction('workspace', 'readwrite')
.objectStore('workspace'); .objectStore('workspace');
const data = await store.get(id); const data = await store.get(id);
if (!connect) { if (!connected) {
return; return;
} }
if (!data) { if (!data) {
@@ -267,15 +273,18 @@ export const createIndexedDBProvider = (
resolve(); resolve();
}, },
disconnect() { disconnect() {
connect = false; connected = false;
if (early) { if (early) {
reject(new EarlyDisconnectError()); reject(new EarlyDisconnectError());
} }
doc.off('update', handleUpdate); doc.off('update', handleUpdate);
doc.off('destroy', handleDestroy); doc.off('destroy', handleDestroy);
}, },
cleanup() { async cleanup() {
// todo if (connected) {
throw new CleanupWhenConnectingError();
}
(await dbPromise).delete('workspace', id);
}, },
whenSynced: Promise.resolve(), whenSynced: Promise.resolve(),
}; };

View File

@@ -11,7 +11,7 @@ export function upgradeDB(db: IDBPDatabase<BlockSuiteBinaryDB>) {
export interface IndexedDBProvider { export interface IndexedDBProvider {
connect: () => void; connect: () => void;
disconnect: () => void; disconnect: () => void;
cleanup: () => void; cleanup: () => Promise<void>;
whenSynced: Promise<void>; whenSynced: Promise<void>;
} }