Par2 merge: a set held by many releases, or a merge far larger than its set, isn't one upload
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Successful in 1m34s

Every kantodoNNN.bin test upload carries the same par2 set: 64 releases held
it nearby and became one release of 631 files for a set of 10. A set held by
more than 4 releases nearby isn't merged, nor members with more than 3x the
set's files plus 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-12 22:29:48 +02:00
1 parent c72bf68fd2
commit 942c4901fa
2 files changed
+32 -1

No files matched your search

+14 -1
View File
@@ -5,6 +5,14 @@ import { looksRandom } from '#lib/release/random'
/** Releases of a set further apart than this (posted) aren't one upload: a repost is merged separately (decision d). */
const MAX_SPREAD_MS = 48 * 3600 * 1000
/**
* A set held by more releases nearby than this is one posted again and again, not one upload's par2 (every
* "kantodoNNN.bin" test upload carries the same set: 64 releases became one of 631 files; LOG.md 2026-10-12 (30)).
*/
const MAX_HOLDERS = 4
/** Members with more files than this many times the set's, plus SLACK_FILES (its par2 volumes), are more than one upload. */
const MAX_FILES_PER_SET_FILE = 3
const SLACK_FILES = 10
/** Between rounds. */
const ROUND_MS = 60_000
/** A round looks back this far past the previous one's start (rows committed while it ran). */
@@ -113,14 +121,19 @@ export class Par2Merger {
releases.set(String(m.id), m)
byFile.set(m.file_id, releases)
}
const nearHolders = holders.filter(near)
if (nearHolders.length > MAX_HOLDERS) return 0
const found = new Map<string, Member>()
for (const r of holders.filter(near)) found.set(String(r.id), r)
for (const r of nearHolders) found.set(String(r.id), r)
for (const releases of byFile.values()) if (releases.size === 1) for (const [id, r] of releases) found.set(id, r)
if (found.size < 2) return 0
// Locked in id order (the batch store and other rounds take the same rows).
const { rows: locked } = await trx.rawQuery(`SELECT id FROM releases WHERE id = ANY(?) ORDER BY id FOR UPDATE`, [[...found.keys()]])
const members: Member[] = locked.map((r: { id: string }) => found.get(String(r.id))!)
if (members.length < 2) return 0
const { rows: described } = await trx.rawQuery(`SELECT count(*) AS n FROM par2_files WHERE set_id = ?`, [setId])
const setFiles = Math.max(Number(described[0].n), 1)
if (members.reduce((n, m) => n + Number(m.files), 0) > MAX_FILES_PER_SET_FILE * setFiles + SLACK_FILES) return 0
const target = members.reduce((a, b) => (Number(b.files) > Number(a.files) ? b : a))
const others = members.filter((m) => m.id !== target.id).map((m) => Number(m.id))
const name = members.every((m) => !m.readable) ? await this.setName(trx, setId) : undefined