@fluidframework/container-loader 2.0.0-dev-rc.2.0.0.245554 → 2.0.0-dev-rc.3.0.0.250606
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/dist/attachment.d.ts +5 -8
- package/dist/attachment.d.ts.map +1 -1
- package/dist/attachment.js +2 -2
- package/dist/attachment.js.map +1 -1
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +2 -2
- package/dist/audience.js.map +1 -1
- package/dist/catchUpMonitor.d.ts +1 -1
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/connectionManager.d.ts +3 -3
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +1 -1
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +3 -3
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +4 -43
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +24 -37
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +17 -7
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +7 -2
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +2 -2
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.d.ts.map +1 -1
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts +5 -5
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +3 -3
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +1 -1
- package/dist/deltaQueue.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/loader.d.ts +3 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +4 -4
- package/dist/loader.js.map +1 -1
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +1 -1
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
- package/dist/noopHeuristic.d.ts +1 -1
- package/dist/noopHeuristic.d.ts.map +1 -1
- package/dist/noopHeuristic.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/quorum.d.ts +1 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +4 -0
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +1 -1
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +1 -1
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/serializedStateManager.d.ts +57 -18
- package/dist/serializedStateManager.d.ts.map +1 -1
- package/dist/serializedStateManager.js +71 -80
- package/dist/serializedStateManager.js.map +1 -1
- package/dist/utils.d.ts +5 -6
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +27 -11
- package/dist/utils.js.map +1 -1
- package/lib/attachment.d.ts +5 -8
- package/lib/attachment.d.ts.map +1 -1
- package/lib/attachment.js.map +1 -1
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js.map +1 -1
- package/lib/catchUpMonitor.d.ts +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/connectionManager.d.ts +3 -3
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +3 -3
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +3 -3
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +4 -43
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +27 -40
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +17 -7
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +7 -2
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +2 -2
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +3 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.d.ts.map +1 -1
- package/lib/debugLogger.js.map +1 -1
- package/lib/deltaManager.d.ts +5 -5
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +3 -3
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +1 -1
- package/lib/deltaQueue.js.map +1 -1
- package/lib/error.d.ts.map +1 -1
- package/lib/error.js.map +1 -1
- package/lib/loader.d.ts +3 -3
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +4 -4
- package/lib/loader.js.map +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
- package/lib/noopHeuristic.d.ts +1 -1
- package/lib/noopHeuristic.d.ts.map +1 -1
- package/lib/noopHeuristic.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/quorum.d.ts +1 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +4 -0
- package/lib/quorum.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +1 -1
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +1 -1
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/serializedStateManager.d.ts +57 -18
- package/lib/serializedStateManager.d.ts.map +1 -1
- package/lib/serializedStateManager.js +68 -79
- package/lib/serializedStateManager.js.map +1 -1
- package/lib/test/attachment.spec.js +2 -2
- package/lib/test/attachment.spec.js.map +1 -1
- package/lib/test/catchUpMonitor.spec.js.map +1 -1
- package/lib/test/connectionStateHandler.spec.js +1 -1
- package/lib/test/connectionStateHandler.spec.js.map +1 -1
- package/lib/test/container.spec.js +1 -1
- package/lib/test/container.spec.js.map +1 -1
- package/lib/test/deltaManager.spec.js +2 -2
- package/lib/test/deltaManager.spec.js.map +1 -1
- package/lib/test/loader.spec.js +4 -4
- package/lib/test/loader.spec.js.map +1 -1
- package/lib/test/serializedStateManager.spec.js +10 -7
- package/lib/test/serializedStateManager.spec.js.map +1 -1
- package/lib/test/snapshotConversionTest.spec.js +12 -12
- package/lib/test/snapshotConversionTest.spec.js.map +1 -1
- package/lib/test/utils.spec.js +66 -1
- package/lib/test/utils.spec.js.map +1 -1
- package/lib/utils.d.ts +5 -6
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +26 -11
- package/lib/utils.js.map +1 -1
- package/package.json +18 -15
- package/src/attachment.ts +7 -6
- package/src/audience.ts +2 -1
- package/src/catchUpMonitor.ts +1 -1
- package/src/connectionManager.ts +15 -15
- package/src/connectionStateHandler.ts +4 -4
- package/src/container.ts +68 -125
- package/src/containerContext.ts +16 -9
- package/src/containerStorageAdapter.ts +3 -3
- package/src/contracts.ts +4 -4
- package/src/debugLogger.ts +1 -1
- package/src/deltaManager.ts +24 -24
- package/src/deltaQueue.ts +1 -1
- package/src/error.ts +1 -1
- package/src/loader.ts +22 -21
- package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +1 -1
- package/src/noopHeuristic.ts +2 -2
- package/src/packageVersion.ts +1 -1
- package/src/quorum.ts +2 -1
- package/src/retriableDocumentStorageService.ts +2 -2
- package/src/serializedStateManager.ts +133 -116
- package/src/utils.ts +47 -18
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
6
7
|
import { assert } from "@fluidframework/core-utils";
|
|
7
8
|
import {
|
|
8
9
|
FetchSource,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
ISnapshotFetchOptions,
|
|
13
14
|
ISummaryContext,
|
|
14
15
|
} from "@fluidframework/driver-definitions";
|
|
16
|
+
import { runWithRetry } from "@fluidframework/driver-utils";
|
|
15
17
|
import {
|
|
16
18
|
ICreateBlobResponse,
|
|
17
19
|
ISnapshotTree,
|
|
@@ -19,9 +21,7 @@ import {
|
|
|
19
21
|
ISummaryTree,
|
|
20
22
|
IVersion,
|
|
21
23
|
} from "@fluidframework/protocol-definitions";
|
|
22
|
-
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
23
24
|
import { GenericError, ITelemetryLoggerExt, UsageError } from "@fluidframework/telemetry-utils";
|
|
24
|
-
import { runWithRetry } from "@fluidframework/driver-utils";
|
|
25
25
|
|
|
26
26
|
export class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
|
|
27
27
|
private _disposed = false;
|
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { IGetPendingLocalStateProps, IRuntime } from "@fluidframework/container-definitions";
|
|
7
|
+
import { assert } from "@fluidframework/core-utils";
|
|
8
|
+
import {
|
|
9
|
+
IDocumentStorageService,
|
|
10
|
+
IResolvedUrl,
|
|
11
|
+
ISnapshot,
|
|
12
|
+
} from "@fluidframework/driver-definitions";
|
|
13
|
+
import { isInstanceOfISnapshot } from "@fluidframework/driver-utils";
|
|
6
14
|
import {
|
|
7
15
|
ISequencedDocumentMessage,
|
|
8
16
|
ISnapshotTree,
|
|
9
17
|
IVersion,
|
|
10
18
|
} from "@fluidframework/protocol-definitions";
|
|
11
|
-
import { IGetPendingLocalStateProps, IRuntime } from "@fluidframework/container-definitions";
|
|
12
19
|
import {
|
|
13
20
|
ITelemetryLoggerExt,
|
|
14
21
|
MonitoringContext,
|
|
@@ -16,24 +23,51 @@ import {
|
|
|
16
23
|
UsageError,
|
|
17
24
|
createChildMonitoringContext,
|
|
18
25
|
} from "@fluidframework/telemetry-utils";
|
|
19
|
-
import { assert } from "@fluidframework/core-utils";
|
|
20
|
-
import {
|
|
21
|
-
IDocumentStorageService,
|
|
22
|
-
IResolvedUrl,
|
|
23
|
-
ISnapshot,
|
|
24
|
-
} from "@fluidframework/driver-definitions";
|
|
25
|
-
import { isInstanceOfISnapshot } from "@fluidframework/driver-utils";
|
|
26
26
|
import { ISerializableBlobContents, getBlobContentsFromTree } from "./containerStorageAdapter.js";
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
export interface SnapshotWithBlobs {
|
|
29
|
+
/**
|
|
30
|
+
* Snapshot from which container initially loaded.
|
|
31
|
+
*/
|
|
32
|
+
baseSnapshot: ISnapshotTree;
|
|
33
|
+
/**
|
|
34
|
+
* Serializable blobs from the base snapshot. Used to load offline since
|
|
35
|
+
* storage is not available.
|
|
36
|
+
*/
|
|
37
|
+
snapshotBlobs: ISerializableBlobContents;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* State saved by a container at close time, to be used to load a new instance
|
|
41
|
+
* of the container to the same state
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export interface IPendingContainerState extends SnapshotWithBlobs {
|
|
45
|
+
attached: true;
|
|
46
|
+
pendingRuntimeState: unknown;
|
|
47
|
+
/**
|
|
48
|
+
* All ops since base snapshot sequence number up to the latest op
|
|
49
|
+
* seen when the container was closed. Used to apply stashed (saved pending)
|
|
50
|
+
* ops at the same sequence number at which they were made.
|
|
51
|
+
*/
|
|
52
|
+
savedOps: ISequencedDocumentMessage[];
|
|
53
|
+
url: string;
|
|
54
|
+
clientId?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* State saved by a container in detached state, to be used to load a new instance
|
|
59
|
+
* of the container to the same state (rehydrate)
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export interface IPendingDetachedContainerState extends SnapshotWithBlobs {
|
|
63
|
+
attached: false;
|
|
64
|
+
hasAttachmentBlobs: boolean;
|
|
65
|
+
pendingRuntimeState?: unknown;
|
|
66
|
+
}
|
|
28
67
|
|
|
29
68
|
export class SerializedStateManager {
|
|
30
69
|
private readonly processedOps: ISequencedDocumentMessage[] = [];
|
|
31
|
-
private snapshot:
|
|
32
|
-
| {
|
|
33
|
-
tree: ISnapshotTree;
|
|
34
|
-
blobs: ISerializableBlobContents;
|
|
35
|
-
}
|
|
36
|
-
| undefined;
|
|
70
|
+
private snapshot: SnapshotWithBlobs | undefined;
|
|
37
71
|
private readonly mc: MonitoringContext;
|
|
38
72
|
|
|
39
73
|
constructor(
|
|
@@ -61,104 +95,32 @@ export class SerializedStateManager {
|
|
|
61
95
|
}
|
|
62
96
|
}
|
|
63
97
|
|
|
64
|
-
private async getVersion(version: string | null): Promise<IVersion | undefined> {
|
|
65
|
-
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
66
|
-
return versions[0];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
98
|
public async fetchSnapshot(
|
|
70
99
|
specifiedVersion: string | undefined,
|
|
71
|
-
supportGetSnapshotApi: boolean
|
|
100
|
+
supportGetSnapshotApi: boolean,
|
|
72
101
|
) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
? await this.
|
|
76
|
-
:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.snapshot = {
|
|
82
|
-
tree: this.pendingLocalState.baseSnapshot,
|
|
83
|
-
blobs: this.pendingLocalState.snapshotBlobs,
|
|
84
|
-
};
|
|
85
|
-
} else {
|
|
86
|
-
assert(snapshotTree !== undefined, 0x8e4 /* Snapshot should exist */);
|
|
102
|
+
if (this.pendingLocalState === undefined) {
|
|
103
|
+
const { snapshot, version } = supportGetSnapshotApi
|
|
104
|
+
? await fetchISnapshot(this.mc, this.storageAdapter, specifiedVersion)
|
|
105
|
+
: await fetchISnapshotTree(this.mc, this.storageAdapter, specifiedVersion);
|
|
106
|
+
const baseSnapshot: ISnapshotTree | undefined = isInstanceOfISnapshot(snapshot)
|
|
107
|
+
? snapshot.snapshotTree
|
|
108
|
+
: snapshot;
|
|
109
|
+
assert(baseSnapshot !== undefined, 0x8e4 /* Snapshot should exist */);
|
|
87
110
|
// non-interactive clients will not have any pending state we want to save
|
|
88
111
|
if (this.offlineLoadEnabled) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private async fetchSnapshotCore(
|
|
97
|
-
specifiedVersion: string | undefined,
|
|
98
|
-
supportGetSnapshotApi: boolean | undefined,
|
|
99
|
-
): Promise<{ snapshot?: ISnapshot | ISnapshotTree; version?: IVersion }> {
|
|
100
|
-
if (
|
|
101
|
-
this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch") ===
|
|
102
|
-
true &&
|
|
103
|
-
supportGetSnapshotApi === true
|
|
104
|
-
) {
|
|
105
|
-
const snapshot =
|
|
106
|
-
(await this.storageAdapter.getSnapshot?.({
|
|
107
|
-
versionId: specifiedVersion,
|
|
108
|
-
})) ?? undefined;
|
|
109
|
-
const version: IVersion | undefined =
|
|
110
|
-
snapshot?.snapshotTree.id === undefined
|
|
111
|
-
? undefined
|
|
112
|
-
: {
|
|
113
|
-
id: snapshot.snapshotTree.id,
|
|
114
|
-
treeId: snapshot.snapshotTree.id,
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
if (snapshot === undefined && specifiedVersion !== undefined) {
|
|
118
|
-
this.mc.logger.sendErrorEvent({
|
|
119
|
-
eventName: "getSnapshotTreeFailed",
|
|
120
|
-
id: specifiedVersion,
|
|
121
|
-
});
|
|
122
|
-
// Not sure if this should be here actually
|
|
123
|
-
} else if (snapshot !== undefined && version?.id === undefined) {
|
|
124
|
-
this.mc.logger.sendErrorEvent({
|
|
125
|
-
eventName: "getSnapshotFetchedTreeWithoutVersionId",
|
|
126
|
-
hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
|
|
127
|
-
});
|
|
112
|
+
const snapshotBlobs = await getBlobContentsFromTree(
|
|
113
|
+
baseSnapshot,
|
|
114
|
+
this.storageAdapter,
|
|
115
|
+
);
|
|
116
|
+
this.snapshot = { baseSnapshot, snapshotBlobs };
|
|
128
117
|
}
|
|
129
|
-
return {
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Get the most recent snapshot, or a specific version.
|
|
136
|
-
* @param specifiedVersion - The specific version of the snapshot to retrieve
|
|
137
|
-
* @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
|
|
138
|
-
*/
|
|
139
|
-
private async fetchSnapshotTree(
|
|
140
|
-
specifiedVersion: string | undefined,
|
|
141
|
-
): Promise<{ snapshot?: ISnapshotTree; version?: IVersion | undefined }> {
|
|
142
|
-
const version = await this.getVersion(specifiedVersion ?? null);
|
|
143
|
-
|
|
144
|
-
if (version === undefined && specifiedVersion !== undefined) {
|
|
145
|
-
// We should have a defined version to load from if specified version requested
|
|
146
|
-
this.mc.logger.sendErrorEvent({
|
|
147
|
-
eventName: "NoVersionFoundWhenSpecified",
|
|
148
|
-
id: specifiedVersion,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
|
|
152
|
-
|
|
153
|
-
if (snapshot === undefined && version !== undefined) {
|
|
154
|
-
this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
|
|
155
|
-
} else if (snapshot !== undefined && version?.id === undefined) {
|
|
156
|
-
this.mc.logger.sendErrorEvent({
|
|
157
|
-
eventName: "getSnapshotFetchedTreeWithoutVersionId",
|
|
158
|
-
hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
|
|
159
|
-
});
|
|
118
|
+
return { baseSnapshot, version };
|
|
119
|
+
} else {
|
|
120
|
+
const { baseSnapshot, snapshotBlobs } = this.pendingLocalState;
|
|
121
|
+
this.snapshot = { baseSnapshot, snapshotBlobs };
|
|
122
|
+
return { baseSnapshot, version: undefined };
|
|
160
123
|
}
|
|
161
|
-
return { snapshot, version };
|
|
162
124
|
}
|
|
163
125
|
|
|
164
126
|
/**
|
|
@@ -166,14 +128,7 @@ export class SerializedStateManager {
|
|
|
166
128
|
* base snapshot when attaching.
|
|
167
129
|
* @param snapshot - snapshot and blobs collected while attaching
|
|
168
130
|
*/
|
|
169
|
-
public setSnapshot(
|
|
170
|
-
snapshot:
|
|
171
|
-
| {
|
|
172
|
-
tree: ISnapshotTree;
|
|
173
|
-
blobs: ISerializableBlobContents;
|
|
174
|
-
}
|
|
175
|
-
| undefined,
|
|
176
|
-
) {
|
|
131
|
+
public setSnapshot(snapshot: SnapshotWithBlobs | undefined) {
|
|
177
132
|
this.snapshot = snapshot;
|
|
178
133
|
}
|
|
179
134
|
|
|
@@ -202,8 +157,8 @@ export class SerializedStateManager {
|
|
|
202
157
|
const pendingState: IPendingContainerState = {
|
|
203
158
|
attached: true,
|
|
204
159
|
pendingRuntimeState,
|
|
205
|
-
baseSnapshot: this.snapshot.
|
|
206
|
-
snapshotBlobs: this.snapshot.
|
|
160
|
+
baseSnapshot: this.snapshot.baseSnapshot,
|
|
161
|
+
snapshotBlobs: this.snapshot.snapshotBlobs,
|
|
207
162
|
savedOps: this.processedOps,
|
|
208
163
|
url: resolvedUrl.url,
|
|
209
164
|
// no need to save this if there is no pending runtime state
|
|
@@ -215,3 +170,65 @@ export class SerializedStateManager {
|
|
|
215
170
|
);
|
|
216
171
|
}
|
|
217
172
|
}
|
|
173
|
+
|
|
174
|
+
export async function fetchISnapshot(
|
|
175
|
+
mc: MonitoringContext,
|
|
176
|
+
storageAdapter: Pick<IDocumentStorageService, "getSnapshot">,
|
|
177
|
+
specifiedVersion: string | undefined,
|
|
178
|
+
): Promise<{ snapshot?: ISnapshot | ISnapshotTree; version?: IVersion }> {
|
|
179
|
+
const snapshot = await storageAdapter.getSnapshot?.({ versionId: specifiedVersion });
|
|
180
|
+
const version: IVersion | undefined =
|
|
181
|
+
snapshot?.snapshotTree.id === undefined
|
|
182
|
+
? undefined
|
|
183
|
+
: {
|
|
184
|
+
id: snapshot.snapshotTree.id,
|
|
185
|
+
treeId: snapshot.snapshotTree.id,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
if (snapshot === undefined && specifiedVersion !== undefined) {
|
|
189
|
+
mc.logger.sendErrorEvent({
|
|
190
|
+
eventName: "getSnapshotTreeFailed",
|
|
191
|
+
id: specifiedVersion,
|
|
192
|
+
});
|
|
193
|
+
// Not sure if this should be here actually
|
|
194
|
+
} else if (snapshot !== undefined && version?.id === undefined) {
|
|
195
|
+
mc.logger.sendErrorEvent({
|
|
196
|
+
eventName: "getSnapshotFetchedTreeWithoutVersionId",
|
|
197
|
+
hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return { snapshot, version };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get the most recent snapshot, or a specific version.
|
|
205
|
+
* @param specifiedVersion - The specific version of the snapshot to retrieve
|
|
206
|
+
* @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
|
|
207
|
+
*/
|
|
208
|
+
export async function fetchISnapshotTree(
|
|
209
|
+
mc: MonitoringContext,
|
|
210
|
+
storageAdapter: Pick<IDocumentStorageService, "getSnapshotTree" | "getVersions">,
|
|
211
|
+
specifiedVersion: string | undefined,
|
|
212
|
+
): Promise<{ snapshot?: ISnapshotTree; version?: IVersion | undefined }> {
|
|
213
|
+
const versions = await storageAdapter.getVersions(specifiedVersion ?? null, 1);
|
|
214
|
+
const version = versions[0];
|
|
215
|
+
|
|
216
|
+
if (version === undefined && specifiedVersion !== undefined) {
|
|
217
|
+
// We should have a defined version to load from if specified version requested
|
|
218
|
+
mc.logger.sendErrorEvent({
|
|
219
|
+
eventName: "NoVersionFoundWhenSpecified",
|
|
220
|
+
id: specifiedVersion,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
const snapshot = (await storageAdapter.getSnapshotTree(version)) ?? undefined;
|
|
224
|
+
|
|
225
|
+
if (snapshot === undefined && version !== undefined) {
|
|
226
|
+
mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
|
|
227
|
+
} else if (snapshot !== undefined && version?.id === undefined) {
|
|
228
|
+
mc.logger.sendErrorEvent({
|
|
229
|
+
eventName: "getSnapshotFetchedTreeWithoutVersionId",
|
|
230
|
+
hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return { snapshot, version };
|
|
234
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -3,19 +3,28 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { v4 as uuid } from "uuid";
|
|
7
6
|
import { Uint8ArrayToString, stringToBuffer } from "@fluid-internal/client-utils";
|
|
8
7
|
import { assert, compareArrays, unreachableCase } from "@fluidframework/core-utils";
|
|
9
|
-
import {
|
|
10
|
-
import { LoggingError, UsageError } from "@fluidframework/telemetry-utils";
|
|
8
|
+
import { DriverErrorTypes, IDocumentStorageService } from "@fluidframework/driver-definitions";
|
|
11
9
|
import {
|
|
12
10
|
CombinedAppAndProtocolSummary,
|
|
13
11
|
DeltaStreamConnectionForbiddenError,
|
|
14
12
|
isCombinedAppAndProtocolSummary,
|
|
13
|
+
readAndParse,
|
|
15
14
|
} from "@fluidframework/driver-utils";
|
|
16
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
IDocumentAttributes,
|
|
17
|
+
ISnapshotTree,
|
|
18
|
+
ISummaryTree,
|
|
19
|
+
SummaryType,
|
|
20
|
+
} from "@fluidframework/protocol-definitions";
|
|
21
|
+
import { LoggingError, UsageError } from "@fluidframework/telemetry-utils";
|
|
22
|
+
import { v4 as uuid } from "uuid";
|
|
17
23
|
import { ISerializableBlobContents } from "./containerStorageAdapter.js";
|
|
18
|
-
import {
|
|
24
|
+
import type {
|
|
25
|
+
IPendingDetachedContainerState,
|
|
26
|
+
SnapshotWithBlobs,
|
|
27
|
+
} from "./serializedStateManager.js";
|
|
19
28
|
|
|
20
29
|
// This is used when we rehydrate a container from the snapshot. Here we put the blob contents
|
|
21
30
|
// in separate property: blobContents.
|
|
@@ -111,10 +120,7 @@ export function combineAppAndProtocolSummary(
|
|
|
111
120
|
* to align detached container format with IPendingContainerState
|
|
112
121
|
* @param summary - ISummaryTree
|
|
113
122
|
*/
|
|
114
|
-
function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
|
|
115
|
-
tree: ISnapshotTree;
|
|
116
|
-
blobs: ISerializableBlobContents;
|
|
117
|
-
} {
|
|
123
|
+
function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): SnapshotWithBlobs {
|
|
118
124
|
let blobContents: ISerializableBlobContents = {};
|
|
119
125
|
const treeNode: ISnapshotTree = {
|
|
120
126
|
blobs: {},
|
|
@@ -129,9 +135,9 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
|
|
|
129
135
|
|
|
130
136
|
switch (summaryObject.type) {
|
|
131
137
|
case SummaryType.Tree: {
|
|
132
|
-
const
|
|
133
|
-
treeNode.trees[key] =
|
|
134
|
-
blobContents = { ...blobContents, ...
|
|
138
|
+
const innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);
|
|
139
|
+
treeNode.trees[key] = innerSnapshot.baseSnapshot;
|
|
140
|
+
blobContents = { ...blobContents, ...innerSnapshot.snapshotBlobs };
|
|
135
141
|
break;
|
|
136
142
|
}
|
|
137
143
|
case SummaryType.Attachment:
|
|
@@ -157,7 +163,8 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
|
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
}
|
|
160
|
-
|
|
166
|
+
const pendingSnapshot = { baseSnapshot: treeNode, snapshotBlobs: blobContents };
|
|
167
|
+
return pendingSnapshot;
|
|
161
168
|
}
|
|
162
169
|
|
|
163
170
|
/**
|
|
@@ -168,7 +175,7 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
|
|
|
168
175
|
function convertProtocolAndAppSummaryToSnapshotAndBlobs(
|
|
169
176
|
protocolSummaryTree: ISummaryTree,
|
|
170
177
|
appSummaryTree: ISummaryTree,
|
|
171
|
-
):
|
|
178
|
+
): SnapshotWithBlobs {
|
|
172
179
|
const combinedSummary: ISummaryTree = {
|
|
173
180
|
type: SummaryType.Tree,
|
|
174
181
|
tree: { ...appSummaryTree.tree },
|
|
@@ -181,7 +188,7 @@ function convertProtocolAndAppSummaryToSnapshotAndBlobs(
|
|
|
181
188
|
|
|
182
189
|
export const getSnapshotTreeAndBlobsFromSerializedContainer = (
|
|
183
190
|
detachedContainerSnapshot: ISummaryTree,
|
|
184
|
-
):
|
|
191
|
+
): SnapshotWithBlobs => {
|
|
185
192
|
assert(
|
|
186
193
|
isCombinedAppAndProtocolSummary(detachedContainerSnapshot),
|
|
187
194
|
0x8e6 /* Protocol and App summary trees should be present */,
|
|
@@ -264,12 +271,12 @@ export function getDetachedContainerStateFromSerializedContainer(
|
|
|
264
271
|
if (isPendingDetachedContainerState(parsedContainerState)) {
|
|
265
272
|
return parsedContainerState;
|
|
266
273
|
} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {
|
|
267
|
-
const {
|
|
274
|
+
const { baseSnapshot, snapshotBlobs } =
|
|
268
275
|
getSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);
|
|
269
276
|
const detachedContainerState: IPendingDetachedContainerState = {
|
|
270
277
|
attached: false,
|
|
271
|
-
baseSnapshot
|
|
272
|
-
snapshotBlobs
|
|
278
|
+
baseSnapshot,
|
|
279
|
+
snapshotBlobs,
|
|
273
280
|
hasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,
|
|
274
281
|
};
|
|
275
282
|
return detachedContainerState;
|
|
@@ -305,3 +312,25 @@ export const runSingle = <A extends any[], R>(func: (...args: A) => Promise<R>)
|
|
|
305
312
|
return running.result;
|
|
306
313
|
};
|
|
307
314
|
};
|
|
315
|
+
|
|
316
|
+
export async function getDocumentAttributes(
|
|
317
|
+
storage: Pick<IDocumentStorageService, "readBlob">,
|
|
318
|
+
tree: ISnapshotTree | undefined,
|
|
319
|
+
): Promise<IDocumentAttributes> {
|
|
320
|
+
if (tree === undefined) {
|
|
321
|
+
return {
|
|
322
|
+
minimumSequenceNumber: 0,
|
|
323
|
+
sequenceNumber: 0,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Backward compatibility: old docs would have ".attributes" instead of "attributes"
|
|
328
|
+
const attributesHash =
|
|
329
|
+
".protocol" in tree.trees
|
|
330
|
+
? tree.trees[".protocol"].blobs.attributes
|
|
331
|
+
: tree.blobs[".attributes"];
|
|
332
|
+
|
|
333
|
+
const attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);
|
|
334
|
+
|
|
335
|
+
return attributes;
|
|
336
|
+
}
|