Skip to content

makedb: add --append to extend an existing database - #991

Merged
bbuchfink merged 2 commits into
bbuchfink:masterfrom
gerontec:makedb-append
Oct 21, 2026
Merged

bbuchfink merged 2 commits into
bbuchfink:masterfrom
gerontec:makedb-append

Conversation

@gerontec

Copy link
Copy Markdown
Contributor

Follow-up to discussion #990.

Rebuilding a large database from scratch to add one day of new sequences is expensive: for NCBI nr a full makedb run takes hours, while a daily delta is a few hundred thousand sequences. This PR adds makedb --append and one prerequisite change.

Commits

1. makedb: write the sequence offset table to disk while building

The offset table (16 bytes per sequence) was collected in a std::vector and written only at the end of the build. For nr (1.15 billion sequences) the vector reallocated at 2^30 entries and needed about 51 GB at that moment, so the build was OOM-killed on a 64 GB machine. The table is append-only during the build and read back once, sequentially, so it is now buffered (2^20 entries) and streamed to <database>.pos_tmp, then appended to the database. File format and entry order are unchanged.

2. makedb: add --append to add sequences to an existing database

--append reads the header of the existing database, truncates the file at pos_array_offset and continues writing sequences there. When the trailer is written, the old offset table is copied back first and the new entries follow; the same is done for the taxon id lists, and TaxonList::build() is called for the newly added sequences only.

Everything from pos_array_offset to EOF is copied to <database>.append_backup before truncating. If the append fails at any point, or if a backup from an earlier interrupted run exists, the database is restored to its previous state.

The taxonomy options must match the original build: --taxonmap if and only if the database contains taxon id lists, likewise --taxonnodes / --taxonnames. Protein databases only.

Verification

Rebased onto current master (ef05efd), built with -DCMAKE_BUILD_TYPE=Release.

  • 2.5 M sequence subset of nr: makedb over all sequences vs. makedb over the first 2.0 M + makedb --append with the remaining 0.5 M → byte-identical .dmnd, including the database hash.
  • 71,699 sequences, split 57,359 + 14,340, on the rebased branch:
    • without taxonomy: byte-identical (md5 1e0eb07f… for both)
    • with --taxonmap/--taxonnodes/--taxonnames: byte-identical (md5 f66d595c… for both)
    • --append without --taxonmap on a database that has taxon lists: rejected with an error, database unchanged, no leftover files.
  • Commit 1 alone: .dmnd byte-identical to the unpatched makedb.
  • In production since 23.09.2026 on a full nr database (1.156 billion sequences, 489 GB): daily GenBank/RefSeq deltas appended in ~2 min instead of a multi-hour rebuild.

🤖 Generated with Claude Code

gerontec2 and others added 2 commits September 30, 2026 15:15
The offset table (16 bytes per sequence) was collected in a std::vector and
written out only at the end of the build. For NCBI nr (1.15 billion sequences)
the vector reallocated at 2^30 entries and needed about 51 GB at that moment,
so the build was killed by the OOM killer on a 64 GB machine.

During the build the table is append-only, and it is read back exactly once,
sequentially, when the trailer is written - so it does not have to be in
memory. PosSpill buffers 2^20 entries and streams them to <database>.pos_tmp;
copy_to() appends that file to the database and removes it, discard() removes
it when the build fails. Format and order of the entries are unchanged.

Verified on a 2.5 million sequence subset of nr: the resulting .dmnd is
byte-identical to the one produced by the unpatched makedb.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rebuilding a large database from scratch in order to add one day of new
sequences is expensive: for NCBI nr a full makedb run takes hours, while the
daily delta is a few hundred thousand sequences.

--append reads the header of the existing database, truncates the file at
pos_array_offset and continues writing sequences there. When the trailer is
written, the old offset table is copied back first and the new entries follow;
the same is done for the taxon id lists, and TaxonList::build() is called with
the number of newly added sequences only.

Everything from pos_array_offset to EOF is copied to <database>.append_backup
before the database is truncated. If the append fails at any point, or if the
backup file already exists from an earlier interrupted run, the database is
restored to its previous state.

The taxonomy options have to be used exactly as in the original build:
--taxonmap if and only if the database contains taxon id lists, and likewise
for --taxonnodes and --taxonnames. Protein databases only.

Verified on a 2.5 million sequence subset of nr: building it in two steps with
--append yields a .dmnd that is byte-identical to the single-step build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gerontec

gerontec commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

see flowchart to better understand how it works: https://github.com/gerontec/blastDiamond/blob/main/doc/append_workflow.pdf

@bbuchfink
bbuchfink merged commit d843858 into bbuchfink:master Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants