reactronic 0.24.275 → 0.24.302
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 +3 -3
- package/build/dist/source/api.js +2 -2
- package/build/dist/source/core/Changeset.d.ts +23 -21
- package/build/dist/source/core/Changeset.js +147 -144
- package/build/dist/source/core/Data.d.ts +19 -20
- package/build/dist/source/core/Data.js +9 -9
- package/build/dist/source/core/Indicator.d.ts +2 -2
- 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/MvccArray.d.ts +1 -0
- package/build/dist/source/core/MvccArray.js +4 -4
- package/build/dist/source/core/{Reaction.d.ts → Operation.d.ts} +21 -20
- package/build/dist/source/core/{Reaction.js → Operation.js} +187 -156
- package/build/dist/source/core/RxNode.d.ts +8 -6
- package/build/dist/source/core/RxNode.js +37 -18
- package/build/dist/source/core/Transaction.d.ts +61 -2
- package/build/dist/source/core/Transaction.js +181 -16
- package/build/dist/source/util/Utils.d.ts +1 -0
- package/build/dist/source/util/Utils.js +8 -0
- package/package.json +4 -4
|
@@ -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,67 @@ 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(
|
|
202
|
-
super(undefined);
|
|
195
|
+
class Launch extends FieldVersion {
|
|
196
|
+
constructor(transaction, operation, changeset, former, clone) {
|
|
197
|
+
super(undefined, 0);
|
|
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.lastEditorChangesetId = former.lastEditorChangesetId;
|
|
209
|
+
this.result = former.result;
|
|
210
|
+
this.error = former.error;
|
|
211
|
+
this.started = former.started;
|
|
212
|
+
this.obsoleteSince = former.obsoleteSince;
|
|
213
|
+
this.obsoleteDueTo = former.obsoleteDueTo;
|
|
214
|
+
this.successor = former.successor;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
this.lastEditorChangesetId = changeset.id;
|
|
218
|
+
this.result = undefined;
|
|
219
|
+
this.error = undefined;
|
|
220
|
+
this.started = 0;
|
|
221
|
+
this.obsoleteSince = 0;
|
|
222
|
+
this.obsoleteDueTo = undefined;
|
|
223
|
+
this.successor = undefined;
|
|
224
|
+
}
|
|
212
225
|
}
|
|
213
226
|
else {
|
|
227
|
+
this.lastEditorChangesetId = changeset.id;
|
|
214
228
|
this.options = former;
|
|
215
|
-
this.args = BOOT_ARGS;
|
|
216
229
|
this.cause = undefined;
|
|
230
|
+
this.args = BOOT_ARGS;
|
|
231
|
+
this.result = undefined;
|
|
232
|
+
this.error = undefined;
|
|
233
|
+
this.started = 0;
|
|
234
|
+
this.obsoleteSince = 0;
|
|
235
|
+
this.obsoleteDueTo = undefined;
|
|
236
|
+
this.successor = undefined;
|
|
217
237
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.successor = undefined;
|
|
222
|
-
}
|
|
223
|
-
get isOperation() { return true; }
|
|
224
|
-
get originSnapshotId() { return this.changeset.id; }
|
|
225
|
-
hint() { return `${Dump.snapshot2(this.reaction.objectHandle, this.changeset, this.reaction.memberName)}`; }
|
|
238
|
+
}
|
|
239
|
+
get isLaunch() { return true; }
|
|
240
|
+
hint() { return `${Dump.snapshot2(this.operation.ownerHandle, this.changeset, this.operation.fieldKey, this)}`; }
|
|
226
241
|
get order() { return this.options.order; }
|
|
227
242
|
get ["#this#"]() {
|
|
228
243
|
return `Operation: ${this.why()}`;
|
|
229
244
|
}
|
|
245
|
+
clone(t, cs) {
|
|
246
|
+
return new Launch(t, this.operation, cs, this, true);
|
|
247
|
+
}
|
|
230
248
|
why() {
|
|
231
249
|
let cause;
|
|
232
250
|
if (this.cause)
|
|
233
251
|
cause = ` ◀◀ ${this.cause}`;
|
|
234
|
-
else if (this.
|
|
252
|
+
else if (this.operation.options.kind === Kind.transactional)
|
|
235
253
|
cause = " ◀◀ operation";
|
|
236
254
|
else
|
|
237
255
|
cause = ` ◀◀ T${this.changeset.id}[${this.changeset.hint}]`;
|
|
@@ -248,7 +266,7 @@ class Launch extends ValueSnapshot {
|
|
|
248
266
|
if (Log.isOn && Log.opt.step && this.result)
|
|
249
267
|
Log.writeAs({ margin2: this.margin }, "║", "‾\\", `${this.hint()} - step in `, 0, " │");
|
|
250
268
|
const started = Date.now();
|
|
251
|
-
const result =
|
|
269
|
+
const result = OperationImpl.proceedWithinGivenLaunch(this, func, ...args);
|
|
252
270
|
const ms = Date.now() - started;
|
|
253
271
|
if (Log.isOn && Log.opt.step && this.result)
|
|
254
272
|
Log.writeAs({ margin2: this.margin }, "║", "_/", `${this.hint()} - step out `, 0, this.started > 0 ? " │" : "");
|
|
@@ -263,37 +281,37 @@ class Launch extends ValueSnapshot {
|
|
|
263
281
|
this.args = args;
|
|
264
282
|
this.obsoleteSince = MAX_REVISION;
|
|
265
283
|
if (!this.error)
|
|
266
|
-
|
|
284
|
+
OperationImpl.proceedWithinGivenLaunch(this, Launch.proceed, this, proxy);
|
|
267
285
|
else
|
|
268
286
|
this.result = Promise.reject(this.error);
|
|
269
287
|
}
|
|
270
|
-
markObsoleteDueTo(observable,
|
|
288
|
+
markObsoleteDueTo(observable, fk, changeset, h, outer, since, obsolete) {
|
|
271
289
|
var _a, _b, _c;
|
|
272
290
|
if (this.observables !== undefined) {
|
|
273
|
-
const skip = !observable.
|
|
274
|
-
changeset === this.
|
|
291
|
+
const skip = !observable.isLaunch &&
|
|
292
|
+
changeset.id === this.lastEditorChangesetId;
|
|
275
293
|
if (!skip) {
|
|
276
|
-
const why = `${Dump.snapshot2(h, changeset,
|
|
294
|
+
const why = `${Dump.snapshot2(h, changeset, fk, observable)} ◀◀ ${outer}`;
|
|
277
295
|
const isReactive = this.options.kind === Kind.reactive;
|
|
278
296
|
this.obsoleteDueTo = why;
|
|
279
297
|
this.obsoleteSince = since;
|
|
280
298
|
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 ===
|
|
299
|
+
Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", isReactive ? "█" : "▒", isReactive && changeset === EMPTY_OBJECT_VERSION.changeset
|
|
282
300
|
? `${this.hint()} is reactive and will run automatically (order ${this.options.order})`
|
|
283
|
-
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset,
|
|
301
|
+
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, fk)} since s${since}${isReactive ? ` and will run automatically (order ${this.options.order})` : ""}`);
|
|
284
302
|
this.unsubscribeFromAllObservables();
|
|
285
303
|
if (isReactive)
|
|
286
304
|
obsolete.push(this);
|
|
287
305
|
else
|
|
288
|
-
(_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.
|
|
306
|
+
(_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
307
|
const tran = this.transaction;
|
|
290
308
|
if (tran.changeset === changeset) {
|
|
291
309
|
}
|
|
292
310
|
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,
|
|
311
|
+
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
312
|
}
|
|
295
313
|
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,
|
|
314
|
+
Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset, fk, observable)}`);
|
|
297
315
|
}
|
|
298
316
|
}
|
|
299
317
|
relaunchIfNotUpToDate(now, nothrow) {
|
|
@@ -303,7 +321,7 @@ class Launch extends ValueSnapshot {
|
|
|
303
321
|
if (now || hold < 0) {
|
|
304
322
|
if (this.isNotUpToDate()) {
|
|
305
323
|
try {
|
|
306
|
-
const launch = this.
|
|
324
|
+
const launch = this.operation.reuseOrRelaunch(false, undefined);
|
|
307
325
|
if (launch.result instanceof Promise)
|
|
308
326
|
launch.result.catch(error => {
|
|
309
327
|
if (launch.options.kind === Kind.reactive)
|
|
@@ -367,6 +385,8 @@ class Launch extends ValueSnapshot {
|
|
|
367
385
|
static proceed(launch, proxy) {
|
|
368
386
|
launch.enter();
|
|
369
387
|
try {
|
|
388
|
+
if (launch.options.getter === undefined)
|
|
389
|
+
console.log("(!)");
|
|
370
390
|
launch.result = launch.options.getter.call(proxy, ...launch.args);
|
|
371
391
|
}
|
|
372
392
|
finally {
|
|
@@ -377,7 +397,7 @@ class Launch extends ValueSnapshot {
|
|
|
377
397
|
if (this.options.indicator)
|
|
378
398
|
this.indicatorEnter(this.options.indicator);
|
|
379
399
|
if (Log.isOn && Log.opt.operation)
|
|
380
|
-
Log.write("║", "‾\\", `${this.hint()} - enter`, undefined, ` [ ${Dump.obj(this.
|
|
400
|
+
Log.write("║", "‾\\", `${this.hint()} - enter`, undefined, ` [ ${Dump.obj(this.operation.ownerHandle, this.operation.fieldKey)} ]`);
|
|
381
401
|
this.started = Date.now();
|
|
382
402
|
}
|
|
383
403
|
leaveOrAsync() {
|
|
@@ -417,53 +437,53 @@ class Launch extends ValueSnapshot {
|
|
|
417
437
|
indicatorEnter(mon) {
|
|
418
438
|
const options = {
|
|
419
439
|
hint: "Indicator.enter",
|
|
420
|
-
|
|
440
|
+
isolation: Isolation.disjoinFromOuterAndInnerTransactions,
|
|
421
441
|
logging: Log.isOn && Log.opt.indicator ? undefined : Log.global
|
|
422
442
|
};
|
|
423
|
-
|
|
443
|
+
OperationImpl.proceedWithinGivenLaunch(undefined, Transaction.run, options, IndicatorImpl.enter, mon, this.transaction);
|
|
424
444
|
}
|
|
425
445
|
indicatorLeave(mon) {
|
|
426
446
|
Transaction.outside(() => {
|
|
427
447
|
const leave = () => {
|
|
428
448
|
const options = {
|
|
429
449
|
hint: "Indicator.leave",
|
|
430
|
-
|
|
450
|
+
isolation: Isolation.disjoinFromOuterAndInnerTransactions,
|
|
431
451
|
logging: Log.isOn && Log.opt.indicator ? undefined : Log.DefaultLevel
|
|
432
452
|
};
|
|
433
|
-
|
|
453
|
+
OperationImpl.proceedWithinGivenLaunch(undefined, Transaction.run, options, IndicatorImpl.leave, mon, this.transaction);
|
|
434
454
|
};
|
|
435
455
|
this.transaction.whenFinished().then(leave, leave);
|
|
436
456
|
});
|
|
437
457
|
}
|
|
438
458
|
addToDeferredReactiveFunctions() {
|
|
439
|
-
Launch.
|
|
440
|
-
if (Launch.
|
|
459
|
+
Launch.deferredReactiveOperations.push(this);
|
|
460
|
+
if (Launch.deferredReactiveOperations.length === 1)
|
|
441
461
|
setTimeout(Launch.processDeferredReactiveFunctions, 0);
|
|
442
462
|
}
|
|
443
463
|
static processDeferredReactiveFunctions() {
|
|
444
|
-
const deferred = Launch.
|
|
445
|
-
Launch.
|
|
464
|
+
const deferred = Launch.deferredReactiveOperations;
|
|
465
|
+
Launch.deferredReactiveOperations = [];
|
|
446
466
|
for (const x of deferred)
|
|
447
467
|
x.relaunchIfNotUpToDate(true, true);
|
|
448
468
|
}
|
|
449
|
-
static markUsed(observable,
|
|
469
|
+
static markUsed(observable, ov, fk, h, kind, weak) {
|
|
450
470
|
if (kind !== Kind.transactional) {
|
|
451
471
|
const launch = Launch.current;
|
|
452
472
|
if (launch && launch.options.kind !== Kind.transactional &&
|
|
453
|
-
launch.transaction === Transaction.current &&
|
|
473
|
+
launch.transaction === Transaction.current && fk !== Meta.Handle) {
|
|
454
474
|
const ctx = Changeset.current();
|
|
455
|
-
if (ctx !==
|
|
456
|
-
ctx.bumpBy(
|
|
475
|
+
if (ctx !== ov.changeset)
|
|
476
|
+
ctx.bumpBy(ov.changeset.timestamp);
|
|
457
477
|
const t = weak ? -1 : ctx.timestamp;
|
|
458
|
-
if (!launch.subscribeTo(observable,
|
|
459
|
-
launch.markObsoleteDueTo(observable,
|
|
478
|
+
if (!launch.subscribeTo(observable, ov, fk, h, t))
|
|
479
|
+
launch.markObsoleteDueTo(observable, fk, h.applied.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.obsolete);
|
|
460
480
|
}
|
|
461
481
|
}
|
|
462
482
|
}
|
|
463
|
-
static markEdited(oldValue, newValue, edited,
|
|
464
|
-
edited ?
|
|
483
|
+
static markEdited(oldValue, newValue, edited, ov, fk, h) {
|
|
484
|
+
edited ? ov.changes.add(fk) : ov.changes.delete(fk);
|
|
465
485
|
if (Log.isOn && Log.opt.write)
|
|
466
|
-
edited ? Log.write("║", " =", `${Dump.snapshot2(h,
|
|
486
|
+
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
487
|
}
|
|
468
488
|
static isConflicting(oldValue, newValue) {
|
|
469
489
|
let result = oldValue !== newValue;
|
|
@@ -475,30 +495,30 @@ class Launch extends ValueSnapshot {
|
|
|
475
495
|
var _a;
|
|
476
496
|
const since = changeset.timestamp;
|
|
477
497
|
const obsolete = changeset.obsolete;
|
|
478
|
-
changeset.items.forEach((
|
|
479
|
-
Launch.
|
|
480
|
-
if (!
|
|
481
|
-
|
|
498
|
+
changeset.items.forEach((ov, h) => {
|
|
499
|
+
Launch.propagateFieldChangeThroughSubscriptions(false, since, ov, Meta.Revision, h, obsolete);
|
|
500
|
+
if (!ov.disposed)
|
|
501
|
+
ov.changes.forEach((o, fk) => Launch.propagateFieldChangeThroughSubscriptions(false, since, ov, fk, h, obsolete));
|
|
482
502
|
else
|
|
483
|
-
for (const
|
|
484
|
-
Launch.
|
|
503
|
+
for (const fk in ov.former.objectVersion.data)
|
|
504
|
+
Launch.propagateFieldChangeThroughSubscriptions(true, since, ov, fk, h, obsolete);
|
|
485
505
|
});
|
|
486
506
|
obsolete.sort(compareObserversByOrder);
|
|
487
507
|
(_a = changeset.options.journal) === null || _a === void 0 ? void 0 : _a.edited(JournalImpl.buildPatch(changeset.hint, changeset.items));
|
|
488
508
|
}
|
|
489
509
|
static revokeAllSubscriptions(changeset) {
|
|
490
|
-
changeset.items.forEach((
|
|
491
|
-
Launch.
|
|
492
|
-
|
|
510
|
+
changeset.items.forEach((ov, h) => {
|
|
511
|
+
Launch.propagateFieldChangeThroughSubscriptions(true, changeset.timestamp, ov, Meta.Revision, h, undefined);
|
|
512
|
+
ov.changes.forEach((o, fk) => Launch.propagateFieldChangeThroughSubscriptions(true, changeset.timestamp, ov, fk, h, undefined));
|
|
493
513
|
});
|
|
494
514
|
}
|
|
495
|
-
static
|
|
515
|
+
static propagateFieldChangeThroughSubscriptions(unsubscribe, timestamp, ov, fk, h, obsolete) {
|
|
496
516
|
var _a;
|
|
497
|
-
const curr =
|
|
517
|
+
const curr = ov.data[fk];
|
|
498
518
|
if (obsolete !== undefined) {
|
|
499
|
-
const former =
|
|
500
|
-
if (former !== undefined && former instanceof
|
|
501
|
-
const why = `T${
|
|
519
|
+
const former = ov.former.objectVersion.data[fk];
|
|
520
|
+
if (former !== undefined && former instanceof FieldVersion) {
|
|
521
|
+
const why = `T${ov.changeset.id}[${ov.changeset.hint}]`;
|
|
502
522
|
if (former instanceof Launch) {
|
|
503
523
|
if ((former.obsoleteSince === MAX_REVISION || former.obsoleteSince <= 0)) {
|
|
504
524
|
former.obsoleteDueTo = why;
|
|
@@ -508,16 +528,16 @@ class Launch extends ValueSnapshot {
|
|
|
508
528
|
const formerSuccessor = former.successor;
|
|
509
529
|
if (formerSuccessor !== curr) {
|
|
510
530
|
if (formerSuccessor && !formerSuccessor.transaction.isFinished)
|
|
511
|
-
formerSuccessor.transaction.cancel(new Error(`T${formerSuccessor.transaction.id}[${formerSuccessor.transaction.hint}] is canceled by T${
|
|
531
|
+
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
532
|
}
|
|
513
533
|
else
|
|
514
534
|
former.successor = undefined;
|
|
515
535
|
}
|
|
516
|
-
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former,
|
|
536
|
+
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former, fk, ov.changeset, h, why, timestamp, obsolete));
|
|
517
537
|
}
|
|
518
538
|
}
|
|
519
539
|
if (curr instanceof Launch) {
|
|
520
|
-
if (curr.changeset ===
|
|
540
|
+
if (curr.changeset === ov.changeset && curr.observables !== undefined) {
|
|
521
541
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
522
542
|
curr.observables.forEach((info, v) => {
|
|
523
543
|
if (info.usageCount > Mvcc.repetitiveUsageWarningThreshold)
|
|
@@ -528,26 +548,34 @@ class Launch extends ValueSnapshot {
|
|
|
528
548
|
curr.unsubscribeFromAllObservables();
|
|
529
549
|
}
|
|
530
550
|
}
|
|
531
|
-
else if (curr instanceof
|
|
551
|
+
else if (curr instanceof FieldVersion && curr.observers) {
|
|
532
552
|
}
|
|
533
553
|
}
|
|
534
554
|
static enqueueReactiveFunctionsToRun(reactive) {
|
|
535
|
-
const queue = Launch.
|
|
555
|
+
const queue = Launch.queuedReactiveOperations;
|
|
536
556
|
const isReactiveLoopRequired = queue.length === 0;
|
|
537
557
|
for (const r of reactive)
|
|
538
558
|
queue.push(r);
|
|
539
559
|
if (isReactiveLoopRequired)
|
|
540
|
-
|
|
560
|
+
OperationImpl.proceedWithinGivenLaunch(undefined, Launch.processQueuedReactiveOperations);
|
|
561
|
+
}
|
|
562
|
+
static migrateFieldVersion(fv, target) {
|
|
563
|
+
let result;
|
|
564
|
+
if (fv instanceof Launch)
|
|
565
|
+
result = new Launch(target, fv.operation, target.changeset, fv, true);
|
|
566
|
+
else
|
|
567
|
+
result = new FieldVersion(fv.content, fv.lastEditorChangesetId);
|
|
568
|
+
return result;
|
|
541
569
|
}
|
|
542
|
-
static
|
|
543
|
-
const queue = Launch.
|
|
570
|
+
static processQueuedReactiveOperations() {
|
|
571
|
+
const queue = Launch.queuedReactiveOperations;
|
|
544
572
|
let i = 0;
|
|
545
573
|
while (i < queue.length) {
|
|
546
574
|
const reactive = queue[i];
|
|
547
575
|
reactive.relaunchIfNotUpToDate(false, true);
|
|
548
576
|
i++;
|
|
549
577
|
}
|
|
550
|
-
Launch.
|
|
578
|
+
Launch.queuedReactiveOperations = [];
|
|
551
579
|
}
|
|
552
580
|
unsubscribeFromAllObservables() {
|
|
553
581
|
var _a;
|
|
@@ -559,9 +587,10 @@ class Launch extends ValueSnapshot {
|
|
|
559
587
|
});
|
|
560
588
|
this.observables = undefined;
|
|
561
589
|
}
|
|
562
|
-
subscribeTo(observable,
|
|
590
|
+
subscribeTo(observable, ov, fk, h, timestamp) {
|
|
563
591
|
var _a, _b, _c;
|
|
564
|
-
const
|
|
592
|
+
const parent = this.transaction.changeset.parent;
|
|
593
|
+
const ok = Launch.canSubscribeTo(observable, ov, parent, fk, h, timestamp);
|
|
565
594
|
if (ok) {
|
|
566
595
|
let times = 0;
|
|
567
596
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
@@ -571,49 +600,50 @@ class Launch extends ValueSnapshot {
|
|
|
571
600
|
if (this.observables !== undefined) {
|
|
572
601
|
if (!observable.observers)
|
|
573
602
|
observable.observers = new Set();
|
|
574
|
-
const subscription = { memberHint: Dump.snapshot2(h,
|
|
603
|
+
const subscription = { memberHint: Dump.snapshot2(h, ov.changeset, fk), usageCount: times };
|
|
575
604
|
observable.observers.add(this);
|
|
576
605
|
this.observables.set(observable, subscription);
|
|
577
606
|
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,
|
|
607
|
+
Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk, observable)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ""}`);
|
|
579
608
|
}
|
|
580
609
|
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,
|
|
610
|
+
Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk, observable)}`);
|
|
582
611
|
}
|
|
583
612
|
else {
|
|
584
613
|
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,
|
|
614
|
+
Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk, observable)}`);
|
|
586
615
|
}
|
|
587
616
|
return ok;
|
|
588
617
|
}
|
|
589
|
-
static canSubscribeTo(observable,
|
|
590
|
-
const
|
|
591
|
-
|
|
618
|
+
static canSubscribeTo(observable, ov, parent, fk, h, timestamp) {
|
|
619
|
+
const parentSnapshot = parent ? parent.lookupObjectVersion(h, fk, false) : h.applied;
|
|
620
|
+
const observableParent = parentSnapshot.data[fk];
|
|
621
|
+
let result = observable === observableParent || (!ov.changeset.sealed && ov.former.objectVersion.data[fk] === observableParent);
|
|
592
622
|
if (result && timestamp !== -1)
|
|
593
623
|
result = !(observable instanceof Launch && timestamp >= observable.obsoleteSince);
|
|
594
624
|
return result;
|
|
595
625
|
}
|
|
596
|
-
static createOperation(h,
|
|
597
|
-
const rx = new
|
|
626
|
+
static createOperation(h, fk, options) {
|
|
627
|
+
const rx = new OperationImpl(h, fk);
|
|
598
628
|
const operation = (...args) => {
|
|
599
629
|
return rx.reuseOrRelaunch(false, args).result;
|
|
600
630
|
};
|
|
601
631
|
Meta.set(operation, Meta.Controller, rx);
|
|
602
632
|
return operation;
|
|
603
633
|
}
|
|
604
|
-
static rememberOperationOptions(proto,
|
|
634
|
+
static rememberOperationOptions(proto, fk, getter, setter, enumerable, configurable, options, implicit) {
|
|
605
635
|
const initial = Meta.acquire(proto, Meta.Initial);
|
|
606
|
-
let launch = initial[
|
|
607
|
-
const rx = launch ? launch.
|
|
636
|
+
let launch = initial[fk];
|
|
637
|
+
const rx = launch ? launch.operation : new OperationImpl(EMPTY_HANDLE, fk);
|
|
608
638
|
const opts = launch ? launch.options : OptionsImpl.INITIAL;
|
|
609
|
-
initial[
|
|
639
|
+
initial[fk] = launch = new Launch(Transaction.current, rx, EMPTY_OBJECT_VERSION.changeset, new OptionsImpl(getter, setter, opts, options, implicit), false);
|
|
610
640
|
if (launch.options.kind === Kind.reactive && launch.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
611
641
|
const reactive = Meta.acquire(proto, Meta.Reactive);
|
|
612
|
-
reactive[
|
|
642
|
+
reactive[fk] = launch;
|
|
613
643
|
}
|
|
614
644
|
else if (launch.options.kind === Kind.reactive && launch.options.throttling >= Number.MAX_SAFE_INTEGER) {
|
|
615
645
|
const reactive = Meta.getFrom(proto, Meta.Reactive);
|
|
616
|
-
delete reactive[
|
|
646
|
+
delete reactive[fk];
|
|
617
647
|
}
|
|
618
648
|
return launch.options;
|
|
619
649
|
}
|
|
@@ -627,25 +657,26 @@ class Launch extends ValueSnapshot {
|
|
|
627
657
|
Changeset.propagateAllChangesThroughSubscriptions = Launch.propagateAllChangesThroughSubscriptions;
|
|
628
658
|
Changeset.revokeAllSubscriptions = Launch.revokeAllSubscriptions;
|
|
629
659
|
Changeset.enqueueReactiveFunctionsToRun = Launch.enqueueReactiveFunctionsToRun;
|
|
660
|
+
TransactionImpl.migrateFieldVersion = Launch.migrateFieldVersion;
|
|
630
661
|
Mvcc.createOperation = Launch.createOperation;
|
|
631
662
|
Mvcc.rememberOperationOptions = Launch.rememberOperationOptions;
|
|
632
663
|
Promise.prototype.then = reactronicHookedThen;
|
|
633
664
|
try {
|
|
634
665
|
Object.defineProperty(globalThis, "rWhy", {
|
|
635
|
-
get:
|
|
666
|
+
get: OperationImpl.why, configurable: false, enumerable: false,
|
|
636
667
|
});
|
|
637
668
|
Object.defineProperty(globalThis, "rBriefWhy", {
|
|
638
|
-
get:
|
|
669
|
+
get: OperationImpl.briefWhy, configurable: false, enumerable: false,
|
|
639
670
|
});
|
|
640
671
|
}
|
|
641
672
|
catch (e) {
|
|
642
673
|
}
|
|
643
674
|
try {
|
|
644
675
|
Object.defineProperty(global, "rWhy", {
|
|
645
|
-
get:
|
|
676
|
+
get: OperationImpl.why, configurable: false, enumerable: false,
|
|
646
677
|
});
|
|
647
678
|
Object.defineProperty(global, "rBriefWhy", {
|
|
648
|
-
get:
|
|
679
|
+
get: OperationImpl.briefWhy, configurable: false, enumerable: false,
|
|
649
680
|
});
|
|
650
681
|
}
|
|
651
682
|
catch (e) {
|
|
@@ -653,8 +684,8 @@ class Launch extends ValueSnapshot {
|
|
|
653
684
|
}
|
|
654
685
|
}
|
|
655
686
|
Launch.current = undefined;
|
|
656
|
-
Launch.
|
|
657
|
-
Launch.
|
|
687
|
+
Launch.queuedReactiveOperations = [];
|
|
688
|
+
Launch.deferredReactiveOperations = [];
|
|
658
689
|
function valueHint(value) {
|
|
659
690
|
let result = "";
|
|
660
691
|
if (Array.isArray(value))
|
|
@@ -664,7 +695,7 @@ function valueHint(value) {
|
|
|
664
695
|
else if (value instanceof Map)
|
|
665
696
|
result = `Map(${value.size})`;
|
|
666
697
|
else if (value instanceof Launch)
|
|
667
|
-
result = `#${value.
|
|
698
|
+
result = `#${value.operation.ownerHandle.id}t${value.changeset.id}s${value.changeset.timestamp}${value.lastEditorChangesetId !== undefined && value.lastEditorChangesetId !== 0 ? `t${value.lastEditorChangesetId}` : ""}`;
|
|
668
699
|
else if (value === Meta.Undefined)
|
|
669
700
|
result = "undefined";
|
|
670
701
|
else if (typeof (value) === "string")
|