mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-25 22:12:59 +00:00
Protect conflict chunks during garbage collection
This commit is contained in:
@@ -5,7 +5,6 @@ import {
|
||||
LOG_LEVEL_NOTICE,
|
||||
LOG_LEVEL_VERBOSE,
|
||||
REMOTE_COUCHDB,
|
||||
REMOTE_P2P,
|
||||
type DocumentID,
|
||||
type EntryDoc,
|
||||
type EntryLeaf,
|
||||
@@ -53,8 +52,7 @@ export class LocalDatabaseMaintenance extends LiveSyncCommands {
|
||||
name: "Garbage Collection V3 (advanced, beta)",
|
||||
icon: "trash-2",
|
||||
checkCallback: (checking) => {
|
||||
const isApplicableRemote =
|
||||
this.settings.remoteType === REMOTE_COUCHDB || this.settings.remoteType === REMOTE_P2P;
|
||||
const isApplicableRemote = this.settings.remoteType === REMOTE_COUCHDB;
|
||||
if (!this.settings.useEdgeCaseMode || !this._isDatabaseReady() || !isApplicableRemote) {
|
||||
return false;
|
||||
}
|
||||
@@ -464,7 +462,7 @@ Note: **Make sure to synchronise all devices before deletion.**
|
||||
const confirmMessage = `This function deletes unused chunks from the device. If there are differences between devices, some chunks may be missing when resolving conflicts.
|
||||
Be sure to synchronise before executing.
|
||||
|
||||
However, if you have deleted them, you may be able to recover them by performing Hatch -> Recreate missing chunks for all files.
|
||||
If chunks used by current Vault files are deleted, Hatch -> Recreate chunks for current Vault files can recreate them only from files currently present in the Vault. It cannot recover unreadable historical or conflict content.
|
||||
|
||||
Are you ready to delete unused chunks?`;
|
||||
|
||||
@@ -926,41 +924,22 @@ This may indicate that some devices have not completed synchronisation, which co
|
||||
const gcStartTime = Date.now();
|
||||
// Perform Garbage Collection (new implementation).
|
||||
const localDatabase = this.localDatabase.localDatabase;
|
||||
const usedChunks = new Set<DocumentID>();
|
||||
const allChunks = new Map<DocumentID, string>();
|
||||
|
||||
const IDs = this.localDatabase.findEntryNames("", "", {});
|
||||
let i = 0;
|
||||
const doc_count = (await localDatabase.info()).doc_count;
|
||||
for await (const id of IDs) {
|
||||
const doc = await this.localDatabase.getRaw(id as DocumentID);
|
||||
i++;
|
||||
if (i % 100 == 0) {
|
||||
this._notice(`Garbage Collection: Scanned ${i} / ~${doc_count} `, "gc-scanning");
|
||||
}
|
||||
if (!doc) continue;
|
||||
if ("children" in doc) {
|
||||
const children = (doc.children || []) as DocumentID[];
|
||||
for (const chunkId of children) {
|
||||
usedChunks.add(chunkId);
|
||||
}
|
||||
} else if (doc.type === EntryTypes.CHUNK) {
|
||||
allChunks.set(doc._id, doc._rev);
|
||||
}
|
||||
}
|
||||
// Use the revision-aware reachability scan. Reading only winning revisions
|
||||
// would make chunks used exclusively by live conflict branches look unused.
|
||||
const { used: usedChunks, existing: allChunks } = await this.localDatabase.allChunks();
|
||||
this._notice(
|
||||
`Garbage Collection: Scanning completed. Total chunks: ${allChunks.size}, Used chunks: ${usedChunks.size}`,
|
||||
"gc-scanning"
|
||||
);
|
||||
|
||||
const unusedChunks = [...allChunks.keys()].filter((e) => !usedChunks.has(e));
|
||||
const unusedChunks = [...allChunks.entries()].filter(([chunkId]) => !usedChunks.has(chunkId));
|
||||
this._notice(`Garbage Collection: Found ${unusedChunks.length} unused chunks to delete.`, "gc-scanning");
|
||||
const deleteChunkDocs = unusedChunks.map(
|
||||
(chunkId) =>
|
||||
([chunkId, chunk]) =>
|
||||
({
|
||||
_id: chunkId,
|
||||
_id: chunkId as DocumentID,
|
||||
_deleted: true,
|
||||
_rev: allChunks.get(chunkId),
|
||||
_rev: chunk._rev,
|
||||
}) as EntryLeaf
|
||||
);
|
||||
const response = await localDatabase.bulkDocs(deleteChunkDocs);
|
||||
|
||||
Reference in New Issue
Block a user