Skip to content

pit: claim a pasted list in batches, not one round trip at a time - #146

Merged
ralyodio merged 1 commit into
mainfrom
perf/bulk-claim-batch
Jul 31, 2026
Merged

pit: claim a pasted list in batches, not one round trip at a time#146
ralyodio merged 1 commit into
mainfrom
perf/bulk-claim-batch

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Two real pastes, both truncated:

claimed 195 …  389 not attempted
claimed  25 …  234 not attempted   (54 already yours)

Not an API limit, and not the database being slow. This code was asking six or seven questions per ending: insert, log, read the row back, then read-check-write for the price. At ~60ms a round trip that's ~370ms each, and the 20s budget bought about 50 of them.

Batched

  • One INSERT OR IGNORE batch per chunk. rowsAffected per statement is exactly the claimed/taken split — no SELECT per ending.
  • The ones that collided get a single IN query to find out whether they're already yours or someone else's.
  • Price and alias fold into one UPDATE instead of the read-check-write setTldPrice does — ownership was just established by the insert above, so re-reading the row asks a question already answered.
  • Validation happens in memory first. A reserved or malformed ending never needed a round trip to be refused.

INSERT OR IGNORE can't fail on a name someone already holds, so a write-mode batch never rolls back on a collision — that's the property that makes one transaction safe for a list where some entries are expected to lose.

Result

300 endings in ~150ms, down from 54 in 20 seconds.

The time budget is gone — there's nothing left for it to ration, and remaining is always empty. The chunk size that replaced it bounds request size, not throughput.

Tests

The budget tests covered behaviour that no longer exists; in their place is the paste that used to fail — 300 endings, none left over, inside what used to be the whole budget. Plus chunk-boundary double-counting, and claimed / already-yours / someone-else's still told apart.

264/264 pwa suite.

🤖 Generated with Claude Code

A 313-ending paste stopped after 54 with "259 not attempted". That was not an
API limit and not the database being slow — it was this code asking six or
seven questions per ending: insert, log, read the row back, then read-check-
write for the price. At ~60ms a trip that is ~370ms an ending, and the 20s
budget bought 54 of them.

Batched instead. One `INSERT OR IGNORE` batch per chunk, and `rowsAffected`
per statement says which landed — that is exactly the claimed/taken split
without a SELECT each. The ones that collided get a single IN query to find
out whether they are already yours or someone else's. Price and alias fold
into one UPDATE rather than the read-check-write setTldPrice does, because
ownership was just established by the insert above and re-reading the row asks
a question already answered.

Validation happens in memory first. A reserved or malformed ending never
needed a round trip to be refused.

300 endings now land in ~150ms, so the time budget is gone — there is nothing
left for it to ration, and `remaining` is always empty. The chunk size that
replaced it bounds request size, not throughput.

`INSERT OR IGNORE` cannot fail on a name someone already holds, so a batch in
write mode never rolls back on a collision — which is the property that makes
one transaction safe for a list where some entries are expected to lose.

Tests replaced accordingly: the budget ones tested behaviour that no longer
exists, and in their place is the paste that used to fail — 300 endings, none
left over, inside what used to be the whole budget. Chunk boundaries are
tested for double-counting, and claimed / already-yours / someone-else's are
still told apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit cc72de9 into main Jul 31, 2026
3 checks passed
@ralyodio
ralyodio deleted the perf/bulk-claim-batch branch July 31, 2026 11:24
@ralyodio ralyodio mentioned this pull request Jul 31, 2026
ralyodio added a commit that referenced this pull request Jul 31, 2026
* chore(release): v0.13.3

install.sh resolves releases/latest, so everything merged since v0.13.2 has
been sitting on main unreachable — `moshcode dns enable` exists in the source
and not in anyone's binary.

The headline is the DNS bridge (#141). Moshpit names now resolve for every
program on the machine, not just inside TronBrowser: each OS gets the mechanism
that routes ONE SUFFIX rather than the one that replaces the resolver —
/etc/resolver on macOS, systemd-resolved routing-only domains or dnsmasq on
Linux, an NRPT rule per namespace on Windows.

  moshcode dns enable / disable / status
  moshcode uninstall <engine|tool>          (#150, completion in #151)

The pit gained most of a namespace registry in between: key pins per name
(#137), pasted bulk claiming with per-line price and target (#138, #142, #143,
#146), all-numeric endings (#147), /n/<name> serving a name or a directory
(#145, #149), and Buy Now on an unclaimed name (#148).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: restore the em-dash the version bump escaped

The bump rewrote package.json through a JSON serialiser that defaults to ASCII,
turning the em-dash in `description` into —. Valid JSON and the same string
once parsed, but a gratuitous diff in a commit that should touch one line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant