From dd611aa56dab338f069c1f23146e9f3275ba9532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8E=E5=A3=B0?= Date: Wed, 11 Sep 2024 10:37:42 +0800 Subject: [PATCH 1/2] fix: mounting home fs multiple times will throw error --- packages/common/src/index.ts | 1 + packages/common/src/mutex.ts | 22 +++++++ .../sumi-core/src/server/core/filesystem.ts | 57 +++++++++++-------- 3 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 packages/common/src/mutex.ts diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index cf2fce5c..d8149b91 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1,2 +1,3 @@ +export * from './mutex'; export * from './request'; export * from './types'; diff --git a/packages/common/src/mutex.ts b/packages/common/src/mutex.ts new file mode 100644 index 00000000..fb81fe11 --- /dev/null +++ b/packages/common/src/mutex.ts @@ -0,0 +1,22 @@ +export class Mutex { + private mutex = Promise.resolve(); + + lock(): PromiseLike<() => void> { + let begin: (unlock: () => void) => void = () => {}; + + this.mutex = this.mutex.then(() => new Promise(begin)); + + return new Promise((res) => { + begin = res; + }); + } + + async dispatch(fn: () => PromiseLike): Promise { + const unlock = await this.lock(); + try { + return await Promise.resolve(fn()); + } finally { + unlock(); + } + } +} diff --git a/packages/sumi-core/src/server/core/filesystem.ts b/packages/sumi-core/src/server/core/filesystem.ts index 29b31a48..4c0ea71d 100644 --- a/packages/sumi-core/src/server/core/filesystem.ts +++ b/packages/sumi-core/src/server/core/filesystem.ts @@ -1,7 +1,8 @@ -import { Deferred, getDebugLogger } from '@opensumi/ide-core-common'; +import { Mutex } from '@codeblitzjs/ide-common'; +import { Deferred, Disposable, getDebugLogger } from '@opensumi/ide-core-common'; import { HOME_IDB_NAME, HOME_ROOT } from '../../common'; import { RootFS } from '../../common/types'; -import { BrowserFS, FileSystem } from '../node'; +import { BrowserFS, FileSystem, isPathMounted } from '../node'; const { createFileSystem, FileSystem, initialize } = BrowserFS; @@ -32,31 +33,39 @@ export const unmountRootFS = () => { } }; +const initHomeFsMutex = new Mutex(); + export const initializeHomeFileSystem = async (rootFS: RootFS, scenario?: string | null) => { - try { - let homefs: FileSystem | null = null; - // scenario 为 null 时 或者 browser 隐身模式时无法使用 indexedDB 时,回退到 memory - // TODO: 寻找更好的解决方案 - if (scenario !== null && FileSystem.IndexedDB.isAvailable()) { - try { - // 通过 scenario 隔离 indexedDB - homefs = await createFileSystem(FileSystem.IndexedDB, { - storeName: `${HOME_IDB_NAME}${scenario ? `/${scenario}` : ''}`, - }); - } catch (err) { - // @ts-ignore - getDebugLogger().error(`初始化 indexedDB 文件系统失败 ${err?.message || ''}`); - homefs = null; + // 如果用户使用了多个 codeblitz 实例,第一个挂载的先生效 + if (isPathMounted(rootFS, HOME_ROOT)) { + return Disposable.NULL; + } + + await initHomeFsMutex.dispatch(async () => { + try { + let homefs: FileSystem | null = null; + // scenario 为 null 时 或者 browser 隐身模式时无法使用 indexedDB 时,回退到 memory + // TODO: 寻找更好的解决方案 + if (scenario !== null && FileSystem.IndexedDB.isAvailable()) { + try { + // 通过 scenario 隔离 indexedDB + homefs = await createFileSystem(FileSystem.IndexedDB, { + storeName: `${HOME_IDB_NAME}${scenario ? `/${scenario}` : ''}`, + }); + } catch (err) { + getDebugLogger().error(`初始化 indexedDB 文件系统失败 ${(err as Error)?.message || ''}`); + homefs = null; + } } + if (!homefs) { + homefs = await createFileSystem(FileSystem.InMemory, {}); + } + rootFS.mount(HOME_ROOT, homefs); + } catch (err) { + getDebugLogger().error(`初始化 home 目录失败 ${(err as Error)?.message || ''}`); } - if (!homefs) { - homefs = await createFileSystem(FileSystem.InMemory, {}); - } - rootFS.mount(HOME_ROOT, homefs); - } catch (err) { - // @ts-ignore - getDebugLogger().error(`初始化 home 目录失败 ${err?.message || ''}`); - } + }); + return { dispose() { rootFS.umount(HOME_ROOT); From 9c68f51509dfd1e25c581ca2cb7114472f3f1bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8E=E5=A3=B0?= Date: Wed, 11 Sep 2024 10:42:46 +0800 Subject: [PATCH 2/2] fix: multiple times --- .../sumi-core/src/server/core/filesystem.ts | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/sumi-core/src/server/core/filesystem.ts b/packages/sumi-core/src/server/core/filesystem.ts index 4c0ea71d..0cbd009b 100644 --- a/packages/sumi-core/src/server/core/filesystem.ts +++ b/packages/sumi-core/src/server/core/filesystem.ts @@ -12,18 +12,18 @@ export const filesystemDeferred = new Deferred(); export const isFilesystemReady = () => filesystemDeferred.promise; let mountfs: RootFS | null = null; -let mountfsDeferred: Deferred | null = null; +let mountRootFsMutex = new Mutex(); export const initializeRootFileSystem = async () => { - if (mountfsDeferred) return mountfsDeferred.promise; + return mountRootFsMutex.dispatch(async () => { + if (mountfs) return mountfs; - mountfsDeferred = new Deferred(); - mountfs = (await createFileSystem(FileSystem.MountableFileSystem, {})) as RootFS; - mountfsDeferred.resolve(mountfs); + mountfs = (await createFileSystem(FileSystem.MountableFileSystem, {})) as RootFS; - initialize(mountfs); - filesystemDeferred.resolve(); - return mountfs; + initialize(mountfs); + filesystemDeferred.resolve(); + return mountfs; + }); }; export const unmountRootFS = () => { @@ -36,12 +36,12 @@ export const unmountRootFS = () => { const initHomeFsMutex = new Mutex(); export const initializeHomeFileSystem = async (rootFS: RootFS, scenario?: string | null) => { - // 如果用户使用了多个 codeblitz 实例,第一个挂载的先生效 - if (isPathMounted(rootFS, HOME_ROOT)) { - return Disposable.NULL; - } + return await initHomeFsMutex.dispatch(async () => { + // 如果用户使用了多个 codeblitz 实例,第一个挂载的先生效 + if (isPathMounted(rootFS, HOME_ROOT)) { + return Disposable.NULL; + } - await initHomeFsMutex.dispatch(async () => { try { let homefs: FileSystem | null = null; // scenario 为 null 时 或者 browser 隐身模式时无法使用 indexedDB 时,回退到 memory @@ -64,11 +64,11 @@ export const initializeHomeFileSystem = async (rootFS: RootFS, scenario?: string } catch (err) { getDebugLogger().error(`初始化 home 目录失败 ${(err as Error)?.message || ''}`); } - }); - return { - dispose() { - rootFS.umount(HOME_ROOT); - }, - }; + return { + dispose() { + rootFS.umount(HOME_ROOT); + }, + }; + }); };