@fluidframework/map 2.118.0 → 3.0.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/CHANGELOG.md +44 -4
- package/README.md +53 -50
- package/{api-extractor.json → api-extractor/api-extractor-model.json} +1 -1
- package/api-report/map.legacy.beta.api.md +9 -9
- package/api-report/map.legacy.public.api.md +4 -2
- package/dist/directory.js +171 -165
- package/dist/directory.js.map +1 -1
- package/dist/directoryFactory.d.ts +1 -1
- package/dist/directoryFactory.d.ts.map +1 -1
- package/dist/directoryFactory.js +15 -15
- package/dist/directoryFactory.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +26 -15
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/legacy.d.ts +0 -1
- package/dist/localValues.d.ts.map +1 -1
- package/dist/map.js +9 -6
- package/dist/map.js.map +1 -1
- package/dist/mapFactory.d.ts +1 -1
- package/dist/mapFactory.d.ts.map +1 -1
- package/dist/mapFactory.js +15 -15
- package/dist/mapFactory.js.map +1 -1
- package/dist/mapKernel.js +109 -104
- package/dist/mapKernel.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/lib/directory.js +171 -165
- package/lib/directory.js.map +1 -1
- package/lib/directoryFactory.js +15 -15
- package/lib/directoryFactory.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/interfaces.d.ts +26 -15
- package/lib/interfaces.d.ts.map +1 -1
- package/lib/interfaces.js.map +1 -1
- package/lib/legacy.d.ts +1 -2
- package/lib/localValues.d.ts.map +1 -1
- package/lib/map.js +9 -6
- package/lib/map.js.map +1 -1
- package/lib/mapFactory.js +15 -15
- package/lib/mapFactory.js.map +1 -1
- package/lib/mapKernel.js +109 -104
- package/lib/mapKernel.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/package.json +44 -60
- package/src/index.ts +0 -1
- package/src/interfaces.ts +31 -17
- package/src/packageVersion.ts +1 -1
- package/tsconfig.json +1 -1
- package/internal.d.ts +0 -11
- package/legacy.d.ts +0 -11
- /package/api-extractor/{api-extractor.current.json → api-extractor-report.current.json} +0 -0
- /package/api-extractor/{api-extractor.legacy.json → api-extractor-report.legacy.json} +0 -0
package/lib/directory.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
var _a, _b;
|
|
6
5
|
// TODO: Fix prefer-nullish-coalescing and prefer-optional-chain lint violations
|
|
7
6
|
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/prefer-optional-chain */
|
|
8
7
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
@@ -76,12 +75,24 @@ function isAcknowledgedOrDetached(seqData) {
|
|
|
76
75
|
* @sealed
|
|
77
76
|
*/
|
|
78
77
|
export class SharedDirectory extends SharedObject {
|
|
78
|
+
/**
|
|
79
|
+
* String representation for the class.
|
|
80
|
+
*/
|
|
81
|
+
[Symbol.toStringTag] = "SharedDirectory";
|
|
79
82
|
/**
|
|
80
83
|
* {@inheritDoc IDirectory.absolutePath}
|
|
81
84
|
*/
|
|
82
85
|
get absolutePath() {
|
|
83
86
|
return this.root.absolutePath;
|
|
84
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Root of the SharedDirectory, most operations on the SharedDirectory itself act on the root.
|
|
90
|
+
*/
|
|
91
|
+
root = new SubDirectory({ seq: 0, clientSeq: 0 }, new Set(), this, this.runtime, this.serializer, posix.sep, extractTelemetryLoggerExt(this.logger));
|
|
92
|
+
/**
|
|
93
|
+
* Mapping of op types to message handlers.
|
|
94
|
+
*/
|
|
95
|
+
messageHandlers = new Map();
|
|
85
96
|
/**
|
|
86
97
|
* Constructs a new shared directory. If the object is non-local an id and service interfaces will
|
|
87
98
|
* be provided.
|
|
@@ -91,18 +102,6 @@ export class SharedDirectory extends SharedObject {
|
|
|
91
102
|
*/
|
|
92
103
|
constructor(id, runtime, attributes) {
|
|
93
104
|
super(id, runtime, attributes, "fluid_directory_");
|
|
94
|
-
/**
|
|
95
|
-
* String representation for the class.
|
|
96
|
-
*/
|
|
97
|
-
this[_a] = "SharedDirectory";
|
|
98
|
-
/**
|
|
99
|
-
* Root of the SharedDirectory, most operations on the SharedDirectory itself act on the root.
|
|
100
|
-
*/
|
|
101
|
-
this.root = new SubDirectory({ seq: 0, clientSeq: 0 }, new Set(), this, this.runtime, this.serializer, posix.sep, extractTelemetryLoggerExt(this.logger));
|
|
102
|
-
/**
|
|
103
|
-
* Mapping of op types to message handlers.
|
|
104
|
-
*/
|
|
105
|
-
this.messageHandlers = new Map();
|
|
106
105
|
this.setMessageHandlers();
|
|
107
106
|
// Mirror the containedValueChanged op on the SharedDirectory
|
|
108
107
|
this.root.on("containedValueChanged", (changed, local) => {
|
|
@@ -180,7 +179,7 @@ export class SharedDirectory extends SharedObject {
|
|
|
180
179
|
*/
|
|
181
180
|
// TODO: Use `unknown` instead (breaking change).
|
|
182
181
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
183
|
-
[
|
|
182
|
+
[Symbol.iterator]() {
|
|
184
183
|
return this.root[Symbol.iterator]();
|
|
185
184
|
}
|
|
186
185
|
/**
|
|
@@ -603,6 +602,31 @@ function assertNonNullClientId(clientId) {
|
|
|
603
602
|
* @sealed
|
|
604
603
|
*/
|
|
605
604
|
class SubDirectory extends TypedEventEmitter {
|
|
605
|
+
seqData;
|
|
606
|
+
clientIds;
|
|
607
|
+
directory;
|
|
608
|
+
runtime;
|
|
609
|
+
serializer;
|
|
610
|
+
absolutePath;
|
|
611
|
+
/**
|
|
612
|
+
* Tells if the sub directory is deleted or not.
|
|
613
|
+
*/
|
|
614
|
+
_deleted = false;
|
|
615
|
+
/**
|
|
616
|
+
* String representation for the class.
|
|
617
|
+
*/
|
|
618
|
+
[Symbol.toStringTag] = "SubDirectory";
|
|
619
|
+
/**
|
|
620
|
+
* The sequenced subdirectories the directory is holding independent of any pending
|
|
621
|
+
* create/delete subdirectory operations.
|
|
622
|
+
*/
|
|
623
|
+
_sequencedSubdirectories = new Map();
|
|
624
|
+
/**
|
|
625
|
+
* Assigns a unique ID to each subdirectory created locally but pending for acknowledgement, facilitating the tracking
|
|
626
|
+
* of the creation order.
|
|
627
|
+
*/
|
|
628
|
+
localCreationSeq = 0;
|
|
629
|
+
mc;
|
|
606
630
|
/**
|
|
607
631
|
* Constructor.
|
|
608
632
|
* @param sequenceNumber - Message seq number at which this was created.
|
|
@@ -620,156 +644,6 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
620
644
|
this.runtime = runtime;
|
|
621
645
|
this.serializer = serializer;
|
|
622
646
|
this.absolutePath = absolutePath;
|
|
623
|
-
/**
|
|
624
|
-
* Tells if the sub directory is deleted or not.
|
|
625
|
-
*/
|
|
626
|
-
this._deleted = false;
|
|
627
|
-
/**
|
|
628
|
-
* String representation for the class.
|
|
629
|
-
*/
|
|
630
|
-
this[_b] = "SubDirectory";
|
|
631
|
-
/**
|
|
632
|
-
* The sequenced subdirectories the directory is holding independent of any pending
|
|
633
|
-
* create/delete subdirectory operations.
|
|
634
|
-
*/
|
|
635
|
-
this._sequencedSubdirectories = new Map();
|
|
636
|
-
/**
|
|
637
|
-
* Assigns a unique ID to each subdirectory created locally but pending for acknowledgement, facilitating the tracking
|
|
638
|
-
* of the creation order.
|
|
639
|
-
*/
|
|
640
|
-
this.localCreationSeq = 0;
|
|
641
|
-
/**
|
|
642
|
-
* The data this SubDirectory instance is storing, but only including sequenced values (no local pending
|
|
643
|
-
* modifications are included).
|
|
644
|
-
*/
|
|
645
|
-
this.sequencedStorageData = new Map();
|
|
646
|
-
/**
|
|
647
|
-
* A data structure containing all local pending storage modifications, which is used in combination
|
|
648
|
-
* with the sequencedStorageData to compute optimistic values.
|
|
649
|
-
*
|
|
650
|
-
* Pending sets are aggregated into "lifetimes", which permit correct relative iteration order
|
|
651
|
-
* even across remote operations and rollbacks.
|
|
652
|
-
*/
|
|
653
|
-
this.pendingStorageData = [];
|
|
654
|
-
/**
|
|
655
|
-
* A data structure containing all local pending subdirectory create/deletes, which is used in combination
|
|
656
|
-
* with the _sequencedSubdirectories to compute optimistic values.
|
|
657
|
-
*/
|
|
658
|
-
this.pendingSubDirectoryData = [];
|
|
659
|
-
/**
|
|
660
|
-
* An internal iterator that iterates over the entries in the directory.
|
|
661
|
-
*/
|
|
662
|
-
this.internalIterator = () => {
|
|
663
|
-
// We perform iteration in two steps - first by iterating over members of the sequenced storage data that are not
|
|
664
|
-
// optimistically deleted or cleared, and then over the pending data lifetimes that have not subsequently
|
|
665
|
-
// been deleted or cleared. In total, this give an ordering of members based on when they were initially
|
|
666
|
-
// added to the sub directory (even if they were later modified), similar to the native Map.
|
|
667
|
-
const sequencedStorageDataIterator = this.sequencedStorageData.keys();
|
|
668
|
-
const pendingStorageDataIterator = this.pendingStorageData.values();
|
|
669
|
-
const next = () => {
|
|
670
|
-
let nextSequencedKey = sequencedStorageDataIterator.next();
|
|
671
|
-
while (!nextSequencedKey.done) {
|
|
672
|
-
const key = nextSequencedKey.value;
|
|
673
|
-
// If we have any pending deletes or clears, then we won't iterate to this key yet (if at all).
|
|
674
|
-
// Either it is optimistically deleted and will not be part of the iteration, or it was
|
|
675
|
-
// re-added later and we'll iterate to it when we get to the pending data.
|
|
676
|
-
if (!this.pendingStorageData.some((entry) => entry.type === "clear" || (entry.type === "delete" && entry.key === key))) {
|
|
677
|
-
assert(this.has(key), 0xc03 /* key should exist in sequenced or pending data */);
|
|
678
|
-
const optimisticValue = this.getOptimisticValue(key);
|
|
679
|
-
return { value: [key, optimisticValue], done: false };
|
|
680
|
-
}
|
|
681
|
-
nextSequencedKey = sequencedStorageDataIterator.next();
|
|
682
|
-
}
|
|
683
|
-
let nextPending = pendingStorageDataIterator.next();
|
|
684
|
-
while (!nextPending.done) {
|
|
685
|
-
const nextPendingEntry = nextPending.value;
|
|
686
|
-
// A lifetime entry may need to be iterated.
|
|
687
|
-
if (nextPendingEntry.type === "lifetime") {
|
|
688
|
-
const nextPendingEntryIndex = this.pendingStorageData.indexOf(nextPendingEntry);
|
|
689
|
-
const mostRecentDeleteOrClearIndex = findLastIndex(this.pendingStorageData, (entry) => entry.type === "clear" ||
|
|
690
|
-
(entry.type === "delete" && entry.key === nextPendingEntry.key));
|
|
691
|
-
// Only iterate the pending entry now if it hasn't been deleted or cleared.
|
|
692
|
-
if (nextPendingEntryIndex > mostRecentDeleteOrClearIndex) {
|
|
693
|
-
const latestPendingValue =
|
|
694
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
695
|
-
nextPendingEntry.keySets[nextPendingEntry.keySets.length - 1];
|
|
696
|
-
// Skip iterating if we would have would have already iterated it as part of the sequenced data.
|
|
697
|
-
// This is not a perfect check in the case the map has changed since the iterator was created
|
|
698
|
-
// (e.g. if a remote client added the same key in the meantime).
|
|
699
|
-
if (!this.sequencedStorageData.has(nextPendingEntry.key) ||
|
|
700
|
-
mostRecentDeleteOrClearIndex !== -1) {
|
|
701
|
-
return { value: [nextPendingEntry.key, latestPendingValue.value], done: false };
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
nextPending = pendingStorageDataIterator.next();
|
|
706
|
-
}
|
|
707
|
-
return { value: undefined, done: true };
|
|
708
|
-
};
|
|
709
|
-
const iterator = {
|
|
710
|
-
next,
|
|
711
|
-
[Symbol.iterator]() {
|
|
712
|
-
return this;
|
|
713
|
-
},
|
|
714
|
-
};
|
|
715
|
-
return iterator;
|
|
716
|
-
};
|
|
717
|
-
/**
|
|
718
|
-
* Compute the optimistic local value for a given key. This combines the sequenced data with
|
|
719
|
-
* any pending changes that have not yet been sequenced.
|
|
720
|
-
*/
|
|
721
|
-
this.getOptimisticValue = (key) => {
|
|
722
|
-
const latestPendingEntry = findLast(this.pendingStorageData, (entry) => entry.type === "clear" || entry.key === key);
|
|
723
|
-
if (latestPendingEntry === undefined) {
|
|
724
|
-
return this.sequencedStorageData.get(key);
|
|
725
|
-
}
|
|
726
|
-
else if (latestPendingEntry.type === "lifetime") {
|
|
727
|
-
const latestPendingSet =
|
|
728
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
729
|
-
latestPendingEntry.keySets[latestPendingEntry.keySets.length - 1];
|
|
730
|
-
return latestPendingSet.value;
|
|
731
|
-
}
|
|
732
|
-
else {
|
|
733
|
-
// Delete or clear
|
|
734
|
-
return undefined;
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
/**
|
|
738
|
-
* Determine if the directory optimistically has the key.
|
|
739
|
-
* This will return true even if the value is undefined.
|
|
740
|
-
*/
|
|
741
|
-
this.optimisticallyHas = (key) => {
|
|
742
|
-
const latestPendingEntry = findLast(this.pendingStorageData, (entry) => entry.type === "clear" || entry.key === key);
|
|
743
|
-
return latestPendingEntry === undefined
|
|
744
|
-
? this.sequencedStorageData.has(key)
|
|
745
|
-
: latestPendingEntry.type === "lifetime";
|
|
746
|
-
};
|
|
747
|
-
/**
|
|
748
|
-
* Get the optimistic local subdirectory. This combines the sequenced data with
|
|
749
|
-
* any pending changes that have not yet been sequenced. By default, we do not
|
|
750
|
-
* consider disposed directories as optimistically existing, but if `getIfDisposed`
|
|
751
|
-
* is true, we will include them since some scenarios require this.
|
|
752
|
-
*/
|
|
753
|
-
this.getOptimisticSubDirectory = (subdirName, getIfDisposed = false) => {
|
|
754
|
-
const latestPendingEntry = findLast(this.pendingSubDirectoryData, (entry) => entry.subdirName === subdirName);
|
|
755
|
-
let subdir;
|
|
756
|
-
if (latestPendingEntry === undefined) {
|
|
757
|
-
subdir = this._sequencedSubdirectories.get(subdirName);
|
|
758
|
-
}
|
|
759
|
-
else if (latestPendingEntry.type === "createSubDirectory") {
|
|
760
|
-
subdir = latestPendingEntry.subdir;
|
|
761
|
-
assert(subdir !== undefined, 0xc2f /* Subdirectory should exist in pending data */);
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
// Pending delete
|
|
765
|
-
return undefined;
|
|
766
|
-
}
|
|
767
|
-
// If the subdirectory is disposed, treat it as non-existent for optimistic reads (unless specified otherwise)
|
|
768
|
-
if (subdir?.disposed && !getIfDisposed) {
|
|
769
|
-
return undefined;
|
|
770
|
-
}
|
|
771
|
-
return subdir;
|
|
772
|
-
};
|
|
773
647
|
this.mc = createChildMonitoringContext({ logger, namespace: "Directory" });
|
|
774
648
|
}
|
|
775
649
|
dispose(error) {
|
|
@@ -1235,10 +1109,142 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1235
1109
|
* Get an iterator over the entries under this IDirectory.
|
|
1236
1110
|
* @returns The iterator
|
|
1237
1111
|
*/
|
|
1238
|
-
[
|
|
1112
|
+
[Symbol.iterator]() {
|
|
1239
1113
|
this.throwIfDisposed();
|
|
1240
1114
|
return this.internalIterator();
|
|
1241
1115
|
}
|
|
1116
|
+
/**
|
|
1117
|
+
* The data this SubDirectory instance is storing, but only including sequenced values (no local pending
|
|
1118
|
+
* modifications are included).
|
|
1119
|
+
*/
|
|
1120
|
+
sequencedStorageData = new Map();
|
|
1121
|
+
/**
|
|
1122
|
+
* A data structure containing all local pending storage modifications, which is used in combination
|
|
1123
|
+
* with the sequencedStorageData to compute optimistic values.
|
|
1124
|
+
*
|
|
1125
|
+
* Pending sets are aggregated into "lifetimes", which permit correct relative iteration order
|
|
1126
|
+
* even across remote operations and rollbacks.
|
|
1127
|
+
*/
|
|
1128
|
+
pendingStorageData = [];
|
|
1129
|
+
/**
|
|
1130
|
+
* A data structure containing all local pending subdirectory create/deletes, which is used in combination
|
|
1131
|
+
* with the _sequencedSubdirectories to compute optimistic values.
|
|
1132
|
+
*/
|
|
1133
|
+
pendingSubDirectoryData = [];
|
|
1134
|
+
/**
|
|
1135
|
+
* An internal iterator that iterates over the entries in the directory.
|
|
1136
|
+
*/
|
|
1137
|
+
internalIterator = () => {
|
|
1138
|
+
// We perform iteration in two steps - first by iterating over members of the sequenced storage data that are not
|
|
1139
|
+
// optimistically deleted or cleared, and then over the pending data lifetimes that have not subsequently
|
|
1140
|
+
// been deleted or cleared. In total, this give an ordering of members based on when they were initially
|
|
1141
|
+
// added to the sub directory (even if they were later modified), similar to the native Map.
|
|
1142
|
+
const sequencedStorageDataIterator = this.sequencedStorageData.keys();
|
|
1143
|
+
const pendingStorageDataIterator = this.pendingStorageData.values();
|
|
1144
|
+
const next = () => {
|
|
1145
|
+
let nextSequencedKey = sequencedStorageDataIterator.next();
|
|
1146
|
+
while (!nextSequencedKey.done) {
|
|
1147
|
+
const key = nextSequencedKey.value;
|
|
1148
|
+
// If we have any pending deletes or clears, then we won't iterate to this key yet (if at all).
|
|
1149
|
+
// Either it is optimistically deleted and will not be part of the iteration, or it was
|
|
1150
|
+
// re-added later and we'll iterate to it when we get to the pending data.
|
|
1151
|
+
if (!this.pendingStorageData.some((entry) => entry.type === "clear" || (entry.type === "delete" && entry.key === key))) {
|
|
1152
|
+
assert(this.has(key), 0xc03 /* key should exist in sequenced or pending data */);
|
|
1153
|
+
const optimisticValue = this.getOptimisticValue(key);
|
|
1154
|
+
return { value: [key, optimisticValue], done: false };
|
|
1155
|
+
}
|
|
1156
|
+
nextSequencedKey = sequencedStorageDataIterator.next();
|
|
1157
|
+
}
|
|
1158
|
+
let nextPending = pendingStorageDataIterator.next();
|
|
1159
|
+
while (!nextPending.done) {
|
|
1160
|
+
const nextPendingEntry = nextPending.value;
|
|
1161
|
+
// A lifetime entry may need to be iterated.
|
|
1162
|
+
if (nextPendingEntry.type === "lifetime") {
|
|
1163
|
+
const nextPendingEntryIndex = this.pendingStorageData.indexOf(nextPendingEntry);
|
|
1164
|
+
const mostRecentDeleteOrClearIndex = findLastIndex(this.pendingStorageData, (entry) => entry.type === "clear" ||
|
|
1165
|
+
(entry.type === "delete" && entry.key === nextPendingEntry.key));
|
|
1166
|
+
// Only iterate the pending entry now if it hasn't been deleted or cleared.
|
|
1167
|
+
if (nextPendingEntryIndex > mostRecentDeleteOrClearIndex) {
|
|
1168
|
+
const latestPendingValue =
|
|
1169
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1170
|
+
nextPendingEntry.keySets[nextPendingEntry.keySets.length - 1];
|
|
1171
|
+
// Skip iterating if we would have would have already iterated it as part of the sequenced data.
|
|
1172
|
+
// This is not a perfect check in the case the map has changed since the iterator was created
|
|
1173
|
+
// (e.g. if a remote client added the same key in the meantime).
|
|
1174
|
+
if (!this.sequencedStorageData.has(nextPendingEntry.key) ||
|
|
1175
|
+
mostRecentDeleteOrClearIndex !== -1) {
|
|
1176
|
+
return { value: [nextPendingEntry.key, latestPendingValue.value], done: false };
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
nextPending = pendingStorageDataIterator.next();
|
|
1181
|
+
}
|
|
1182
|
+
return { value: undefined, done: true };
|
|
1183
|
+
};
|
|
1184
|
+
const iterator = {
|
|
1185
|
+
next,
|
|
1186
|
+
[Symbol.iterator]() {
|
|
1187
|
+
return this;
|
|
1188
|
+
},
|
|
1189
|
+
};
|
|
1190
|
+
return iterator;
|
|
1191
|
+
};
|
|
1192
|
+
/**
|
|
1193
|
+
* Compute the optimistic local value for a given key. This combines the sequenced data with
|
|
1194
|
+
* any pending changes that have not yet been sequenced.
|
|
1195
|
+
*/
|
|
1196
|
+
getOptimisticValue = (key) => {
|
|
1197
|
+
const latestPendingEntry = findLast(this.pendingStorageData, (entry) => entry.type === "clear" || entry.key === key);
|
|
1198
|
+
if (latestPendingEntry === undefined) {
|
|
1199
|
+
return this.sequencedStorageData.get(key);
|
|
1200
|
+
}
|
|
1201
|
+
else if (latestPendingEntry.type === "lifetime") {
|
|
1202
|
+
const latestPendingSet =
|
|
1203
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1204
|
+
latestPendingEntry.keySets[latestPendingEntry.keySets.length - 1];
|
|
1205
|
+
return latestPendingSet.value;
|
|
1206
|
+
}
|
|
1207
|
+
else {
|
|
1208
|
+
// Delete or clear
|
|
1209
|
+
return undefined;
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
/**
|
|
1213
|
+
* Determine if the directory optimistically has the key.
|
|
1214
|
+
* This will return true even if the value is undefined.
|
|
1215
|
+
*/
|
|
1216
|
+
optimisticallyHas = (key) => {
|
|
1217
|
+
const latestPendingEntry = findLast(this.pendingStorageData, (entry) => entry.type === "clear" || entry.key === key);
|
|
1218
|
+
return latestPendingEntry === undefined
|
|
1219
|
+
? this.sequencedStorageData.has(key)
|
|
1220
|
+
: latestPendingEntry.type === "lifetime";
|
|
1221
|
+
};
|
|
1222
|
+
/**
|
|
1223
|
+
* Get the optimistic local subdirectory. This combines the sequenced data with
|
|
1224
|
+
* any pending changes that have not yet been sequenced. By default, we do not
|
|
1225
|
+
* consider disposed directories as optimistically existing, but if `getIfDisposed`
|
|
1226
|
+
* is true, we will include them since some scenarios require this.
|
|
1227
|
+
*/
|
|
1228
|
+
getOptimisticSubDirectory = (subdirName, getIfDisposed = false) => {
|
|
1229
|
+
const latestPendingEntry = findLast(this.pendingSubDirectoryData, (entry) => entry.subdirName === subdirName);
|
|
1230
|
+
let subdir;
|
|
1231
|
+
if (latestPendingEntry === undefined) {
|
|
1232
|
+
subdir = this._sequencedSubdirectories.get(subdirName);
|
|
1233
|
+
}
|
|
1234
|
+
else if (latestPendingEntry.type === "createSubDirectory") {
|
|
1235
|
+
subdir = latestPendingEntry.subdir;
|
|
1236
|
+
assert(subdir !== undefined, 0xc2f /* Subdirectory should exist in pending data */);
|
|
1237
|
+
}
|
|
1238
|
+
else {
|
|
1239
|
+
// Pending delete
|
|
1240
|
+
return undefined;
|
|
1241
|
+
}
|
|
1242
|
+
// If the subdirectory is disposed, treat it as non-existent for optimistic reads (unless specified otherwise)
|
|
1243
|
+
if (subdir?.disposed && !getIfDisposed) {
|
|
1244
|
+
return undefined;
|
|
1245
|
+
}
|
|
1246
|
+
return subdir;
|
|
1247
|
+
};
|
|
1242
1248
|
/**
|
|
1243
1249
|
* Checks if this directory should be considered visible in the optimistic view.
|
|
1244
1250
|
* This requires both:
|