Optimize storage, GC, and upload hot paths

This commit is contained in:
DioCrafts
2026-07-22 02:06:04 +02:00
parent 67fe944c2a
commit d66956824c
68 changed files with 16500 additions and 108 deletions
@@ -611,14 +611,17 @@
const total = items.length;
const owned = await resolveOwnedHashes(items.map((it) => it.file));
const frac = new Array<number>(total).fill(0);
let progressSum = 0;
let savedBytes = 0;
let failures = 0;
let next = 0;
const refresh = () => {
let sum = 0;
for (const x of frac) sum += x;
ui.updateProgress(nid, Math.round((sum / total) * 100), label(Math.round(sum)));
ui.updateProgress(
nid,
Math.round((progressSum / total) * 100),
label(Math.round(progressSum))
);
};
const worker = async () => {
@@ -626,7 +629,11 @@
const i = next++;
const { file, folderId } = items[i];
const report = (f: number) => {
if (!Number.isNaN(f)) frac[i] = Math.min(1, f);
if (!Number.isNaN(f)) {
const updated = Math.min(1, f);
progressSum += updated - frac[i];
frac[i] = updated;
}
refresh();
};
try {
@@ -637,6 +644,7 @@
// work so we don't fire hundreds of doomed uploads.
if ((e as { isQuota?: boolean } | null)?.isQuota) next = total;
} finally {
progressSum += 1 - frac[i];
frac[i] = 1;
refresh();
}
+47 -3
View File
@@ -13,7 +13,12 @@ const { goto, pageState, session, ui, confirmDialog, promptDialog } = vi.hoisted
loadHomeFolder: vi.fn(async () => 'home'),
refresh: vi.fn(async () => {})
},
ui: { notify: vi.fn() },
ui: {
notify: vi.fn(),
startProgress: vi.fn(() => 1),
updateProgress: vi.fn(),
finishProgress: vi.fn()
},
confirmDialog: vi.fn(),
promptDialog: vi.fn()
}));
@@ -24,7 +29,11 @@ vi.mock('$lib/stores/ui.svelte', () => ({ ui }));
vi.mock('$lib/stores/dialogs.svelte', () => ({ confirmDialog, promptDialog }));
vi.mock('$lib/api/client', () => ({ apiFetch: vi.fn() }));
vi.mock('$lib/api/csrf', () => ({ getCsrfHeaders: () => ({}) }));
vi.mock('$lib/api/endpoints/deltaUpload', () => ({ tryDeltaUpload: vi.fn() }));
vi.mock('$lib/api/endpoints/deltaUpload', () => ({
instantUploadOwned: vi.fn(),
resolveOwnedHashes: vi.fn(),
tryDeltaUpload: vi.fn()
}));
vi.mock('$lib/api/endpoints/favorites', () => ({ addFavorite: vi.fn(), removeFavorite: vi.fn() }));
vi.mock('$lib/api/endpoints/wopi', () => ({
canEditWithWopi: () => false,
@@ -59,7 +68,8 @@ vi.mock('$lib/api/endpoints/folders', () => ({
}));
import { fetchFolderPage, createFolder, deleteFolder } from '$lib/api/endpoints/folders';
import { deleteFile } from '$lib/api/endpoints/files';
import { deleteFile, uploadFileWithProgress } from '$lib/api/endpoints/files';
import { resolveOwnedHashes, tryDeltaUpload } from '$lib/api/endpoints/deltaUpload';
import { apiFetch } from '$lib/api/client';
import { files as filesStore } from '$lib/stores/files.svelte';
import FilesPage from './[...path]/+page.svelte';
@@ -122,6 +132,8 @@ function folderItem(id: string, name: string) {
beforeEach(() => {
vi.clearAllMocks();
m(resolveOwnedHashes).mockResolvedValue(new Map());
m(tryDeltaUpload).mockResolvedValue(null);
// A concrete folder in the path: bare `/files` now canonicalizes to
// `/files/<drive-root>` via goto (see the external-user test), so the
// listing-oriented tests target a folder directly.
@@ -130,6 +142,38 @@ beforeEach(() => {
filesStore.viewMode = 'list';
});
it('keeps aggregate upload progress exact when one file restarts', async () => {
withListing();
const pending = new Map<string, { report: (fraction: number) => void; resolve: () => void }>();
m(uploadFileWithProgress).mockImplementation(
(_folderId: string | null, file: File, report: (fraction: number) => void) =>
new Promise<void>((resolve) => pending.set(file.name, { report, resolve }))
);
render(FilesPage);
const input = await screen.findByTestId('files-upload-file-input');
const uploads = [new File(['a'], 'a.txt'), new File(['b'], 'b.txt')];
Object.defineProperty(input, 'files', { configurable: true, value: uploads });
const changed = fireEvent.change(input);
await waitFor(() => expect(pending.size).toBe(2));
pending.get('a.txt')!.report(0.5);
pending.get('b.txt')!.report(0.25);
pending.get('a.txt')!.report(0);
pending.get('a.txt')!.report(0.75);
expect(ui.updateProgress.mock.calls.map((call) => call[1])).toEqual([25, 38, 13, 50]);
pending.get('a.txt')!.resolve();
await waitFor(() =>
expect(ui.updateProgress.mock.calls.map((call) => call[1])).toEqual([25, 38, 13, 50, 63])
);
pending.get('b.txt')!.resolve();
await changed;
await waitFor(() =>
expect(ui.updateProgress).toHaveBeenLastCalledWith(1, 100, expect.any(String))
);
});
it('loads the home folder listing on mount and renders its contents', async () => {
withListing();
render(FilesPage);