1 Commits
Author SHA1 Message Date
sneak 8e06cd5723 quak files COLLECTION fetches that collection's files alone (closes #217)
check / check (push) Canceled after 0s
`quak files COLLECTION` used to wait for a full refresh, which on an
empty cache fetched the files of every collection before it listed one.
It now reads the collection list, then calls the new
`Library.refreshCollection()`, which brings that one collection up to
date in the store as a refresh would, and saves it. It sends no request
for the files when the stored copy is current. It leaves the refresh
cursor alone, so the next refresh still fetches every other collection
that changed. `refreshOnce` and `refreshCollection` share the commit
step. `quak files` with no argument still waits for a refresh.

Model: opus-5-5
2026-10-25 23:24:16 +00:00
2 changed files with 4 additions and 55 deletions
+3 -6
View File
@@ -645,10 +645,6 @@ export class Library {
collectionKey: collection.key,
sinceTime: known ? known.updationTime : 0,
});
// A refresh that ran during the fetch may have stored a copy as new as
// `collection` or newer. Committing this result would replace it.
const stored = this.store.getCollection(collection.id);
if (stored && collection.updationTime <= stored.updationTime) return;
// The stored cursor stays where it is, so the next refresh still
// fetches the files of every other collection that changed.
await this.commit(
@@ -840,8 +836,9 @@ export class Library {
// Commit a collections page and the file pages fetched for its collections
// to the store, then save. A collection or file that does not decrypt is
// left out, as if deleted, with the reason kept in the store, and no later
// refresh sees it again until the server's copy changes.
// left out, as if deleted, with the reason kept in the store: the cursor
// moves past it, so no later refresh sees it again until the server's copy
// changes.
private async commit(
page: CollectionsPage,
filePages: { collectionID: number; page: FilesPage }[],
+1 -49
View File
@@ -19,8 +19,7 @@
* fetches the files of every collection (issue #210).
* 5. `refreshCollection()` brings one collection up to date in the store and
* leaves the stored cursor where it was, so the next refresh still fetches
* the files of every other collection that changed (issue #217). A newer
* copy that a refresh stores while it fetches the files is kept.
* the files of every other collection that changed (issue #217).
*
* The client is the same metadata-only mock the background-refresh tests use:
* no crypto, no network, scripted pages, and a record of each call. A long
@@ -425,51 +424,4 @@ describe("Library.refreshCollection", () => {
await lib.close();
}
});
// Collection 1 is stored at 100. `refreshCollection()` asks for it at 110,
// which adds file 1002. While that files request waits, a refresh stores
// it at 120, where 1002 is deleted again and 1003 added.
it("keeps a newer copy that a refresh stores while the files are fetched", async () => {
const { client, lib } = await openSeeded(cacheDirectory);
let release!: () => void;
const held = new Promise<void>((r) => (release = r));
try {
client.filesFor(
1,
{ files: [file(1002, 1, 110)], deleted: [], cursor: 110 },
{ files: [file(1003, 1, 120)], deleted: [1002], cursor: 120 },
);
client.collectionsQueue.push({
collections: [collection(1, 120)],
deleted: [],
cursor: 120,
});
// Hold the next files request, refreshCollection's, until the
// test releases it. The refresh's request after it is answered
// at once.
let fetchStarted!: () => void;
const started = new Promise<void>((r) => (fetchStarted = r));
const realFilesSince = client.filesSince.bind(client);
client.filesSince = async (args) => {
client.filesSince = realFilesSince;
const page = await realFilesSince(args);
fetchStarted();
await held;
return page;
};
const refreshing = lib.refreshCollection(collection(1, 110));
await started;
await lib.fresh();
release();
await refreshing;
expect(lib.getCollection(1)?.updationTime).toBe(120);
expect(lib.listFiles(1).map((f) => f.id)).toEqual([1001, 1003]);
} finally {
release();
await lib.close();
}
});
});