@fluidframework/routerlicious-driver 0.51.0 → 0.52.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/dist/createNewUtils.js +4 -3
- package/dist/createNewUtils.js.map +1 -1
- package/dist/documentStorageService.d.ts.map +1 -1
- package/dist/documentStorageService.js +4 -261
- package/dist/documentStorageService.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/shreddedSummaryDocumentStorageService.d.ts +36 -0
- package/dist/shreddedSummaryDocumentStorageService.d.ts.map +1 -0
- package/dist/shreddedSummaryDocumentStorageService.js +143 -0
- package/dist/shreddedSummaryDocumentStorageService.js.map +1 -0
- package/dist/wholeSummaryDocumentStorageService.d.ts +31 -0
- package/dist/wholeSummaryDocumentStorageService.d.ts.map +1 -0
- package/dist/wholeSummaryDocumentStorageService.js +157 -0
- package/dist/wholeSummaryDocumentStorageService.js.map +1 -0
- package/lib/createNewUtils.js +4 -3
- package/lib/createNewUtils.js.map +1 -1
- package/lib/documentStorageService.d.ts.map +1 -1
- package/lib/documentStorageService.js +3 -260
- package/lib/documentStorageService.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/shreddedSummaryDocumentStorageService.d.ts +36 -0
- package/lib/shreddedSummaryDocumentStorageService.d.ts.map +1 -0
- package/lib/shreddedSummaryDocumentStorageService.js +139 -0
- package/lib/shreddedSummaryDocumentStorageService.js.map +1 -0
- package/lib/wholeSummaryDocumentStorageService.d.ts +31 -0
- package/lib/wholeSummaryDocumentStorageService.d.ts.map +1 -0
- package/lib/wholeSummaryDocumentStorageService.js +153 -0
- package/lib/wholeSummaryDocumentStorageService.js.map +1 -0
- package/package.json +11 -11
- package/src/documentStorageService.ts +20 -374
- package/src/packageVersion.ts +1 -1
- package/src/shreddedSummaryDocumentStorageService.ts +213 -0
- package/src/wholeSummaryDocumentStorageService.ts +231 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shreddedSummaryDocumentStorageService.js","sourceRoot":"","sources":["../src/shreddedSummaryDocumentStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n stringToBuffer,\n Uint8ArrayToString,\n} from \"@fluidframework/common-utils\";\nimport {\n IDocumentStorageService,\n ISummaryContext,\n IDocumentStorageServicePolicies,\n } from \"@fluidframework/driver-definitions\";\nimport { buildHierarchy } from \"@fluidframework/protocol-base\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISnapshotTreeEx,\n ISummaryHandle,\n ISummaryTree,\n ITree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n GitManager,\n ISummaryUploadManager,\n SummaryTreeUploadManager,\n} from \"@fluidframework/server-services-client\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { IRouterliciousDriverPolicies } from \"./policies\";\nimport { ICache, InMemoryCache } from \"./cache\";\nimport { RetriableGitManager } from \"./retriableGitManager\";\n\n// eslint-disable-next-line no-new-func,@typescript-eslint/no-implied-eval\nconst isNode = (new Function(\"try {return this===global;}catch(e){ return false;}\"))();\n\n/**\n * Document access to underlying storage for routerlicious driver.\n * Uploads summaries piece-by-piece traversing the tree recursively.\n * Downloads summaries piece-by-piece on-demand, or up-front when prefetch is enabled.\n */\nexport class ShreddedSummaryDocumentStorageService implements IDocumentStorageService {\n // The values of this cache is useless. We only need the keys. So we are always putting\n // empty strings as values.\n protected readonly blobsShaCache = new Map<string, string>();\n private readonly blobCache: ICache<ArrayBufferLike> | undefined;\n private readonly snapshotTreeCache: ICache<ISnapshotTreeEx> | undefined;\n private readonly summaryUploadManager: ISummaryUploadManager;\n\n public get repositoryUrl(): string {\n return \"\";\n }\n\n constructor(\n protected readonly id: string,\n protected readonly manager: GitManager,\n protected readonly logger: ITelemetryLogger,\n public readonly policies: IDocumentStorageServicePolicies = {},\n driverPolicies?: IRouterliciousDriverPolicies,\n blobCache?: ICache<ArrayBufferLike>,\n snapshotTreeCache?: ICache<ISnapshotTree>) {\n this.summaryUploadManager = new SummaryTreeUploadManager(\n new RetriableGitManager(manager, logger),\n this.blobsShaCache,\n this.getPreviousFullSnapshot.bind(this),\n );\n if (driverPolicies?.enableRestLess === true || isNode) {\n this.blobCache = blobCache ?? new InMemoryCache();\n this.snapshotTreeCache = (snapshotTreeCache ?? new InMemoryCache()) as ICache<ISnapshotTreeEx>;\n }\n }\n\n public async getVersions(versionId: string, count: number): Promise<IVersion[]> {\n const id = versionId ? versionId : this.id;\n const commits = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"getVersions\",\n versionId: id,\n count,\n },\n async () => this.manager.getCommits(id, count),\n );\n return commits.map((commit) => ({\n date: commit.commit.author.date,\n id: commit.sha,\n treeId: commit.commit.tree.sha,\n }));\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTreeEx | null> {\n let requestVersion = version;\n if (!requestVersion) {\n const versions = await this.getVersions(this.id, 1);\n if (versions.length === 0) {\n return null;\n }\n\n requestVersion = versions[0];\n }\n\n const cachedSnapshotTree = await this.snapshotTreeCache?.get(requestVersion.treeId);\n if (cachedSnapshotTree) {\n return cachedSnapshotTree;\n }\n\n const rawTree = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"getSnapshotTree\",\n treeId: requestVersion.treeId,\n },\n async (event) => {\n const response = await this.manager.getTree(requestVersion!.treeId);\n event.end({\n size: response.tree.length,\n });\n return response;\n },\n );\n const tree = buildHierarchy(rawTree, this.blobsShaCache, true);\n await this.snapshotTreeCache?.put(tree.id, tree);\n return tree;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n const cachedBlob = await this.blobCache?.get(blobId);\n if (cachedBlob) {\n return cachedBlob;\n }\n\n const value = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"readBlob\",\n blobId,\n },\n async (event) => {\n const response = await this.manager.getBlob(blobId);\n event.end({\n size: response.size,\n });\n return response;\n },\n );\n this.blobsShaCache.set(value.sha, \"\");\n const bufferContent = stringToBuffer(value.content, value.encoding);\n await this.blobCache?.put(value.sha, bufferContent);\n return bufferContent;\n }\n\n public async write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion> {\n const branch = ref ? `datastores/${this.id}/${ref}` : this.id;\n const commit = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"write\",\n id: branch,\n },\n async () => this.manager.write(branch, tree, parents, message),\n );\n return { date: commit.committer.date, id: commit.sha, treeId: commit.tree.sha };\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n const summaryHandle = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"uploadSummaryWithContext\",\n },\n async () => this.summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? \"\", \"channel\"),\n );\n return summaryHandle;\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n throw new Error(\"NOT IMPLEMENTED!\");\n }\n\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n const uint8ArrayFile = new Uint8Array(file);\n return PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"createBlob\",\n size: uint8ArrayFile.length,\n },\n async (event) => {\n const response = await this.manager.createBlob(\n Uint8ArrayToString(\n uint8ArrayFile, \"base64\"),\n \"base64\").then((r) => ({ id: r.sha, url: r.url }));\n event.end({\n blobId: response.id,\n });\n return response;\n },\n );\n }\n\n private async getPreviousFullSnapshot(parentHandle: string): Promise<ISnapshotTreeEx | null | undefined> {\n return parentHandle\n ? this.getVersions(parentHandle, 1)\n .then(async (versions) => {\n // Clear the cache as the getSnapshotTree call will fill the cache.\n this.blobsShaCache.clear();\n return this.getSnapshotTree(versions[0]);\n })\n : undefined;\n }\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
|
+
import { IDocumentStorageService, ISummaryContext, IDocumentStorageServicePolicies } from "@fluidframework/driver-definitions";
|
|
7
|
+
import { ICreateBlobResponse, ISnapshotTree, ISummaryHandle, ISummaryTree, ITree, IVersion } from "@fluidframework/protocol-definitions";
|
|
8
|
+
import { GitManager } from "@fluidframework/server-services-client";
|
|
9
|
+
import { ICache } from "./cache";
|
|
10
|
+
export declare class WholeSummaryDocumentStorageService implements IDocumentStorageService {
|
|
11
|
+
protected readonly id: string;
|
|
12
|
+
protected readonly manager: GitManager;
|
|
13
|
+
protected readonly logger: ITelemetryLogger;
|
|
14
|
+
readonly policies: IDocumentStorageServicePolicies;
|
|
15
|
+
private readonly blobCache;
|
|
16
|
+
private readonly snapshotTreeCache;
|
|
17
|
+
private readonly summaryUploadManager;
|
|
18
|
+
private firstVersionsCall;
|
|
19
|
+
get repositoryUrl(): string;
|
|
20
|
+
constructor(id: string, manager: GitManager, logger: ITelemetryLogger, policies?: IDocumentStorageServicePolicies, blobCache?: ICache<ArrayBufferLike>, snapshotTreeCache?: ICache<ISnapshotTree>);
|
|
21
|
+
getVersions(versionId: string | null, count: number): Promise<IVersion[]>;
|
|
22
|
+
getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null>;
|
|
23
|
+
readBlob(blobId: string): Promise<ArrayBufferLike>;
|
|
24
|
+
uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string>;
|
|
25
|
+
downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree>;
|
|
26
|
+
write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion>;
|
|
27
|
+
createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse>;
|
|
28
|
+
private fetchAndCacheSnapshotTree;
|
|
29
|
+
private initBlobCache;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=wholeSummaryDocumentStorageService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wholeSummaryDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/wholeSummaryDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAM3E,OAAO,EACH,uBAAuB,EACvB,eAAe,EACf,+BAA+B,EACjC,MAAM,oCAAoC,CAAC;AAC7C,OAAO,EACH,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,KAAK,EACL,QAAQ,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAEH,UAAU,EAGb,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAiB,MAAM,SAAS,CAAC;AAIhD,qBAAa,kCAAmC,YAAW,uBAAuB;IAS1E,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM;IAC7B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU;IACtC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB;aAC3B,QAAQ,EAAE,+BAA+B;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAbtC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAwB;IAC7D,OAAO,CAAC,iBAAiB,CAAiB;IAE1C,IAAW,aAAa,IAAI,MAAM,CAEjC;gBAGsB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,+BAAoC,EAC7C,SAAS,GAAE,MAAM,CAAC,eAAe,CAAuB,EACxD,iBAAiB,GAAE,MAAM,CAAC,aAAa,CAAuB;IAItE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAoCzE,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAclE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA2BlD,wBAAwB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAW1F,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAI9D,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAItF,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAqB9D,yBAAyB;YAqDzB,aAAa;CAO9B"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.WholeSummaryDocumentStorageService = void 0;
|
|
8
|
+
const common_utils_1 = require("@fluidframework/common-utils");
|
|
9
|
+
const server_services_client_1 = require("@fluidframework/server-services-client");
|
|
10
|
+
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
11
|
+
const cache_1 = require("./cache");
|
|
12
|
+
const latestSnapshotId = "latest";
|
|
13
|
+
class WholeSummaryDocumentStorageService {
|
|
14
|
+
constructor(id, manager, logger, policies = {}, blobCache = new cache_1.InMemoryCache(), snapshotTreeCache = new cache_1.InMemoryCache()) {
|
|
15
|
+
this.id = id;
|
|
16
|
+
this.manager = manager;
|
|
17
|
+
this.logger = logger;
|
|
18
|
+
this.policies = policies;
|
|
19
|
+
this.blobCache = blobCache;
|
|
20
|
+
this.snapshotTreeCache = snapshotTreeCache;
|
|
21
|
+
this.firstVersionsCall = true;
|
|
22
|
+
this.summaryUploadManager = new server_services_client_1.WholeSummaryUploadManager(manager);
|
|
23
|
+
}
|
|
24
|
+
get repositoryUrl() {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
async getVersions(versionId, count) {
|
|
28
|
+
if (versionId !== this.id && versionId !== null) {
|
|
29
|
+
// Blobs in this scenario will never have multiple versions, so return blobId as is
|
|
30
|
+
return [{
|
|
31
|
+
id: versionId,
|
|
32
|
+
treeId: undefined,
|
|
33
|
+
}];
|
|
34
|
+
}
|
|
35
|
+
// If this is the first versions call for the document, we know we will want the latest summary.
|
|
36
|
+
// Fetch latest summary, cache it, and return its id.
|
|
37
|
+
if (this.firstVersionsCall && count === 1) {
|
|
38
|
+
this.firstVersionsCall = false;
|
|
39
|
+
return [{
|
|
40
|
+
id: (await this.fetchAndCacheSnapshotTree(latestSnapshotId)).id,
|
|
41
|
+
treeId: undefined,
|
|
42
|
+
}];
|
|
43
|
+
}
|
|
44
|
+
// Otherwise, get the latest version of the document as normal.
|
|
45
|
+
const id = versionId ? versionId : this.id;
|
|
46
|
+
const commits = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, {
|
|
47
|
+
eventName: "getVersions",
|
|
48
|
+
versionId: id,
|
|
49
|
+
count,
|
|
50
|
+
}, async () => this.manager.getCommits(id, count));
|
|
51
|
+
return commits.map((commit) => ({
|
|
52
|
+
date: commit.commit.author.date,
|
|
53
|
+
id: commit.sha,
|
|
54
|
+
treeId: undefined,
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
async getSnapshotTree(version) {
|
|
58
|
+
let requestVersion = version;
|
|
59
|
+
if (!requestVersion) {
|
|
60
|
+
const versions = await this.getVersions(this.id, 1);
|
|
61
|
+
if (versions.length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
requestVersion = versions[0];
|
|
65
|
+
}
|
|
66
|
+
return (await this.fetchAndCacheSnapshotTree(requestVersion.id)).snapshotTree;
|
|
67
|
+
}
|
|
68
|
+
async readBlob(blobId) {
|
|
69
|
+
const cachedBlob = await this.blobCache.get(blobId);
|
|
70
|
+
if (cachedBlob !== undefined) {
|
|
71
|
+
return cachedBlob;
|
|
72
|
+
}
|
|
73
|
+
const blob = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, {
|
|
74
|
+
eventName: "readBlob",
|
|
75
|
+
blobId,
|
|
76
|
+
}, async (event) => {
|
|
77
|
+
const response = await this.manager.getBlob(blobId);
|
|
78
|
+
event.end({
|
|
79
|
+
size: response.size,
|
|
80
|
+
});
|
|
81
|
+
return response;
|
|
82
|
+
});
|
|
83
|
+
const bufferValue = common_utils_1.stringToBuffer(blob.content, blob.encoding);
|
|
84
|
+
await this.blobCache.put(blob.sha, bufferValue);
|
|
85
|
+
return bufferValue;
|
|
86
|
+
}
|
|
87
|
+
async uploadSummaryWithContext(summary, context) {
|
|
88
|
+
const summaryHandle = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, {
|
|
89
|
+
eventName: "uploadSummaryWithContext",
|
|
90
|
+
}, async () => { var _a; return this.summaryUploadManager.writeSummaryTree(summary, (_a = context.ackHandle) !== null && _a !== void 0 ? _a : "", "channel"); });
|
|
91
|
+
return summaryHandle;
|
|
92
|
+
}
|
|
93
|
+
async downloadSummary(handle) {
|
|
94
|
+
throw new Error("NOT IMPLEMENTED!");
|
|
95
|
+
}
|
|
96
|
+
async write(tree, parents, message, ref) {
|
|
97
|
+
throw new Error("NOT IMPLEMENTED!");
|
|
98
|
+
}
|
|
99
|
+
async createBlob(file) {
|
|
100
|
+
const uint8ArrayFile = new Uint8Array(file);
|
|
101
|
+
return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, {
|
|
102
|
+
eventName: "createBlob",
|
|
103
|
+
size: uint8ArrayFile.length,
|
|
104
|
+
}, async (event) => {
|
|
105
|
+
const response = await this.manager.createBlob(common_utils_1.Uint8ArrayToString(uint8ArrayFile, "base64"), "base64").then((r) => ({ id: r.sha, url: r.url }));
|
|
106
|
+
event.end({
|
|
107
|
+
blobId: response.id,
|
|
108
|
+
});
|
|
109
|
+
return response;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async fetchAndCacheSnapshotTree(versionId) {
|
|
113
|
+
const cachedSnapshotTree = await this.snapshotTreeCache.get(versionId);
|
|
114
|
+
if (cachedSnapshotTree !== undefined) {
|
|
115
|
+
return { id: cachedSnapshotTree.id, snapshotTree: cachedSnapshotTree };
|
|
116
|
+
}
|
|
117
|
+
const wholeFlatSummary = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.logger, {
|
|
118
|
+
eventName: "getWholeFlatSummary",
|
|
119
|
+
treeId: versionId,
|
|
120
|
+
}, async (event) => {
|
|
121
|
+
var _a;
|
|
122
|
+
const response = await this.manager.getSummary(versionId);
|
|
123
|
+
event.end({
|
|
124
|
+
size: (_a = response.trees[0]) === null || _a === void 0 ? void 0 : _a.entries.length,
|
|
125
|
+
});
|
|
126
|
+
return response;
|
|
127
|
+
});
|
|
128
|
+
const normalizedWholeSummary = server_services_client_1.convertWholeFlatSummaryToSnapshotTreeAndBlobs(wholeFlatSummary);
|
|
129
|
+
const snapshotId = normalizedWholeSummary.snapshotTree.id;
|
|
130
|
+
common_utils_1.assert(snapshotId !== undefined, 0x275 /* "Root tree should contain the id" */);
|
|
131
|
+
const cachePs = [
|
|
132
|
+
this.snapshotTreeCache.put(snapshotId, normalizedWholeSummary.snapshotTree),
|
|
133
|
+
this.initBlobCache(normalizedWholeSummary.blobs),
|
|
134
|
+
];
|
|
135
|
+
if (snapshotId !== versionId) {
|
|
136
|
+
// versionId could be "latest". When summarizer checks cache for "latest", we want it to be available.
|
|
137
|
+
// TODO: For in-memory cache, <latest,snapshotTree> will be a shared pointer with <snapshotId,snapshotTree>,
|
|
138
|
+
// However, for something like Redis, this will cache the same value twice. Alternatively, could we simply
|
|
139
|
+
// cache with versionId?
|
|
140
|
+
cachePs.push(this.snapshotTreeCache.put(versionId, normalizedWholeSummary.snapshotTree));
|
|
141
|
+
}
|
|
142
|
+
await Promise.all([
|
|
143
|
+
this.snapshotTreeCache.put(snapshotId, normalizedWholeSummary.snapshotTree),
|
|
144
|
+
this.initBlobCache(normalizedWholeSummary.blobs),
|
|
145
|
+
]);
|
|
146
|
+
return { id: snapshotId, snapshotTree: normalizedWholeSummary.snapshotTree };
|
|
147
|
+
}
|
|
148
|
+
async initBlobCache(blobs) {
|
|
149
|
+
const blobCachePutPs = [];
|
|
150
|
+
blobs.forEach((value, id) => {
|
|
151
|
+
blobCachePutPs.push(this.blobCache.put(id, value));
|
|
152
|
+
});
|
|
153
|
+
await Promise.all(blobCachePutPs);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.WholeSummaryDocumentStorageService = WholeSummaryDocumentStorageService;
|
|
157
|
+
//# sourceMappingURL=wholeSummaryDocumentStorageService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wholeSummaryDocumentStorageService.js","sourceRoot":"","sources":["../src/wholeSummaryDocumentStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n assert,\n stringToBuffer,\n Uint8ArrayToString,\n} from \"@fluidframework/common-utils\";\nimport {\n IDocumentStorageService,\n ISummaryContext,\n IDocumentStorageServicePolicies,\n } from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n ITree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport {\n convertWholeFlatSummaryToSnapshotTreeAndBlobs,\n GitManager,\n ISummaryUploadManager,\n WholeSummaryUploadManager,\n} from \"@fluidframework/server-services-client\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { ICache, InMemoryCache } from \"./cache\";\n\nconst latestSnapshotId: string = \"latest\";\n\nexport class WholeSummaryDocumentStorageService implements IDocumentStorageService {\n private readonly summaryUploadManager: ISummaryUploadManager;\n private firstVersionsCall: boolean = true;\n\n public get repositoryUrl(): string {\n return \"\";\n }\n\n constructor(\n protected readonly id: string,\n protected readonly manager: GitManager,\n protected readonly logger: ITelemetryLogger,\n public readonly policies: IDocumentStorageServicePolicies = {},\n private readonly blobCache: ICache<ArrayBufferLike> = new InMemoryCache(),\n private readonly snapshotTreeCache: ICache<ISnapshotTree> = new InMemoryCache()) {\n this.summaryUploadManager = new WholeSummaryUploadManager(manager);\n }\n\n public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n if (versionId !== this.id && versionId !== null) {\n // Blobs in this scenario will never have multiple versions, so return blobId as is\n return [{\n id: versionId,\n treeId: undefined!,\n }];\n }\n // If this is the first versions call for the document, we know we will want the latest summary.\n // Fetch latest summary, cache it, and return its id.\n if (this.firstVersionsCall && count === 1) {\n this.firstVersionsCall = false;\n return [{\n id: (await this.fetchAndCacheSnapshotTree(latestSnapshotId)).id,\n treeId: undefined!,\n }];\n }\n\n // Otherwise, get the latest version of the document as normal.\n const id = versionId ? versionId : this.id;\n const commits = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"getVersions\",\n versionId: id,\n count,\n },\n async () => this.manager.getCommits(id, count),\n );\n return commits.map((commit) => ({\n date: commit.commit.author.date,\n id: commit.sha,\n treeId: undefined!,\n }));\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n let requestVersion = version;\n if (!requestVersion) {\n const versions = await this.getVersions(this.id, 1);\n if (versions.length === 0) {\n return null;\n }\n\n requestVersion = versions[0];\n }\n\n return (await this.fetchAndCacheSnapshotTree(requestVersion.id)).snapshotTree;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n const cachedBlob = await this.blobCache.get(blobId);\n if (cachedBlob !== undefined) {\n return cachedBlob;\n }\n\n const blob = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"readBlob\",\n blobId,\n },\n async (event) => {\n const response = await this.manager.getBlob(blobId);\n event.end({\n size: response.size,\n });\n return response;\n },\n );\n const bufferValue = stringToBuffer(blob.content, blob.encoding);\n\n await this.blobCache.put(blob.sha, bufferValue);\n\n return bufferValue;\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n const summaryHandle = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"uploadSummaryWithContext\",\n },\n async () => this.summaryUploadManager.writeSummaryTree(summary, context.ackHandle ?? \"\", \"channel\"),\n );\n return summaryHandle;\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n throw new Error(\"NOT IMPLEMENTED!\");\n }\n\n public async write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion> {\n throw new Error(\"NOT IMPLEMENTED!\");\n }\n\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n const uint8ArrayFile = new Uint8Array(file);\n return PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"createBlob\",\n size: uint8ArrayFile.length,\n },\n async (event) => {\n const response = await this.manager.createBlob(\n Uint8ArrayToString(\n uint8ArrayFile, \"base64\"),\n \"base64\").then((r) => ({ id: r.sha, url: r.url }));\n event.end({\n blobId: response.id,\n });\n return response;\n },\n );\n }\n\n private async fetchAndCacheSnapshotTree(versionId: string): Promise<{ id: string, snapshotTree: ISnapshotTree }> {\n const cachedSnapshotTree = await this.snapshotTreeCache.get(versionId);\n if (cachedSnapshotTree !== undefined) {\n return { id: cachedSnapshotTree.id!, snapshotTree: cachedSnapshotTree };\n }\n\n const wholeFlatSummary = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"getWholeFlatSummary\",\n treeId: versionId,\n },\n async (event) => {\n const response = await this.manager.getSummary(versionId);\n event.end({\n size: response.trees[0]?.entries.length,\n });\n return response;\n },\n );\n const normalizedWholeSummary = convertWholeFlatSummaryToSnapshotTreeAndBlobs(wholeFlatSummary);\n const snapshotId = normalizedWholeSummary.snapshotTree.id;\n assert(snapshotId !== undefined, 0x275 /* \"Root tree should contain the id\" */);\n\n const cachePs: Promise<any>[] = [\n this.snapshotTreeCache.put(\n snapshotId,\n normalizedWholeSummary.snapshotTree,\n ),\n this.initBlobCache(normalizedWholeSummary.blobs),\n ];\n if (snapshotId !== versionId) {\n // versionId could be \"latest\". When summarizer checks cache for \"latest\", we want it to be available.\n // TODO: For in-memory cache, <latest,snapshotTree> will be a shared pointer with <snapshotId,snapshotTree>,\n // However, for something like Redis, this will cache the same value twice. Alternatively, could we simply\n // cache with versionId?\n cachePs.push(this.snapshotTreeCache.put(\n versionId,\n normalizedWholeSummary.snapshotTree,\n ));\n }\n\n await Promise.all([\n this.snapshotTreeCache.put(\n snapshotId,\n normalizedWholeSummary.snapshotTree,\n ),\n this.initBlobCache(normalizedWholeSummary.blobs),\n ]);\n\n return { id: snapshotId, snapshotTree: normalizedWholeSummary.snapshotTree};\n }\n\n private async initBlobCache(blobs: Map<string, ArrayBuffer>): Promise<void> {\n const blobCachePutPs: Promise<void>[] = [];\n blobs.forEach((value, id) => {\n blobCachePutPs.push(this.blobCache.put(id, value));\n });\n await Promise.all(blobCachePutPs);\n }\n}\n"]}
|
package/lib/createNewUtils.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { Uint8ArrayToString } from "@fluidframework/common-utils";
|
|
6
|
+
import { SummaryType } from "@fluidframework/protocol-definitions";
|
|
6
7
|
/**
|
|
7
8
|
* Utility api to convert ISummaryTree to a summary tree where blob contents are only utf8 strings.
|
|
8
9
|
* @param summary - Summary supplied by the runtime to upload.
|
|
@@ -13,16 +14,16 @@ export function convertSummaryToCreateNewSummary(summary) {
|
|
|
13
14
|
for (const key of keys) {
|
|
14
15
|
const summaryObject = summary.tree[key];
|
|
15
16
|
switch (summaryObject.type) {
|
|
16
|
-
case
|
|
17
|
+
case SummaryType.Tree: {
|
|
17
18
|
summary.tree[key] = convertSummaryToCreateNewSummary(summaryObject);
|
|
18
19
|
break;
|
|
19
20
|
}
|
|
20
|
-
case
|
|
21
|
+
case SummaryType.Blob: {
|
|
21
22
|
summaryObject.content = typeof summaryObject.content === "string" ?
|
|
22
23
|
summaryObject.content : Uint8ArrayToString(summaryObject.content, "utf8");
|
|
23
24
|
break;
|
|
24
25
|
}
|
|
25
|
-
case
|
|
26
|
+
case SummaryType.Handle: {
|
|
26
27
|
throw new Error("No handle should be present for first summary!!");
|
|
27
28
|
}
|
|
28
29
|
default: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNewUtils.js","sourceRoot":"","sources":["../src/createNewUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"createNewUtils.js","sourceRoot":"","sources":["../src/createNewUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAgB,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAEjF;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAAC,OAAqB;IAClE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;QACpB,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAExC,QAAQ,aAAa,CAAC,IAAI,EAAE;YACxB,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,gCAAgC,CAAC,aAAa,CAAC,CAAC;gBACpE,MAAM;aACT;YACD,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC;gBACnB,aAAa,CAAC,OAAO,GAAG,OAAO,aAAa,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC;oBAC/D,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAC9E,MAAM;aACT;YACD,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;aACtE;YACD,OAAO,CAAC,CAAC;gBACL,MAAM,IAAI,KAAK,CAAC,qBAAqB,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;aAC9D;SACJ;KACJ;IAED,OAAO,OAAO,CAAC;AACnB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { Uint8ArrayToString } from \"@fluidframework/common-utils\";\nimport { ISummaryTree, SummaryType } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Utility api to convert ISummaryTree to a summary tree where blob contents are only utf8 strings.\n * @param summary - Summary supplied by the runtime to upload.\n * @returns - Modified summary tree where the blob contents could be utf8 string only.\n */\nexport function convertSummaryToCreateNewSummary(summary: ISummaryTree): ISummaryTree {\n const keys = Object.keys(summary.tree);\n for (const key of keys) {\n const summaryObject = summary.tree[key];\n\n switch (summaryObject.type) {\n case SummaryType.Tree: {\n summary.tree[key] = convertSummaryToCreateNewSummary(summaryObject);\n break;\n }\n case SummaryType.Blob: {\n summaryObject.content = typeof summaryObject.content === \"string\" ?\n summaryObject.content : Uint8ArrayToString(summaryObject.content, \"utf8\");\n break;\n }\n case SummaryType.Handle: {\n throw new Error(\"No handle should be present for first summary!!\");\n }\n default: {\n throw new Error(`Unknown tree type ${summaryObject.type}`);\n }\n }\n }\n\n return summary;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentStorageService.d.ts","sourceRoot":"","sources":["../src/documentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"documentStorageService.d.ts","sourceRoot":"","sources":["../src/documentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAEH,+BAA+B,EAEjC,MAAM,oCAAoC,CAAC;AAC7C,OAAO,EACH,aAAa,EACb,QAAQ,EACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,UAAU,EACb,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,2BAA2B,EAAkC,MAAM,8BAA8B,CAAC;AAC3G,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,qBAAa,sBAAuB,SAAQ,2BAA2B;aAyC/C,EAAE,EAAE,MAAM;IACnB,OAAO,EAAE,UAAU;IAzC9B,OAAO,CAAC,WAAW,CAAiC;IAEpD,IAAW,UAAU,IAAI,MAAM,GAAG,SAAS,CAE1C;IAED,OAAO,CAAC,MAAM,CAAC,kCAAkC;gBAkC7B,EAAE,EAAE,MAAM,EACnB,OAAO,EAAE,UAAU,EAC1B,MAAM,EAAE,gBAAgB,EACxB,QAAQ,GAAE,+BAAoC,EAC9C,cAAc,CAAC,EAAE,4BAA4B,EAC7C,SAAS,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,EACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC;IAYhC,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CAOlF"}
|
|
@@ -2,267 +2,10 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { assert, stringToBuffer, Uint8ArrayToString, } from "@fluidframework/common-utils";
|
|
6
5
|
import { LoaderCachingPolicy, } from "@fluidframework/driver-definitions";
|
|
7
|
-
import { buildHierarchy } from "@fluidframework/protocol-base";
|
|
8
|
-
import { convertWholeFlatSummaryToSnapshotTreeAndBlobs, SummaryTreeUploadManager, WholeSummaryUploadManager, } from "@fluidframework/server-services-client";
|
|
9
|
-
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
10
6
|
import { DocumentStorageServiceProxy, PrefetchDocumentStorageService } from "@fluidframework/driver-utils";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
/**
|
|
14
|
-
* Document access to underlying storage for routerlicious driver.
|
|
15
|
-
* Uploads summaries piece-by-piece traversing the tree recursively.
|
|
16
|
-
* Downloads summaries
|
|
17
|
-
*/
|
|
18
|
-
class ShreddedSummaryDocumentStorageService {
|
|
19
|
-
constructor(id, manager, logger, policies = {}) {
|
|
20
|
-
this.id = id;
|
|
21
|
-
this.manager = manager;
|
|
22
|
-
this.logger = logger;
|
|
23
|
-
this.policies = policies;
|
|
24
|
-
// The values of this cache is useless. We only need the keys. So we are always putting
|
|
25
|
-
// empty strings as values.
|
|
26
|
-
this.blobsShaCache = new Map();
|
|
27
|
-
this.summaryUploadManager = new SummaryTreeUploadManager(new RetriableGitManager(manager, logger), this.blobsShaCache, this.getPreviousFullSnapshot.bind(this));
|
|
28
|
-
}
|
|
29
|
-
get repositoryUrl() {
|
|
30
|
-
return "";
|
|
31
|
-
}
|
|
32
|
-
async getVersions(versionId, count) {
|
|
33
|
-
const id = versionId ? versionId : this.id;
|
|
34
|
-
const commits = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
35
|
-
eventName: "getVersions",
|
|
36
|
-
versionId: id,
|
|
37
|
-
count,
|
|
38
|
-
}, async () => this.manager.getCommits(id, count));
|
|
39
|
-
return commits.map((commit) => ({
|
|
40
|
-
date: commit.commit.author.date,
|
|
41
|
-
id: commit.sha,
|
|
42
|
-
treeId: commit.commit.tree.sha,
|
|
43
|
-
}));
|
|
44
|
-
}
|
|
45
|
-
async getSnapshotTree(version) {
|
|
46
|
-
let requestVersion = version;
|
|
47
|
-
if (!requestVersion) {
|
|
48
|
-
const versions = await this.getVersions(this.id, 1);
|
|
49
|
-
if (versions.length === 0) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
requestVersion = versions[0];
|
|
53
|
-
}
|
|
54
|
-
const rawTree = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
55
|
-
eventName: "getSnapshotTree",
|
|
56
|
-
treeId: requestVersion.treeId,
|
|
57
|
-
}, async (event) => {
|
|
58
|
-
const response = await this.manager.getTree(requestVersion.treeId);
|
|
59
|
-
event.end({
|
|
60
|
-
size: response.tree.length,
|
|
61
|
-
});
|
|
62
|
-
return response;
|
|
63
|
-
});
|
|
64
|
-
const tree = buildHierarchy(rawTree, this.blobsShaCache, true);
|
|
65
|
-
return tree;
|
|
66
|
-
}
|
|
67
|
-
async readBlob(blobId) {
|
|
68
|
-
const value = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
69
|
-
eventName: "readBlob",
|
|
70
|
-
blobId,
|
|
71
|
-
}, async (event) => {
|
|
72
|
-
const response = await this.manager.getBlob(blobId);
|
|
73
|
-
event.end({
|
|
74
|
-
size: response.size,
|
|
75
|
-
});
|
|
76
|
-
return response;
|
|
77
|
-
});
|
|
78
|
-
this.blobsShaCache.set(value.sha, "");
|
|
79
|
-
return stringToBuffer(value.content, value.encoding);
|
|
80
|
-
}
|
|
81
|
-
async write(tree, parents, message, ref) {
|
|
82
|
-
const branch = ref ? `datastores/${this.id}/${ref}` : this.id;
|
|
83
|
-
const commit = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
84
|
-
eventName: "write",
|
|
85
|
-
id: branch,
|
|
86
|
-
}, async () => this.manager.write(branch, tree, parents, message));
|
|
87
|
-
return { date: commit.committer.date, id: commit.sha, treeId: commit.tree.sha };
|
|
88
|
-
}
|
|
89
|
-
async uploadSummaryWithContext(summary, context) {
|
|
90
|
-
const summaryHandle = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
91
|
-
eventName: "uploadSummaryWithContext",
|
|
92
|
-
}, async () => { var _a; return this.summaryUploadManager.writeSummaryTree(summary, (_a = context.ackHandle) !== null && _a !== void 0 ? _a : "", "channel"); });
|
|
93
|
-
return summaryHandle;
|
|
94
|
-
}
|
|
95
|
-
async downloadSummary(handle) {
|
|
96
|
-
throw new Error("NOT IMPLEMENTED!");
|
|
97
|
-
}
|
|
98
|
-
async createBlob(file) {
|
|
99
|
-
const uint8ArrayFile = new Uint8Array(file);
|
|
100
|
-
return PerformanceEvent.timedExecAsync(this.logger, {
|
|
101
|
-
eventName: "createBlob",
|
|
102
|
-
size: uint8ArrayFile.length,
|
|
103
|
-
}, async (event) => {
|
|
104
|
-
const response = await this.manager.createBlob(Uint8ArrayToString(uint8ArrayFile, "base64"), "base64").then((r) => ({ id: r.sha, url: r.url }));
|
|
105
|
-
event.end({
|
|
106
|
-
blobId: response.id,
|
|
107
|
-
});
|
|
108
|
-
return response;
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
async getPreviousFullSnapshot(parentHandle) {
|
|
112
|
-
return parentHandle
|
|
113
|
-
? this.getVersions(parentHandle, 1)
|
|
114
|
-
.then(async (versions) => {
|
|
115
|
-
// Clear the cache as the getSnapshotTree call will fill the cache.
|
|
116
|
-
this.blobsShaCache.clear();
|
|
117
|
-
return this.getSnapshotTree(versions[0]);
|
|
118
|
-
})
|
|
119
|
-
: undefined;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const latestSnapshotId = "latest";
|
|
123
|
-
class WholeSummaryDocumentStorageService {
|
|
124
|
-
constructor(id, manager, logger, policies = {}, blobCache = new InMemoryCache(), snapshotTreeCache = new InMemoryCache()) {
|
|
125
|
-
this.id = id;
|
|
126
|
-
this.manager = manager;
|
|
127
|
-
this.logger = logger;
|
|
128
|
-
this.policies = policies;
|
|
129
|
-
this.blobCache = blobCache;
|
|
130
|
-
this.snapshotTreeCache = snapshotTreeCache;
|
|
131
|
-
this.firstVersionsCall = true;
|
|
132
|
-
this.summaryUploadManager = new WholeSummaryUploadManager(manager);
|
|
133
|
-
}
|
|
134
|
-
get repositoryUrl() {
|
|
135
|
-
return "";
|
|
136
|
-
}
|
|
137
|
-
async getVersions(versionId, count) {
|
|
138
|
-
if (versionId !== this.id && versionId !== null) {
|
|
139
|
-
// Blobs in this scenario will never have multiple versions, so return blobId as is
|
|
140
|
-
return [{
|
|
141
|
-
id: versionId,
|
|
142
|
-
treeId: undefined,
|
|
143
|
-
}];
|
|
144
|
-
}
|
|
145
|
-
// If this is the first versions call for the document, we know we will want the latest summary.
|
|
146
|
-
// Fetch latest summary, cache it, and return its id.
|
|
147
|
-
if (this.firstVersionsCall && count === 1) {
|
|
148
|
-
this.firstVersionsCall = false;
|
|
149
|
-
return [{
|
|
150
|
-
id: (await this.fetchAndCacheSnapshotTree(latestSnapshotId)).id,
|
|
151
|
-
treeId: undefined,
|
|
152
|
-
}];
|
|
153
|
-
}
|
|
154
|
-
// Otherwise, get the latest version of the document as normal.
|
|
155
|
-
const id = versionId ? versionId : this.id;
|
|
156
|
-
const commits = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
157
|
-
eventName: "getVersions",
|
|
158
|
-
versionId: id,
|
|
159
|
-
count,
|
|
160
|
-
}, async () => this.manager.getCommits(id, count));
|
|
161
|
-
return commits.map((commit) => ({
|
|
162
|
-
date: commit.commit.author.date,
|
|
163
|
-
id: commit.sha,
|
|
164
|
-
treeId: undefined,
|
|
165
|
-
}));
|
|
166
|
-
}
|
|
167
|
-
async getSnapshotTree(version) {
|
|
168
|
-
let requestVersion = version;
|
|
169
|
-
if (!requestVersion) {
|
|
170
|
-
const versions = await this.getVersions(this.id, 1);
|
|
171
|
-
if (versions.length === 0) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
requestVersion = versions[0];
|
|
175
|
-
}
|
|
176
|
-
return (await this.fetchAndCacheSnapshotTree(requestVersion.id)).snapshotTree;
|
|
177
|
-
}
|
|
178
|
-
async readBlob(blobId) {
|
|
179
|
-
const cachedBlob = await this.blobCache.get(blobId);
|
|
180
|
-
if (cachedBlob !== undefined) {
|
|
181
|
-
return cachedBlob;
|
|
182
|
-
}
|
|
183
|
-
const blob = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
184
|
-
eventName: "readBlob",
|
|
185
|
-
blobId,
|
|
186
|
-
}, async (event) => {
|
|
187
|
-
const response = await this.manager.getBlob(blobId);
|
|
188
|
-
event.end({
|
|
189
|
-
size: response.size,
|
|
190
|
-
});
|
|
191
|
-
return response;
|
|
192
|
-
});
|
|
193
|
-
const bufferValue = stringToBuffer(blob.content, blob.encoding);
|
|
194
|
-
await this.blobCache.put(blob.sha, bufferValue);
|
|
195
|
-
return bufferValue;
|
|
196
|
-
}
|
|
197
|
-
async uploadSummaryWithContext(summary, context) {
|
|
198
|
-
const summaryHandle = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
199
|
-
eventName: "uploadSummaryWithContext",
|
|
200
|
-
}, async () => { var _a; return this.summaryUploadManager.writeSummaryTree(summary, (_a = context.ackHandle) !== null && _a !== void 0 ? _a : "", "channel"); });
|
|
201
|
-
return summaryHandle;
|
|
202
|
-
}
|
|
203
|
-
async downloadSummary(handle) {
|
|
204
|
-
throw new Error("NOT IMPLEMENTED!");
|
|
205
|
-
}
|
|
206
|
-
async write(tree, parents, message, ref) {
|
|
207
|
-
throw new Error("NOT IMPLEMENTED!");
|
|
208
|
-
}
|
|
209
|
-
async createBlob(file) {
|
|
210
|
-
const uint8ArrayFile = new Uint8Array(file);
|
|
211
|
-
return PerformanceEvent.timedExecAsync(this.logger, {
|
|
212
|
-
eventName: "createBlob",
|
|
213
|
-
size: uint8ArrayFile.length,
|
|
214
|
-
}, async (event) => {
|
|
215
|
-
const response = await this.manager.createBlob(Uint8ArrayToString(uint8ArrayFile, "base64"), "base64").then((r) => ({ id: r.sha, url: r.url }));
|
|
216
|
-
event.end({
|
|
217
|
-
blobId: response.id,
|
|
218
|
-
});
|
|
219
|
-
return response;
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
async fetchAndCacheSnapshotTree(versionId) {
|
|
223
|
-
const cachedSnapshotTree = await this.snapshotTreeCache.get(versionId);
|
|
224
|
-
if (cachedSnapshotTree !== undefined) {
|
|
225
|
-
return { id: versionId, snapshotTree: cachedSnapshotTree };
|
|
226
|
-
}
|
|
227
|
-
const wholeFlatSummary = await PerformanceEvent.timedExecAsync(this.logger, {
|
|
228
|
-
eventName: "getWholeFlatSummary",
|
|
229
|
-
treeId: versionId,
|
|
230
|
-
}, async (event) => {
|
|
231
|
-
var _a;
|
|
232
|
-
const response = await this.manager.getSummary(versionId);
|
|
233
|
-
event.end({
|
|
234
|
-
size: (_a = response.trees[0]) === null || _a === void 0 ? void 0 : _a.entries.length,
|
|
235
|
-
});
|
|
236
|
-
return response;
|
|
237
|
-
});
|
|
238
|
-
const normalizedWholeSummary = convertWholeFlatSummaryToSnapshotTreeAndBlobs(wholeFlatSummary);
|
|
239
|
-
const snapshotId = normalizedWholeSummary.snapshotTree.id;
|
|
240
|
-
assert(snapshotId !== undefined, 0x275 /* "Root tree should contain the id" */);
|
|
241
|
-
const cachePs = [
|
|
242
|
-
this.snapshotTreeCache.put(snapshotId, normalizedWholeSummary.snapshotTree),
|
|
243
|
-
this.initBlobCache(normalizedWholeSummary.blobs),
|
|
244
|
-
];
|
|
245
|
-
if (snapshotId !== versionId) {
|
|
246
|
-
// versionId could be "latest". When summarizer checks cache for "latest", we want it to be available.
|
|
247
|
-
// TODO: For in-memory cache, <latest,snapshotTree> will be a shared pointer with <snapshotId,snapshotTree>,
|
|
248
|
-
// However, for something like Redis, this will cache the same value twice. Alternatively, could we simply
|
|
249
|
-
// cache with versionId?
|
|
250
|
-
cachePs.push(this.snapshotTreeCache.put(versionId, normalizedWholeSummary.snapshotTree));
|
|
251
|
-
}
|
|
252
|
-
await Promise.all([
|
|
253
|
-
this.snapshotTreeCache.put(snapshotId, normalizedWholeSummary.snapshotTree),
|
|
254
|
-
this.initBlobCache(normalizedWholeSummary.blobs),
|
|
255
|
-
]);
|
|
256
|
-
return { id: snapshotId, snapshotTree: normalizedWholeSummary.snapshotTree };
|
|
257
|
-
}
|
|
258
|
-
async initBlobCache(blobs) {
|
|
259
|
-
const blobCachePutPs = [];
|
|
260
|
-
blobs.forEach((value, id) => {
|
|
261
|
-
blobCachePutPs.push(this.blobCache.put(id, value));
|
|
262
|
-
});
|
|
263
|
-
await Promise.all(blobCachePutPs);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
7
|
+
import { WholeSummaryDocumentStorageService } from "./wholeSummaryDocumentStorageService";
|
|
8
|
+
import { ShreddedSummaryDocumentStorageService } from "./shreddedSummaryDocumentStorageService";
|
|
266
9
|
export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
267
10
|
constructor(id, manager, logger, policies = {}, driverPolicies, blobCache, snapshotTreeCache) {
|
|
268
11
|
super(DocumentStorageService.loadInternalDocumentStorageService(id, manager, logger, policies, driverPolicies, blobCache, snapshotTreeCache));
|
|
@@ -276,7 +19,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|
|
276
19
|
static loadInternalDocumentStorageService(id, manager, logger, policies, driverPolicies, blobCache, snapshotTreeCache) {
|
|
277
20
|
const storageService = (driverPolicies === null || driverPolicies === void 0 ? void 0 : driverPolicies.enableWholeSummaryUpload) ?
|
|
278
21
|
new WholeSummaryDocumentStorageService(id, manager, logger, policies, blobCache, snapshotTreeCache) :
|
|
279
|
-
new ShreddedSummaryDocumentStorageService(id, manager, logger, policies);
|
|
22
|
+
new ShreddedSummaryDocumentStorageService(id, manager, logger, policies, driverPolicies, blobCache, snapshotTreeCache);
|
|
280
23
|
// TODO: worth prefetching latest summary making version + snapshot call with WholeSummary storage?
|
|
281
24
|
if (!(driverPolicies === null || driverPolicies === void 0 ? void 0 : driverPolicies.enableWholeSummaryUpload) && policies.caching === LoaderCachingPolicy.Prefetch) {
|
|
282
25
|
return new PrefetchDocumentStorageService(storageService);
|