reactronic 0.21.602 → 0.21.603
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/build/dist/source/impl/Data.d.ts +3 -2
- package/build/dist/source/impl/Operation.d.ts +6 -6
- package/build/dist/source/impl/Operation.js +53 -67
- package/build/dist/source/impl/Snapshot.d.ts +2 -2
- package/build/dist/source/impl/Snapshot.js +16 -18
- package/build/dist/source/impl/Transaction.js +1 -1
- package/package.json +1 -1
|
@@ -18,12 +18,13 @@ export interface Observer {
|
|
|
18
18
|
readonly observables: Map<Observable, MemberInfo> | undefined;
|
|
19
19
|
readonly obsoleteSince: number;
|
|
20
20
|
hint(nop?: boolean): string;
|
|
21
|
-
markObsoleteDueTo(observable: Observable,
|
|
21
|
+
markObsoleteDueTo(observable: Observable, memberName: MemberName, snapshot: AbstractSnapshot, holder: ObjectHolder, outer: string, since: number, reactions: Observer[]): void;
|
|
22
22
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
23
23
|
}
|
|
24
24
|
export declare type MemberName = PropertyKey;
|
|
25
25
|
export interface MemberInfo {
|
|
26
|
-
readonly
|
|
26
|
+
readonly holder: ObjectHolder;
|
|
27
|
+
readonly snapshot: AbstractSnapshot;
|
|
27
28
|
readonly memberName: MemberName;
|
|
28
29
|
readonly usageCount: number;
|
|
29
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { F } from '../util/Utils';
|
|
2
2
|
import { MemberOptions } from '../Options';
|
|
3
3
|
import { Controller } from '../Controller';
|
|
4
|
-
import {
|
|
4
|
+
import { MemberName, ObjectHolder, Observable, Observer, MemberInfo, AbstractSnapshot } from './Data';
|
|
5
5
|
import { Transaction } from './Transaction';
|
|
6
6
|
import { OptionsImpl } from './Hooks';
|
|
7
7
|
export declare class OperationController extends Controller<any> {
|
|
@@ -39,18 +39,18 @@ declare class Operation extends Observable implements Observer {
|
|
|
39
39
|
readonly margin: number;
|
|
40
40
|
readonly transaction: Transaction;
|
|
41
41
|
readonly controller: OperationController;
|
|
42
|
-
readonly
|
|
42
|
+
readonly snapshot: AbstractSnapshot;
|
|
43
43
|
observables: Map<Observable, MemberInfo> | undefined;
|
|
44
44
|
options: OptionsImpl;
|
|
45
|
-
cause:
|
|
45
|
+
cause: string | undefined;
|
|
46
46
|
args: any[];
|
|
47
47
|
result: any;
|
|
48
48
|
error: any;
|
|
49
49
|
started: number;
|
|
50
|
-
obsoleteDueTo:
|
|
50
|
+
obsoleteDueTo: string | undefined;
|
|
51
51
|
obsoleteSince: number;
|
|
52
52
|
successor: Operation | undefined;
|
|
53
|
-
constructor(controller: OperationController,
|
|
53
|
+
constructor(controller: OperationController, snapshot: AbstractSnapshot, prev: Operation | OptionsImpl);
|
|
54
54
|
get isOperation(): boolean;
|
|
55
55
|
get selfSnapshotId(): number;
|
|
56
56
|
hint(): string;
|
|
@@ -61,7 +61,7 @@ declare class Operation extends Observable implements Observer {
|
|
|
61
61
|
dependencies(): string[];
|
|
62
62
|
wrap<T>(func: F<T>): F<T>;
|
|
63
63
|
run(proxy: any, args: any[] | undefined): void;
|
|
64
|
-
markObsoleteDueTo(observable: Observable,
|
|
64
|
+
markObsoleteDueTo(observable: Observable, memberName: MemberName, snapshot: AbstractSnapshot, holder: ObjectHolder, outer: string, since: number, reactions: Observer[]): void;
|
|
65
65
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
66
66
|
isNotUpToDate(): boolean;
|
|
67
67
|
reenterOver(head: Operation): this;
|
|
@@ -12,7 +12,7 @@ const Hooks_1 = require("./Hooks");
|
|
|
12
12
|
const TransactionJournal_1 = require("./TransactionJournal");
|
|
13
13
|
const ROOT_ARGS = [];
|
|
14
14
|
const ROOT_HOLDER = new Data_1.ObjectHolder(undefined, undefined, Hooks_1.Hooks.proxy, Snapshot_1.ROOT_REV, 'root-holder');
|
|
15
|
-
const
|
|
15
|
+
const INITIAL_CAUSE = 'initial';
|
|
16
16
|
class OperationController extends Controller_1.Controller {
|
|
17
17
|
constructor(ownHolder, memberName) {
|
|
18
18
|
super();
|
|
@@ -36,7 +36,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
36
36
|
const op = oc.operation;
|
|
37
37
|
const opts = op.options;
|
|
38
38
|
if (!oc.isUpToDate && oc.revision.data[Data_1.Meta.Disposed] === undefined
|
|
39
|
-
&& (!weak || op.cause ===
|
|
39
|
+
&& (!weak || op.cause === INITIAL_CAUSE || !op.successor ||
|
|
40
40
|
op.successor.transaction.isFinished)) {
|
|
41
41
|
const outerOpts = (_a = Operation.current) === null || _a === void 0 ? void 0 : _a.options;
|
|
42
42
|
const standalone = weak || opts.standalone || opts.kind === Options_1.Kind.Reaction ||
|
|
@@ -45,13 +45,13 @@ class OperationController extends Controller_1.Controller {
|
|
|
45
45
|
oc.revision.prev.revision !== Snapshot_1.ROOT_REV));
|
|
46
46
|
const token = opts.noSideEffects ? this : undefined;
|
|
47
47
|
const oc2 = this.run(oc, standalone, opts, token, args);
|
|
48
|
-
const ctx2 = oc2.operation.
|
|
48
|
+
const ctx2 = oc2.operation.snapshot;
|
|
49
49
|
if (!weak || ctx === ctx2 || (ctx2.sealed && ctx.timestamp >= ctx2.timestamp))
|
|
50
50
|
oc = oc2;
|
|
51
51
|
}
|
|
52
52
|
else if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.operation && (opts.trace === undefined ||
|
|
53
53
|
opts.trace.operation === undefined || opts.trace.operation === true))
|
|
54
|
-
Dbg_1.Dbg.log(Transaction_1.Transaction.current.isFinished ? '' : '║', ' (=)', `${Snapshot_1.Dump.
|
|
54
|
+
Dbg_1.Dbg.log(Transaction_1.Transaction.current.isFinished ? '' : '║', ' (=)', `${Snapshot_1.Dump.rev2(oc.operation.controller.ownHolder, oc.snapshot, this.memberName)} result is reused from T${oc.operation.transaction.id}[${oc.operation.transaction.hint}]`);
|
|
55
55
|
const t = oc.operation;
|
|
56
56
|
Snapshot_1.Snapshot.markUsed(t, oc.revision, this.memberName, this.ownHolder, t.options.kind, weak);
|
|
57
57
|
return t;
|
|
@@ -108,8 +108,8 @@ class OperationController extends Controller_1.Controller {
|
|
|
108
108
|
const ctx = Snapshot_1.Snapshot.current();
|
|
109
109
|
const r = ctx.seekRevision(this.ownHolder, this.memberName);
|
|
110
110
|
const op = this.peekFromRevision(r, args);
|
|
111
|
-
const isValid = op.options.kind !== Options_1.Kind.Transaction && op.cause !==
|
|
112
|
-
(ctx === op.
|
|
111
|
+
const isValid = op.options.kind !== Options_1.Kind.Transaction && op.cause !== INITIAL_CAUSE &&
|
|
112
|
+
(ctx === op.snapshot || ctx.timestamp < op.obsoleteSince) &&
|
|
113
113
|
(!op.options.sensitiveArgs || args === undefined ||
|
|
114
114
|
op.args.length === args.length && op.args.every((t, i) => t === args[i])) ||
|
|
115
115
|
r.data[Data_1.Meta.Disposed] !== undefined;
|
|
@@ -126,8 +126,8 @@ class OperationController extends Controller_1.Controller {
|
|
|
126
126
|
const ctx = Snapshot_1.Snapshot.edit();
|
|
127
127
|
const r = ctx.getEditableRevision(h, m, Data_1.Meta.Holder, this);
|
|
128
128
|
let op = this.peekFromRevision(r, undefined);
|
|
129
|
-
if (op.
|
|
130
|
-
const op2 = new Operation(this, r, op);
|
|
129
|
+
if (op.snapshot !== r.snapshot) {
|
|
130
|
+
const op2 = new Operation(this, r.snapshot, op);
|
|
131
131
|
r.data[m] = op2.reenterOver(op);
|
|
132
132
|
ctx.bumpBy(r.prev.revision.snapshot.timestamp);
|
|
133
133
|
Snapshot_1.Snapshot.markEdited(op, op2, true, r, m, h);
|
|
@@ -147,10 +147,10 @@ class OperationController extends Controller_1.Controller {
|
|
|
147
147
|
let op2 = r2.data[m];
|
|
148
148
|
if (op2.controller !== this) {
|
|
149
149
|
r2 = Snapshot_1.Snapshot.edit().getEditableRevision(h, m, Data_1.Meta.Holder, this);
|
|
150
|
-
const t = new Operation(this, r2, op2);
|
|
150
|
+
const t = new Operation(this, r2.snapshot, op2);
|
|
151
151
|
if (args)
|
|
152
152
|
t.args = args;
|
|
153
|
-
t.cause =
|
|
153
|
+
t.cause = INITIAL_CAUSE;
|
|
154
154
|
r2.data[m] = t;
|
|
155
155
|
Snapshot_1.Snapshot.markEdited(op2, t, true, r2, m, h);
|
|
156
156
|
op2 = t;
|
|
@@ -188,17 +188,17 @@ class OperationController extends Controller_1.Controller {
|
|
|
188
188
|
static markObsolete(self) {
|
|
189
189
|
const oc = self.peek(undefined);
|
|
190
190
|
const ctx = oc.snapshot;
|
|
191
|
-
oc.operation.markObsoleteDueTo(oc.operation,
|
|
191
|
+
oc.operation.markObsoleteDueTo(oc.operation, self.memberName, Snapshot_1.ROOT_REV.snapshot, ROOT_HOLDER, INITIAL_CAUSE, ctx.timestamp, ctx.reactions);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
exports.OperationController = OperationController;
|
|
195
195
|
class Operation extends Data_1.Observable {
|
|
196
|
-
constructor(controller,
|
|
196
|
+
constructor(controller, snapshot, prev) {
|
|
197
197
|
super(undefined);
|
|
198
198
|
this.margin = Operation.current ? Operation.current.margin + 1 : 1;
|
|
199
199
|
this.transaction = Transaction_1.Transaction.current;
|
|
200
200
|
this.controller = controller;
|
|
201
|
-
this.
|
|
201
|
+
this.snapshot = snapshot;
|
|
202
202
|
this.observables = new Map();
|
|
203
203
|
if (prev instanceof Operation) {
|
|
204
204
|
this.options = prev.options;
|
|
@@ -216,28 +216,24 @@ class Operation extends Data_1.Observable {
|
|
|
216
216
|
this.successor = undefined;
|
|
217
217
|
}
|
|
218
218
|
get isOperation() { return true; }
|
|
219
|
-
get selfSnapshotId() { return this.
|
|
220
|
-
hint() { return `${Snapshot_1.Dump.
|
|
219
|
+
get selfSnapshotId() { return this.snapshot.id; }
|
|
220
|
+
hint() { return `${Snapshot_1.Dump.rev2(this.controller.ownHolder, this.snapshot, this.controller.memberName)}`; }
|
|
221
221
|
get order() { return this.options.order; }
|
|
222
222
|
get ['#this']() {
|
|
223
223
|
return `Operation: ${this.why()}`;
|
|
224
224
|
}
|
|
225
225
|
why() {
|
|
226
|
-
let
|
|
227
|
-
const prev = this.revision.prev.revision.data[this.controller.memberName];
|
|
228
|
-
if (prev instanceof Operation)
|
|
229
|
-
ms = prev.started !== 0 ? Math.abs(this.started || ms) - Math.abs(prev.started) : Infinity;
|
|
230
|
-
let trigger;
|
|
226
|
+
let cause;
|
|
231
227
|
if (this.cause)
|
|
232
|
-
|
|
228
|
+
cause = ` << ${this.cause}`;
|
|
233
229
|
else if (this.controller.options.kind === Options_1.Kind.Transaction)
|
|
234
|
-
|
|
230
|
+
cause = ' << operation';
|
|
235
231
|
else
|
|
236
|
-
|
|
237
|
-
return `${this.hint()}${
|
|
232
|
+
cause = ` << T${this.snapshot.id}[${this.snapshot.hint}]`;
|
|
233
|
+
return `${this.hint()}${cause}`;
|
|
238
234
|
}
|
|
239
235
|
briefWhy() {
|
|
240
|
-
return this.
|
|
236
|
+
return this.why();
|
|
241
237
|
}
|
|
242
238
|
dependencies() {
|
|
243
239
|
throw (0, Dbg_1.misuse)('not implemented yet');
|
|
@@ -266,34 +262,33 @@ class Operation extends Data_1.Observable {
|
|
|
266
262
|
else
|
|
267
263
|
this.result = Promise.reject(this.error);
|
|
268
264
|
}
|
|
269
|
-
markObsoleteDueTo(observable,
|
|
265
|
+
markObsoleteDueTo(observable, memberName, snapshot, holder, outer, since, reactions) {
|
|
270
266
|
var _a, _b, _c;
|
|
271
267
|
if (this.observables !== undefined) {
|
|
272
268
|
const skip = !observable.isOperation &&
|
|
273
|
-
|
|
274
|
-
cause.revision.changes.has(cause.memberName);
|
|
269
|
+
snapshot === this.snapshot;
|
|
275
270
|
if (!skip) {
|
|
271
|
+
const why = `${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} << ${outer}`;
|
|
276
272
|
this.unsubscribeFromAllObservables();
|
|
277
|
-
this.obsoleteDueTo =
|
|
273
|
+
this.obsoleteDueTo = why;
|
|
278
274
|
this.obsoleteSince = since;
|
|
279
275
|
const isReaction = this.options.kind === Options_1.Kind.Reaction;
|
|
280
276
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.obsolete)))
|
|
281
|
-
Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', isReaction ? '█' : '▒', isReaction &&
|
|
277
|
+
Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', isReaction ? '█' : '▒', isReaction && snapshot === Snapshot_1.ROOT_REV.snapshot
|
|
282
278
|
? `${this.hint()} is a reaction and will run automatically (order ${this.options.order})`
|
|
283
|
-
: `${this.hint()} is obsolete due to ${Snapshot_1.Dump.
|
|
279
|
+
: `${this.hint()} is obsolete due to ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} since v${since}${isReaction ? ` and will run automatically (order ${this.options.order})` : ''}`);
|
|
284
280
|
if (isReaction)
|
|
285
281
|
reactions.push(this);
|
|
286
282
|
else
|
|
287
|
-
(_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(c => c.markObsoleteDueTo(this,
|
|
283
|
+
(_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(c => c.markObsoleteDueTo(this, this.controller.memberName, this.snapshot, this.controller.ownHolder, why, since, reactions));
|
|
288
284
|
const tran = this.transaction;
|
|
289
|
-
if (tran.snapshot ===
|
|
290
|
-
(0, Dbg_1.misuse)('not implemented: running reactions within original transaction');
|
|
285
|
+
if (tran.snapshot === snapshot) {
|
|
291
286
|
}
|
|
292
287
|
else if (!tran.isFinished && this !== observable)
|
|
293
|
-
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Snapshot_1.Dump.
|
|
288
|
+
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} changed by T${snapshot.id}[${snapshot.hint}]`), null);
|
|
294
289
|
}
|
|
295
290
|
else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
296
|
-
Dbg_1.Dbg.log(' ', 'x', `${this.hint()} is not obsolete due to its own change to ${Snapshot_1.Dump.
|
|
291
|
+
Dbg_1.Dbg.log(' ', 'x', `${this.hint()} is not obsolete due to its own change to ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)}`);
|
|
297
292
|
}
|
|
298
293
|
}
|
|
299
294
|
runIfNotUpToDate(now, nothrow) {
|
|
@@ -455,19 +450,19 @@ class Operation extends Data_1.Observable {
|
|
|
455
450
|
ctx.bumpBy(r.snapshot.timestamp);
|
|
456
451
|
const t = weak ? -1 : ctx.timestamp;
|
|
457
452
|
if (!op.subscribeTo(observable, r, m, h, t))
|
|
458
|
-
op.markObsoleteDueTo(observable,
|
|
453
|
+
op.markObsoleteDueTo(observable, m, r.snapshot, h, INITIAL_CAUSE, ctx.timestamp, ctx.reactions);
|
|
459
454
|
}
|
|
460
455
|
}
|
|
461
456
|
}
|
|
462
457
|
static markEdited(oldValue, newValue, edited, r, m, h) {
|
|
463
458
|
edited ? r.changes.add(m) : r.changes.delete(m);
|
|
464
459
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
|
|
465
|
-
edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.
|
|
460
|
+
edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev2(h, r.snapshot, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`) : Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev2(h, r.snapshot, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`, undefined, ' (same as previous)');
|
|
466
461
|
}
|
|
467
462
|
static isConflicting(oldValue, newValue) {
|
|
468
463
|
let result = oldValue !== newValue;
|
|
469
464
|
if (result)
|
|
470
|
-
result = oldValue instanceof Operation && oldValue.cause !==
|
|
465
|
+
result = oldValue instanceof Operation && oldValue.cause !== INITIAL_CAUSE;
|
|
471
466
|
return result;
|
|
472
467
|
}
|
|
473
468
|
static propagateAllChangesThroughSubscriptions(snapshot) {
|
|
@@ -493,26 +488,30 @@ class Operation extends Data_1.Observable {
|
|
|
493
488
|
if (reactions) {
|
|
494
489
|
const prev = r.prev.revision.data[m];
|
|
495
490
|
if (prev !== undefined && prev instanceof Data_1.Observable) {
|
|
496
|
-
const
|
|
491
|
+
const why = `T${r.snapshot.id}[${r.snapshot.hint}]`;
|
|
497
492
|
if (prev instanceof Operation) {
|
|
498
493
|
if ((prev.obsoleteSince === Snapshot_1.MAX_TIMESTAMP || prev.obsoleteSince <= 0)) {
|
|
499
|
-
prev.obsoleteDueTo =
|
|
494
|
+
prev.obsoleteDueTo = why;
|
|
500
495
|
prev.obsoleteSince = timestamp;
|
|
501
496
|
prev.unsubscribeFromAllObservables();
|
|
502
497
|
}
|
|
503
|
-
const
|
|
504
|
-
if (
|
|
505
|
-
|
|
498
|
+
const prevSuccessor = prev.successor;
|
|
499
|
+
if (prevSuccessor !== curr) {
|
|
500
|
+
if (prevSuccessor && !prevSuccessor.transaction.isFinished)
|
|
501
|
+
prevSuccessor.transaction.cancel(new Error(`T${prevSuccessor.transaction.id}[${prevSuccessor.transaction.hint}] is canceled by T${r.snapshot.id}[${r.snapshot.hint}] and will not run anymore`), null);
|
|
502
|
+
}
|
|
503
|
+
else
|
|
504
|
+
prev.successor = undefined;
|
|
506
505
|
}
|
|
507
|
-
(_a = prev.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(prev,
|
|
506
|
+
(_a = prev.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(prev, m, r.snapshot, h, why, timestamp, reactions));
|
|
508
507
|
}
|
|
509
508
|
}
|
|
510
509
|
if (curr instanceof Operation) {
|
|
511
|
-
if (curr.
|
|
510
|
+
if (curr.snapshot === r.snapshot && curr.observables !== undefined) {
|
|
512
511
|
if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
513
512
|
curr.observables.forEach((hint, v) => {
|
|
514
513
|
if (hint.usageCount > Hooks_1.Hooks.repetitiveUsageWarningThreshold)
|
|
515
|
-
Dbg_1.Dbg.log('', '[!]', `${curr.hint()} uses ${Snapshot_1.Dump.
|
|
514
|
+
Dbg_1.Dbg.log('', '[!]', `${curr.hint()} uses ${Snapshot_1.Dump.rev2(hint.holder, hint.snapshot, hint.memberName)} ${hint.usageCount} times (consider remembering it in a local variable)`, 0, ' *** WARNING ***');
|
|
516
515
|
});
|
|
517
516
|
}
|
|
518
517
|
if (unsubscribe)
|
|
@@ -552,7 +551,7 @@ class Operation extends Data_1.Observable {
|
|
|
552
551
|
var _a;
|
|
553
552
|
value.observers.delete(this);
|
|
554
553
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
|
|
555
|
-
Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${Snapshot_1.Dump.
|
|
554
|
+
Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${Snapshot_1.Dump.rev2(hint.holder, hint.snapshot, hint.memberName)}`);
|
|
556
555
|
});
|
|
557
556
|
this.observables = undefined;
|
|
558
557
|
}
|
|
@@ -568,18 +567,18 @@ class Operation extends Data_1.Observable {
|
|
|
568
567
|
if (this.observables !== undefined) {
|
|
569
568
|
if (!observable.observers)
|
|
570
569
|
observable.observers = new Set();
|
|
571
|
-
const info = {
|
|
570
|
+
const info = { holder: h, snapshot: r.snapshot, memberName: m, usageCount: times };
|
|
572
571
|
observable.observers.add(this);
|
|
573
572
|
this.observables.set(observable, info);
|
|
574
573
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
|
|
575
|
-
Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.
|
|
574
|
+
Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
|
|
576
575
|
}
|
|
577
576
|
else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_b = this.options.trace) === null || _b === void 0 ? void 0 : _b.read)))
|
|
578
|
-
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.
|
|
577
|
+
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}`);
|
|
579
578
|
}
|
|
580
579
|
else {
|
|
581
580
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.read)))
|
|
582
|
-
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.
|
|
581
|
+
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}`);
|
|
583
582
|
}
|
|
584
583
|
return ok;
|
|
585
584
|
}
|
|
@@ -602,7 +601,7 @@ class Operation extends Data_1.Observable {
|
|
|
602
601
|
let op = initial[m];
|
|
603
602
|
const ctl = op ? op.controller : new OperationController(ROOT_HOLDER, m);
|
|
604
603
|
const opts = op ? op.options : Hooks_1.OptionsImpl.INITIAL;
|
|
605
|
-
initial[m] = op = new Operation(ctl, Snapshot_1.ROOT_REV, new Hooks_1.OptionsImpl(getter, setter, opts, options, implicit));
|
|
604
|
+
initial[m] = op = new Operation(ctl, Snapshot_1.ROOT_REV.snapshot, new Hooks_1.OptionsImpl(getter, setter, opts, options, implicit));
|
|
606
605
|
if (op.options.kind === Options_1.Kind.Reaction && op.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
607
606
|
const reactions = Data_1.Meta.acquire(proto, Data_1.Meta.Reactions);
|
|
608
607
|
reactions[m] = op;
|
|
@@ -615,7 +614,6 @@ class Operation extends Data_1.Observable {
|
|
|
615
614
|
}
|
|
616
615
|
static init() {
|
|
617
616
|
Object.freeze(ROOT_ARGS);
|
|
618
|
-
Object.freeze(ROOT_TRIGGER);
|
|
619
617
|
Dbg_1.Dbg.getMergedTraceOptions = getMergedTraceOptions;
|
|
620
618
|
Snapshot_1.Snapshot.markUsed = Operation.markUsed;
|
|
621
619
|
Snapshot_1.Snapshot.markEdited = Operation.markEdited;
|
|
@@ -651,18 +649,6 @@ class Operation extends Data_1.Observable {
|
|
|
651
649
|
Operation.current = undefined;
|
|
652
650
|
Operation.queuedReactions = [];
|
|
653
651
|
Operation.deferredReactions = [];
|
|
654
|
-
function propagationHint(cause, full) {
|
|
655
|
-
const result = [];
|
|
656
|
-
let observable = cause.revision.data[cause.memberName];
|
|
657
|
-
while (observable instanceof Operation && observable.obsoleteDueTo) {
|
|
658
|
-
full && result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
|
|
659
|
-
cause = observable.obsoleteDueTo;
|
|
660
|
-
observable = cause.revision.data[cause.memberName];
|
|
661
|
-
}
|
|
662
|
-
result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
|
|
663
|
-
full && result.push(cause.revision.snapshot.hint);
|
|
664
|
-
return result;
|
|
665
|
-
}
|
|
666
652
|
function valueHint(value, m) {
|
|
667
653
|
let result = '';
|
|
668
654
|
if (Array.isArray(value))
|
|
@@ -672,7 +658,7 @@ function valueHint(value, m) {
|
|
|
672
658
|
else if (value instanceof Map)
|
|
673
659
|
result = `Map(${value.size})`;
|
|
674
660
|
else if (value instanceof Operation)
|
|
675
|
-
result = `${Snapshot_1.Dump.
|
|
661
|
+
result = `${Snapshot_1.Dump.rev2(value.controller.ownHolder, value.snapshot, m)}`;
|
|
676
662
|
else if (value === Data_1.Meta.Disposed)
|
|
677
663
|
result = '<disposed>';
|
|
678
664
|
else if (value !== undefined && value !== null)
|
|
@@ -43,14 +43,14 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
43
43
|
applyOrDiscard(error?: any): Array<Observer>;
|
|
44
44
|
static sealObjectRevision(h: ObjectHolder, r: ObjectRevision): void;
|
|
45
45
|
static sealObservable(observable: Observable | symbol, m: MemberName, typeName: string): void;
|
|
46
|
-
collectGarbage(): void;
|
|
47
46
|
static freezeObjectRevision(r: ObjectRevision): ObjectRevision;
|
|
48
|
-
|
|
47
|
+
triggerGarbageCollection(): void;
|
|
49
48
|
private unlinkHistory;
|
|
50
49
|
static _init(): void;
|
|
51
50
|
}
|
|
52
51
|
export declare class Dump {
|
|
53
52
|
static obj(h: ObjectHolder | undefined, m?: MemberName | undefined, stamp?: number, op?: number, xop?: number, typeless?: boolean): string;
|
|
53
|
+
static rev2(h: ObjectHolder, s: AbstractSnapshot, m?: MemberName, value?: Observable): string;
|
|
54
54
|
static rev(r: ObjectRevision, m?: MemberName): string;
|
|
55
55
|
static conflicts(conflicts: ObjectRevision[]): string;
|
|
56
56
|
static conflictingMemberHint(m: MemberName, ours: ObjectRevision, theirs: ObjectRevision): string;
|
|
@@ -130,14 +130,14 @@ class Snapshot {
|
|
|
130
130
|
if (this.changeset.size > 0) {
|
|
131
131
|
this.changeset.forEach((r, h) => {
|
|
132
132
|
if (r.prev.revision !== h.head) {
|
|
133
|
-
const merged = Snapshot.merge(
|
|
133
|
+
const merged = Snapshot.merge(h, r);
|
|
134
134
|
if (r.conflicts.size > 0) {
|
|
135
135
|
if (!conflicts)
|
|
136
136
|
conflicts = [];
|
|
137
137
|
conflicts.push(r);
|
|
138
138
|
}
|
|
139
139
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.transaction)
|
|
140
|
-
Dbg_1.Dbg.log('╠╝', '', `${Dump.
|
|
140
|
+
Dbg_1.Dbg.log('╠╝', '', `${Dump.rev2(h, r.snapshot)} is merged with ${Dump.rev2(h, h.head.snapshot)} among ${merged} properties with ${r.conflicts.size} conflicts.`);
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
143
|
if (this.options.token === undefined) {
|
|
@@ -154,8 +154,9 @@ class Snapshot {
|
|
|
154
154
|
}
|
|
155
155
|
return conflicts;
|
|
156
156
|
}
|
|
157
|
-
static merge(
|
|
157
|
+
static merge(h, ours) {
|
|
158
158
|
let counter = 0;
|
|
159
|
+
const head = h.head;
|
|
159
160
|
const disposed = head.changes.has(Data_1.Meta.Disposed);
|
|
160
161
|
const merged = Object.assign({}, head.data);
|
|
161
162
|
ours.changes.forEach((o, m) => {
|
|
@@ -164,7 +165,7 @@ class Snapshot {
|
|
|
164
165
|
if (disposed || m === Data_1.Meta.Disposed) {
|
|
165
166
|
if (disposed !== (m === Data_1.Meta.Disposed)) {
|
|
166
167
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
167
|
-
Dbg_1.Dbg.log('║╠', '', `${Dump.
|
|
168
|
+
Dbg_1.Dbg.log('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} <> ${Dump.rev2(h, head.snapshot, m)}`, 0, ' *** CONFLICT ***');
|
|
168
169
|
ours.conflicts.set(m, head);
|
|
169
170
|
}
|
|
170
171
|
}
|
|
@@ -173,7 +174,7 @@ class Snapshot {
|
|
|
173
174
|
if (conflict)
|
|
174
175
|
ours.conflicts.set(m, head);
|
|
175
176
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
176
|
-
Dbg_1.Dbg.log('║╠', '', `${Dump.
|
|
177
|
+
Dbg_1.Dbg.log('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} ${conflict ? '<>' : '=='} ${Dump.rev2(h, head.snapshot, m)}`, 0, conflict ? ' *** CONFLICT ***' : undefined);
|
|
177
178
|
}
|
|
178
179
|
});
|
|
179
180
|
Utils_1.Utils.copyAllMembers(merged, ours.data);
|
|
@@ -202,7 +203,7 @@ class Snapshot {
|
|
|
202
203
|
const members = [];
|
|
203
204
|
r.changes.forEach((o, m) => members.push(m.toString()));
|
|
204
205
|
const s = members.join(', ');
|
|
205
|
-
Dbg_1.Dbg.log('║', '√', `${Dump.
|
|
206
|
+
Dbg_1.Dbg.log('║', '√', `${Dump.rev2(h, r.snapshot)} (${s}) is ${r.prev.revision === exports.ROOT_REV ? 'constructed' : `applied on top of ${Dump.rev2(h, r.prev.revision.snapshot)}`}`);
|
|
206
207
|
});
|
|
207
208
|
}
|
|
208
209
|
if (Dbg_1.Dbg.trace.transaction)
|
|
@@ -231,16 +232,6 @@ class Snapshot {
|
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
}
|
|
234
|
-
collectGarbage() {
|
|
235
|
-
this.changeset = EMPTY_MAP;
|
|
236
|
-
this.reactions = EMPTY_ARRAY;
|
|
237
|
-
if (Dbg_1.Dbg.isOn) {
|
|
238
|
-
Utils_1.Utils.freezeMap(this.changeset);
|
|
239
|
-
Object.freeze(this.reactions);
|
|
240
|
-
Object.freeze(this);
|
|
241
|
-
}
|
|
242
|
-
this.triggerGarbageCollection();
|
|
243
|
-
}
|
|
244
235
|
static freezeObjectRevision(r) {
|
|
245
236
|
Object.freeze(r.data);
|
|
246
237
|
Utils_1.Utils.freezeSet(r.changes);
|
|
@@ -272,7 +263,7 @@ class Snapshot {
|
|
|
272
263
|
Dbg_1.Dbg.log('', '[G]', `Dismiss history below v${this.stamp}t${this.id} (${this.hint})`);
|
|
273
264
|
this.changeset.forEach((r, h) => {
|
|
274
265
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.gc && r.prev.revision !== exports.ROOT_REV)
|
|
275
|
-
Dbg_1.Dbg.log(' ', ' ', `${Dump.
|
|
266
|
+
Dbg_1.Dbg.log(' ', ' ', `${Dump.rev2(h, r.prev.revision.snapshot)} is ready for GC because overwritten by ${Dump.rev2(h, r.snapshot)}`);
|
|
276
267
|
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
277
268
|
if (r.prev.revision !== exports.ROOT_REV)
|
|
278
269
|
Snapshot.totalObjectRevisionCount--;
|
|
@@ -281,12 +272,16 @@ class Snapshot {
|
|
|
281
272
|
}
|
|
282
273
|
r.prev.revision = exports.ROOT_REV;
|
|
283
274
|
});
|
|
275
|
+
this.changeset = EMPTY_MAP;
|
|
276
|
+
this.reactions = EMPTY_ARRAY;
|
|
277
|
+
if (Dbg_1.Dbg.isOn)
|
|
278
|
+
Object.freeze(this);
|
|
284
279
|
}
|
|
285
280
|
static _init() {
|
|
286
281
|
const root = exports.ROOT_REV.snapshot;
|
|
287
282
|
root.acquire(root);
|
|
288
283
|
root.applyOrDiscard();
|
|
289
|
-
root.
|
|
284
|
+
root.triggerGarbageCollection();
|
|
290
285
|
Snapshot.freezeObjectRevision(exports.ROOT_REV);
|
|
291
286
|
Snapshot.idGen = 100;
|
|
292
287
|
Snapshot.stampGen = 101;
|
|
@@ -320,6 +315,9 @@ class Dump {
|
|
|
320
315
|
? `root${member}`
|
|
321
316
|
: stamp === undefined ? `${h.hint}${member} #${h.id}` : `${h.hint}${member} #${h.id}t${op}v${stamp}${xop !== undefined && xop !== 0 ? `t${xop}` : ''}`;
|
|
322
317
|
}
|
|
318
|
+
static rev2(h, s, m, value) {
|
|
319
|
+
return Dump.obj(h, m, s.timestamp, s.id, value === null || value === void 0 ? void 0 : value.selfSnapshotId);
|
|
320
|
+
}
|
|
323
321
|
static rev(r, m) {
|
|
324
322
|
const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
|
|
325
323
|
const value = m !== undefined ? r.data[m] : undefined;
|
|
@@ -264,7 +264,7 @@ class TransactionImpl extends Transaction {
|
|
|
264
264
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
265
265
|
Dbg_1.Dbg.log('╠═', '', '', undefined, 'changes');
|
|
266
266
|
reactions = this.snapshot.applyOrDiscard(this.canceled);
|
|
267
|
-
this.snapshot.
|
|
267
|
+
this.snapshot.triggerGarbageCollection();
|
|
268
268
|
if (this.promise) {
|
|
269
269
|
if (this.canceled && !this.after)
|
|
270
270
|
this.reject(this.canceled);
|