updb sliced across Durable Object invocations: the plan, the cursor and the contract that
makes a half-applied update impossible to produce silently.
No clock works here (microtime() reads 0, Date.now() is frozen in a synchronous run), so
no loop is clock-driven and every budget decision is a pre-check. The object hibernates after
~10 s idle and drops the interpreter. drupal_flush_all_caches() (282.9 ms) is split into the
eleven units core names (UPDB_FLUSH_STEPS).
The chain is maintenance-fenced and two-beat: a claim beat commits in its own event, then a run
beat enters PHP, because DO SQLite commits at each event's end and a marker written in the
event that enters PHP dies with it. snapshot copies only update bookkeeping, so whole-site
rollback is the R2 export (requireExport can demand it). Copy-and-swap was rejected: a
written row per row, no table prefixes in the driver, and DDL dirties sqlite_master.
Crash detection is a single-use in-memory token. A unit found claimed with no token halts
the run (unit-unverifiable, maintenance left on): fail closed, with one false positive if
the object is evicted between beats. Whether a killed event's writes are discarded is
unmeasured, so retryPolicy: "core" is opt-in. A cold interpreter is refused
(cold-interpreter, bounded by maxColdWaits) only for a caller passing phpReady.
Preconditions are checked in JS before PHP, so a refusal costs ~0 ms: the run's code_id (a
deploy can swap the pack under a live cursor), maintenance still on, expect_schema, a
post-update not already recorded, and the cursor unit's state. An unparseable value reads
null and refuses (unknown beats incorrect).
updbsliced across Durable Object invocations: the plan, the cursor and the contract that makes a half-applied update impossible to produce silently.No clock works here (
microtime()reads 0,Date.now()is frozen in a synchronous run), so no loop is clock-driven and every budget decision is a pre-check. The object hibernates after ~10 s idle and drops the interpreter.drupal_flush_all_caches()(282.9 ms) is split into the eleven units core names (UPDB_FLUSH_STEPS).The chain is maintenance-fenced and two-beat: a claim beat commits in its own event, then a run beat enters PHP, because DO SQLite commits at each event's end and a marker written in the event that enters PHP dies with it.
snapshotcopies only update bookkeeping, so whole-site rollback is the R2 export (requireExportcan demand it). Copy-and-swap was rejected: a written row per row, no table prefixes in the driver, and DDL dirtiessqlite_master.Crash detection is a single-use in-memory token. A unit found
claimedwith no token halts the run (unit-unverifiable, maintenance left on): fail closed, with one false positive if the object is evicted between beats. Whether a killed event's writes are discarded is unmeasured, soretryPolicy: "core"is opt-in. A cold interpreter is refused (cold-interpreter, bounded bymaxColdWaits) only for a caller passingphpReady.Preconditions are checked in JS before PHP, so a refusal costs ~0 ms: the run's
code_id(a deploy can swap the pack under a live cursor), maintenance still on,expect_schema, a post-update not already recorded, and the cursor unit's state. An unparseable value readsnulland refuses (unknown beats incorrect).