mercury-agent 0.18.1 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
newId,
|
|
27
27
|
readLines,
|
|
28
28
|
} from "./manifest.js";
|
|
29
|
+
import { readPending } from "./queue.js";
|
|
29
30
|
|
|
30
31
|
export interface GcLog {
|
|
31
32
|
info: (msg: string, meta?: unknown) => void;
|
|
@@ -172,6 +173,22 @@ export async function reconcileSpace(
|
|
|
172
173
|
live.map((l) => l.sha256).filter((h): h is string => typeof h === "string"),
|
|
173
174
|
);
|
|
174
175
|
|
|
176
|
+
// Spooled records count as wanted even though no manifest line names them
|
|
177
|
+
// yet. `drainSpace` uploads the bytes first and appends the line after, so
|
|
178
|
+
// between those two awaits the hash is on the backend and absent from the
|
|
179
|
+
// manifest — indistinguishable, from here, from an orphan. Deleting then
|
|
180
|
+
// leaves a live line whose bytes are gone, which is the one state this
|
|
181
|
+
// module can report and never repair. The window is a whole `put` (a Drive
|
|
182
|
+
// upload), and both jobs fire together on every startup: `jobs.ts` runs each
|
|
183
|
+
// interval job immediately, so drain and reconcile overlap exactly when the
|
|
184
|
+
// spool is non-empty — after a crash or a backend outage.
|
|
185
|
+
//
|
|
186
|
+
// This also covers a record backing off after a crash between `put` and the
|
|
187
|
+
// append: its bytes must survive until the retry records them.
|
|
188
|
+
for (const record of readPending(dataDir, spaceId)) {
|
|
189
|
+
wanted.add(record.sha256);
|
|
190
|
+
}
|
|
191
|
+
|
|
175
192
|
let stored: Array<{ sha256: string; ref?: string }>;
|
|
176
193
|
try {
|
|
177
194
|
stored = await backend.list(spaceId);
|
|
@@ -190,6 +207,11 @@ export async function reconcileSpace(
|
|
|
190
207
|
|
|
191
208
|
for (const object of stored) {
|
|
192
209
|
if (wanted.has(object.sha256)) continue;
|
|
210
|
+
// Claim the hash like `collectHash` does, so a drain that resolves its
|
|
211
|
+
// `put` while this sweep runs observes the same protocol rather than
|
|
212
|
+
// racing a bare delete. The set above already spares spooled hashes; this
|
|
213
|
+
// closes the record that appears mid-listing.
|
|
214
|
+
if (!beginDelete(spaceId, object.sha256)) continue;
|
|
193
215
|
try {
|
|
194
216
|
await backend.delete(spaceId, object.sha256, object.ref);
|
|
195
217
|
result.orphansDeleted++;
|
|
@@ -199,6 +221,8 @@ export async function reconcileSpace(
|
|
|
199
221
|
err instanceof Error ? err.message : String(err)
|
|
200
222
|
}`,
|
|
201
223
|
);
|
|
224
|
+
} finally {
|
|
225
|
+
endDelete(spaceId, object.sha256);
|
|
202
226
|
}
|
|
203
227
|
}
|
|
204
228
|
|