Par2 merge: a set held by two merged releases; one failed set doesn't stop a round
A par2 index and its repost both hold a set: moving both rows to the target broke par2_sets' primary key, and the round failed on it every minute from 20:28 UTC (no merges at all). Duplicates among the others go first; a set that fails is logged and the round goes on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b99cfdb0e
commit
c72bf68fd2
2 files changed
+36
-3
No files matched your search
@@ -72,7 +72,11 @@ export class Par2Merger {
|
||||
const round: MergeRound = { sets: rows.length, merges: 0, releases: 0 }
|
||||
for (const { set_id: setId } of rows) {
|
||||
if (this.stopped) return round
|
||||
const merged = await this.mergeSet(setId.trim())
|
||||
// One set that fails doesn't hold up the others (nor the next round, which would start from the same point).
|
||||
const merged = await this.mergeSet(setId.trim()).catch((error) => {
|
||||
logger.error(`Par2 merge of set ${setId.trim()} failed: ${error.message}`)
|
||||
return 0
|
||||
})
|
||||
if (merged > 0) {
|
||||
round.merges++
|
||||
round.releases += merged + 1
|
||||
@@ -129,8 +133,14 @@ export class Par2Merger {
|
||||
for (const table of ['release_chunks', 'probe_candidates', 'release_inspections', 'file_hashes']) {
|
||||
await trx.rawQuery(`UPDATE ${table} SET release_id = ? WHERE release_id = ANY(?)`, [target.id, others])
|
||||
}
|
||||
// A set held by the target already isn't held twice.
|
||||
await trx.rawQuery(`DELETE FROM par2_sets WHERE release_id = ANY(?) AND set_id IN (SELECT set_id FROM par2_sets WHERE release_id = ?)`, [others, target.id])
|
||||
// A set held by the target already, or by two of the others (a par2 and its repost), isn't held twice (every
|
||||
// round failed on the primary key from 20:28 UTC on 2026-10-12; LOG.md 2026-10-12 (30)).
|
||||
await trx.rawQuery(
|
||||
`DELETE FROM par2_sets p WHERE p.release_id = ANY(?)
|
||||
AND (EXISTS (SELECT 1 FROM par2_sets t WHERE t.set_id = p.set_id AND t.release_id = ?)
|
||||
OR EXISTS (SELECT 1 FROM par2_sets o WHERE o.set_id = p.set_id AND o.release_id = ANY(?) AND o.release_id < p.release_id))`,
|
||||
[others, target.id, others]
|
||||
)
|
||||
await trx.rawQuery(`UPDATE par2_sets SET release_id = ? WHERE release_id = ANY(?)`, [target.id, others])
|
||||
await trx.rawQuery(
|
||||
`UPDATE releases t SET
|
||||
|
||||
@@ -63,6 +63,29 @@ test.group('Par2Merger', (group) => {
|
||||
assert.deepEqual(await new Par2Merger().round().then((r) => r.merges), 0)
|
||||
})
|
||||
|
||||
test('a set held by two of the releases merged is held once by the target', async ({ assert }) => {
|
||||
const at = new Date('2022-07-08T03:46:00Z')
|
||||
const ids: number[] = []
|
||||
for (const [key, files] of [['bb000001', 1], ['bb000002', 1], ['bb000003', 3]] as const) {
|
||||
const [row] = await db
|
||||
.table('releases')
|
||||
.insert({ release_key: key.padEnd(40, '0'), identity_key: key.padEnd(40, '0'), name: key, source: 'stem', groups: '[]', group_id: 1, files, posted_at: at, readable: false })
|
||||
.returning('id')
|
||||
ids.push(Number(row.id))
|
||||
}
|
||||
const setId = hash('7')
|
||||
// The par2 index and its repost each hold the set; the third release holds the data file.
|
||||
await db.table('par2_sets').multiInsert([
|
||||
{ set_id: setId, release_id: ids[0], files: 1 },
|
||||
{ set_id: setId, release_id: ids[1], files: 1 },
|
||||
])
|
||||
await db.table('par2_files').insert({ set_id: setId, file_id: hash('6'), hash16k: hash('5'), length: 1000, name: 'x.rar' })
|
||||
await db.table('file_hashes').insert({ candidate_id: 3001, release_id: ids[2], hash16k: hash('5'), size: 1000 })
|
||||
assert.equal(await new Par2Merger().mergeSet(setId), 2)
|
||||
const held = await db.from('par2_sets').where('set_id', setId).select('release_id')
|
||||
assert.deepEqual(held.map((r) => Number(r.release_id)), [ids[2]])
|
||||
})
|
||||
|
||||
test('a set file that matches several releases nearby is ambiguous: not merged', async ({ assert }) => {
|
||||
const at = new Date('2022-07-08T03:46:00Z')
|
||||
const ids: number[] = []
|
||||
|
||||
Reference in new issue
Block a user