mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-10-25 10:33:21 +00:00
perf(startup): inspect storage sizes without loading healthy files
This commit is contained in:
1 parent
ce0524d49f
commit
fc2b35e0dc
2 files changed
+60
-9
No files matched your search
@@ -31,7 +31,7 @@ export interface IncompleteDocumentsDependencies {
|
|||||||
readonly localDatabase: Pick<LiveSyncLocalDB, "findAllNormalDocs" | "getDBEntryFromMeta">;
|
readonly localDatabase: Pick<LiveSyncLocalDB, "findAllNormalDocs" | "getDBEntryFromMeta">;
|
||||||
readonly getPath: StartupPathReader;
|
readonly getPath: StartupPathReader;
|
||||||
readonly isTargetFile: (path: string) => Promise<boolean>;
|
readonly isTargetFile: (path: string) => Promise<boolean>;
|
||||||
readonly storageAccess: Pick<StorageAccess, "readHiddenFileBinary" | "getFileStub">;
|
readonly storageAccess: Pick<StorageAccess, "readHiddenFileBinary" | "statHidden" | "getFileStub">;
|
||||||
readonly fileHandler: Pick<IFileHandler, "storeFileToDB">;
|
readonly fileHandler: Pick<IFileHandler, "storeFileToDB">;
|
||||||
readonly keyValueDB: Pick<KeyValueDatabase, "get" | "set">;
|
readonly keyValueDB: Pick<KeyValueDatabase, "get" | "set">;
|
||||||
readonly noticeGroups: NoticeGroups;
|
readonly noticeGroups: NoticeGroups;
|
||||||
@@ -94,16 +94,11 @@ export async function checkIncompleteDocuments(
|
|||||||
}
|
}
|
||||||
const isConflicted = metaDoc?._conflicts && metaDoc._conflicts.length > 0;
|
const isConflicted = metaDoc?._conflicts && metaDoc._conflicts.length > 0;
|
||||||
|
|
||||||
let storageFileContent;
|
const storageStat = await dependencies.storageAccess.statHidden(path);
|
||||||
try {
|
if (!storageStat || storageStat.type !== "file") {
|
||||||
storageFileContent = await dependencies.storageAccess.readHiddenFileBinary(path);
|
|
||||||
} catch (e) {
|
|
||||||
Logger(`Failed to read file ${path}: Possibly unprocessed or missing`);
|
|
||||||
Logger(e, LOG_LEVEL_VERBOSE);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// const storageFileBlob = createBlob(storageFileContent);
|
let sizeOnStorage = storageStat.size;
|
||||||
const sizeOnStorage = storageFileContent.byteLength;
|
|
||||||
const recordedSize = doc.size;
|
const recordedSize = doc.size;
|
||||||
const docBlob = readAsBlob(doc);
|
const docBlob = readAsBlob(doc);
|
||||||
const actualSize = docBlob.size;
|
const actualSize = docBlob.size;
|
||||||
@@ -113,6 +108,15 @@ export async function checkIncompleteDocuments(
|
|||||||
sizeOnStorage !== recordedSize ||
|
sizeOnStorage !== recordedSize ||
|
||||||
isConflicted
|
isConflicted
|
||||||
) {
|
) {
|
||||||
|
let storageFileContent;
|
||||||
|
try {
|
||||||
|
storageFileContent = await dependencies.storageAccess.readHiddenFileBinary(path);
|
||||||
|
} catch (e) {
|
||||||
|
Logger(`Failed to read file ${path}: Possibly unprocessed or missing`);
|
||||||
|
Logger(e, LOG_LEVEL_VERBOSE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sizeOnStorage = storageFileContent.byteLength;
|
||||||
const contentMatched = await isDocContentSame(doc.data, storageFileContent);
|
const contentMatched = await isDocContentSame(doc.data, storageFileContent);
|
||||||
errorFiles.push({
|
errorFiles.push({
|
||||||
path,
|
path,
|
||||||
@@ -125,6 +129,17 @@ export async function checkIncompleteDocuments(
|
|||||||
Logger(
|
Logger(
|
||||||
`Size mismatch for ${path}: ${recordedSize} (DB Recorded) , ${actualSize} (DB Stored) , ${sizeOnStorage} (Storage Stored), ${contentMatched ? "Content Matched" : "Content Mismatched"} ${isConflicted ? "Conflicted" : "Not Conflicted"}`
|
`Size mismatch for ${path}: ${recordedSize} (DB Recorded) , ${actualSize} (DB Stored) , ${sizeOnStorage} (Storage Stored), ${contentMatched ? "Content Matched" : "Content Mismatched"} ${isConflicted ? "Conflicted" : "Not Conflicted"}`
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
const currentStat = await dependencies.storageAccess.statHidden(path);
|
||||||
|
if (
|
||||||
|
!currentStat ||
|
||||||
|
currentStat.type !== "file" ||
|
||||||
|
currentStat.size !== storageStat.size ||
|
||||||
|
currentStat.mtime !== storageStat.mtime ||
|
||||||
|
currentStat.ctime !== storageStat.ctime
|
||||||
|
) {
|
||||||
|
throw new Error("Storage changed during the incomplete document check");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errorFiles.length == 0) {
|
if (errorFiles.length == 0) {
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ function createDependencies(findAllNormalDocs: FindAllNormalDocs = noDocuments,
|
|||||||
isTargetFile: vi.fn(async () => true),
|
isTargetFile: vi.fn(async () => true),
|
||||||
storageAccess: {
|
storageAccess: {
|
||||||
readHiddenFileBinary,
|
readHiddenFileBinary,
|
||||||
|
statHidden: vi.fn(async (path: string) => getFixture(path)?.stub.stat ?? null),
|
||||||
getFileStub,
|
getFileStub,
|
||||||
},
|
},
|
||||||
fileHandler: { storeFileToDB },
|
fileHandler: { storeFileToDB },
|
||||||
@@ -157,6 +158,41 @@ describe("checkIncompleteDocuments", () => {
|
|||||||
expect(noticeGroups.finish).toHaveBeenCalledWith("startup-integrity-check");
|
expect(noticeGroups.finish).toHaveBeenCalledWith("startup-integrity-check");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not read healthy storage contents only to determine their size", async () => {
|
||||||
|
const healthy = documentFixture("healthy.md", { storageContent: "abc" });
|
||||||
|
const fixture = createDependencies(documentsFrom([healthy]), [healthy]);
|
||||||
|
|
||||||
|
await expect(checkIncompleteDocuments(fixture.dependencies)).resolves.toBe(true);
|
||||||
|
|
||||||
|
expect(fixture.readHiddenFileBinary).not.toHaveBeenCalled();
|
||||||
|
expect(fixture.askSelectStringDialogue).not.toHaveBeenCalled();
|
||||||
|
expect(fixture.dependencies.keyValueDB.set).toHaveBeenCalledWith("checkIncompleteDocs", true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not mark a scan complete when storage changes during the size check", async () => {
|
||||||
|
const healthy = documentFixture("changing.md", { storageContent: "abc" });
|
||||||
|
const fixture = createDependencies(documentsFrom([healthy]), [healthy]);
|
||||||
|
vi.mocked(fixture.dependencies.storageAccess.statHidden)
|
||||||
|
.mockResolvedValueOnce(healthy.stub.stat)
|
||||||
|
.mockResolvedValueOnce({ ...healthy.stub.stat, mtime: 3 });
|
||||||
|
|
||||||
|
await expect(checkIncompleteDocuments(fixture.dependencies)).rejects.toThrow("Storage changed");
|
||||||
|
|
||||||
|
expect(fixture.readHiddenFileBinary).not.toHaveBeenCalled();
|
||||||
|
expect(fixture.dependencies.keyValueDB.set).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still reads conflicted storage for the existing repair dialogue", async () => {
|
||||||
|
const conflicted = documentFixture("conflicted.md", { storageContent: "abc", conflicts: ["2-other"] });
|
||||||
|
const fixture = createDependencies(documentsFrom([conflicted]), [conflicted]);
|
||||||
|
fixture.askSelectStringDialogue.mockImplementation(selectButton(0));
|
||||||
|
|
||||||
|
await expect(checkIncompleteDocuments(fixture.dependencies)).resolves.toBe(true);
|
||||||
|
|
||||||
|
expect(fixture.readHiddenFileBinary).toHaveBeenCalledWith("conflicted.md");
|
||||||
|
expect(fixture.dependencies.keyValueDB.set).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("repairs a recoverable document when FIX is selected", async () => {
|
it("repairs a recoverable document when FIX is selected", async () => {
|
||||||
const recoverable = documentFixture("recoverable.md");
|
const recoverable = documentFixture("recoverable.md");
|
||||||
const fixture = createDependencies(documentsFrom([recoverable]), [recoverable]);
|
const fixture = createDependencies(documentsFrom([recoverable]), [recoverable]);
|
||||||
|
|||||||
Reference in new issue
Block a user