entangle-batches-2
Simon Holthausen 5 days ago
parent b96a3dad45
commit 451679a412
No known key found for this signature in database

@ -103,11 +103,6 @@ var source_stacks = new Set();
let uid = 1;
let effect_version = 1;
/** @type {WeakMap<Effect, number>} */
const effect_versions = new WeakMap();
/**
* @template T
* @param {Set<T> | null} target
@ -270,11 +265,12 @@ export class Batch {
merged_into = null;
/**
* Async and block effects that ran or were proven clean inside this fork.
* The version is that of the latest real-world execution when the effect was
* validated. Fork executions do not advance it, so forks remain independent.
* Async and block effects that ran or were proven clean inside this fork,
* mapped to whether that validation has since been superseded by a
* real-world run of the effect (see `record_effect`). Runs inside other
* forks don't supersede anything, so forks remain independent.
* Lazily initialised for perf reasons
* @type {Map<Effect, number> | null}
* @type {Map<Effect, boolean> | null}
*/
fork_effects = null;
@ -541,26 +537,31 @@ export class Batch {
if ((effect.f & (ASYNC | BLOCK_EFFECT)) === 0) return;
if (this.is_fork) {
(this.fork_effects ??= new Map()).set(effect, effect_versions.get(effect) ?? 0);
(this.fork_effects ??= new Map()).set(effect, false);
} else if (ran) {
effect_versions.set(effect, effect_version++);
// a real-world run supersedes any fork's validation of this effect
for (var batch = first_batch; batch !== null; batch = batch.#next) {
if (batch.is_fork && batch.fork_effects?.has(effect)) {
batch.fork_effects.set(effect, true);
}
}
}
}
claim_fork_effects() {
if (this.fork_effects === null) return;
for (const [effect, version] of this.fork_effects) {
if ((effect.f & DESTROYED) !== 0 || version !== (effect_versions.get(effect) ?? 0)) {
for (const [effect, superseded] of this.fork_effects) {
if ((effect.f & DESTROYED) !== 0 || superseded) {
this.#dirty_effects?.delete(effect);
this.#maybe_dirty_effects?.delete(effect);
}
}
for (const [effect, version] of this.fork_effects) {
for (const [effect, superseded] of this.fork_effects) {
if ((effect.f & DESTROYED) !== 0) continue;
if (version !== (effect_versions.get(effect) ?? 0)) {
if (superseded) {
var owner = effect.batch && effect.batch.resolved();
if (owner !== null && owner !== this && owner.linked && !owner.is_fork) {
@ -1154,11 +1155,8 @@ export class Batch {
continue;
}
for (const [effect, version] of fork.fork_effects) {
if (
version === (effect_versions.get(effect) ?? 0) ||
(effect.f & (DESTROYED | INERT)) !== 0
) {
for (const [effect, superseded] of fork.fork_effects) {
if (!superseded || (effect.f & (DESTROYED | INERT)) !== 0) {
continue;
}
@ -1169,7 +1167,7 @@ export class Batch {
// the fork's view of every dependency matches the committed
// state — the latest real run is valid for the fork's world
// too, so it doesn't need to re-run speculatively
fork.fork_effects.set(effect, effect_versions.get(effect) ?? 0);
fork.fork_effects.set(effect, false);
continue;
}
@ -1733,20 +1731,18 @@ function mark_committed_reactions(value, batch, marked, status) {
var effect = /** @type {Effect} */ (reaction);
var owner = effect.batch && effect.batch.resolved();
var fork_version = batch.fork_effects?.get(effect);
var validated =
fork_version !== undefined && fork_version === (effect_versions.get(effect) ?? 0);
var superseded = batch.fork_effects?.get(effect);
var stale =
batch.stale_readers?.has(effect) === true || owner?.stale_readers?.has(effect) === true;
if (fork_version === undefined || stale) {
if (superseded === undefined || stale) {
if ((reaction.f & DIRTY) === 0) {
set_signal_status(reaction, status);
}
batch.schedule(effect);
} else if (
!validated &&
superseded &&
owner !== null &&
owner !== batch &&
owner.linked &&

Loading…
Cancel
Save