@milaboratories/pl-tree 1.6.12 → 1.7.0

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/src/state.ts CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  stringifyWithResourceId,
18
18
  } from '@milaboratories/pl-client';
19
19
  import type { Watcher } from '@milaboratories/computable';
20
- import { ChangeSource } from '@milaboratories/computable';
20
+ import { ChangeSource, KeyedChangeSource } from '@milaboratories/computable';
21
21
  import { PlTreeEntry } from './accessors';
22
22
  import type { ValueAndError } from './value_and_error';
23
23
  import type { MiLogger } from '@milaboratories/ts-helpers';
@@ -94,7 +94,8 @@ export class PlTreeResource implements ResourceDataWithFinalState {
94
94
  outputFieldListChanged? = new ChangeSource();
95
95
  dynamicFieldListChanged? = new ChangeSource();
96
96
 
97
- kvChanged? = new ChangeSource();
97
+ // kvChangedGlobal? = new ChangeSource();
98
+ kvChangedPerKey? = new KeyedChangeSource();
98
99
 
99
100
  readonly id: ResourceId;
100
101
  originalResourceId: OptionalResourceId;
@@ -294,7 +295,7 @@ export class PlTreeResource implements ResourceDataWithFinalState {
294
295
  }
295
296
 
296
297
  public getKeyValue(watcher: Watcher, key: string): Uint8Array | undefined {
297
- this.kvChanged?.attachWatcher(watcher);
298
+ this.kvChangedPerKey?.attachWatcher(key, watcher);
298
299
  return this.kv.get(key);
299
300
  }
300
301
 
@@ -355,26 +356,29 @@ export class PlTreeResource implements ResourceDataWithFinalState {
355
356
  if (this._finalState) return;
356
357
 
357
358
  this._finalState = true;
358
- notEmpty(this.finalChanged).markChanged();
359
+ notEmpty(this.finalChanged).markChanged('marked final');
359
360
  this.finalChanged = undefined;
360
361
  this.resourceStateChange = undefined;
361
362
  this.dynamicFieldListChanged = undefined;
362
363
  this.inputAndServiceFieldListChanged = undefined;
363
364
  this.outputFieldListChanged = undefined;
364
365
  this.lockedChange = undefined;
366
+ // this.kvChangedGlobal = undefined;
367
+ this.kvChangedPerKey = undefined;
365
368
  }
366
369
 
367
370
  /** Used for invalidation */
368
371
  markAllChanged() {
369
- this.fieldsMap.forEach((field) => field.change.markChanged());
370
- this.finalChanged?.markChanged();
371
- this.resourceStateChange?.markChanged();
372
- this.lockedChange?.markChanged();
373
- this.inputAndServiceFieldListChanged?.markChanged();
374
- this.outputFieldListChanged?.markChanged();
375
- this.dynamicFieldListChanged?.markChanged();
376
- this.kvChanged?.markChanged();
377
- this.resourceRemoved.markChanged();
372
+ this.fieldsMap.forEach((field) => field.change.markChanged('marked all changed'));
373
+ this.finalChanged?.markChanged('marked all changed');
374
+ this.resourceStateChange?.markChanged('marked all changed');
375
+ this.lockedChange?.markChanged('marked all changed');
376
+ this.inputAndServiceFieldListChanged?.markChanged('marked all changed');
377
+ this.outputFieldListChanged?.markChanged('marked all changed');
378
+ this.dynamicFieldListChanged?.markChanged('marked all changed');
379
+ // this.kvChangedGlobal?.markChanged('marked all changed');
380
+ this.kvChangedPerKey?.markAllChanged('marked all changed');
381
+ this.resourceRemoved.markChanged('marked all changed');
378
382
  }
379
383
  }
380
384
 
@@ -453,7 +457,7 @@ export class PlTreeState {
453
457
  unexpectedTransitionError('originalResourceId can\'t change after it is set');
454
458
  resource.originalResourceId = rd.originalResourceId;
455
459
  // duplicate status of the resource counts as ready for the external observer
456
- notEmpty(resource.resourceStateChange).markChanged();
460
+ notEmpty(resource.resourceStateChange).markChanged(`originalResourceId changed for ${resourceIdToString(resource.id)}`);
457
461
  changed = true;
458
462
  }
459
463
 
@@ -463,7 +467,7 @@ export class PlTreeState {
463
467
  unexpectedTransitionError('resource can\'t change attached error after it is set');
464
468
  resource.error = rd.error;
465
469
  incrementRefs.push(resource.error as ResourceId);
466
- notEmpty(resource.resourceStateChange).markChanged();
470
+ notEmpty(resource.resourceStateChange).markChanged(`error changed for ${resourceIdToString(resource.id)}`);
467
471
  changed = true;
468
472
  }
469
473
 
@@ -491,15 +495,15 @@ export class PlTreeState {
491
495
  unexpectedTransitionError(
492
496
  `adding ${fd.type} (${fd.name}) field while inputs locked`,
493
497
  );
494
- notEmpty(resource.inputAndServiceFieldListChanged).markChanged();
498
+ notEmpty(resource.inputAndServiceFieldListChanged).markChanged(`new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`);
495
499
  } else if (fd.type === 'Output') {
496
500
  if (resource.outputsLocked)
497
501
  unexpectedTransitionError(
498
502
  `adding ${fd.type} (${fd.name}) field while outputs locked`,
499
503
  );
500
- notEmpty(resource.outputFieldListChanged).markChanged();
504
+ notEmpty(resource.outputFieldListChanged).markChanged(`new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`);
501
505
  } else {
502
- notEmpty(resource.dynamicFieldListChanged).markChanged();
506
+ notEmpty(resource.dynamicFieldListChanged).markChanged(`new ${fd.type} field ${fd.name} added to ${resourceIdToString(resource.id)}`);
503
507
  }
504
508
 
505
509
  resource.fieldsMap.set(fd.name, field);
@@ -512,23 +516,23 @@ export class PlTreeState {
512
516
  if (field.type !== fd.type) {
513
517
  if (field.type !== 'Dynamic')
514
518
  unexpectedTransitionError(`field changed type ${field.type} -> ${fd.type}`);
515
- notEmpty(resource.dynamicFieldListChanged).markChanged();
519
+ notEmpty(resource.dynamicFieldListChanged).markChanged(`field ${fd.name} changed type from Dynamic to ${fd.type} in ${resourceIdToString(resource.id)}`);
516
520
  if (field.type === 'Input' || field.type === 'Service') {
517
521
  if (resource.inputsLocked)
518
522
  unexpectedTransitionError(
519
523
  `adding input field "${fd.name}", while corresponding list is locked`,
520
524
  );
521
- notEmpty(resource.inputAndServiceFieldListChanged).markChanged();
525
+ notEmpty(resource.inputAndServiceFieldListChanged).markChanged(`field ${fd.name} changed to type ${fd.type} in ${resourceIdToString(resource.id)}`);
522
526
  }
523
527
  if (field.type === 'Output') {
524
528
  if (resource.outputsLocked)
525
529
  unexpectedTransitionError(
526
530
  `adding output field "${fd.name}", while corresponding list is locked`,
527
531
  );
528
- notEmpty(resource.outputFieldListChanged).markChanged();
532
+ notEmpty(resource.outputFieldListChanged).markChanged(`field ${fd.name} changed to type ${fd.type} in ${resourceIdToString(resource.id)}`);
529
533
  }
530
534
  field.type = fd.type;
531
- field.change.markChanged();
535
+ field.change.markChanged(`field ${fd.name} type changed to ${fd.type} in ${resourceIdToString(resource.id)}`);
532
536
  changed = true;
533
537
  }
534
538
 
@@ -537,7 +541,7 @@ export class PlTreeState {
537
541
  if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);
538
542
  field.value = fd.value;
539
543
  if (isNotNullResourceId(fd.value)) incrementRefs.push(fd.value);
540
- field.change.markChanged();
544
+ field.change.markChanged(`field ${fd.name} value changed in ${resourceIdToString(resource.id)}`);
541
545
  changed = true;
542
546
  }
543
547
 
@@ -546,21 +550,21 @@ export class PlTreeState {
546
550
  if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);
547
551
  field.error = fd.error;
548
552
  if (isNotNullResourceId(fd.error)) incrementRefs.push(fd.error);
549
- field.change.markChanged();
553
+ field.change.markChanged(`field ${fd.name} error changed in ${resourceIdToString(resource.id)}`);
550
554
  changed = true;
551
555
  }
552
556
 
553
557
  // field status
554
558
  if (field.status !== fd.status) {
555
559
  field.status = fd.status;
556
- field.change.markChanged();
560
+ field.change.markChanged(`field ${fd.name} status changed to ${fd.status} in ${resourceIdToString(resource.id)}`);
557
561
  changed = true;
558
562
  }
559
563
 
560
564
  // field valueIsFinal flag
561
565
  if (field.valueIsFinal !== fd.valueIsFinal) {
562
566
  field.valueIsFinal = fd.valueIsFinal;
563
- field.change.markChanged();
567
+ field.change.markChanged(`field ${fd.name} valueIsFinal changed to ${fd.valueIsFinal} in ${resourceIdToString(resource.id)}`);
564
568
  changed = true;
565
569
  }
566
570
 
@@ -573,13 +577,13 @@ export class PlTreeState {
573
577
  if (field.resourceVersion !== resource!.version) {
574
578
  if (field.type === 'Input' || field.type === 'Service' || field.type === 'Output')
575
579
  unexpectedTransitionError(`removal of ${field.type} field ${fieldName}`);
576
- field.change.markChanged();
580
+ field.change.markChanged(`dynamic field ${fieldName} removed from ${resourceIdToString(resource!.id)}`);
577
581
  fields.delete(fieldName);
578
582
 
579
583
  if (isNotNullResourceId(field.value)) decrementRefs.push(field.value);
580
584
  if (isNotNullResourceId(field.error)) decrementRefs.push(field.error);
581
585
 
582
- notEmpty(resource!.dynamicFieldListChanged).markChanged();
586
+ notEmpty(resource!.dynamicFieldListChanged).markChanged(`dynamic field ${fieldName} removed from ${resourceIdToString(resource!.id)}`);
583
587
  }
584
588
  });
585
589
 
@@ -587,7 +591,7 @@ export class PlTreeState {
587
591
  if (resource.inputsLocked !== rd.inputsLocked) {
588
592
  if (resource.inputsLocked) unexpectedTransitionError('inputs unlocking is not permitted');
589
593
  resource.inputsLocked = rd.inputsLocked;
590
- notEmpty(resource.lockedChange).markChanged();
594
+ notEmpty(resource.lockedChange).markChanged(`inputs locked for ${resourceIdToString(resource.id)}`);
591
595
  changed = true;
592
596
  }
593
597
 
@@ -596,7 +600,7 @@ export class PlTreeState {
596
600
  if (resource.outputsLocked)
597
601
  unexpectedTransitionError('outputs unlocking is not permitted');
598
602
  resource.outputsLocked = rd.outputsLocked;
599
- notEmpty(resource.lockedChange).markChanged();
603
+ notEmpty(resource.lockedChange).markChanged(`outputs locked for ${resourceIdToString(resource.id)}`);
600
604
  changed = true;
601
605
  }
602
606
 
@@ -609,20 +613,19 @@ export class PlTreeState {
609
613
  unexpectedTransitionError(
610
614
  `resource can't lose it's ready or error state (ready state before ${readyStateBefore})`,
611
615
  );
612
- notEmpty(resource.resourceStateChange).markChanged();
616
+ notEmpty(resource.resourceStateChange).markChanged(`ready flag changed to ${rd.resourceReady} for ${resourceIdToString(resource.id)}`);
613
617
  changed = true;
614
618
  }
615
619
 
616
620
  // syncing kv
617
- let kvChanged = false;
618
621
  for (const kv of rd.kv) {
619
622
  const current = resource.kv.get(kv.key);
620
623
  if (current === undefined) {
621
624
  resource.kv.set(kv.key, kv.value);
622
- kvChanged = true;
625
+ notEmpty(resource.kvChangedPerKey).markChanged(kv.key, `kv added for ${resourceIdToString(resource.id)}: ${kv.key}`);
623
626
  } else if (Buffer.compare(current, kv.value) !== 0) {
624
627
  resource.kv.set(kv.key, kv.value);
625
- kvChanged = true;
628
+ notEmpty(resource.kvChangedPerKey).markChanged(kv.key, `kv changed for ${resourceIdToString(resource.id)}: ${kv.key}`);
626
629
  }
627
630
  }
628
631
 
@@ -632,14 +635,13 @@ export class PlTreeState {
632
635
 
633
636
  // deleting keys not present in resource anymore
634
637
  resource.kv.forEach((_value, key, map) => {
635
- if (!newStateKeys.has(key)) map.delete(key);
638
+ if (!newStateKeys.has(key)) {
639
+ map.delete(key);
640
+ notEmpty(resource!.kvChangedPerKey).markChanged(key, `kv deleted for ${resourceIdToString(resource!.id)}: ${key}`);
641
+ }
636
642
  });
637
-
638
- kvChanged = true;
639
643
  }
640
644
 
641
- if (kvChanged) notEmpty(resource.kvChanged).markChanged();
642
-
643
645
  if (changed) {
644
646
  // if resource was changed, updating resource data version
645
647
  resource.dataVersion = resource.version;
@@ -674,7 +676,7 @@ export class PlTreeState {
674
676
 
675
677
  // adding the resource to the heap
676
678
  this.resources.set(resource.id, resource);
677
- this.resourcesAdded.markChanged();
679
+ this.resourcesAdded.markChanged(`new resource ${resourceIdToString(resource.id)} added`);
678
680
  }
679
681
  }
680
682
 
@@ -706,10 +708,10 @@ export class PlTreeState {
706
708
  res.fieldsMap.forEach((field) => {
707
709
  if (isNotNullResourceId(field.value)) nextRefs.push(field.value);
708
710
  if (isNotNullResourceId(field.error)) nextRefs.push(field.error);
709
- field.change.markChanged();
711
+ field.change.markChanged(`field ${field.name} removed during garbage collection of ${resourceIdToString(res.id)}`);
710
712
  });
711
713
  if (isNotNullResourceId(res.error)) nextRefs.push(res.error);
712
- res.resourceRemoved.markChanged();
714
+ res.resourceRemoved.markChanged(`resource removed during garbage collection: ${resourceIdToString(res.id)}`);
713
715
  this.resources.delete(rid);
714
716
  }
715
717
  }