perf: reduce unused provider connection (#3090)

This commit is contained in:
Alex Yang 2023-07-07 16:13:32 +08:00 committed by GitHub
parent 152fbaabda
commit 3294043180
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 41 deletions

View File

@ -8,6 +8,7 @@ import type { WorkspaceFlavour } from '@affine/env/workspace';
import {
rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom,
workspaceAdaptersAtom,
} from '@affine/workspace/atom';
import { assertExists } from '@blocksuite/global/utils';
import type { ActiveDocProvider } from '@blocksuite/store';
@ -22,7 +23,7 @@ const logger = new DebugLogger('web:atoms:root');
*/
export const workspacesAtom = atom<Promise<AllWorkspace[]>>(
async (get, { signal }) => {
const { WorkspaceAdapters } = await import('../adapters/workspace');
const WorkspaceAdapters = get(workspaceAdaptersAtom);
const flavours: string[] = Object.values(WorkspaceAdapters).map(
plugin => plugin.flavour
);
@ -87,7 +88,7 @@ export const workspacesAtom = atom<Promise<AllWorkspace[]>>(
*/
export const rootCurrentWorkspaceAtom = atom<Promise<AllWorkspace>>(
async (get, { signal }) => {
const { WorkspaceAdapters } = await import('../adapters/workspace');
const WorkspaceAdapters = get(workspaceAdaptersAtom);
const metadata = await get(rootWorkspacesMetadataAtom);
const targetId = get(rootCurrentWorkspaceIdAtom);
if (targetId === null) {

View File

@ -5,8 +5,10 @@ import {
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { ContactWithUsIcon } from '@blocksuite/icons';
import type { PassiveDocProvider } from '@blocksuite/store';
import { noop } from 'foxact/noop';
import type React from 'react';
import { useCallback, useMemo } from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useWorkspaces } from '../../../hooks/use-workspaces';
@ -19,7 +21,7 @@ import {
} from './general-setting';
import { SettingSidebar } from './setting-sidebar';
import { settingContent } from './style.css';
import { WorkSpaceSetting } from './workspace-setting';
import { WorkspaceSetting } from './workspace-setting';
type ActiveTab = GeneralSettingKeys | 'workspace' | 'account';
export type SettingProps = {
@ -70,6 +72,24 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
onSettingClick({ activeTab: 'account', workspace: null });
}, [onSettingClick]);
useEffect(() => {
if (workspace && workspace !== currentWorkspace) {
const providers = workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is PassiveDocProvider =>
'passive' in provider && provider.passive
);
providers.forEach(provider => {
provider.connect();
});
return () => {
providers.forEach(provider => {
provider.disconnect();
});
};
}
return noop;
}, [currentWorkspace, workspace]);
return (
<SettingModalBase open={open} setOpen={setOpen}>
<SettingSidebar
@ -87,7 +107,7 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
<div className="wrapper">
<div className="content">
{activeTab === 'workspace' && workspace ? (
<WorkSpaceSetting key={workspace.id} workspace={workspace} />
<WorkspaceSetting key={workspace.id} workspace={workspace} />
) : null}
{generalSettingList.find(v => v.key === activeTab) ? (
<GeneralSetting generalKey={activeTab as GeneralSettingKeys} />

View File

@ -5,7 +5,7 @@ import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform
import { useAppHelper } from '../../../../hooks/use-workspaces';
import type { AllWorkspace } from '../../../../shared';
export const WorkSpaceSetting = ({
export const WorkspaceSetting = ({
workspace,
}: {
workspace: AllWorkspace;

View File

@ -99,27 +99,7 @@ export const QuickSearch: FC = () => {
export const AllWorkspaceContext = ({
children,
}: PropsWithChildren): ReactElement => {
const currentWorkspaceId = useAtomValue(rootCurrentWorkspaceIdAtom);
const workspaces = useWorkspaces();
useEffect(() => {
const providers = workspaces
// ignore current workspace
.filter(workspace => workspace.id !== currentWorkspaceId)
.flatMap(workspace =>
workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is PassiveDocProvider =>
'passive' in provider && provider.passive
)
);
providers.forEach(provider => {
provider.connect();
});
return () => {
providers.forEach(provider => {
provider.disconnect();
});
};
}, [currentWorkspaceId, workspaces]);
useWorkspaces();
return <>{children}</>;
};

View File

@ -1,3 +1,4 @@
import { DebugLogger } from '@affine/debug';
import type {
LocalIndexedDBBackgroundProvider,
LocalIndexedDBDownloadProvider,
@ -13,26 +14,25 @@ import {
} from '@toeverything/y-indexeddb';
import type { Doc } from 'yjs';
import { CallbackSet } from '../utils';
import { localProviderLogger as logger } from './logger';
import {
createSQLiteDBDownloadProvider,
createSQLiteProvider,
} from './sqlite-providers';
const Y = Workspace.Y;
const logger = new DebugLogger('indexeddb-provider');
const createIndexedDBBackgroundProvider: DocProviderCreator = (
id,
blockSuiteWorkspace
): LocalIndexedDBBackgroundProvider => {
const indexeddbProvider = create(blockSuiteWorkspace);
const callbacks = new CallbackSet();
let connected = false;
return {
flavour: 'local-indexeddb-background',
passive: true,
get connected() {
return callbacks.ready;
return connected;
},
cleanup: () => {
indexeddbProvider.cleanup().catch(console.error);
@ -42,27 +42,27 @@ const createIndexedDBBackgroundProvider: DocProviderCreator = (
indexeddbProvider.connect();
indexeddbProvider.whenSynced
.then(() => {
callbacks.ready = true;
callbacks.forEach(cb => cb());
connected = true;
})
.catch(error => {
callbacks.ready = false;
connected = false;
if (error instanceof EarlyDisconnectError) {
return;
} else {
throw error;
}
throw error;
});
},
disconnect: () => {
assertExists(indexeddbProvider);
logger.info('disconnect indexeddb provider', id);
indexeddbProvider.disconnect();
callbacks.ready = false;
connected = false;
},
};
};
const cache: WeakMap<Doc, Uint8Array> = new WeakMap();
const createIndexedDBDownloadProvider: DocProviderCreator = (
id,
doc
@ -74,11 +74,17 @@ const createIndexedDBDownloadProvider: DocProviderCreator = (
_reject = reject;
});
async function downloadBinaryRecursively(doc: Doc) {
const binary = await downloadBinary(doc.guid);
if (binary) {
if (cache.has(doc)) {
const binary = cache.get(doc) as Uint8Array;
Y.applyUpdate(doc, binary);
await Promise.all([...doc.subdocs].map(downloadBinaryRecursively));
} else {
const binary = await downloadBinary(doc.guid);
if (binary) {
Y.applyUpdate(doc, binary);
cache.set(doc, binary);
}
}
await Promise.all([...doc.subdocs].map(downloadBinaryRecursively));
}
return {
flavour: 'local-indexeddb',
@ -90,7 +96,7 @@ const createIndexedDBDownloadProvider: DocProviderCreator = (
// todo: cleanup data
},
sync: () => {
logger.info('connect indexeddb provider', id);
logger.info('sync indexeddb provider', id);
downloadBinaryRecursively(doc).then(_resolve).catch(_reject);
},
};