@../stardust-alpha-2610171653 new stardust release. give me an overview of changes in the abi and in the rust sdk
changes from alpha-2610112101 to alpha-2610171653 (released 2026-10-17). releases
set_notify shipped, close to the
proposal.
rust subscriptions are now async only.
typedef void (*stardust_db_subscription_notify)(void *ctx);
uint32_t stardust_db_subscription_set_notify(
stardust_db_subscription *sub,
stardust_db_subscription_notify notify,
void *ctx);- registration: as proposed.
set_notifyMUST be called once, before the firstnext.- a second or late call returns
INVALID_ARGUMENT. - any
nextcounts as the first, including one that failed. ctxmay beNULL.- a failed call has no side effects.
- arming: after registering, check with
next(0).TIMEOUTarms one notify. changes that arrive before it fires are merged into it. - timing:
notifycan run on any thread, before the armingnext(0)returns. - notify: must not call stardust "or run application code, directly or indirectly". the proposal only ruled out blocking and stardust calls.
- ownership: "keep callback code and caller-owned context valid until
release returns. after release returns, no callback is running or can
run again." this covers
ctxand the code the function pointer names. - release: now also waits for "admitted callbacks".
- not proposed: in callback mode,
next(0)hands query evaluation to shared workers.
pub async fn next(&mut self) -> Result<Option<Event>>;
// was: fn next(&self, Duration)
pub fn canceller(&self) -> Canceller;
// Clone, may outlive the Subscription
impl Events<'_> { pub async fn next(&mut self) -> Option<Result<Event>> }
// no longer an Iteratorthis is the proposal's public api. any executor works. the main change is underneath: wakes go through one shared thread, described below.
stardust forbids notify from running application code. waking a task
means calling its Waker, which is the executor's code and can do
anything. so notify can't wake the task itself. it hands off to one
thread, stardust-wake, shared by every subscription in the process.
what happens during sub.next().await:
nextsaves the task'sWakerin the subscription'sSignal.nextasks stardust for an event without waiting (next(0)). if one is ready, it returns it. if not, stardust armsnotifyand the future returnsPending. the task is parked. no thread is blocked.- a commit changes the query's result. stardust calls
notify. notifypushes theSignalonto a queue and returns.stardust-wakepops theSignaland calls its savedWaker.- the executor polls the task.
nextrepeats step 2 and gets the event.
step 1 comes before step 2 because notify can run as soon as step 2 arms
it, even before step 2 returns. the Waker is already saved, so that wake
isn't lost.
the queue:
- has one slot per subscription, up to 1024 per cpu, reserved up front,
so
notifynever allocates. - holds each
Signalat most once. repeat notifies before the thread gets to it are merged. - when every slot is taken,
subscribefails withLOCKED. a slot is freed when the subscription and its cancellers are dropped.
the thread:
- starts with the first subscription and exits after the last one is dropped.
- calls wakers outside all locks and catches their panics.
ctx points at the Signal, which holds no native handle, so a callback
can never drop the last owner and re-enter release.