@fluidframework/datastore 2.0.0-rc.1.0.3 → 2.0.0-rc.1.0.5
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/api-report/datastore.api.md +1 -0
- package/dist/channelContext.d.ts +1 -0
- package/dist/channelContext.d.ts.map +1 -1
- package/dist/channelContext.js +1 -0
- package/dist/channelContext.js.map +1 -1
- package/dist/dataStoreRuntime.d.ts +12 -2
- package/dist/dataStoreRuntime.d.ts.map +1 -1
- package/dist/dataStoreRuntime.js +53 -19
- package/dist/dataStoreRuntime.js.map +1 -1
- package/dist/datastore-alpha.d.ts +12 -2
- package/dist/datastore-untrimmed.d.ts +12 -2
- package/dist/localChannelContext.d.ts +12 -0
- package/dist/localChannelContext.d.ts.map +1 -1
- package/dist/localChannelContext.js +16 -0
- package/dist/localChannelContext.js.map +1 -1
- package/lib/channelContext.d.mts +1 -0
- package/lib/channelContext.d.mts.map +1 -1
- package/lib/channelContext.mjs +1 -0
- package/lib/channelContext.mjs.map +1 -1
- package/lib/dataStoreRuntime.d.mts +12 -2
- package/lib/dataStoreRuntime.d.mts.map +1 -1
- package/lib/dataStoreRuntime.mjs +55 -21
- package/lib/dataStoreRuntime.mjs.map +1 -1
- package/lib/datastore-alpha.d.mts +12 -2
- package/lib/datastore-untrimmed.d.mts +12 -2
- package/lib/localChannelContext.d.mts +12 -0
- package/lib/localChannelContext.d.mts.map +1 -1
- package/lib/localChannelContext.mjs +16 -0
- package/lib/localChannelContext.mjs.map +1 -1
- package/package.json +18 -14
- package/src/channelContext.ts +1 -0
- package/src/dataStoreRuntime.ts +78 -28
- package/src/localChannelContext.ts +18 -0
package/src/channelContext.ts
CHANGED
package/src/dataStoreRuntime.ts
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
VisibilityState,
|
|
53
53
|
ITelemetryContext,
|
|
54
54
|
IIdCompressor,
|
|
55
|
+
gcDataBlobKey,
|
|
55
56
|
} from "@fluidframework/runtime-definitions";
|
|
56
57
|
import {
|
|
57
58
|
convertSnapshotTreeToSummaryTree,
|
|
@@ -64,6 +65,8 @@ import {
|
|
|
64
65
|
exceptionToResponse,
|
|
65
66
|
GCDataBuilder,
|
|
66
67
|
unpackChildNodesUsedRoutes,
|
|
68
|
+
addBlobToSummary,
|
|
69
|
+
processAttachMessageGCData,
|
|
67
70
|
} from "@fluidframework/runtime-utils";
|
|
68
71
|
import {
|
|
69
72
|
IChannel,
|
|
@@ -482,7 +485,7 @@ export class FluidDataStoreRuntime
|
|
|
482
485
|
this.notBoundedChannelContextSet.delete(channel.id);
|
|
483
486
|
// If our data store is attached, then attach the channel.
|
|
484
487
|
if (this.isAttached) {
|
|
485
|
-
this.
|
|
488
|
+
this.makeChannelLocallyVisible(channel);
|
|
486
489
|
return;
|
|
487
490
|
}
|
|
488
491
|
|
|
@@ -610,6 +613,13 @@ export class FluidDataStoreRuntime
|
|
|
610
613
|
const attachMessage = message.contents as IAttachMessage;
|
|
611
614
|
const id = attachMessage.id;
|
|
612
615
|
|
|
616
|
+
// We need to process the GC Data for both local and remote attach messages
|
|
617
|
+
processAttachMessageGCData(attachMessage.snapshot, (nodeId, toPath) => {
|
|
618
|
+
// Note: nodeId will be "/" unless and until we support sub-DDS GC Nodes
|
|
619
|
+
const fromPath = `/${this.id}/${id}${nodeId === "/" ? "" : nodeId}`;
|
|
620
|
+
this.dataStoreContext.addedGCOutboundRoute?.(fromPath, toPath);
|
|
621
|
+
});
|
|
622
|
+
|
|
613
623
|
// If a non-local operation then go and create the object
|
|
614
624
|
// Otherwise mark it as officially attached.
|
|
615
625
|
if (local) {
|
|
@@ -812,6 +822,64 @@ export class FluidDataStoreRuntime
|
|
|
812
822
|
}
|
|
813
823
|
|
|
814
824
|
public getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats {
|
|
825
|
+
const summaryBuilder = new SummaryTreeBuilder();
|
|
826
|
+
this.visitLocalBoundContextsDuringAttach(
|
|
827
|
+
(contextId: string, context: LocalChannelContextBase) => {
|
|
828
|
+
let summaryTree: ISummaryTreeWithStats;
|
|
829
|
+
if (context.isLoaded) {
|
|
830
|
+
const contextSummary = context.getAttachSummary(telemetryContext);
|
|
831
|
+
assert(
|
|
832
|
+
contextSummary.summary.type === SummaryType.Tree,
|
|
833
|
+
0x180 /* "getAttachSummary should always return a tree" */,
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
summaryTree = { stats: contextSummary.stats, summary: contextSummary.summary };
|
|
837
|
+
} else {
|
|
838
|
+
// If this channel is not yet loaded, then there should be no changes in the snapshot from which
|
|
839
|
+
// it was created as it is detached container. So just use the previous snapshot.
|
|
840
|
+
assert(
|
|
841
|
+
!!this.dataStoreContext.baseSnapshot,
|
|
842
|
+
0x181 /* "BaseSnapshot should be there as detached container loaded from snapshot" */,
|
|
843
|
+
);
|
|
844
|
+
summaryTree = convertSnapshotTreeToSummaryTree(
|
|
845
|
+
this.dataStoreContext.baseSnapshot.trees[contextId],
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
summaryBuilder.addWithStats(contextId, summaryTree);
|
|
849
|
+
},
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
return summaryBuilder.getSummaryTree();
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Get the GC Data for the initial state being attached so remote clients can learn of this DataStore's outbound routes
|
|
857
|
+
*/
|
|
858
|
+
public getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData {
|
|
859
|
+
const gcDataBuilder = new GCDataBuilder();
|
|
860
|
+
this.visitLocalBoundContextsDuringAttach(
|
|
861
|
+
(contextId: string, context: LocalChannelContextBase) => {
|
|
862
|
+
if (context.isLoaded) {
|
|
863
|
+
const contextGCData = context.getAttachGCData(telemetryContext);
|
|
864
|
+
|
|
865
|
+
// Incorporate the GC Data for this context
|
|
866
|
+
gcDataBuilder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
|
|
867
|
+
}
|
|
868
|
+
// else: Rehydrating detached container case. GC doesn't run until the container is attached, so nothing to do here.
|
|
869
|
+
},
|
|
870
|
+
);
|
|
871
|
+
this.updateGCNodes(gcDataBuilder);
|
|
872
|
+
|
|
873
|
+
return gcDataBuilder.getGCData();
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Helper method for preparing to attach this dataStore.
|
|
878
|
+
* Runs the callback for each bound context to incorporate its data however the caller specifies
|
|
879
|
+
*/
|
|
880
|
+
private visitLocalBoundContextsDuringAttach(
|
|
881
|
+
visitor: (contextId: string, context: LocalChannelContextBase) => void,
|
|
882
|
+
): void {
|
|
815
883
|
/**
|
|
816
884
|
* back-compat 0.59.1000 - getAttachSummary() is called when making a data store globally visible (previously
|
|
817
885
|
* attaching state). Ideally, attachGraph() should have already be called making it locally visible. However,
|
|
@@ -832,39 +900,15 @@ export class FluidDataStoreRuntime
|
|
|
832
900
|
// "The data store should be locally visible when generating attach summary",
|
|
833
901
|
// );
|
|
834
902
|
|
|
835
|
-
const summaryBuilder = new SummaryTreeBuilder();
|
|
836
|
-
|
|
837
|
-
// Craft the .attributes file for each shared object
|
|
838
903
|
for (const [contextId, context] of this.contexts) {
|
|
839
904
|
if (!(context instanceof LocalChannelContextBase)) {
|
|
840
905
|
throw new LoggingError("Should only be called with local channel handles");
|
|
841
906
|
}
|
|
842
907
|
|
|
843
908
|
if (!this.notBoundedChannelContextSet.has(contextId)) {
|
|
844
|
-
|
|
845
|
-
if (context.isLoaded) {
|
|
846
|
-
const contextSummary = context.getAttachSummary(telemetryContext);
|
|
847
|
-
assert(
|
|
848
|
-
contextSummary.summary.type === SummaryType.Tree,
|
|
849
|
-
0x180 /* "getAttachSummary should always return a tree" */,
|
|
850
|
-
);
|
|
851
|
-
summaryTree = { stats: contextSummary.stats, summary: contextSummary.summary };
|
|
852
|
-
} else {
|
|
853
|
-
// If this channel is not yet loaded, then there should be no changes in the snapshot from which
|
|
854
|
-
// it was created as it is detached container. So just use the previous snapshot.
|
|
855
|
-
assert(
|
|
856
|
-
!!this.dataStoreContext.baseSnapshot,
|
|
857
|
-
0x181 /* "BaseSnapshot should be there as detached container loaded from snapshot" */,
|
|
858
|
-
);
|
|
859
|
-
summaryTree = convertSnapshotTreeToSummaryTree(
|
|
860
|
-
this.dataStoreContext.baseSnapshot.trees[contextId],
|
|
861
|
-
);
|
|
862
|
-
}
|
|
863
|
-
summaryBuilder.addWithStats(contextId, summaryTree);
|
|
909
|
+
visitor(contextId, context);
|
|
864
910
|
}
|
|
865
911
|
}
|
|
866
|
-
|
|
867
|
-
return summaryBuilder.getSummaryTree();
|
|
868
912
|
}
|
|
869
913
|
|
|
870
914
|
public submitMessage(type: DataStoreMessageType, content: any, localOpMetadata: unknown) {
|
|
@@ -890,9 +934,10 @@ export class FluidDataStoreRuntime
|
|
|
890
934
|
}
|
|
891
935
|
|
|
892
936
|
/**
|
|
893
|
-
*
|
|
937
|
+
* Assuming this DataStore is already attached, this will make the given channel locally visible
|
|
938
|
+
* by submitting its attach op.
|
|
894
939
|
*/
|
|
895
|
-
private
|
|
940
|
+
private makeChannelLocallyVisible(channel: IChannel): void {
|
|
896
941
|
this.verifyNotClosed();
|
|
897
942
|
// If this handle is already attached no need to attach again.
|
|
898
943
|
if (channel.handle.isAttached) {
|
|
@@ -912,6 +957,11 @@ export class FluidDataStoreRuntime
|
|
|
912
957
|
true /* fullTree */,
|
|
913
958
|
false /* trackState */,
|
|
914
959
|
);
|
|
960
|
+
|
|
961
|
+
// We need to include the channel's GC Data so remote clients can learn of this channel's outbound routes
|
|
962
|
+
const gcData = channel.getGCData(/* fullGC: */ true);
|
|
963
|
+
addBlobToSummary(summarizeResult, gcDataBlobKey, JSON.stringify(gcData));
|
|
964
|
+
|
|
915
965
|
// Attach message needs the summary in ITree format. Convert the ISummaryTree into an ITree.
|
|
916
966
|
const snapshot = convertSummaryTreeToITree(summarizeResult.summary);
|
|
917
967
|
|
|
@@ -125,6 +125,11 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
125
125
|
return summarizeChannelAsync(channel, fullTree, trackState, telemetryContext);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* For crafting the DataStore attach op. Only to be called when the channel is loaded (if applicable).
|
|
130
|
+
*
|
|
131
|
+
* Synchronously generates the channel's attach summary to be joined with the same from the DataStore's other channels
|
|
132
|
+
*/
|
|
128
133
|
public getAttachSummary(telemetryContext?: ITelemetryContext): ISummarizeResult {
|
|
129
134
|
assert(
|
|
130
135
|
this._channel !== undefined,
|
|
@@ -138,6 +143,19 @@ export abstract class LocalChannelContextBase implements IChannelContext {
|
|
|
138
143
|
);
|
|
139
144
|
}
|
|
140
145
|
|
|
146
|
+
/**
|
|
147
|
+
* For crafting the DataStore attach op. Only to be called when the channel is loaded (if applicable).
|
|
148
|
+
*
|
|
149
|
+
* Synchronously generates the channel's attach GC data (set of outbound routes in the initial state)
|
|
150
|
+
* to be joined with the same from the DataStore's other channels
|
|
151
|
+
*/
|
|
152
|
+
public getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData {
|
|
153
|
+
assert(this._channel !== undefined, "Local Channel should be loaded before being attached");
|
|
154
|
+
|
|
155
|
+
// We need the GC Data to detect references added in this attach op
|
|
156
|
+
return this._channel.getGCData(/* fullGC: */ true);
|
|
157
|
+
}
|
|
158
|
+
|
|
141
159
|
public makeVisible(): void {
|
|
142
160
|
if (this.globallyVisible) {
|
|
143
161
|
throw new Error("Channel is already globally visible");
|