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

Loading…
Cancel
Save