Skip to content

Commit 3264796

Browse files
committed
chore: cleanup embeddings cache when the connection is closed
1 parent 94fdcda commit 3264796

File tree

2 files changed

+67
-41
lines changed

2 files changed

+67
-41
lines changed

src/common/search/vectorSearchEmbeddings.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ export class VectorSearchEmbeddings {
1717
private readonly config: UserConfig,
1818
private readonly connectionManager: ConnectionManager,
1919
private readonly embeddings: Map<EmbeddingNamespace, VectorFieldIndexDefinition[]> = new Map()
20-
) {}
20+
) {
21+
connectionManager.events.on("connection-close", () => {
22+
this.embeddings.clear();
23+
});
24+
}
2125

2226
cleanupEmbeddingsForNamespace({ database, collection }: { database: string; collection: string }): void {
2327
const embeddingDefKey: EmbeddingNamespace = `${database}.${collection}`;

tests/unit/common/search/vectorSearchEmbeddings.test.ts

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { ConnectionManager, UserConfig } from "../../../../src/lib.js";
1111
import { ConnectionStateConnected } from "../../../../src/common/connectionManager.js";
1212
import type { InsertOneResult } from "mongodb";
1313
import type { DropDatabaseResult } from "@mongosh/service-provider-node-driver/lib/node-driver-service-provider.js";
14+
import EventEmitter from "events";
1415

1516
type MockedServiceProvider = NodeDriverServiceProvider & {
1617
getSearchIndexes: MockedFunction<NodeDriverServiceProvider["getSearchIndexes"]>;
@@ -23,13 +24,50 @@ type MockedConnectionManager = ConnectionManager & {
2324
currentConnectionState: ConnectionStateConnected;
2425
};
2526

27+
const database = "my" as const;
28+
const collection = "collection" as const;
29+
const mapKey = `${database}.${collection}` as EmbeddingNamespace;
30+
31+
const embeddingConfig: Map<EmbeddingNamespace, VectorFieldIndexDefinition[]> = new Map([
32+
[
33+
mapKey,
34+
[
35+
{
36+
type: "vector",
37+
path: "embedding_field",
38+
numDimensions: 8,
39+
quantization: "scalar",
40+
similarity: "euclidean",
41+
},
42+
{
43+
type: "vector",
44+
path: "embedding_field_binary",
45+
numDimensions: 8,
46+
quantization: "binary",
47+
similarity: "euclidean",
48+
},
49+
{
50+
type: "vector",
51+
path: "a.nasty.scalar.field",
52+
numDimensions: 8,
53+
quantization: "scalar",
54+
similarity: "euclidean",
55+
},
56+
{
57+
type: "vector",
58+
path: "a.nasty.binary.field",
59+
numDimensions: 8,
60+
quantization: "binary",
61+
similarity: "euclidean",
62+
},
63+
],
64+
],
65+
]);
66+
2667
describe("VectorSearchEmbeddings", () => {
2768
const embeddingValidationEnabled: UserConfig = { disableEmbeddingsValidation: false } as UserConfig;
2869
const embeddingValidationDisabled: UserConfig = { disableEmbeddingsValidation: true } as UserConfig;
29-
30-
const database = "my" as const;
31-
const collection = "collection" as const;
32-
const mapKey = `${database}.${collection}` as EmbeddingNamespace;
70+
const eventEmitter = new EventEmitter();
3371

3472
const provider: MockedServiceProvider = {
3573
getSearchIndexes: vi.fn(),
@@ -41,6 +79,7 @@ describe("VectorSearchEmbeddings", () => {
4179

4280
const connectionManager: MockedConnectionManager = {
4381
currentConnectionState: new ConnectionStateConnected(provider),
82+
events: eventEmitter,
4483
} as unknown as MockedConnectionManager;
4584

4685
beforeEach(() => {
@@ -51,6 +90,25 @@ describe("VectorSearchEmbeddings", () => {
5190
provider.dropDatabase.mockResolvedValue({} as unknown as DropDatabaseResult);
5291
});
5392

93+
describe("embeddings cache", () => {
94+
it("the connection is closed gets cleared", async () => {
95+
const configCopy = new Map(embeddingConfig);
96+
const embeddings = new VectorSearchEmbeddings(embeddingValidationEnabled, connectionManager, configCopy);
97+
98+
eventEmitter.emit("connection-close");
99+
void embeddings; // we don't need to call it, it's already subscribed by the constructor
100+
101+
const isEmpty = await vi.waitFor(() => {
102+
if (configCopy.size > 0) {
103+
throw new Error("Didn't consume the 'connection-close' event yet");
104+
}
105+
return true;
106+
});
107+
108+
expect(isEmpty).toBeTruthy();
109+
});
110+
});
111+
54112
describe("embedding retrieval", () => {
55113
describe("when the embeddings have not been cached", () => {
56114
beforeEach(() => {
@@ -138,42 +196,6 @@ describe("VectorSearchEmbeddings", () => {
138196
});
139197

140198
describe("when there are embeddings", () => {
141-
const embeddingConfig: Map<EmbeddingNamespace, VectorFieldIndexDefinition[]> = new Map([
142-
[
143-
mapKey,
144-
[
145-
{
146-
type: "vector",
147-
path: "embedding_field",
148-
numDimensions: 8,
149-
quantization: "scalar",
150-
similarity: "euclidean",
151-
},
152-
{
153-
type: "vector",
154-
path: "embedding_field_binary",
155-
numDimensions: 8,
156-
quantization: "binary",
157-
similarity: "euclidean",
158-
},
159-
{
160-
type: "vector",
161-
path: "a.nasty.scalar.field",
162-
numDimensions: 8,
163-
quantization: "scalar",
164-
similarity: "euclidean",
165-
},
166-
{
167-
type: "vector",
168-
path: "a.nasty.binary.field",
169-
numDimensions: 8,
170-
quantization: "binary",
171-
similarity: "euclidean",
172-
},
173-
],
174-
],
175-
]);
176-
177199
describe("when the validation is disabled", () => {
178200
let embeddings: VectorSearchEmbeddings;
179201

0 commit comments

Comments
 (0)