Rebuild: first end-to-end runs; prefetch per chunk, executable rule, wire fixes
End to end on the workstation (coordinator:run, the API, edge:node, real NNTP): a.b.e-book.french and a.b.cd.image.playstation2.dvdiso ranges. - Prefetcher: every connection takes the next missing chunk (leased ranges first, in order); one connection per range (~26k lines/s) kept the worker waiting - executable rule: releases of bare executables (malware floods named after films and software) are dropped; they were 92% of the catalog rows of the test ranges, 21% of the segments - fragments per file (details once) and gzipped batch bodies; the JSON limit (1 MB by default) raised to 256 MB, empty strings kept (a rule count's key is '') - release_chunks.batch_from is a bigint (boneless article numbers) - tests get their own database; edge:bench --store times BatchStore: 1.3 s for a boneless range (1.24 ms per release chunk) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d5f168d8d2
commit
cd06f96f85
15 files changed
+201
-99
No files matched your search
+12
-6
@@ -1,7 +1,7 @@
|
||||
import { BaseCommand, flags } from '@adonisjs/core/ace'
|
||||
import type { CommandOptions } from '@adonisjs/core/types/ace'
|
||||
import { setTimeout as sleep } from 'node:timers/promises'
|
||||
import { unzipSync } from 'node:zlib'
|
||||
import { gzipSync, unzipSync } from 'node:zlib'
|
||||
import { parseOverviews } from '#lib/nntp/index'
|
||||
import { RangeIndexer, decodeFrames, toWire, type EdgeBatch, type Lease } from '#lib/edge/index'
|
||||
|
||||
@@ -68,10 +68,13 @@ export default class EdgeNode extends BaseCommand {
|
||||
const { range, rules } = lease
|
||||
const started = Date.now()
|
||||
const indexer = new RangeIndexer({ group: range.group, start: range.start, end: range.end, rules })
|
||||
const totals = { headers: 0, releases: 0, candidates: 0 }
|
||||
const totals = { headers: 0, releases: 0, candidates: 0, bytes: 0, postMs: 0 }
|
||||
let chunks = 0
|
||||
const post = async (batch: EdgeBatch) => {
|
||||
const at = Date.now()
|
||||
const stored = await api.batch(range.id, batch)
|
||||
totals.postMs += Date.now() - at
|
||||
totals.bytes += stored.bytes
|
||||
totals.headers += batch.headers
|
||||
totals.releases += stored.releases
|
||||
totals.candidates += stored.candidates
|
||||
@@ -94,7 +97,8 @@ export default class EdgeNode extends BaseCommand {
|
||||
const seconds = (Date.now() - started) / 1000
|
||||
this.logger.info(
|
||||
`${range.group} ${range.start}–${range.end}: ${totals.headers.toLocaleString('en')} headers in ${seconds.toFixed(0)} s ` +
|
||||
`(${Math.round(totals.headers / seconds).toLocaleString('en')}/s), ${totals.releases} release chunks, ${totals.candidates} probe candidates.`
|
||||
`(${Math.round(totals.headers / seconds).toLocaleString('en')}/s), ${totals.releases} release chunks, ${totals.candidates} probe candidates; ` +
|
||||
`posted ${(totals.bytes / 1e6).toFixed(1)} MB in ${(totals.postMs / 1000).toFixed(1)} s.`
|
||||
)
|
||||
} catch (error: any) {
|
||||
if (error instanceof LeaseLost) {
|
||||
@@ -144,10 +148,12 @@ class Api {
|
||||
return response.body as unknown as AsyncIterable<Uint8Array>
|
||||
}
|
||||
|
||||
async batch(rangeId: number, batch: EdgeBatch): Promise<{ releases: number; candidates: number }> {
|
||||
const response = await this.request(`ranges/${rangeId}/batches`, { method: 'POST', body: JSON.stringify(toWire(batch)) })
|
||||
async batch(rangeId: number, batch: EdgeBatch): Promise<{ releases: number; candidates: number; bytes: number }> {
|
||||
// Gzipped: chunk payloads are compressed already, the rest (names, fragments, candidates) compresses well.
|
||||
const body = gzipSync(JSON.stringify(toWire(batch)), { level: 1 })
|
||||
const response = await this.request(`ranges/${rangeId}/batches`, { method: 'POST', body, headers: { 'Content-Encoding': 'gzip' } })
|
||||
if (!response.ok) throw new Error(`batch: HTTP ${response.status}`)
|
||||
return response.json() as Promise<{ releases: number; candidates: number }>
|
||||
return { ...((await response.json()) as { releases: number; candidates: number }), bytes: body.length }
|
||||
}
|
||||
|
||||
async call(rangeId: number, action: 'finish' | 'release' | 'heartbeat') {
|
||||
|
||||
Reference in new issue
Block a user