reactronic 0.21.601 → 0.22.101
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 +4 -4
- package/build/dist/source/Rx.d.ts +1 -1
- package/build/dist/source/Rx.js +4 -4
- package/build/dist/source/Trace.d.ts +1 -0
- package/build/dist/source/Trace.js +18 -0
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +2 -2
- package/build/dist/source/impl/Data.d.ts +4 -3
- package/build/dist/source/impl/Data.js +1 -1
- package/build/dist/source/impl/Operation.d.ts +7 -7
- package/build/dist/source/impl/Operation.js +63 -72
- package/build/dist/source/impl/Snapshot.d.ts +6 -6
- package/build/dist/source/impl/Snapshot.js +23 -22
- package/build/dist/source/impl/Transaction.d.ts +1 -1
- package/build/dist/source/impl/Transaction.js +9 -7
- package/build/dist/source/util/Utils.d.ts +2 -2
- package/build/dist/source/util/Utils.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -196,7 +196,7 @@ class Component<P> extends React.Component<P> {
|
|
|
196
196
|
@reaction // called immediately in response to changes
|
|
197
197
|
ensureUpToDate(): void {
|
|
198
198
|
if (this.shouldComponentUpdate())
|
|
199
|
-
|
|
199
|
+
nontransactional(() => this.setState({})) // ask React to re-render
|
|
200
200
|
} // ensureUpToDate is subscribed to render
|
|
201
201
|
|
|
202
202
|
shouldComponentUpdate(): boolean {
|
|
@@ -208,7 +208,7 @@ class Component<P> extends React.Component<P> {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
componentWillUnmount(): void {
|
|
211
|
-
standalone
|
|
211
|
+
Transaction.runAs({ standalone: true }, Rx.dispose, this)
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
```
|
|
@@ -310,7 +310,7 @@ function monitor(value: Monitor | null)
|
|
|
310
310
|
function trace(value: Partial<TraceOptions>)
|
|
311
311
|
|
|
312
312
|
function nonreactive<T>(func: F<T>, ...args: any[]): T
|
|
313
|
-
function
|
|
313
|
+
function nontransactional<T>(func: F<T>, ...args: any[]): T
|
|
314
314
|
function sensitive<T>(sensitivity: Sensitivity, func: F<T>, ...args: any[]): T
|
|
315
315
|
|
|
316
316
|
// Options, ObjectOptions, Kind, Reentrance, Monitor, TraceOptions, ProfilingOptions
|
|
@@ -421,7 +421,7 @@ class Transaction implements Worker {
|
|
|
421
421
|
static run<T>(hint: string, func: F<T>, ...args: any[]): T
|
|
422
422
|
static runEx<T>(hint: string, standalone: boolean, sidebyside: boolean,
|
|
423
423
|
trace: Partial<TraceOptions | undefined>, func: F<T>, ...args: any[]): T
|
|
424
|
-
static
|
|
424
|
+
static nontransactional<T>(func: F<T>, ...args: any[]): T
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
// Controller
|
|
@@ -18,7 +18,7 @@ export declare class Rx {
|
|
|
18
18
|
static setProfilingMode(enabled: boolean, options?: Partial<ProfilingOptions>): void;
|
|
19
19
|
}
|
|
20
20
|
export declare function nonreactive<T>(func: F<T>, ...args: any[]): T;
|
|
21
|
-
export declare function
|
|
21
|
+
export declare function nontransactional<T>(func: F<T>, ...args: any[]): T;
|
|
22
22
|
export declare function sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
23
23
|
export declare function unobservable(proto: object, prop: PropertyKey): any;
|
|
24
24
|
export declare function transaction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
package/build/dist/source/Rx.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.
|
|
3
|
+
exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.nontransactional = exports.nonreactive = exports.Rx = void 0;
|
|
4
4
|
const Dbg_1 = require("./util/Dbg");
|
|
5
5
|
const Options_1 = require("./Options");
|
|
6
6
|
const Data_1 = require("./impl/Data");
|
|
@@ -29,10 +29,10 @@ function nonreactive(func, ...args) {
|
|
|
29
29
|
return Operation_1.OperationController.runWithin(undefined, func, ...args);
|
|
30
30
|
}
|
|
31
31
|
exports.nonreactive = nonreactive;
|
|
32
|
-
function
|
|
33
|
-
return Operation_1.OperationController.runWithin(undefined, Transaction_1.Transaction.
|
|
32
|
+
function nontransactional(func, ...args) {
|
|
33
|
+
return Operation_1.OperationController.runWithin(undefined, Transaction_1.Transaction.nontransactional, func, ...args);
|
|
34
34
|
}
|
|
35
|
-
exports.
|
|
35
|
+
exports.nontransactional = nontransactional;
|
|
36
36
|
function sensitive(sensitivity, func, ...args) {
|
|
37
37
|
return Hooks_1.Hooks.sensitive(sensitivity, func, ...args);
|
|
38
38
|
}
|
|
@@ -20,6 +20,24 @@ exports.TraceLevel = {
|
|
|
20
20
|
margin1: 0,
|
|
21
21
|
margin2: 0,
|
|
22
22
|
},
|
|
23
|
+
Reactions: {
|
|
24
|
+
silent: false,
|
|
25
|
+
transaction: false,
|
|
26
|
+
operation: false,
|
|
27
|
+
step: false,
|
|
28
|
+
monitor: false,
|
|
29
|
+
read: false,
|
|
30
|
+
write: false,
|
|
31
|
+
change: false,
|
|
32
|
+
obsolete: true,
|
|
33
|
+
error: true,
|
|
34
|
+
warning: true,
|
|
35
|
+
gc: false,
|
|
36
|
+
color: 37,
|
|
37
|
+
prefix: '',
|
|
38
|
+
margin1: 0,
|
|
39
|
+
margin2: 0,
|
|
40
|
+
},
|
|
23
41
|
Transactions: {
|
|
24
42
|
silent: false,
|
|
25
43
|
transaction: true,
|
|
@@ -11,4 +11,4 @@ export { Snapshot } from './impl/Snapshot';
|
|
|
11
11
|
export { Transaction } from './impl/Transaction';
|
|
12
12
|
export { Monitor } from './impl/Monitor';
|
|
13
13
|
export { TransactionJournal } from './impl/TransactionJournal';
|
|
14
|
-
export { Rx, nonreactive,
|
|
14
|
+
export { Rx, nonreactive, nontransactional, sensitive, unobservable, transaction, reaction, cached, options } from './Rx';
|
package/build/dist/source/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.
|
|
3
|
+
exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.nontransactional = exports.nonreactive = exports.Rx = exports.TransactionJournal = exports.Monitor = exports.Transaction = exports.Snapshot = exports.ObservableObject = exports.ToggleRef = exports.Ref = exports.Controller = exports.TraceLevel = exports.Reentrance = exports.Kind = exports.SealedSet = exports.SealedMap = exports.SealedArray = exports.pause = exports.all = void 0;
|
|
4
4
|
var Utils_1 = require("./util/Utils");
|
|
5
5
|
Object.defineProperty(exports, "all", { enumerable: true, get: function () { return Utils_1.all; } });
|
|
6
6
|
Object.defineProperty(exports, "pause", { enumerable: true, get: function () { return Utils_1.pause; } });
|
|
@@ -32,7 +32,7 @@ Object.defineProperty(exports, "TransactionJournal", { enumerable: true, get: fu
|
|
|
32
32
|
var Rx_1 = require("./Rx");
|
|
33
33
|
Object.defineProperty(exports, "Rx", { enumerable: true, get: function () { return Rx_1.Rx; } });
|
|
34
34
|
Object.defineProperty(exports, "nonreactive", { enumerable: true, get: function () { return Rx_1.nonreactive; } });
|
|
35
|
-
Object.defineProperty(exports, "
|
|
35
|
+
Object.defineProperty(exports, "nontransactional", { enumerable: true, get: function () { return Rx_1.nontransactional; } });
|
|
36
36
|
Object.defineProperty(exports, "sensitive", { enumerable: true, get: function () { return Rx_1.sensitive; } });
|
|
37
37
|
Object.defineProperty(exports, "unobservable", { enumerable: true, get: function () { return Rx_1.unobservable; } });
|
|
38
38
|
Object.defineProperty(exports, "transaction", { enumerable: true, get: function () { return Rx_1.transaction; } });
|
|
@@ -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
|
}
|
|
@@ -33,7 +34,7 @@ export declare class ObjectRevision {
|
|
|
33
34
|
revision: ObjectRevision;
|
|
34
35
|
};
|
|
35
36
|
readonly data: any;
|
|
36
|
-
readonly changes:
|
|
37
|
+
readonly changes: Set<MemberName>;
|
|
37
38
|
readonly conflicts: Map<MemberName, ObjectRevision>;
|
|
38
39
|
constructor(snapshot: AbstractSnapshot, prev: ObjectRevision | undefined, data: object);
|
|
39
40
|
}
|
|
@@ -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;
|
|
@@ -79,7 +79,7 @@ declare class Operation extends Observable implements Observer {
|
|
|
79
79
|
private static propagateAllChangesThroughSubscriptions;
|
|
80
80
|
private static revokeAllSubscriptions;
|
|
81
81
|
private static propagateMemberChangeThroughSubscriptions;
|
|
82
|
-
private static
|
|
82
|
+
private static enqueueReactionsToRun;
|
|
83
83
|
private static runQueuedReactionsLoop;
|
|
84
84
|
private unsubscribeFromAllObservables;
|
|
85
85
|
private subscribeTo;
|
|
@@ -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,31 +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 &&
|
|
269
|
+
snapshot === this.snapshot;
|
|
270
|
+
if (!skip) {
|
|
271
|
+
const why = `${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} << ${outer}`;
|
|
273
272
|
this.unsubscribeFromAllObservables();
|
|
274
|
-
this.obsoleteDueTo =
|
|
273
|
+
this.obsoleteDueTo = why;
|
|
275
274
|
this.obsoleteSince = since;
|
|
276
275
|
const isReaction = this.options.kind === Options_1.Kind.Reaction;
|
|
277
276
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.obsolete)))
|
|
278
|
-
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
|
|
279
278
|
? `${this.hint()} is a reaction and will run automatically (order ${this.options.order})`
|
|
280
|
-
: `${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})` : ''}`);
|
|
281
280
|
if (isReaction)
|
|
282
281
|
reactions.push(this);
|
|
283
282
|
else
|
|
284
|
-
(_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));
|
|
285
284
|
const tran = this.transaction;
|
|
286
|
-
if (tran.snapshot ===
|
|
287
|
-
(0, Dbg_1.misuse)('not implemented: running reactions within original transaction');
|
|
285
|
+
if (tran.snapshot === snapshot) {
|
|
288
286
|
}
|
|
289
287
|
else if (!tran.isFinished && this !== observable)
|
|
290
|
-
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);
|
|
291
289
|
}
|
|
292
290
|
else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
293
|
-
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)}`);
|
|
294
292
|
}
|
|
295
293
|
}
|
|
296
294
|
runIfNotUpToDate(now, nothrow) {
|
|
@@ -407,6 +405,7 @@ class Operation extends Data_1.Observable {
|
|
|
407
405
|
Dbg_1.Dbg.log('║', `${op}`, `${this.hint()} ${message}`, ms, highlight);
|
|
408
406
|
if (ms > (main ? Hooks_1.Hooks.mainThreadBlockingWarningThreshold : Hooks_1.Hooks.asyncActionDurationWarningThreshold))
|
|
409
407
|
Dbg_1.Dbg.log('', '[!]', this.why(), ms, main ? ' *** main thread is too busy ***' : ' *** async is too long ***');
|
|
408
|
+
this.cause = undefined;
|
|
410
409
|
if (this.options.monitor)
|
|
411
410
|
this.monitorLeave(this.options.monitor);
|
|
412
411
|
}
|
|
@@ -419,7 +418,7 @@ class Operation extends Data_1.Observable {
|
|
|
419
418
|
OperationController.runWithin(undefined, Transaction_1.Transaction.runAs, options, Monitor_1.MonitorImpl.enter, mon, this.transaction);
|
|
420
419
|
}
|
|
421
420
|
monitorLeave(mon) {
|
|
422
|
-
Transaction_1.Transaction.
|
|
421
|
+
Transaction_1.Transaction.nontransactional(() => {
|
|
423
422
|
const leave = () => {
|
|
424
423
|
const options = {
|
|
425
424
|
hint: 'Monitor.leave',
|
|
@@ -445,25 +444,26 @@ class Operation extends Data_1.Observable {
|
|
|
445
444
|
static markUsed(observable, r, m, h, kind, weak) {
|
|
446
445
|
if (kind !== Options_1.Kind.Transaction) {
|
|
447
446
|
const op = Operation.current;
|
|
448
|
-
if (op && op.options.kind !== Options_1.Kind.Transaction &&
|
|
447
|
+
if (op && op.options.kind !== Options_1.Kind.Transaction &&
|
|
448
|
+
op.transaction === Transaction_1.Transaction.current && m !== Data_1.Meta.Holder) {
|
|
449
449
|
const ctx = Snapshot_1.Snapshot.current();
|
|
450
450
|
if (ctx !== r.snapshot)
|
|
451
451
|
ctx.bumpBy(r.snapshot.timestamp);
|
|
452
452
|
const t = weak ? -1 : ctx.timestamp;
|
|
453
453
|
if (!op.subscribeTo(observable, r, m, h, t))
|
|
454
|
-
op.markObsoleteDueTo(observable,
|
|
454
|
+
op.markObsoleteDueTo(observable, m, r.snapshot, h, INITIAL_CAUSE, ctx.timestamp, ctx.reactions);
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
static markEdited(oldValue, newValue, edited, r, m, h) {
|
|
459
|
-
edited ? r.changes.
|
|
459
|
+
edited ? r.changes.add(m) : r.changes.delete(m);
|
|
460
460
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
|
|
461
|
-
edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.
|
|
461
|
+
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)');
|
|
462
462
|
}
|
|
463
463
|
static isConflicting(oldValue, newValue) {
|
|
464
464
|
let result = oldValue !== newValue;
|
|
465
465
|
if (result)
|
|
466
|
-
result = oldValue instanceof Operation && oldValue.cause !==
|
|
466
|
+
result = oldValue instanceof Operation && oldValue.cause !== INITIAL_CAUSE;
|
|
467
467
|
return result;
|
|
468
468
|
}
|
|
469
469
|
static propagateAllChangesThroughSubscriptions(snapshot) {
|
|
@@ -489,26 +489,30 @@ class Operation extends Data_1.Observable {
|
|
|
489
489
|
if (reactions) {
|
|
490
490
|
const prev = r.prev.revision.data[m];
|
|
491
491
|
if (prev !== undefined && prev instanceof Data_1.Observable) {
|
|
492
|
-
const
|
|
492
|
+
const why = `T${r.snapshot.id}[${r.snapshot.hint}]`;
|
|
493
493
|
if (prev instanceof Operation) {
|
|
494
494
|
if ((prev.obsoleteSince === Snapshot_1.MAX_TIMESTAMP || prev.obsoleteSince <= 0)) {
|
|
495
|
-
prev.obsoleteDueTo =
|
|
495
|
+
prev.obsoleteDueTo = why;
|
|
496
496
|
prev.obsoleteSince = timestamp;
|
|
497
497
|
prev.unsubscribeFromAllObservables();
|
|
498
498
|
}
|
|
499
|
-
const
|
|
500
|
-
if (
|
|
501
|
-
|
|
499
|
+
const prevSuccessor = prev.successor;
|
|
500
|
+
if (prevSuccessor !== curr) {
|
|
501
|
+
if (prevSuccessor && !prevSuccessor.transaction.isFinished)
|
|
502
|
+
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);
|
|
503
|
+
}
|
|
504
|
+
else
|
|
505
|
+
prev.successor = undefined;
|
|
502
506
|
}
|
|
503
|
-
(_a = prev.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(prev,
|
|
507
|
+
(_a = prev.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(prev, m, r.snapshot, h, why, timestamp, reactions));
|
|
504
508
|
}
|
|
505
509
|
}
|
|
506
510
|
if (curr instanceof Operation) {
|
|
507
|
-
if (curr.
|
|
511
|
+
if (curr.snapshot === r.snapshot && curr.observables !== undefined) {
|
|
508
512
|
if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
509
513
|
curr.observables.forEach((hint, v) => {
|
|
510
514
|
if (hint.usageCount > Hooks_1.Hooks.repetitiveUsageWarningThreshold)
|
|
511
|
-
Dbg_1.Dbg.log('', '[!]', `${curr.hint()} uses ${Snapshot_1.Dump.
|
|
515
|
+
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 ***');
|
|
512
516
|
});
|
|
513
517
|
}
|
|
514
518
|
if (unsubscribe)
|
|
@@ -524,10 +528,10 @@ class Operation extends Data_1.Observable {
|
|
|
524
528
|
curr.observers = undefined;
|
|
525
529
|
}
|
|
526
530
|
}
|
|
527
|
-
static
|
|
531
|
+
static enqueueReactionsToRun(reactions) {
|
|
528
532
|
const queue = Operation.queuedReactions;
|
|
529
533
|
const isReactionLoopRequired = queue.length === 0;
|
|
530
|
-
for (const r of
|
|
534
|
+
for (const r of reactions)
|
|
531
535
|
queue.push(r);
|
|
532
536
|
if (isReactionLoopRequired)
|
|
533
537
|
OperationController.runWithin(undefined, Operation.runQueuedReactionsLoop);
|
|
@@ -548,7 +552,7 @@ class Operation extends Data_1.Observable {
|
|
|
548
552
|
var _a;
|
|
549
553
|
value.observers.delete(this);
|
|
550
554
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
|
|
551
|
-
Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${Snapshot_1.Dump.
|
|
555
|
+
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)}`);
|
|
552
556
|
});
|
|
553
557
|
this.observables = undefined;
|
|
554
558
|
}
|
|
@@ -564,18 +568,18 @@ class Operation extends Data_1.Observable {
|
|
|
564
568
|
if (this.observables !== undefined) {
|
|
565
569
|
if (!observable.observers)
|
|
566
570
|
observable.observers = new Set();
|
|
567
|
-
const info = {
|
|
571
|
+
const info = { holder: h, snapshot: r.snapshot, memberName: m, usageCount: times };
|
|
568
572
|
observable.observers.add(this);
|
|
569
573
|
this.observables.set(observable, info);
|
|
570
574
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
|
|
571
|
-
Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.
|
|
575
|
+
Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
|
|
572
576
|
}
|
|
573
577
|
else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_b = this.options.trace) === null || _b === void 0 ? void 0 : _b.read)))
|
|
574
|
-
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.
|
|
578
|
+
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}`);
|
|
575
579
|
}
|
|
576
580
|
else {
|
|
577
581
|
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.read)))
|
|
578
|
-
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.
|
|
582
|
+
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}`);
|
|
579
583
|
}
|
|
580
584
|
return ok;
|
|
581
585
|
}
|
|
@@ -598,7 +602,7 @@ class Operation extends Data_1.Observable {
|
|
|
598
602
|
let op = initial[m];
|
|
599
603
|
const ctl = op ? op.controller : new OperationController(ROOT_HOLDER, m);
|
|
600
604
|
const opts = op ? op.options : Hooks_1.OptionsImpl.INITIAL;
|
|
601
|
-
initial[m] = op = new Operation(ctl, Snapshot_1.ROOT_REV, new Hooks_1.OptionsImpl(getter, setter, opts, options, implicit));
|
|
605
|
+
initial[m] = op = new Operation(ctl, Snapshot_1.ROOT_REV.snapshot, new Hooks_1.OptionsImpl(getter, setter, opts, options, implicit));
|
|
602
606
|
if (op.options.kind === Options_1.Kind.Reaction && op.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
603
607
|
const reactions = Data_1.Meta.acquire(proto, Data_1.Meta.Reactions);
|
|
604
608
|
reactions[m] = op;
|
|
@@ -611,14 +615,13 @@ class Operation extends Data_1.Observable {
|
|
|
611
615
|
}
|
|
612
616
|
static init() {
|
|
613
617
|
Object.freeze(ROOT_ARGS);
|
|
614
|
-
Object.freeze(ROOT_TRIGGER);
|
|
615
618
|
Dbg_1.Dbg.getMergedTraceOptions = getMergedTraceOptions;
|
|
616
619
|
Snapshot_1.Snapshot.markUsed = Operation.markUsed;
|
|
617
620
|
Snapshot_1.Snapshot.markEdited = Operation.markEdited;
|
|
618
621
|
Snapshot_1.Snapshot.isConflicting = Operation.isConflicting;
|
|
619
622
|
Snapshot_1.Snapshot.propagateAllChangesThroughSubscriptions = Operation.propagateAllChangesThroughSubscriptions;
|
|
620
623
|
Snapshot_1.Snapshot.revokeAllSubscriptions = Operation.revokeAllSubscriptions;
|
|
621
|
-
Snapshot_1.Snapshot.
|
|
624
|
+
Snapshot_1.Snapshot.enqueueReactionsToRun = Operation.enqueueReactionsToRun;
|
|
622
625
|
Hooks_1.Hooks.createControllerAndGetHook = Operation.createControllerAndGetHook;
|
|
623
626
|
Hooks_1.Hooks.rememberOperationOptions = Operation.rememberOperationOptions;
|
|
624
627
|
Promise.prototype.then = reactronicHookedThen;
|
|
@@ -647,18 +650,6 @@ class Operation extends Data_1.Observable {
|
|
|
647
650
|
Operation.current = undefined;
|
|
648
651
|
Operation.queuedReactions = [];
|
|
649
652
|
Operation.deferredReactions = [];
|
|
650
|
-
function propagationHint(cause, full) {
|
|
651
|
-
const result = [];
|
|
652
|
-
let observable = cause.revision.data[cause.memberName];
|
|
653
|
-
while (observable instanceof Operation && observable.obsoleteDueTo) {
|
|
654
|
-
full && result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
|
|
655
|
-
cause = observable.obsoleteDueTo;
|
|
656
|
-
observable = cause.revision.data[cause.memberName];
|
|
657
|
-
}
|
|
658
|
-
result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
|
|
659
|
-
full && result.push(cause.revision.snapshot.hint);
|
|
660
|
-
return result;
|
|
661
|
-
}
|
|
662
653
|
function valueHint(value, m) {
|
|
663
654
|
let result = '';
|
|
664
655
|
if (Array.isArray(value))
|
|
@@ -668,7 +659,7 @@ function valueHint(value, m) {
|
|
|
668
659
|
else if (value instanceof Map)
|
|
669
660
|
result = `Map(${value.size})`;
|
|
670
661
|
else if (value instanceof Operation)
|
|
671
|
-
result = `${Snapshot_1.Dump.
|
|
662
|
+
result = `${Snapshot_1.Dump.rev2(value.controller.ownHolder, value.snapshot, m)}`;
|
|
672
663
|
else if (value === Data_1.Meta.Disposed)
|
|
673
664
|
result = '<disposed>';
|
|
674
665
|
else if (value !== undefined && value !== null)
|
|
@@ -17,8 +17,8 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
17
17
|
get timestamp(): number;
|
|
18
18
|
private stamp;
|
|
19
19
|
private bumper;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
changeset: Map<ObjectHolder, ObjectRevision>;
|
|
21
|
+
reactions: Observer[];
|
|
22
22
|
sealed: boolean;
|
|
23
23
|
constructor(options: SnapshotOptions | null);
|
|
24
24
|
static current: () => Snapshot;
|
|
@@ -28,7 +28,7 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
28
28
|
static isConflicting: (oldValue: any, newValue: any) => boolean;
|
|
29
29
|
static propagateAllChangesThroughSubscriptions: (snapshot: Snapshot) => void;
|
|
30
30
|
static revokeAllSubscriptions: (snapshot: Snapshot) => void;
|
|
31
|
-
static
|
|
31
|
+
static enqueueReactionsToRun: (reactions: Array<Observer>) => void;
|
|
32
32
|
seekRevision(h: ObjectHolder, m: MemberName): ObjectRevision;
|
|
33
33
|
getCurrentRevision(h: ObjectHolder, m: MemberName): ObjectRevision;
|
|
34
34
|
getEditableRevision(h: ObjectHolder, m: MemberName, value: any, token?: any): ObjectRevision;
|
|
@@ -40,17 +40,17 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
40
40
|
bumpBy(timestamp: number): void;
|
|
41
41
|
rebase(): ObjectRevision[] | undefined;
|
|
42
42
|
private static merge;
|
|
43
|
-
applyOrDiscard(error?: any):
|
|
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;
|
|
@@ -27,6 +27,8 @@ Object.defineProperty(Data_1.ObjectHolder.prototype, '#this', {
|
|
|
27
27
|
return result;
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
|
+
const EMPTY_ARRAY = Object.freeze([]);
|
|
31
|
+
const EMPTY_MAP = Utils_1.Utils.freezeMap(new Map());
|
|
30
32
|
class Snapshot {
|
|
31
33
|
constructor(options) {
|
|
32
34
|
this.id = ++Snapshot.idGen;
|
|
@@ -128,14 +130,14 @@ class Snapshot {
|
|
|
128
130
|
if (this.changeset.size > 0) {
|
|
129
131
|
this.changeset.forEach((r, h) => {
|
|
130
132
|
if (r.prev.revision !== h.head) {
|
|
131
|
-
const merged = Snapshot.merge(
|
|
133
|
+
const merged = Snapshot.merge(h, r);
|
|
132
134
|
if (r.conflicts.size > 0) {
|
|
133
135
|
if (!conflicts)
|
|
134
136
|
conflicts = [];
|
|
135
137
|
conflicts.push(r);
|
|
136
138
|
}
|
|
137
139
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.transaction)
|
|
138
|
-
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.`);
|
|
139
141
|
}
|
|
140
142
|
});
|
|
141
143
|
if (this.options.token === undefined) {
|
|
@@ -152,8 +154,9 @@ class Snapshot {
|
|
|
152
154
|
}
|
|
153
155
|
return conflicts;
|
|
154
156
|
}
|
|
155
|
-
static merge(
|
|
157
|
+
static merge(h, ours) {
|
|
156
158
|
let counter = 0;
|
|
159
|
+
const head = h.head;
|
|
157
160
|
const disposed = head.changes.has(Data_1.Meta.Disposed);
|
|
158
161
|
const merged = Object.assign({}, head.data);
|
|
159
162
|
ours.changes.forEach((o, m) => {
|
|
@@ -162,7 +165,7 @@ class Snapshot {
|
|
|
162
165
|
if (disposed || m === Data_1.Meta.Disposed) {
|
|
163
166
|
if (disposed !== (m === Data_1.Meta.Disposed)) {
|
|
164
167
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
165
|
-
Dbg_1.Dbg.log('║╠', '', `${Dump.
|
|
168
|
+
Dbg_1.Dbg.log('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} <> ${Dump.rev2(h, head.snapshot, m)}`, 0, ' *** CONFLICT ***');
|
|
166
169
|
ours.conflicts.set(m, head);
|
|
167
170
|
}
|
|
168
171
|
}
|
|
@@ -171,7 +174,7 @@ class Snapshot {
|
|
|
171
174
|
if (conflict)
|
|
172
175
|
ours.conflicts.set(m, head);
|
|
173
176
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
174
|
-
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);
|
|
175
178
|
}
|
|
176
179
|
});
|
|
177
180
|
Utils_1.Utils.copyAllMembers(merged, ours.data);
|
|
@@ -200,7 +203,7 @@ class Snapshot {
|
|
|
200
203
|
const members = [];
|
|
201
204
|
r.changes.forEach((o, m) => members.push(m.toString()));
|
|
202
205
|
const s = members.join(', ');
|
|
203
|
-
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)}`}`);
|
|
204
207
|
});
|
|
205
208
|
}
|
|
206
209
|
if (Dbg_1.Dbg.trace.transaction)
|
|
@@ -208,6 +211,7 @@ class Snapshot {
|
|
|
208
211
|
}
|
|
209
212
|
if (!error)
|
|
210
213
|
Snapshot.propagateAllChangesThroughSubscriptions(this);
|
|
214
|
+
return this.reactions;
|
|
211
215
|
}
|
|
212
216
|
static sealObjectRevision(h, r) {
|
|
213
217
|
if (!r.changes.has(Data_1.Meta.Disposed))
|
|
@@ -228,17 +232,9 @@ class Snapshot {
|
|
|
228
232
|
}
|
|
229
233
|
}
|
|
230
234
|
}
|
|
231
|
-
collectGarbage() {
|
|
232
|
-
if (Dbg_1.Dbg.isOn) {
|
|
233
|
-
Utils_1.Utils.freezeMap(this.changeset);
|
|
234
|
-
Object.freeze(this.reactions);
|
|
235
|
-
Object.freeze(this);
|
|
236
|
-
}
|
|
237
|
-
this.triggerGarbageCollection();
|
|
238
|
-
}
|
|
239
235
|
static freezeObjectRevision(r) {
|
|
240
236
|
Object.freeze(r.data);
|
|
241
|
-
Utils_1.Utils.
|
|
237
|
+
Utils_1.Utils.freezeSet(r.changes);
|
|
242
238
|
Utils_1.Utils.freezeMap(r.conflicts);
|
|
243
239
|
return r;
|
|
244
240
|
}
|
|
@@ -267,23 +263,25 @@ class Snapshot {
|
|
|
267
263
|
Dbg_1.Dbg.log('', '[G]', `Dismiss history below v${this.stamp}t${this.id} (${this.hint})`);
|
|
268
264
|
this.changeset.forEach((r, h) => {
|
|
269
265
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.gc && r.prev.revision !== exports.ROOT_REV)
|
|
270
|
-
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)}`);
|
|
271
267
|
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
272
|
-
if (r.prev.revision !== exports.ROOT_REV)
|
|
268
|
+
if (r.prev.revision !== exports.ROOT_REV)
|
|
273
269
|
Snapshot.totalObjectRevisionCount--;
|
|
274
|
-
|
|
275
|
-
if (r.changes.has(Data_1.Meta.Disposed)) {
|
|
270
|
+
if (r.changes.has(Data_1.Meta.Disposed))
|
|
276
271
|
Snapshot.totalObjectHolderCount--;
|
|
277
|
-
}
|
|
278
272
|
}
|
|
279
273
|
r.prev.revision = exports.ROOT_REV;
|
|
280
274
|
});
|
|
275
|
+
this.changeset = EMPTY_MAP;
|
|
276
|
+
this.reactions = EMPTY_ARRAY;
|
|
277
|
+
if (Dbg_1.Dbg.isOn)
|
|
278
|
+
Object.freeze(this);
|
|
281
279
|
}
|
|
282
280
|
static _init() {
|
|
283
281
|
const root = exports.ROOT_REV.snapshot;
|
|
284
282
|
root.acquire(root);
|
|
285
283
|
root.applyOrDiscard();
|
|
286
|
-
root.
|
|
284
|
+
root.triggerGarbageCollection();
|
|
287
285
|
Snapshot.freezeObjectRevision(exports.ROOT_REV);
|
|
288
286
|
Snapshot.idGen = 100;
|
|
289
287
|
Snapshot.stampGen = 101;
|
|
@@ -309,7 +307,7 @@ Snapshot.markEdited = Utils_1.UNDEF;
|
|
|
309
307
|
Snapshot.isConflicting = Utils_1.UNDEF;
|
|
310
308
|
Snapshot.propagateAllChangesThroughSubscriptions = (snapshot) => { };
|
|
311
309
|
Snapshot.revokeAllSubscriptions = (snapshot) => { };
|
|
312
|
-
Snapshot.
|
|
310
|
+
Snapshot.enqueueReactionsToRun = (reactions) => { };
|
|
313
311
|
class Dump {
|
|
314
312
|
static obj(h, m, stamp, op, xop, typeless) {
|
|
315
313
|
const member = m !== undefined ? `.${m.toString()}` : '';
|
|
@@ -317,6 +315,9 @@ class Dump {
|
|
|
317
315
|
? `root${member}`
|
|
318
316
|
: stamp === undefined ? `${h.hint}${member} #${h.id}` : `${h.hint}${member} #${h.id}t${op}v${stamp}${xop !== undefined && xop !== 0 ? `t${xop}` : ''}`;
|
|
319
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
|
+
}
|
|
320
321
|
static rev(r, m) {
|
|
321
322
|
const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
|
|
322
323
|
const value = m !== undefined ? r.data[m] : undefined;
|
|
@@ -23,7 +23,7 @@ export declare abstract class Transaction implements Worker {
|
|
|
23
23
|
static create(options: SnapshotOptions | null): Transaction;
|
|
24
24
|
static run<T>(func: F<T>, ...args: any[]): T;
|
|
25
25
|
static runAs<T>(options: SnapshotOptions | null, func: F<T>, ...args: any[]): T;
|
|
26
|
-
static
|
|
26
|
+
static nontransactional<T>(func: F<T>, ...args: any[]): T;
|
|
27
27
|
static isFrameOver(everyN?: number, timeLimit?: number): boolean;
|
|
28
28
|
static requestNextFrame(sleepTime?: number): Promise<void>;
|
|
29
29
|
static get isCanceled(): boolean;
|
|
@@ -21,7 +21,7 @@ class Transaction {
|
|
|
21
21
|
static create(options) { return new TransactionImpl(options); }
|
|
22
22
|
static run(func, ...args) { return TransactionImpl.run(func, ...args); }
|
|
23
23
|
static runAs(options, func, ...args) { return TransactionImpl.runAs(options, func, ...args); }
|
|
24
|
-
static
|
|
24
|
+
static nontransactional(func, ...args) { return TransactionImpl.nontransactional(func, ...args); }
|
|
25
25
|
static isFrameOver(everyN = 1, timeLimit = 14) { return TransactionImpl.isFrameOver(everyN, timeLimit); }
|
|
26
26
|
static requestNextFrame(sleepTime = 0) { return TransactionImpl.requestNextFrame(sleepTime); }
|
|
27
27
|
static get isCanceled() { return TransactionImpl.current.isCanceled; }
|
|
@@ -125,7 +125,7 @@ class TransactionImpl extends Transaction {
|
|
|
125
125
|
let result = t.runImpl(options === null || options === void 0 ? void 0 : options.trace, func, ...args);
|
|
126
126
|
if (root) {
|
|
127
127
|
if (result instanceof Promise) {
|
|
128
|
-
result = TransactionImpl.
|
|
128
|
+
result = TransactionImpl.nontransactional(() => {
|
|
129
129
|
return t.wrapToRetry(t.wrapToWaitUntilFinish(result), func, ...args);
|
|
130
130
|
});
|
|
131
131
|
}
|
|
@@ -133,7 +133,7 @@ class TransactionImpl extends Transaction {
|
|
|
133
133
|
}
|
|
134
134
|
return result;
|
|
135
135
|
}
|
|
136
|
-
static
|
|
136
|
+
static nontransactional(func, ...args) {
|
|
137
137
|
const outer = TransactionImpl.curr;
|
|
138
138
|
try {
|
|
139
139
|
TransactionImpl.curr = TransactionImpl.none;
|
|
@@ -228,9 +228,9 @@ class TransactionImpl extends Transaction {
|
|
|
228
228
|
finally {
|
|
229
229
|
this.pending--;
|
|
230
230
|
if (this.sealed && this.pending === 0) {
|
|
231
|
-
this.applyOrDiscard();
|
|
231
|
+
const reactions = this.applyOrDiscard();
|
|
232
232
|
TransactionImpl.curr = outer;
|
|
233
|
-
TransactionImpl.
|
|
233
|
+
TransactionImpl.nontransactional(Snapshot_1.Snapshot.enqueueReactionsToRun, reactions);
|
|
234
234
|
}
|
|
235
235
|
else
|
|
236
236
|
TransactionImpl.curr = outer;
|
|
@@ -259,11 +259,12 @@ class TransactionImpl extends Transaction {
|
|
|
259
259
|
throw (0, Dbg_1.error)(`T${this.id}[${this.hint}] conflicts with: ${Snapshot_1.Dump.conflicts(conflicts)}`, undefined);
|
|
260
260
|
}
|
|
261
261
|
applyOrDiscard() {
|
|
262
|
+
let reactions;
|
|
262
263
|
try {
|
|
263
264
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
264
265
|
Dbg_1.Dbg.log('╠═', '', '', undefined, 'changes');
|
|
265
|
-
this.snapshot.applyOrDiscard(this.canceled);
|
|
266
|
-
this.snapshot.
|
|
266
|
+
reactions = this.snapshot.applyOrDiscard(this.canceled);
|
|
267
|
+
this.snapshot.triggerGarbageCollection();
|
|
267
268
|
if (this.promise) {
|
|
268
269
|
if (this.canceled && !this.after)
|
|
269
270
|
this.reject(this.canceled);
|
|
@@ -277,6 +278,7 @@ class TransactionImpl extends Transaction {
|
|
|
277
278
|
(0, Dbg_1.fatal)(e);
|
|
278
279
|
throw e;
|
|
279
280
|
}
|
|
281
|
+
return reactions;
|
|
280
282
|
}
|
|
281
283
|
acquirePromise() {
|
|
282
284
|
if (!this.promise) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare type F<T> = (...args: any[]) => T;
|
|
2
2
|
export declare class Utils {
|
|
3
|
-
static freezeSet<T>(obj?: Set<T>):
|
|
4
|
-
static freezeMap<K, V>(obj?: Map<K, V>):
|
|
3
|
+
static freezeSet<T>(obj?: Set<T>): Set<T> | undefined;
|
|
4
|
+
static freezeMap<K, V>(obj?: Map<K, V>): Map<K, V> | undefined;
|
|
5
5
|
static copyAllMembers(source: any, target: any): any;
|
|
6
6
|
}
|
|
7
7
|
export declare function UNDEF(...args: any[]): never;
|
|
@@ -19,6 +19,7 @@ class Utils {
|
|
|
19
19
|
Object.defineProperty(obj, 'clear', pd);
|
|
20
20
|
Object.freeze(obj);
|
|
21
21
|
}
|
|
22
|
+
return obj;
|
|
22
23
|
}
|
|
23
24
|
static freezeMap(obj) {
|
|
24
25
|
if (obj instanceof Map) {
|
|
@@ -28,6 +29,7 @@ class Utils {
|
|
|
28
29
|
Object.defineProperty(obj, 'clear', pd);
|
|
29
30
|
Object.freeze(obj);
|
|
30
31
|
}
|
|
32
|
+
return obj;
|
|
31
33
|
}
|
|
32
34
|
static copyAllMembers(source, target) {
|
|
33
35
|
for (const m of Object.getOwnPropertyNames(source))
|