reactronic 0.24.304 → 0.24.306
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/Options.d.ts +2 -1
- package/build/dist/source/core/Changeset.d.ts +4 -1
- package/build/dist/source/core/Changeset.js +9 -5
- package/build/dist/source/core/Indicator.js +5 -5
- package/build/dist/source/core/Mvcc.d.ts +1 -0
- package/build/dist/source/core/Mvcc.js +2 -0
- package/build/dist/source/core/Operation.d.ts +2 -2
- package/build/dist/source/core/Operation.js +31 -16
- package/build/dist/source/core/RxNode.js +2 -1
- package/build/dist/source/core/Transaction.d.ts +1 -0
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@ export type MemberOptions = {
|
|
|
18
18
|
readonly triggeringArgs: boolean;
|
|
19
19
|
readonly throttling: number;
|
|
20
20
|
readonly reentrance: Reentrance;
|
|
21
|
+
readonly allowObsoleteToFinish: boolean;
|
|
21
22
|
readonly journal: Journal | undefined;
|
|
22
23
|
readonly indicator: Indicator | null;
|
|
23
24
|
readonly logging?: Partial<LoggingOptions>;
|
|
@@ -49,7 +50,7 @@ export type Operation<T> = {
|
|
|
49
50
|
readonly result: T;
|
|
50
51
|
readonly error: any;
|
|
51
52
|
readonly stamp: number;
|
|
52
|
-
readonly
|
|
53
|
+
readonly isReusable: boolean;
|
|
53
54
|
configure(options: Partial<MemberOptions>): MemberOptions;
|
|
54
55
|
markObsolete(): void;
|
|
55
56
|
pullLastResult(args?: any[]): T | undefined;
|
|
@@ -26,7 +26,10 @@ export declare class Changeset implements AbstractChangeset {
|
|
|
26
26
|
static edit: () => Changeset;
|
|
27
27
|
static markUsed: (fv: FieldVersion, ov: ObjectVersion, fk: FieldKey, h: ObjectHandle, kind: Kind, weak: boolean) => void;
|
|
28
28
|
static markEdited: (oldValue: any, newValue: any, edited: boolean, ov: ObjectVersion, fk: FieldKey, h: ObjectHandle) => void;
|
|
29
|
-
static
|
|
29
|
+
static tryResolveConflict: (theirValue: any, ourFormerValue: any, ourValue: any) => {
|
|
30
|
+
isResolved: boolean;
|
|
31
|
+
resolvedValue: any;
|
|
32
|
+
};
|
|
30
33
|
static propagateAllChangesThroughSubscriptions: (changeset: Changeset) => void;
|
|
31
34
|
static revokeAllSubscriptions: (changeset: Changeset) => void;
|
|
32
35
|
static enqueueReactiveFunctionsToRun: (reactive: Array<Observer>) => void;
|
|
@@ -157,7 +157,7 @@ export class Changeset {
|
|
|
157
157
|
let conflicts = undefined;
|
|
158
158
|
if (this.items.size > 0) {
|
|
159
159
|
this.items.forEach((ov, h) => {
|
|
160
|
-
const theirs = this.parent ? this.parent.lookupObjectVersion(h, Meta.Handle,
|
|
160
|
+
const theirs = this.parent ? this.parent.lookupObjectVersion(h, Meta.Handle, true) : h.applied;
|
|
161
161
|
if (ov.former.objectVersion !== theirs) {
|
|
162
162
|
const merged = this.merge(h, ov, theirs);
|
|
163
163
|
if (ov.conflicts.size > 0) {
|
|
@@ -202,11 +202,15 @@ export class Changeset {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
else {
|
|
205
|
-
const
|
|
206
|
-
|
|
205
|
+
const theirValue = theirs.data[fk];
|
|
206
|
+
const ourFormerValue = ours.former.objectVersion.data[fk];
|
|
207
|
+
const { isResolved, resolvedValue } = Changeset.tryResolveConflict(theirValue, ourFormerValue, ourFieldVersion);
|
|
208
|
+
if (!isResolved)
|
|
207
209
|
ours.conflicts.set(fk, theirs);
|
|
210
|
+
else if (resolvedValue.isLaunch)
|
|
211
|
+
merged[fk] = resolvedValue;
|
|
208
212
|
if (Log.isOn && Log.opt.change)
|
|
209
|
-
Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset, fk)} ${
|
|
213
|
+
Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset, fk)} ${!isResolved ? "<>" : "=="} ${Dump.snapshot2(h, theirs.changeset, fk)}`, 0, !isResolved ? " *** CONFLICT ***" : undefined);
|
|
210
214
|
}
|
|
211
215
|
});
|
|
212
216
|
Utils.copyAllMembers(merged, ours.data);
|
|
@@ -311,7 +315,7 @@ Changeset.current = UNDEF;
|
|
|
311
315
|
Changeset.edit = UNDEF;
|
|
312
316
|
Changeset.markUsed = UNDEF;
|
|
313
317
|
Changeset.markEdited = UNDEF;
|
|
314
|
-
Changeset.
|
|
318
|
+
Changeset.tryResolveConflict = UNDEF;
|
|
315
319
|
Changeset.propagateAllChangesThroughSubscriptions = (changeset) => { };
|
|
316
320
|
Changeset.revokeAllSubscriptions = (changeset) => { };
|
|
317
321
|
Changeset.enqueueReactiveFunctionsToRun = (reactive) => { };
|
|
@@ -131,13 +131,13 @@ export class IndicatorImpl extends Indicator {
|
|
|
131
131
|
}
|
|
132
132
|
static tick(mon) {
|
|
133
133
|
if (mon.internals.started !== 0) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
mon.busyDuration = Math.round(resolution * (performance.now() - mon.internals.started)) / resolution;
|
|
137
|
-
});
|
|
134
|
+
const resolution = mon.internals.durationResolution;
|
|
135
|
+
mon.busyDuration = Math.round(resolution * (performance.now() - mon.internals.started)) / resolution;
|
|
138
136
|
const t = globalThis !== null && globalThis !== void 0 ? globalThis : global;
|
|
139
137
|
if (t.requestAnimationFrame)
|
|
140
|
-
requestAnimationFrame(() =>
|
|
138
|
+
requestAnimationFrame(() => {
|
|
139
|
+
Transaction.run(INDICATOR_TICK_OPTIONS, () => IndicatorImpl.tick(mon));
|
|
140
|
+
});
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
}
|
|
@@ -24,6 +24,7 @@ export declare class OptionsImpl implements MemberOptions {
|
|
|
24
24
|
readonly triggeringArgs: boolean;
|
|
25
25
|
readonly throttling: number;
|
|
26
26
|
readonly reentrance: Reentrance;
|
|
27
|
+
readonly allowObsoleteToFinish: boolean;
|
|
27
28
|
readonly journal: Journal | undefined;
|
|
28
29
|
readonly indicator: Indicator | null;
|
|
29
30
|
readonly logging?: Partial<LoggingOptions>;
|
|
@@ -33,6 +33,7 @@ const DEFAULT_OPTIONS = Object.freeze({
|
|
|
33
33
|
triggeringArgs: false,
|
|
34
34
|
throttling: Number.MAX_SAFE_INTEGER,
|
|
35
35
|
reentrance: Reentrance.preventWithError,
|
|
36
|
+
allowObsoleteToFinish: false,
|
|
36
37
|
journal: undefined,
|
|
37
38
|
indicator: null,
|
|
38
39
|
logging: undefined,
|
|
@@ -48,6 +49,7 @@ export class OptionsImpl {
|
|
|
48
49
|
this.triggeringArgs = merge(DEFAULT_OPTIONS.triggeringArgs, existing.triggeringArgs, patch.triggeringArgs, implicit);
|
|
49
50
|
this.throttling = merge(DEFAULT_OPTIONS.throttling, existing.throttling, patch.throttling, implicit);
|
|
50
51
|
this.reentrance = merge(DEFAULT_OPTIONS.reentrance, existing.reentrance, patch.reentrance, implicit);
|
|
52
|
+
this.allowObsoleteToFinish = merge(DEFAULT_OPTIONS.allowObsoleteToFinish, existing.allowObsoleteToFinish, patch.allowObsoleteToFinish, implicit);
|
|
51
53
|
this.journal = merge(DEFAULT_OPTIONS.journal, existing.journal, patch.journal, implicit);
|
|
52
54
|
this.indicator = merge(DEFAULT_OPTIONS.indicator, existing.indicator, patch.indicator, implicit);
|
|
53
55
|
this.logging = merge(DEFAULT_OPTIONS.logging, existing.logging, patch.logging, implicit);
|
|
@@ -13,7 +13,7 @@ export declare class OperationImpl implements Operation<any> {
|
|
|
13
13
|
get result(): any;
|
|
14
14
|
get error(): boolean;
|
|
15
15
|
get stamp(): number;
|
|
16
|
-
get
|
|
16
|
+
get isReusable(): boolean;
|
|
17
17
|
markObsolete(): void;
|
|
18
18
|
pullLastResult(args?: any[]): any;
|
|
19
19
|
constructor(h: ObjectHandle, fk: FieldKey);
|
|
@@ -74,7 +74,7 @@ declare class Launch extends FieldVersion implements Observer {
|
|
|
74
74
|
private static processDeferredReactiveFunctions;
|
|
75
75
|
private static markUsed;
|
|
76
76
|
private static markEdited;
|
|
77
|
-
private static
|
|
77
|
+
private static tryResolveConflict;
|
|
78
78
|
private static propagateAllChangesThroughSubscriptions;
|
|
79
79
|
private static revokeAllSubscriptions;
|
|
80
80
|
private static propagateFieldChangeThroughSubscriptions;
|
|
@@ -17,7 +17,7 @@ export class OperationImpl {
|
|
|
17
17
|
get result() { return this.reuseOrRelaunch(true, undefined).content; }
|
|
18
18
|
get error() { return this.use().launch.error; }
|
|
19
19
|
get stamp() { return this.use().objectVersion.changeset.timestamp; }
|
|
20
|
-
get
|
|
20
|
+
get isReusable() { return this.use().isReusable; }
|
|
21
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
23
|
constructor(h, fk) {
|
|
@@ -29,7 +29,7 @@ export class OperationImpl {
|
|
|
29
29
|
const ctx = ror.changeset;
|
|
30
30
|
const launch = ror.launch;
|
|
31
31
|
const opts = launch.options;
|
|
32
|
-
if (!ror.
|
|
32
|
+
if (!ror.isReusable && !ror.objectVersion.disposed
|
|
33
33
|
&& (!weak || launch.cause === BOOT_CAUSE || !launch.successor ||
|
|
34
34
|
launch.successor.transaction.isFinished)) {
|
|
35
35
|
const isolation = !weak ? opts.isolation : Isolation.disjoinFromOuterTransaction;
|
|
@@ -98,11 +98,12 @@ export class OperationImpl {
|
|
|
98
98
|
const ctx = Changeset.current();
|
|
99
99
|
const ov = ctx.lookupObjectVersion(this.ownerHandle, this.fieldKey, false);
|
|
100
100
|
const launch = this.acquireFromObjectVersion(ov, args);
|
|
101
|
-
const
|
|
102
|
-
|
|
101
|
+
const applied = this.ownerHandle.applied.data[this.fieldKey];
|
|
102
|
+
const isReusable = launch.options.kind !== Kind.transactional && launch.cause !== BOOT_CAUSE &&
|
|
103
|
+
(ctx === launch.changeset || ctx.timestamp < launch.obsoleteSince || applied.obsoleteDueTo === undefined) &&
|
|
103
104
|
(!launch.options.triggeringArgs || args === undefined ||
|
|
104
105
|
launch.args.length === args.length && launch.args.every((t, i) => t === args[i])) || ov.disposed;
|
|
105
|
-
return { launch,
|
|
106
|
+
return { launch, isReusable, changeset: ctx, objectVersion: ov };
|
|
106
107
|
}
|
|
107
108
|
use() {
|
|
108
109
|
const ror = this.peek(undefined);
|
|
@@ -122,7 +123,7 @@ export class OperationImpl {
|
|
|
122
123
|
Changeset.markEdited(launch, relaunch, true, ov, fk, h);
|
|
123
124
|
launch = relaunch;
|
|
124
125
|
}
|
|
125
|
-
return { launch,
|
|
126
|
+
return { launch, isReusable: true, changeset: ctx, objectVersion: ov };
|
|
126
127
|
}
|
|
127
128
|
acquireFromObjectVersion(ov, args) {
|
|
128
129
|
const fk = this.fieldKey;
|
|
@@ -174,7 +175,7 @@ export class OperationImpl {
|
|
|
174
175
|
}
|
|
175
176
|
else {
|
|
176
177
|
ror = this.peek(argsx);
|
|
177
|
-
if (ror.launch.options.kind === Kind.transactional || !ror.
|
|
178
|
+
if (ror.launch.options.kind === Kind.transactional || !ror.isReusable) {
|
|
178
179
|
ror = this.edit();
|
|
179
180
|
if (Log.isOn && Log.opt.operation)
|
|
180
181
|
Log.write("║", " o", `${ror.launch.why()}`);
|
|
@@ -189,7 +190,8 @@ export class OperationImpl {
|
|
|
189
190
|
static markObsolete(self) {
|
|
190
191
|
const ror = self.peek(undefined);
|
|
191
192
|
const ctx = ror.changeset;
|
|
192
|
-
ror.launch.
|
|
193
|
+
const obsolete = ror.launch.transaction.isFinished ? ctx.obsolete : ror.launch.transaction.changeset.obsolete;
|
|
194
|
+
ror.launch.markObsoleteDueTo(ror.launch, self.fieldKey, EMPTY_OBJECT_VERSION.changeset, EMPTY_HANDLE, BOOT_CAUSE, ctx.timestamp, obsolete);
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
class Launch extends FieldVersion {
|
|
@@ -307,7 +309,7 @@ class Launch extends FieldVersion {
|
|
|
307
309
|
const tran = this.transaction;
|
|
308
310
|
if (tran.changeset === changeset) {
|
|
309
311
|
}
|
|
310
|
-
else if (!tran.isFinished && this !== observable)
|
|
312
|
+
else if (!tran.isFinished && this !== observable && !this.options.allowObsoleteToFinish)
|
|
311
313
|
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);
|
|
312
314
|
}
|
|
313
315
|
else if (Log.isOn && (Log.opt.obsolete || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
@@ -485,11 +487,20 @@ class Launch extends FieldVersion {
|
|
|
485
487
|
if (Log.isOn && Log.opt.write)
|
|
486
488
|
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)");
|
|
487
489
|
}
|
|
488
|
-
static
|
|
489
|
-
let
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
490
|
+
static tryResolveConflict(theirValue, ourFormerValue, ourValue) {
|
|
491
|
+
let isResolved = theirValue === ourFormerValue;
|
|
492
|
+
let resolvedValue = ourValue;
|
|
493
|
+
if (!isResolved) {
|
|
494
|
+
if (ourValue instanceof Launch && ourValue.obsoleteDueTo === undefined) {
|
|
495
|
+
isResolved = true;
|
|
496
|
+
resolvedValue = ourValue;
|
|
497
|
+
}
|
|
498
|
+
else if (theirValue instanceof Launch && (theirValue.obsoleteDueTo === undefined || theirValue.cause === BOOT_CAUSE)) {
|
|
499
|
+
isResolved = true;
|
|
500
|
+
resolvedValue = theirValue;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return { isResolved, resolvedValue };
|
|
493
504
|
}
|
|
494
505
|
static propagateAllChangesThroughSubscriptions(changeset) {
|
|
495
506
|
var _a;
|
|
@@ -533,7 +544,11 @@ class Launch extends FieldVersion {
|
|
|
533
544
|
else
|
|
534
545
|
former.successor = undefined;
|
|
535
546
|
}
|
|
536
|
-
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s =>
|
|
547
|
+
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s => {
|
|
548
|
+
const t = s.transaction;
|
|
549
|
+
const o = t.isFinished ? obsolete : t.changeset.obsolete;
|
|
550
|
+
return s.markObsoleteDueTo(former, fk, ov.changeset, h, why, timestamp, o);
|
|
551
|
+
});
|
|
537
552
|
}
|
|
538
553
|
}
|
|
539
554
|
if (curr instanceof Launch) {
|
|
@@ -653,7 +668,7 @@ class Launch extends FieldVersion {
|
|
|
653
668
|
Dump.valueHint = valueHint;
|
|
654
669
|
Changeset.markUsed = Launch.markUsed;
|
|
655
670
|
Changeset.markEdited = Launch.markEdited;
|
|
656
|
-
Changeset.
|
|
671
|
+
Changeset.tryResolveConflict = Launch.tryResolveConflict;
|
|
657
672
|
Changeset.propagateAllChangesThroughSubscriptions = Launch.propagateAllChangesThroughSubscriptions;
|
|
658
673
|
Changeset.revokeAllSubscriptions = Launch.revokeAllSubscriptions;
|
|
659
674
|
Changeset.enqueueReactiveFunctionsToRun = Launch.enqueueReactiveFunctionsToRun;
|
|
@@ -354,7 +354,8 @@ RxNodeImpl.disposableNodeCount = 0;
|
|
|
354
354
|
__decorate([
|
|
355
355
|
reactive,
|
|
356
356
|
options({
|
|
357
|
-
reentrance: Reentrance.
|
|
357
|
+
reentrance: Reentrance.cancelAndWaitPrevious,
|
|
358
|
+
allowObsoleteToFinish: true,
|
|
358
359
|
triggeringArgs: true,
|
|
359
360
|
noSideEffects: false,
|
|
360
361
|
}),
|
|
@@ -12,6 +12,7 @@ export declare abstract class Transaction implements Worker {
|
|
|
12
12
|
abstract readonly error: Error | undefined;
|
|
13
13
|
abstract readonly changeset: Changeset;
|
|
14
14
|
abstract readonly margin: number;
|
|
15
|
+
abstract readonly parent?: Transaction;
|
|
15
16
|
abstract run<T>(func: F<T>, ...args: any[]): T;
|
|
16
17
|
abstract inspect<T>(func: F<T>, ...args: any[]): T;
|
|
17
18
|
abstract apply(): void;
|