reactronic 0.24.275 → 0.24.301
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/dist/source/Options.d.ts +10 -4
- package/build/dist/source/Options.js +8 -0
- package/build/dist/source/RxSystem.d.ts +2 -2
- package/build/dist/source/RxSystem.js +21 -10
- package/build/dist/source/api.d.ts +2 -2
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/core/Changeset.d.ts +23 -21
- package/build/dist/source/core/Changeset.js +145 -143
- package/build/dist/source/core/Data.d.ts +17 -18
- package/build/dist/source/core/Data.js +8 -7
- package/build/dist/source/core/Indicator.js +9 -8
- package/build/dist/source/core/Journal.d.ts +2 -2
- package/build/dist/source/core/Journal.js +36 -35
- package/build/dist/source/core/Mvcc.d.ts +12 -12
- package/build/dist/source/core/Mvcc.js +47 -62
- package/build/dist/source/core/{Reaction.d.ts → Operation.d.ts} +21 -19
- package/build/dist/source/core/{Reaction.js → Operation.js} +181 -152
- package/build/dist/source/core/RxNode.js +5 -5
- package/build/dist/source/core/Transaction.d.ts +61 -2
- package/build/dist/source/core/Transaction.js +175 -16
- package/package.json +3 -3
|
@@ -1,54 +1,49 @@
|
|
|
1
1
|
import { Log, misuse } from "../util/Dbg.js";
|
|
2
|
-
import { Kind, Reentrance } from "../Options.js";
|
|
3
|
-
import { ObjectHandle,
|
|
4
|
-
import { Changeset, Dump,
|
|
5
|
-
import { Transaction } from "./Transaction.js";
|
|
2
|
+
import { Kind, Reentrance, Isolation } from "../Options.js";
|
|
3
|
+
import { ObjectHandle, FieldVersion, Meta } from "./Data.js";
|
|
4
|
+
import { Changeset, Dump, EMPTY_OBJECT_VERSION, MAX_REVISION } from "./Changeset.js";
|
|
5
|
+
import { Transaction, TransactionImpl } from "./Transaction.js";
|
|
6
6
|
import { IndicatorImpl } from "./Indicator.js";
|
|
7
7
|
import { Mvcc, OptionsImpl } from "./Mvcc.js";
|
|
8
8
|
import { JournalImpl } from "./Journal.js";
|
|
9
9
|
const BOOT_ARGS = [];
|
|
10
10
|
const BOOT_CAUSE = "<boot>";
|
|
11
|
-
const EMPTY_HANDLE = new ObjectHandle(undefined, undefined, Mvcc.observable,
|
|
12
|
-
export class
|
|
13
|
-
configure(options) { return
|
|
11
|
+
const EMPTY_HANDLE = new ObjectHandle(undefined, undefined, Mvcc.observable, EMPTY_OBJECT_VERSION, "<boot>");
|
|
12
|
+
export class OperationImpl {
|
|
13
|
+
configure(options) { return OperationImpl.configureImpl(this, options); }
|
|
14
14
|
get options() { return this.peek(undefined).launch.options; }
|
|
15
15
|
get unobs() { return this.peek(undefined).launch.content; }
|
|
16
16
|
get args() { return this.use().launch.args; }
|
|
17
17
|
get result() { return this.reuseOrRelaunch(true, undefined).content; }
|
|
18
18
|
get error() { return this.use().launch.error; }
|
|
19
|
-
get stamp() { return this.use().
|
|
19
|
+
get stamp() { return this.use().objectVersion.changeset.timestamp; }
|
|
20
20
|
get isUpToDate() { return this.use().isUpToDate; }
|
|
21
|
-
markObsolete() { Transaction.run({ hint: Log.isOn ? `markObsolete(${Dump.obj(this.
|
|
21
|
+
markObsolete() { Transaction.run({ hint: Log.isOn ? `markObsolete(${Dump.obj(this.ownerHandle, this.fieldKey)})` : "markObsolete()" }, OperationImpl.markObsolete, this); }
|
|
22
22
|
pullLastResult(args) { return this.reuseOrRelaunch(true, args).content; }
|
|
23
|
-
constructor(h,
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
23
|
+
constructor(h, fk) {
|
|
24
|
+
this.ownerHandle = h;
|
|
25
|
+
this.fieldKey = fk;
|
|
26
26
|
}
|
|
27
27
|
reuseOrRelaunch(weak, args) {
|
|
28
|
-
var _a;
|
|
29
28
|
let ror = this.peek(args);
|
|
30
29
|
const ctx = ror.changeset;
|
|
31
30
|
const launch = ror.launch;
|
|
32
31
|
const opts = launch.options;
|
|
33
|
-
if (!ror.isUpToDate && !ror.
|
|
32
|
+
if (!ror.isUpToDate && !ror.objectVersion.disposed
|
|
34
33
|
&& (!weak || launch.cause === BOOT_CAUSE || !launch.successor ||
|
|
35
34
|
launch.successor.transaction.isFinished)) {
|
|
36
|
-
const
|
|
37
|
-
const separation = weak || opts.separation !== false || opts.kind === Kind.reactive ||
|
|
38
|
-
(opts.kind === Kind.transactional && outerOpts && (outerOpts.noSideEffects || outerOpts.kind === Kind.cached)) ||
|
|
39
|
-
(opts.kind === Kind.cached && (ror.snapshot.changeset.sealed ||
|
|
40
|
-
ror.snapshot.former.snapshot !== EMPTY_SNAPSHOT));
|
|
35
|
+
const isolation = !weak ? opts.isolation : Isolation.disjoinFromOuterTransaction;
|
|
41
36
|
const token = opts.noSideEffects ? this : undefined;
|
|
42
|
-
const ror2 = this.relaunch(ror,
|
|
37
|
+
const ror2 = this.relaunch(ror, isolation, opts, token, args);
|
|
43
38
|
const ctx2 = ror2.launch.changeset;
|
|
44
39
|
if (!weak || ctx === ctx2 || (ctx2.sealed && ctx.timestamp >= ctx2.timestamp))
|
|
45
40
|
ror = ror2;
|
|
46
41
|
}
|
|
47
42
|
else if (Log.isOn && Log.opt.operation && (opts.logging === undefined ||
|
|
48
43
|
opts.logging.operation === undefined || opts.logging.operation === true))
|
|
49
|
-
Log.write(Transaction.current.isFinished ? "" : "║", " (=)", `${Dump.snapshot2(ror.launch.
|
|
44
|
+
Log.write(Transaction.current.isFinished ? "" : "║", " (=)", `${Dump.snapshot2(ror.launch.operation.ownerHandle, ror.changeset, this.fieldKey)} result is reused from T${ror.launch.transaction.id}[${ror.launch.transaction.hint}]`);
|
|
50
45
|
const t = ror.launch;
|
|
51
|
-
Changeset.markUsed(t, ror.
|
|
46
|
+
Changeset.markUsed(t, ror.objectVersion, this.fieldKey, this.ownerHandle, t.options.kind, weak);
|
|
52
47
|
return t;
|
|
53
48
|
}
|
|
54
49
|
static getControllerOf(method) {
|
|
@@ -101,81 +96,81 @@ export class ReactionImpl {
|
|
|
101
96
|
}
|
|
102
97
|
peek(args) {
|
|
103
98
|
const ctx = Changeset.current();
|
|
104
|
-
const
|
|
105
|
-
const launch = this.
|
|
99
|
+
const ov = ctx.lookupObjectVersion(this.ownerHandle, this.fieldKey, false);
|
|
100
|
+
const launch = this.acquireFromObjectVersion(ov, args);
|
|
106
101
|
const isValid = launch.options.kind !== Kind.transactional && launch.cause !== BOOT_CAUSE &&
|
|
107
102
|
(ctx === launch.changeset || ctx.timestamp < launch.obsoleteSince) &&
|
|
108
103
|
(!launch.options.triggeringArgs || args === undefined ||
|
|
109
|
-
launch.args.length === args.length && launch.args.every((t, i) => t === args[i])) ||
|
|
110
|
-
return { launch, isUpToDate: isValid, changeset: ctx,
|
|
104
|
+
launch.args.length === args.length && launch.args.every((t, i) => t === args[i])) || ov.disposed;
|
|
105
|
+
return { launch, isUpToDate: isValid, changeset: ctx, objectVersion: ov };
|
|
111
106
|
}
|
|
112
107
|
use() {
|
|
113
108
|
const ror = this.peek(undefined);
|
|
114
|
-
Changeset.markUsed(ror.launch, ror.
|
|
109
|
+
Changeset.markUsed(ror.launch, ror.objectVersion, this.fieldKey, this.ownerHandle, ror.launch.options.kind, true);
|
|
115
110
|
return ror;
|
|
116
111
|
}
|
|
117
112
|
edit() {
|
|
118
|
-
const h = this.
|
|
119
|
-
const
|
|
113
|
+
const h = this.ownerHandle;
|
|
114
|
+
const fk = this.fieldKey;
|
|
120
115
|
const ctx = Changeset.edit();
|
|
121
|
-
const
|
|
122
|
-
let launch = this.
|
|
123
|
-
if (launch.changeset !==
|
|
124
|
-
const relaunch = new Launch(this,
|
|
125
|
-
|
|
126
|
-
ctx.bumpBy(
|
|
127
|
-
Changeset.markEdited(launch, relaunch, true,
|
|
116
|
+
const ov = ctx.getEditableObjectVersion(h, fk, Meta.Handle, this);
|
|
117
|
+
let launch = this.acquireFromObjectVersion(ov, undefined);
|
|
118
|
+
if (launch.changeset !== ov.changeset) {
|
|
119
|
+
const relaunch = new Launch(Transaction.current, this, ov.changeset, launch, false);
|
|
120
|
+
ov.data[fk] = relaunch.reenterOver(launch);
|
|
121
|
+
ctx.bumpBy(ov.former.objectVersion.changeset.timestamp);
|
|
122
|
+
Changeset.markEdited(launch, relaunch, true, ov, fk, h);
|
|
128
123
|
launch = relaunch;
|
|
129
124
|
}
|
|
130
|
-
return { launch, isUpToDate: true, changeset: ctx,
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
let launch =
|
|
135
|
-
if (launch.
|
|
136
|
-
if (
|
|
137
|
-
const hint = Log.isOn ? `${Dump.obj(this.
|
|
138
|
-
const
|
|
139
|
-
launch = Transaction.run({ hint,
|
|
140
|
-
const h = this.
|
|
141
|
-
let r = Changeset.current().
|
|
142
|
-
let relaunch = r.data[
|
|
143
|
-
if (relaunch.
|
|
144
|
-
r = Changeset.edit().
|
|
145
|
-
const t = new Launch(this, r.changeset, relaunch);
|
|
125
|
+
return { launch, isUpToDate: true, changeset: ctx, objectVersion: ov };
|
|
126
|
+
}
|
|
127
|
+
acquireFromObjectVersion(ov, args) {
|
|
128
|
+
const fk = this.fieldKey;
|
|
129
|
+
let launch = ov.data[fk];
|
|
130
|
+
if (launch.operation !== this) {
|
|
131
|
+
if (ov.changeset !== EMPTY_OBJECT_VERSION.changeset) {
|
|
132
|
+
const hint = Log.isOn ? `${Dump.obj(this.ownerHandle, fk)}/init` : "MethodController/init";
|
|
133
|
+
const isolation = Isolation.joinToCurrentTransaction;
|
|
134
|
+
launch = Transaction.run({ hint, isolation, token: this }, () => {
|
|
135
|
+
const h = this.ownerHandle;
|
|
136
|
+
let r = Changeset.current().getObjectVersion(h, fk);
|
|
137
|
+
let relaunch = r.data[fk];
|
|
138
|
+
if (relaunch.operation !== this) {
|
|
139
|
+
r = Changeset.edit().getEditableObjectVersion(h, fk, Meta.Handle, this);
|
|
140
|
+
const t = new Launch(Transaction.current, this, r.changeset, relaunch, false);
|
|
146
141
|
if (args)
|
|
147
142
|
t.args = args;
|
|
148
143
|
t.cause = BOOT_CAUSE;
|
|
149
|
-
r.data[
|
|
150
|
-
Changeset.markEdited(relaunch, t, true, r,
|
|
144
|
+
r.data[fk] = t;
|
|
145
|
+
Changeset.markEdited(relaunch, t, true, r, fk, h);
|
|
151
146
|
relaunch = t;
|
|
152
147
|
}
|
|
153
148
|
return relaunch;
|
|
154
149
|
});
|
|
155
150
|
}
|
|
156
151
|
else {
|
|
157
|
-
const initialLaunch = new Launch(this,
|
|
152
|
+
const initialLaunch = new Launch(Transaction.current, this, ov.changeset, launch, false);
|
|
158
153
|
if (args)
|
|
159
154
|
initialLaunch.args = args;
|
|
160
155
|
initialLaunch.cause = BOOT_CAUSE;
|
|
161
|
-
|
|
156
|
+
ov.data[fk] = initialLaunch;
|
|
162
157
|
launch = initialLaunch;
|
|
163
158
|
if (Log.isOn && Log.opt.write)
|
|
164
|
-
Log.write("║", " ++", `${Dump.obj(this.
|
|
159
|
+
Log.write("║", " ++", `${Dump.obj(this.ownerHandle, fk)} is initialized (revision ${ov.revision})`);
|
|
165
160
|
}
|
|
166
161
|
}
|
|
167
162
|
return launch;
|
|
168
163
|
}
|
|
169
|
-
relaunch(existing,
|
|
170
|
-
const hint = Log.isOn ? `${Dump.obj(this.
|
|
164
|
+
relaunch(existing, isolation, options, token, args) {
|
|
165
|
+
const hint = Log.isOn ? `${Dump.obj(this.ownerHandle, this.fieldKey)}${args && args.length > 0 && (typeof args[0] === "number" || typeof args[0] === "string") ? ` - ${args[0]}` : ""}` : `${Dump.obj(this.ownerHandle, this.fieldKey)}`;
|
|
171
166
|
let ror = existing;
|
|
172
|
-
const opts = { hint,
|
|
167
|
+
const opts = { hint, isolation, journal: options.journal, logging: options.logging, token };
|
|
173
168
|
const result = Transaction.run(opts, (argsx) => {
|
|
174
169
|
if (!ror.launch.transaction.isCanceled) {
|
|
175
170
|
ror = this.edit();
|
|
176
171
|
if (Log.isOn && Log.opt.operation)
|
|
177
172
|
Log.write("║", " o", `${ror.launch.why()}`);
|
|
178
|
-
ror.launch.proceed(this.
|
|
173
|
+
ror.launch.proceed(this.ownerHandle.proxy, argsx);
|
|
179
174
|
}
|
|
180
175
|
else {
|
|
181
176
|
ror = this.peek(argsx);
|
|
@@ -183,7 +178,7 @@ export class ReactionImpl {
|
|
|
183
178
|
ror = this.edit();
|
|
184
179
|
if (Log.isOn && Log.opt.operation)
|
|
185
180
|
Log.write("║", " o", `${ror.launch.why()}`);
|
|
186
|
-
ror.launch.proceed(this.
|
|
181
|
+
ror.launch.proceed(this.ownerHandle.proxy, argsx);
|
|
187
182
|
}
|
|
188
183
|
}
|
|
189
184
|
return ror.launch.result;
|
|
@@ -194,44 +189,65 @@ export class ReactionImpl {
|
|
|
194
189
|
static markObsolete(self) {
|
|
195
190
|
const ror = self.peek(undefined);
|
|
196
191
|
const ctx = ror.changeset;
|
|
197
|
-
ror.launch.markObsoleteDueTo(ror.launch, self.
|
|
192
|
+
ror.launch.markObsoleteDueTo(ror.launch, self.fieldKey, EMPTY_OBJECT_VERSION.changeset, EMPTY_HANDLE, BOOT_CAUSE, ctx.timestamp, ctx.obsolete);
|
|
198
193
|
}
|
|
199
194
|
}
|
|
200
|
-
class Launch extends
|
|
201
|
-
constructor(
|
|
195
|
+
class Launch extends FieldVersion {
|
|
196
|
+
constructor(transaction, operation, changeset, former, clone) {
|
|
202
197
|
super(undefined);
|
|
203
198
|
this.margin = Launch.current ? Launch.current.margin + 1 : 1;
|
|
204
|
-
this.transaction =
|
|
205
|
-
this.
|
|
199
|
+
this.transaction = transaction;
|
|
200
|
+
this.operation = operation;
|
|
206
201
|
this.changeset = changeset;
|
|
207
202
|
this.observables = new Map();
|
|
208
203
|
if (former instanceof Launch) {
|
|
209
204
|
this.options = former.options;
|
|
210
|
-
this.args = former.args;
|
|
211
205
|
this.cause = former.obsoleteDueTo;
|
|
206
|
+
this.args = former.args;
|
|
207
|
+
if (clone) {
|
|
208
|
+
this.result = former.result;
|
|
209
|
+
this.error = former.error;
|
|
210
|
+
this.started = former.started;
|
|
211
|
+
this.obsoleteSince = former.obsoleteSince;
|
|
212
|
+
this.obsoleteDueTo = former.obsoleteDueTo;
|
|
213
|
+
this.successor = former.successor;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.result = undefined;
|
|
217
|
+
this.error = undefined;
|
|
218
|
+
this.started = 0;
|
|
219
|
+
this.obsoleteSince = 0;
|
|
220
|
+
this.obsoleteDueTo = undefined;
|
|
221
|
+
this.successor = undefined;
|
|
222
|
+
}
|
|
212
223
|
}
|
|
213
224
|
else {
|
|
214
225
|
this.options = former;
|
|
215
|
-
this.args = BOOT_ARGS;
|
|
216
226
|
this.cause = undefined;
|
|
227
|
+
this.args = BOOT_ARGS;
|
|
228
|
+
this.result = undefined;
|
|
229
|
+
this.error = undefined;
|
|
230
|
+
this.started = 0;
|
|
231
|
+
this.obsoleteSince = 0;
|
|
232
|
+
this.obsoleteDueTo = undefined;
|
|
233
|
+
this.successor = undefined;
|
|
217
234
|
}
|
|
218
|
-
this.started = 0;
|
|
219
|
-
this.obsoleteSince = 0;
|
|
220
|
-
this.obsoleteDueTo = undefined;
|
|
221
|
-
this.successor = undefined;
|
|
222
235
|
}
|
|
223
|
-
get
|
|
236
|
+
get isLaunch() { return true; }
|
|
224
237
|
get originSnapshotId() { return this.changeset.id; }
|
|
225
|
-
hint() { return `${Dump.snapshot2(this.
|
|
238
|
+
hint() { return `${Dump.snapshot2(this.operation.ownerHandle, this.changeset, this.operation.fieldKey)}`; }
|
|
226
239
|
get order() { return this.options.order; }
|
|
227
240
|
get ["#this#"]() {
|
|
228
241
|
return `Operation: ${this.why()}`;
|
|
229
242
|
}
|
|
243
|
+
clone(t, cs) {
|
|
244
|
+
return new Launch(t, this.operation, cs, this, true);
|
|
245
|
+
}
|
|
230
246
|
why() {
|
|
231
247
|
let cause;
|
|
232
248
|
if (this.cause)
|
|
233
249
|
cause = ` ◀◀ ${this.cause}`;
|
|
234
|
-
else if (this.
|
|
250
|
+
else if (this.operation.options.kind === Kind.transactional)
|
|
235
251
|
cause = " ◀◀ operation";
|
|
236
252
|
else
|
|
237
253
|
cause = ` ◀◀ T${this.changeset.id}[${this.changeset.hint}]`;
|
|
@@ -248,7 +264,7 @@ class Launch extends ValueSnapshot {
|
|
|
248
264
|
if (Log.isOn && Log.opt.step && this.result)
|
|
249
265
|
Log.writeAs({ margin2: this.margin }, "║", "‾\\", `${this.hint()} - step in `, 0, " │");
|
|
250
266
|
const started = Date.now();
|
|
251
|
-
const result =
|
|
267
|
+
const result = OperationImpl.proceedWithinGivenLaunch(this, func, ...args);
|
|
252
268
|
const ms = Date.now() - started;
|
|
253
269
|
if (Log.isOn && Log.opt.step && this.result)
|
|
254
270
|
Log.writeAs({ margin2: this.margin }, "║", "_/", `${this.hint()} - step out `, 0, this.started > 0 ? " │" : "");
|
|
@@ -263,37 +279,37 @@ class Launch extends ValueSnapshot {
|
|
|
263
279
|
this.args = args;
|
|
264
280
|
this.obsoleteSince = MAX_REVISION;
|
|
265
281
|
if (!this.error)
|
|
266
|
-
|
|
282
|
+
OperationImpl.proceedWithinGivenLaunch(this, Launch.proceed, this, proxy);
|
|
267
283
|
else
|
|
268
284
|
this.result = Promise.reject(this.error);
|
|
269
285
|
}
|
|
270
|
-
markObsoleteDueTo(observable,
|
|
286
|
+
markObsoleteDueTo(observable, fk, changeset, h, outer, since, obsolete) {
|
|
271
287
|
var _a, _b, _c;
|
|
272
288
|
if (this.observables !== undefined) {
|
|
273
|
-
const skip = !observable.
|
|
289
|
+
const skip = !observable.isLaunch &&
|
|
274
290
|
changeset === this.changeset;
|
|
275
291
|
if (!skip) {
|
|
276
|
-
const why = `${Dump.snapshot2(h, changeset,
|
|
292
|
+
const why = `${Dump.snapshot2(h, changeset, fk, observable)} ◀◀ ${outer}`;
|
|
277
293
|
const isReactive = this.options.kind === Kind.reactive;
|
|
278
294
|
this.obsoleteDueTo = why;
|
|
279
295
|
this.obsoleteSince = since;
|
|
280
296
|
if (Log.isOn && (Log.opt.obsolete || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.obsolete)))
|
|
281
|
-
Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", isReactive ? "█" : "▒", isReactive && changeset ===
|
|
297
|
+
Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", isReactive ? "█" : "▒", isReactive && changeset === EMPTY_OBJECT_VERSION.changeset
|
|
282
298
|
? `${this.hint()} is reactive and will run automatically (order ${this.options.order})`
|
|
283
|
-
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset,
|
|
299
|
+
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, fk)} since s${since}${isReactive ? ` and will run automatically (order ${this.options.order})` : ""}`);
|
|
284
300
|
this.unsubscribeFromAllObservables();
|
|
285
301
|
if (isReactive)
|
|
286
302
|
obsolete.push(this);
|
|
287
303
|
else
|
|
288
|
-
(_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.
|
|
304
|
+
(_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.operation.fieldKey, this.changeset, this.operation.ownerHandle, why, since, obsolete));
|
|
289
305
|
const tran = this.transaction;
|
|
290
306
|
if (tran.changeset === changeset) {
|
|
291
307
|
}
|
|
292
308
|
else if (!tran.isFinished && this !== observable)
|
|
293
|
-
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Dump.snapshot2(h, changeset,
|
|
309
|
+
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Dump.snapshot2(h, changeset, fk)} changed by T${changeset.id}[${changeset.hint}]`), null);
|
|
294
310
|
}
|
|
295
311
|
else if (Log.isOn && (Log.opt.obsolete || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
296
|
-
Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset,
|
|
312
|
+
Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset, fk)}`);
|
|
297
313
|
}
|
|
298
314
|
}
|
|
299
315
|
relaunchIfNotUpToDate(now, nothrow) {
|
|
@@ -303,7 +319,7 @@ class Launch extends ValueSnapshot {
|
|
|
303
319
|
if (now || hold < 0) {
|
|
304
320
|
if (this.isNotUpToDate()) {
|
|
305
321
|
try {
|
|
306
|
-
const launch = this.
|
|
322
|
+
const launch = this.operation.reuseOrRelaunch(false, undefined);
|
|
307
323
|
if (launch.result instanceof Promise)
|
|
308
324
|
launch.result.catch(error => {
|
|
309
325
|
if (launch.options.kind === Kind.reactive)
|
|
@@ -367,6 +383,8 @@ class Launch extends ValueSnapshot {
|
|
|
367
383
|
static proceed(launch, proxy) {
|
|
368
384
|
launch.enter();
|
|
369
385
|
try {
|
|
386
|
+
if (launch.options.getter === undefined)
|
|
387
|
+
console.log("(!)");
|
|
370
388
|
launch.result = launch.options.getter.call(proxy, ...launch.args);
|
|
371
389
|
}
|
|
372
390
|
finally {
|
|
@@ -377,7 +395,7 @@ class Launch extends ValueSnapshot {
|
|
|
377
395
|
if (this.options.indicator)
|
|
378
396
|
this.indicatorEnter(this.options.indicator);
|
|
379
397
|
if (Log.isOn && Log.opt.operation)
|
|
380
|
-
Log.write("║", "‾\\", `${this.hint()} - enter`, undefined, ` [ ${Dump.obj(this.
|
|
398
|
+
Log.write("║", "‾\\", `${this.hint()} - enter`, undefined, ` [ ${Dump.obj(this.operation.ownerHandle, this.operation.fieldKey)} ]`);
|
|
381
399
|
this.started = Date.now();
|
|
382
400
|
}
|
|
383
401
|
leaveOrAsync() {
|
|
@@ -417,53 +435,53 @@ class Launch extends ValueSnapshot {
|
|
|
417
435
|
indicatorEnter(mon) {
|
|
418
436
|
const options = {
|
|
419
437
|
hint: "Indicator.enter",
|
|
420
|
-
|
|
438
|
+
isolation: Isolation.disjoinFromOuterAndInnerTransactions,
|
|
421
439
|
logging: Log.isOn && Log.opt.indicator ? undefined : Log.global
|
|
422
440
|
};
|
|
423
|
-
|
|
441
|
+
OperationImpl.proceedWithinGivenLaunch(undefined, Transaction.run, options, IndicatorImpl.enter, mon, this.transaction);
|
|
424
442
|
}
|
|
425
443
|
indicatorLeave(mon) {
|
|
426
444
|
Transaction.outside(() => {
|
|
427
445
|
const leave = () => {
|
|
428
446
|
const options = {
|
|
429
447
|
hint: "Indicator.leave",
|
|
430
|
-
|
|
448
|
+
isolation: Isolation.disjoinFromOuterAndInnerTransactions,
|
|
431
449
|
logging: Log.isOn && Log.opt.indicator ? undefined : Log.DefaultLevel
|
|
432
450
|
};
|
|
433
|
-
|
|
451
|
+
OperationImpl.proceedWithinGivenLaunch(undefined, Transaction.run, options, IndicatorImpl.leave, mon, this.transaction);
|
|
434
452
|
};
|
|
435
453
|
this.transaction.whenFinished().then(leave, leave);
|
|
436
454
|
});
|
|
437
455
|
}
|
|
438
456
|
addToDeferredReactiveFunctions() {
|
|
439
|
-
Launch.
|
|
440
|
-
if (Launch.
|
|
457
|
+
Launch.deferredReactiveOperations.push(this);
|
|
458
|
+
if (Launch.deferredReactiveOperations.length === 1)
|
|
441
459
|
setTimeout(Launch.processDeferredReactiveFunctions, 0);
|
|
442
460
|
}
|
|
443
461
|
static processDeferredReactiveFunctions() {
|
|
444
|
-
const deferred = Launch.
|
|
445
|
-
Launch.
|
|
462
|
+
const deferred = Launch.deferredReactiveOperations;
|
|
463
|
+
Launch.deferredReactiveOperations = [];
|
|
446
464
|
for (const x of deferred)
|
|
447
465
|
x.relaunchIfNotUpToDate(true, true);
|
|
448
466
|
}
|
|
449
|
-
static markUsed(observable,
|
|
467
|
+
static markUsed(observable, ov, fk, h, kind, weak) {
|
|
450
468
|
if (kind !== Kind.transactional) {
|
|
451
469
|
const launch = Launch.current;
|
|
452
470
|
if (launch && launch.options.kind !== Kind.transactional &&
|
|
453
|
-
launch.transaction === Transaction.current &&
|
|
471
|
+
launch.transaction === Transaction.current && fk !== Meta.Handle) {
|
|
454
472
|
const ctx = Changeset.current();
|
|
455
|
-
if (ctx !==
|
|
456
|
-
ctx.bumpBy(
|
|
473
|
+
if (ctx !== ov.changeset)
|
|
474
|
+
ctx.bumpBy(ov.changeset.timestamp);
|
|
457
475
|
const t = weak ? -1 : ctx.timestamp;
|
|
458
|
-
if (!launch.subscribeTo(observable,
|
|
459
|
-
launch.markObsoleteDueTo(observable,
|
|
476
|
+
if (!launch.subscribeTo(observable, ov, fk, h, t))
|
|
477
|
+
launch.markObsoleteDueTo(observable, fk, h.applied.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.obsolete);
|
|
460
478
|
}
|
|
461
479
|
}
|
|
462
480
|
}
|
|
463
|
-
static markEdited(oldValue, newValue, edited,
|
|
464
|
-
edited ?
|
|
481
|
+
static markEdited(oldValue, newValue, edited, ov, fk, h) {
|
|
482
|
+
edited ? ov.changes.add(fk) : ov.changes.delete(fk);
|
|
465
483
|
if (Log.isOn && Log.opt.write)
|
|
466
|
-
edited ? Log.write("║", " =", `${Dump.snapshot2(h,
|
|
484
|
+
edited ? Log.write("║", " =", `${Dump.snapshot2(h, ov.changeset, fk)} is changed: ${valueHint(oldValue)} ▸▸ ${valueHint(newValue)}`) : Log.write("║", " =", `${Dump.snapshot2(h, ov.changeset, fk)} is changed: ${valueHint(oldValue)} ▸▸ ${valueHint(newValue)}`, undefined, " (same as previous)");
|
|
467
485
|
}
|
|
468
486
|
static isConflicting(oldValue, newValue) {
|
|
469
487
|
let result = oldValue !== newValue;
|
|
@@ -475,30 +493,30 @@ class Launch extends ValueSnapshot {
|
|
|
475
493
|
var _a;
|
|
476
494
|
const since = changeset.timestamp;
|
|
477
495
|
const obsolete = changeset.obsolete;
|
|
478
|
-
changeset.items.forEach((
|
|
479
|
-
Launch.
|
|
480
|
-
if (!
|
|
481
|
-
|
|
496
|
+
changeset.items.forEach((ov, h) => {
|
|
497
|
+
Launch.propagateFieldChangeThroughSubscriptions(false, since, ov, Meta.Revision, h, obsolete);
|
|
498
|
+
if (!ov.disposed)
|
|
499
|
+
ov.changes.forEach((o, fk) => Launch.propagateFieldChangeThroughSubscriptions(false, since, ov, fk, h, obsolete));
|
|
482
500
|
else
|
|
483
|
-
for (const
|
|
484
|
-
Launch.
|
|
501
|
+
for (const fk in ov.former.objectVersion.data)
|
|
502
|
+
Launch.propagateFieldChangeThroughSubscriptions(true, since, ov, fk, h, obsolete);
|
|
485
503
|
});
|
|
486
504
|
obsolete.sort(compareObserversByOrder);
|
|
487
505
|
(_a = changeset.options.journal) === null || _a === void 0 ? void 0 : _a.edited(JournalImpl.buildPatch(changeset.hint, changeset.items));
|
|
488
506
|
}
|
|
489
507
|
static revokeAllSubscriptions(changeset) {
|
|
490
|
-
changeset.items.forEach((
|
|
491
|
-
Launch.
|
|
492
|
-
|
|
508
|
+
changeset.items.forEach((ov, h) => {
|
|
509
|
+
Launch.propagateFieldChangeThroughSubscriptions(true, changeset.timestamp, ov, Meta.Revision, h, undefined);
|
|
510
|
+
ov.changes.forEach((o, fk) => Launch.propagateFieldChangeThroughSubscriptions(true, changeset.timestamp, ov, fk, h, undefined));
|
|
493
511
|
});
|
|
494
512
|
}
|
|
495
|
-
static
|
|
513
|
+
static propagateFieldChangeThroughSubscriptions(unsubscribe, timestamp, ov, fk, h, obsolete) {
|
|
496
514
|
var _a;
|
|
497
|
-
const curr =
|
|
515
|
+
const curr = ov.data[fk];
|
|
498
516
|
if (obsolete !== undefined) {
|
|
499
|
-
const former =
|
|
500
|
-
if (former !== undefined && former instanceof
|
|
501
|
-
const why = `T${
|
|
517
|
+
const former = ov.former.objectVersion.data[fk];
|
|
518
|
+
if (former !== undefined && former instanceof FieldVersion) {
|
|
519
|
+
const why = `T${ov.changeset.id}[${ov.changeset.hint}]`;
|
|
502
520
|
if (former instanceof Launch) {
|
|
503
521
|
if ((former.obsoleteSince === MAX_REVISION || former.obsoleteSince <= 0)) {
|
|
504
522
|
former.obsoleteDueTo = why;
|
|
@@ -508,16 +526,16 @@ class Launch extends ValueSnapshot {
|
|
|
508
526
|
const formerSuccessor = former.successor;
|
|
509
527
|
if (formerSuccessor !== curr) {
|
|
510
528
|
if (formerSuccessor && !formerSuccessor.transaction.isFinished)
|
|
511
|
-
formerSuccessor.transaction.cancel(new Error(`T${formerSuccessor.transaction.id}[${formerSuccessor.transaction.hint}] is canceled by T${
|
|
529
|
+
formerSuccessor.transaction.cancel(new Error(`T${formerSuccessor.transaction.id}[${formerSuccessor.transaction.hint}] is canceled by T${ov.changeset.id}[${ov.changeset.hint}] and will not run anymore`), null);
|
|
512
530
|
}
|
|
513
531
|
else
|
|
514
532
|
former.successor = undefined;
|
|
515
533
|
}
|
|
516
|
-
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former,
|
|
534
|
+
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former, fk, ov.changeset, h, why, timestamp, obsolete));
|
|
517
535
|
}
|
|
518
536
|
}
|
|
519
537
|
if (curr instanceof Launch) {
|
|
520
|
-
if (curr.changeset ===
|
|
538
|
+
if (curr.changeset === ov.changeset && curr.observables !== undefined) {
|
|
521
539
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
522
540
|
curr.observables.forEach((info, v) => {
|
|
523
541
|
if (info.usageCount > Mvcc.repetitiveUsageWarningThreshold)
|
|
@@ -528,26 +546,34 @@ class Launch extends ValueSnapshot {
|
|
|
528
546
|
curr.unsubscribeFromAllObservables();
|
|
529
547
|
}
|
|
530
548
|
}
|
|
531
|
-
else if (curr instanceof
|
|
549
|
+
else if (curr instanceof FieldVersion && curr.observers) {
|
|
532
550
|
}
|
|
533
551
|
}
|
|
534
552
|
static enqueueReactiveFunctionsToRun(reactive) {
|
|
535
|
-
const queue = Launch.
|
|
553
|
+
const queue = Launch.queuedReactiveOperations;
|
|
536
554
|
const isReactiveLoopRequired = queue.length === 0;
|
|
537
555
|
for (const r of reactive)
|
|
538
556
|
queue.push(r);
|
|
539
557
|
if (isReactiveLoopRequired)
|
|
540
|
-
|
|
558
|
+
OperationImpl.proceedWithinGivenLaunch(undefined, Launch.processQueuedReactiveOperations);
|
|
559
|
+
}
|
|
560
|
+
static createFieldVersion(fv, target) {
|
|
561
|
+
let result;
|
|
562
|
+
if (fv instanceof Launch)
|
|
563
|
+
result = new Launch(target, fv.operation, target.changeset, fv, true);
|
|
564
|
+
else
|
|
565
|
+
result = new FieldVersion(fv === null || fv === void 0 ? void 0 : fv.content);
|
|
566
|
+
return result;
|
|
541
567
|
}
|
|
542
|
-
static
|
|
543
|
-
const queue = Launch.
|
|
568
|
+
static processQueuedReactiveOperations() {
|
|
569
|
+
const queue = Launch.queuedReactiveOperations;
|
|
544
570
|
let i = 0;
|
|
545
571
|
while (i < queue.length) {
|
|
546
572
|
const reactive = queue[i];
|
|
547
573
|
reactive.relaunchIfNotUpToDate(false, true);
|
|
548
574
|
i++;
|
|
549
575
|
}
|
|
550
|
-
Launch.
|
|
576
|
+
Launch.queuedReactiveOperations = [];
|
|
551
577
|
}
|
|
552
578
|
unsubscribeFromAllObservables() {
|
|
553
579
|
var _a;
|
|
@@ -559,9 +585,10 @@ class Launch extends ValueSnapshot {
|
|
|
559
585
|
});
|
|
560
586
|
this.observables = undefined;
|
|
561
587
|
}
|
|
562
|
-
subscribeTo(observable,
|
|
588
|
+
subscribeTo(observable, ov, fk, h, timestamp) {
|
|
563
589
|
var _a, _b, _c;
|
|
564
|
-
const
|
|
590
|
+
const parent = this.transaction.changeset.parent;
|
|
591
|
+
const ok = Launch.canSubscribeTo(observable, ov, parent, fk, h, timestamp);
|
|
565
592
|
if (ok) {
|
|
566
593
|
let times = 0;
|
|
567
594
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
@@ -571,49 +598,50 @@ class Launch extends ValueSnapshot {
|
|
|
571
598
|
if (this.observables !== undefined) {
|
|
572
599
|
if (!observable.observers)
|
|
573
600
|
observable.observers = new Set();
|
|
574
|
-
const subscription = { memberHint: Dump.snapshot2(h,
|
|
601
|
+
const subscription = { memberHint: Dump.snapshot2(h, ov.changeset, fk), usageCount: times };
|
|
575
602
|
observable.observers.add(this);
|
|
576
603
|
this.observables.set(observable, subscription);
|
|
577
604
|
if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
578
|
-
Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h,
|
|
605
|
+
Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ""}`);
|
|
579
606
|
}
|
|
580
607
|
else if (Log.isOn && (Log.opt.read || ((_b = this.options.logging) === null || _b === void 0 ? void 0 : _b.read)))
|
|
581
|
-
Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h,
|
|
608
|
+
Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk)}`);
|
|
582
609
|
}
|
|
583
610
|
else {
|
|
584
611
|
if (Log.isOn && (Log.opt.read || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.read)))
|
|
585
|
-
Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h,
|
|
612
|
+
Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk)}`);
|
|
586
613
|
}
|
|
587
614
|
return ok;
|
|
588
615
|
}
|
|
589
|
-
static canSubscribeTo(observable,
|
|
590
|
-
const
|
|
591
|
-
|
|
616
|
+
static canSubscribeTo(observable, ov, parent, fk, h, timestamp) {
|
|
617
|
+
const parentSnapshot = parent ? parent.lookupObjectVersion(h, fk, false) : h.applied;
|
|
618
|
+
const observableParent = parentSnapshot.data[fk];
|
|
619
|
+
let result = observable === observableParent || (!ov.changeset.sealed && ov.former.objectVersion.data[fk] === observableParent);
|
|
592
620
|
if (result && timestamp !== -1)
|
|
593
621
|
result = !(observable instanceof Launch && timestamp >= observable.obsoleteSince);
|
|
594
622
|
return result;
|
|
595
623
|
}
|
|
596
|
-
static createOperation(h,
|
|
597
|
-
const rx = new
|
|
624
|
+
static createOperation(h, fk, options) {
|
|
625
|
+
const rx = new OperationImpl(h, fk);
|
|
598
626
|
const operation = (...args) => {
|
|
599
627
|
return rx.reuseOrRelaunch(false, args).result;
|
|
600
628
|
};
|
|
601
629
|
Meta.set(operation, Meta.Controller, rx);
|
|
602
630
|
return operation;
|
|
603
631
|
}
|
|
604
|
-
static rememberOperationOptions(proto,
|
|
632
|
+
static rememberOperationOptions(proto, fk, getter, setter, enumerable, configurable, options, implicit) {
|
|
605
633
|
const initial = Meta.acquire(proto, Meta.Initial);
|
|
606
|
-
let launch = initial[
|
|
607
|
-
const rx = launch ? launch.
|
|
634
|
+
let launch = initial[fk];
|
|
635
|
+
const rx = launch ? launch.operation : new OperationImpl(EMPTY_HANDLE, fk);
|
|
608
636
|
const opts = launch ? launch.options : OptionsImpl.INITIAL;
|
|
609
|
-
initial[
|
|
637
|
+
initial[fk] = launch = new Launch(Transaction.current, rx, EMPTY_OBJECT_VERSION.changeset, new OptionsImpl(getter, setter, opts, options, implicit), false);
|
|
610
638
|
if (launch.options.kind === Kind.reactive && launch.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
611
639
|
const reactive = Meta.acquire(proto, Meta.Reactive);
|
|
612
|
-
reactive[
|
|
640
|
+
reactive[fk] = launch;
|
|
613
641
|
}
|
|
614
642
|
else if (launch.options.kind === Kind.reactive && launch.options.throttling >= Number.MAX_SAFE_INTEGER) {
|
|
615
643
|
const reactive = Meta.getFrom(proto, Meta.Reactive);
|
|
616
|
-
delete reactive[
|
|
644
|
+
delete reactive[fk];
|
|
617
645
|
}
|
|
618
646
|
return launch.options;
|
|
619
647
|
}
|
|
@@ -627,25 +655,26 @@ class Launch extends ValueSnapshot {
|
|
|
627
655
|
Changeset.propagateAllChangesThroughSubscriptions = Launch.propagateAllChangesThroughSubscriptions;
|
|
628
656
|
Changeset.revokeAllSubscriptions = Launch.revokeAllSubscriptions;
|
|
629
657
|
Changeset.enqueueReactiveFunctionsToRun = Launch.enqueueReactiveFunctionsToRun;
|
|
658
|
+
TransactionImpl.createFieldVersion = Launch.createFieldVersion;
|
|
630
659
|
Mvcc.createOperation = Launch.createOperation;
|
|
631
660
|
Mvcc.rememberOperationOptions = Launch.rememberOperationOptions;
|
|
632
661
|
Promise.prototype.then = reactronicHookedThen;
|
|
633
662
|
try {
|
|
634
663
|
Object.defineProperty(globalThis, "rWhy", {
|
|
635
|
-
get:
|
|
664
|
+
get: OperationImpl.why, configurable: false, enumerable: false,
|
|
636
665
|
});
|
|
637
666
|
Object.defineProperty(globalThis, "rBriefWhy", {
|
|
638
|
-
get:
|
|
667
|
+
get: OperationImpl.briefWhy, configurable: false, enumerable: false,
|
|
639
668
|
});
|
|
640
669
|
}
|
|
641
670
|
catch (e) {
|
|
642
671
|
}
|
|
643
672
|
try {
|
|
644
673
|
Object.defineProperty(global, "rWhy", {
|
|
645
|
-
get:
|
|
674
|
+
get: OperationImpl.why, configurable: false, enumerable: false,
|
|
646
675
|
});
|
|
647
676
|
Object.defineProperty(global, "rBriefWhy", {
|
|
648
|
-
get:
|
|
677
|
+
get: OperationImpl.briefWhy, configurable: false, enumerable: false,
|
|
649
678
|
});
|
|
650
679
|
}
|
|
651
680
|
catch (e) {
|
|
@@ -653,8 +682,8 @@ class Launch extends ValueSnapshot {
|
|
|
653
682
|
}
|
|
654
683
|
}
|
|
655
684
|
Launch.current = undefined;
|
|
656
|
-
Launch.
|
|
657
|
-
Launch.
|
|
685
|
+
Launch.queuedReactiveOperations = [];
|
|
686
|
+
Launch.deferredReactiveOperations = [];
|
|
658
687
|
function valueHint(value) {
|
|
659
688
|
let result = "";
|
|
660
689
|
if (Array.isArray(value))
|
|
@@ -664,7 +693,7 @@ function valueHint(value) {
|
|
|
664
693
|
else if (value instanceof Map)
|
|
665
694
|
result = `Map(${value.size})`;
|
|
666
695
|
else if (value instanceof Launch)
|
|
667
|
-
result = `#${value.
|
|
696
|
+
result = `#${value.operation.ownerHandle.id}t${value.changeset.id}s${value.changeset.timestamp}${value.originSnapshotId !== undefined && value.originSnapshotId !== 0 ? `t${value.originSnapshotId}` : ""}`;
|
|
668
697
|
else if (value === Meta.Undefined)
|
|
669
698
|
result = "undefined";
|
|
670
699
|
else if (typeof (value) === "string")
|