Fall back to fastq-dump for heavily-aligned SRA runs - #342
Conversation
fasterq-dump re-pairs reads from reference-aligned (cSRA) submissions by
building a spot-id lookup over the PRIMARY_ALIGNMENT table and sorting it
externally. That phase does not scale, and on VGP-scale data it does not
finish at all.
Measured on Pseudophryne corroboree (GCA_028390025.1):
accession aligned reads reference fasterq-dump fastq-dump
SRR000001 0 (unaligned) - 3 s 6 s
SRR28349113 54.2M 0.69 Gbp 47 min 88 min
SRR28349114 1,108.7M 8.88 Gbp ~577 h (est.) ~3.3 h (est.)
The cost is not merely proportional to alignment count: the third run has
20x more alignments but is ~90x slower per alignment, so total cost tracks
alignments x f(reference size). Buffer tuning does not recover it -- raising
--curcache/--bufsize/--mem gained at most 1.46x against the ~29x needed.
fastq-dump streams in spot order and builds no lookup, so it is unaffected.
It is also ~2x slower everywhere else, so it must not become the default;
this adds it as a fallback instead.
Output equivalence was verified rather than assumed: given --split-3 and
--skip-technical (fastq-dump's defaults differ from fasterq-dump's on both),
the two produce byte-identical FASTQ. Checked on SRR000001 and on all 307 GB
of SRR28349113 -- 400,318,389 reads per mate, cmp-clean.
Routing:
- Skip fasterq-dump outright only when a run has many alignments AND a
large reference. Both conditions are required because the two axes are
confounded in the only dataset measured, so the shortcut fires only
inside the region actually observed to fail.
- Otherwise run fasterq-dump under a wall-clock budget and fall back if it
expires. The budget cannot mis-classify, which the thresholds can.
- Log SEQ/PRIM/REF/SEC on every download so the thresholds can later be
recalibrated from real data.
A timed-out fasterq-dump leaves a partial FASTQ behind; it is deleted before
the fallback runs, since pigz would otherwise compress a truncated file and
hand silently corrupt reads to fastp.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
prefetch was invoked without -O, so it wrote into the Snakemake working directory: one <accession>/ directory per download in the workflow root, created and removed by jobs running up to 500-wide. The rule bracketed itself with `rm -rf <accession>`, which is safe only while no two jobs touch the same name -- but nothing prevents two sample rows from referencing one accession, and in that case either job's teardown could delete the other's in-flight download or its .sra mid-extraction. Give each job its own directory under resources.tmpdir instead, and remove it with an EXIT trap so it is cleaned up however the job ends, including on a timeout or a cancelled Slurm allocation. The fasterq-dump scratch moves inside it, which drops a second mktemp and its matching cleanup. Extractors now take the .sra path rather than the bare accession, so resolution no longer depends on the working directory. Verified that a full path still resolves a run's sibling reference object -- fastq-dump reconstructs real bases from a cSRA run given an absolute path from an unrelated cwd -- and that both tools name output files from the basename, so downstream globs are unchanged. Exercised end-to-end on SRR000001, both branches: normal budget (fasterq-dump succeeds) and a 1-second budget (forced timeout, partial cleanup, fastq-dump fallback). Both produce the same reads, the working directory is left with no accession directory, and the scratch directory is gone afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Marking draft: the performance comparison in the description is being re-tested. The fastq-dump timings were extrapolated from a partial run and do not account for extraction rate varying with position in the file, so the claimed speedup is not established. The prefetch isolation fix in 5408621 is unaffected and will be split out. |
|
Closing this in favour of a new branch off The performance argument here does not hold. The The replacement routes aligned (cSRA) runs through The job-private download directory from 5408621 is unaffected and carries over to the new branch — it fixes a real bug where concurrent Superseded by #343. |
Problem
download_sracannot extract some reference-aligned (cSRA) accessions at all. On a Pseudophryne corroboree run (GCA_028390025.1, 8.87 Gbp), 11 of 20 accessions burned two 48 h walls and ~2,100 CPU-hours without producing a single FASTQ.The cause is
fasterq-dump's lookup phase. For reference-aligned submissions it re-pairs reads by building a spot-id lookup over the entirePRIMARY_ALIGNMENTtable and sorting it externally. Forensics on the leftover temp dirs show it emitting one 244 MB sorted run every ~2 hours, steadily, for 18.6 h — ~122 MB/h, still in lookup construction, nowhere near done.Measurements
fasterq-dumpfastq-dumpSRR000001SRR28349113SRR28349114The blow-up is not just "more alignments". The third run has 20× more, but is ~90× slower per alignment, so cost tracks
alignments × f(reference size)rather than alignment count alone.fastq-dumpstreams in spot order and builds no lookup, so it is unaffected — but it is ~2× slower everywhere else, so it must not become the default.What was ruled out
--curcache 4G --bufsize 64M --mem 8G): 1.46× at best, against the ~29× needed. Measured head-to-head at 45 min per arm.fasterq-dumpsizes the lookup upfront (~176 GB) and refuses to start withdisk-limit exeeded.sam-dump: viable (~13.8 h) but 4× slower thanfastq-dumpand needscollateto re-pair.fastq_ftp,submitted_ftporsra_ftpat ENA, so the rule's existing ffq fallback could not have helped.Changes
1.
fastq-dumpas a fallback, never the default.SEQ/PRIM/REF/SECon every download, so thresholds can be recalibrated from real data later.fasterq-dumpoutright only when a run has both many alignments and a large reference. Both are required because the two axes are confounded in the only dataset measured — the shortcut fires only inside the region actually observed to fail.fasterq-dumpunder a wall-clock budget (default 6 h) and fall back if it expires. The budget cannot mis-classify, which the thresholds can.fasterq-dumpleaves a partial FASTQ; it is deleted before the fallback runs, sincepigzwould otherwise compress a truncated file and hand silently corrupt reads tofastp.2. Downloads into a job-private directory.
prefetchran without-O, writing one<accession>/dir into the workflow root with jobs running up to 500-wide, and the rule bracketed itself withrm -rf <accession>. If two sample rows reference one accession, either job's teardown can delete the other's in-flight download. Each job now gets its own directory underresources.tmpdir, removed by anEXITtrap so it cleans up on timeout or cancellation too.Verification
--split-3 --skip-technical(both needed —fastq-dump's defaults differ fromfasterq-dump's on each), the two produce byte-identical FASTQ. Confirmed onSRR000001and on all 307 GB ofSRR28349113: 400,318,389 reads per mate,cmp-clean.vdb-dumpoutput for all three shapes, including a flat run wherePRIM/REFlines are absent and the parse degrades safely to 0.SRR000001: normal budget (fasterq-dumpsucceeds) and a 1-second budget (forced timeout → partial cleanup → fallback). Same reads either way; no accession dir left behind; scratch removed..srapath still resolves a run's sibling reference object, and both tools name output from the basename, so downstream globs are unchanged.Notes for reviewers
fasterq_budget_minuteswould force the path and assert parity — worth adding, and I'm happy to.fastq.smkheader comment say so explicitly, and the logging exists so they can be revisited.test_markdupfails on this machine (sambambaon macOS/arm64), identically on an unmodified tree — pre-existing, unrelated.🤖 Generated with Claude Code