diff --git a/packages/drivers/driver-web-cache/src/FluidCacheIndexedDb.ts b/packages/drivers/driver-web-cache/src/FluidCacheIndexedDb.ts index e23a20e2ec3b..6b4fed7fce44 100644 --- a/packages/drivers/driver-web-cache/src/FluidCacheIndexedDb.ts +++ b/packages/drivers/driver-web-cache/src/FluidCacheIndexedDb.ts @@ -4,7 +4,10 @@ */ import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces"; -import { ICacheEntry } from "@fluidframework/odsp-driver-definitions/internal"; +import { + ICacheEntry, + getKeyForCacheEntry as odspGetKeyForCacheEntry, +} from "@fluidframework/odsp-driver-definitions/internal"; import { createChildLogger } from "@fluidframework/telemetry-utils/internal"; import { DBSchema, DeleteDBCallbacks, IDBPDatabase, deleteDB, openDB } from "idb"; @@ -25,7 +28,7 @@ export const oldVersionNameMapping: Partial<{ [key: number]: string }> = { }; export function getKeyForCacheEntry(entry: ICacheEntry) { - return `${entry.file.docId}_${entry.type}_${entry.key}`; + return odspGetKeyForCacheEntry(entry); } export function getFluidCacheIndexedDbInstance( diff --git a/packages/drivers/odsp-driver-definitions/src/odspCache.ts b/packages/drivers/odsp-driver-definitions/src/odspCache.ts index 09a2181d93c5..2352346f9b69 100644 --- a/packages/drivers/odsp-driver-definitions/src/odspCache.ts +++ b/packages/drivers/odsp-driver-definitions/src/odspCache.ts @@ -114,7 +114,7 @@ export interface IPersistedCache { put(entry: ICacheEntry, value: any): Promise; /** - * Removes the entries from the cache for given parametres. + * Removes the entries from the cache for given parameters. * @param file - file entry to be deleted. */ removeEntries(file: IFileEntry): Promise; @@ -127,5 +127,24 @@ export interface IPersistedCache { * @internal */ export function getKeyForCacheEntry(entry: ICacheEntry): string { - return `${entry.file.docId}_${entry.type}_${entry.key}`; + const version = + "fileVersion" in entry.file.resolvedUrl && entry.file.resolvedUrl.fileVersion !== undefined + ? `_${entry.file.resolvedUrl.fileVersion}` + : ""; + switch (entry.type) { + case snapshotWithLoadingGroupIdKey: + case snapshotKey: { + // example versioned entry: docId_4.0_snapshot_ + // example non-versioned entry: docId_snapshot_ + // The trailing '_' is included for consistency with existing cache entries + return `${entry.file.docId}${version}_${entry.type}_`; + } + case "ops": { + // example versioned entry: docId_4.0_ops_100_3 + // example non-versioned entry: docId_ops_100_3 + return `${entry.file.docId}${version}_${entry.type}_${entry.key}`; + } + default: + return `${entry.file.docId}_${entry.type}_${entry.key}`; + } } diff --git a/packages/drivers/odsp-driver/src/odspDocumentService.ts b/packages/drivers/odsp-driver/src/odspDocumentService.ts index 9e36bae5457a..9ed2d7865acd 100644 --- a/packages/drivers/odsp-driver/src/odspDocumentService.ts +++ b/packages/drivers/odsp-driver/src/odspDocumentService.ts @@ -348,7 +348,7 @@ export class OdspDocumentService return this._opsCache; } - // Called whenever re receive ops through any channel for this document (snapshot, delta connection, delta storage) + // Called whenever we receive ops through any channel for this document (snapshot, delta connection, delta storage) // We use it to notify caching layer of how stale is snapshot stored in cache. protected opsReceived(ops: ISequencedDocumentMessage[]): void { // No need for two clients to save same ops diff --git a/packages/drivers/odsp-driver/src/odspUtils.ts b/packages/drivers/odsp-driver/src/odspUtils.ts index aaa5ad66c010..5b73d4d115f0 100644 --- a/packages/drivers/odsp-driver/src/odspUtils.ts +++ b/packages/drivers/odsp-driver/src/odspUtils.ts @@ -467,7 +467,7 @@ export function createCacheSnapshotKey( ): ICacheEntry { const cacheEntry: ICacheEntry = { type: snapshotWithLoadingGroupId ? snapshotWithLoadingGroupIdKey : snapshotKey, - key: odspResolvedUrl.fileVersion ?? "", + key: "", file: { resolvedUrl: odspResolvedUrl, docId: odspResolvedUrl.hashedDocumentId, diff --git a/packages/drivers/odsp-driver/src/test/getKeyForCacheEntry.spec.ts b/packages/drivers/odsp-driver/src/test/getKeyForCacheEntry.spec.ts new file mode 100644 index 000000000000..8c1946dc6594 --- /dev/null +++ b/packages/drivers/odsp-driver/src/test/getKeyForCacheEntry.spec.ts @@ -0,0 +1,98 @@ +/*! + * Copyright (c) Microsoft Corporation and contributors. All rights reserved. + * Licensed under the MIT License. + */ + +import { strict as assert } from "node:assert"; + +import { + getKeyForCacheEntry, + type CacheContentType, + type ICacheEntry, + type IOdspResolvedUrl, +} from "@fluidframework/odsp-driver-definitions/internal"; + +function createMockCacheEntry( + url: IOdspResolvedUrl, + type: CacheContentType, + key: string, +): ICacheEntry { + return { + type, + key, + file: { + resolvedUrl: url, + docId: "test-doc-id", + }, + }; +} + +// Define both cache entry types here for readability +const opType = "ops"; +const snapshotType = "snapshot"; + +describe("getKeyForCacheEntry", () => { + const odspResolvedUrlWithoutVersion: IOdspResolvedUrl = { + type: "fluid", + odspResolvedUrl: true, + id: "1", + siteUrl: "fakeUrl", + driveId: "1", + itemId: "1", + url: "fakeUrl", + hashedDocumentId: "1", + endpoints: { + snapshotStorageUrl: "fakeUrl", + attachmentPOSTStorageUrl: "fakeUrl", + attachmentGETStorageUrl: "fakeUrl", + deltaStorageUrl: "fakeUrl", + }, + tokens: {}, + fileName: "fakeName", + summarizer: false, + fileVersion: undefined, + }; + + const odspResolvedUrlWithVersion: IOdspResolvedUrl = { + type: "fluid", + odspResolvedUrl: true, + id: "1", + siteUrl: "fakeUrl", + driveId: "1", + itemId: "1", + url: "fakeUrl", + hashedDocumentId: "1", + endpoints: { + snapshotStorageUrl: "fakeUrl", + attachmentPOSTStorageUrl: "fakeUrl", + attachmentGETStorageUrl: "fakeUrl", + deltaStorageUrl: "fakeUrl", + }, + tokens: {}, + fileName: "fakeName", + summarizer: false, + fileVersion: "3.0", + }; + + it("creates a non-versioned snapshot cache entry", () => { + const entry = createMockCacheEntry(odspResolvedUrlWithoutVersion, snapshotType, ""); + const key = getKeyForCacheEntry(entry); + assert.equal(key, "test-doc-id_snapshot_"); + }); + it("creates a versioned snapshot cache entry", () => { + const entry = createMockCacheEntry(odspResolvedUrlWithVersion, snapshotType, ""); + const key = getKeyForCacheEntry(entry); + assert.equal(key, "test-doc-id_3.0_snapshot_"); + }); + + it("creates a non-versioned op cache entry", () => { + const entry = createMockCacheEntry(odspResolvedUrlWithoutVersion, opType, "100_5"); + const key = getKeyForCacheEntry(entry); + assert.equal(key, "test-doc-id_ops_100_5"); + }); + it("creates a versioned op cache entry", () => { + const entry = createMockCacheEntry(odspResolvedUrlWithVersion, opType, "100_5"); + const key = getKeyForCacheEntry(entry); + assert.equal(key, "test-doc-id_3.0_ops_100_5"); + }); +});