Skip to content

Commit 76312ed

Browse files
committed
refactor: replace array with Map for PENDING_CHANGES to improve performance and ensure unique keys
1 parent c74186b commit 76312ed

File tree

1 file changed

+36
-38
lines changed

1 file changed

+36
-38
lines changed

src/lib/kuviewAtom.ts

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@ type _change_operation = {
3030
object: KubernetesObject;
3131
};
3232

33-
const PENDING_CHANGES: _change_operation[] = [];
33+
const PENDING_CHANGES = new Map<string, _change_operation>();
34+
35+
function getObjectKey(object: KubernetesObject): string {
36+
// it is suprising that sometimes the uid is not unique, so we need to check the apiVersion and kind as well
37+
return `${object.apiVersion}/${object.kind}:${object.metadata.uid}`;
38+
}
3439

3540
export function handleEvent(event: KuviewEvent) {
41+
const key = getObjectKey(event.object);
3642
switch (event.type) {
3743
case "create":
3844
case "update":
3945
case "generic":
40-
PENDING_CHANGES.push({ type: "UPSERT", object: event.object });
46+
PENDING_CHANGES.set(key, { type: "UPSERT", object: event.object });
4147
break;
4248
case "delete":
43-
PENDING_CHANGES.push({ type: "DELETE", object: event.object });
49+
PENDING_CHANGES.set(key, { type: "DELETE", object: event.object });
4450
break;
4551
}
4652
}
@@ -51,13 +57,21 @@ export function useGVKSyncHook(gvk: string) {
5157
const [objects, setObjects] = useAtom(objectAtom);
5258

5359
const sync = () => {
54-
const operations = PENDING_CHANGES.filter(
55-
(operation) =>
56-
`${operation.object.apiVersion}/${operation.object.kind}` === gvk,
57-
);
58-
if (operations.length == 0) return;
60+
const operations: _change_operation[] = [];
61+
PENDING_CHANGES.forEach((op, key) => {
62+
if (`${op.object.apiVersion}/${op.object.kind}` === gvk) {
63+
operations.push(op);
64+
PENDING_CHANGES.delete(key);
65+
}
66+
});
67+
68+
if (operations.length === 0) return;
69+
70+
const newObjects = { ...objects };
71+
let updated = false;
5972

6073
operations.forEach((operation) => {
74+
updated = true;
6175
const { type, object } = operation;
6276
const { metadata } = object;
6377
const nn = metadata.namespace
@@ -68,28 +82,17 @@ export function useGVKSyncHook(gvk: string) {
6882

6983
switch (type) {
7084
case "UPSERT":
71-
objects[nn] = object;
85+
newObjects[nn] = object;
7286
break;
7387
case "DELETE":
74-
delete objects[nn];
88+
delete newObjects[nn];
7589
break;
7690
}
7791
});
7892

79-
for (const operation of operations) {
80-
const index = PENDING_CHANGES.findIndex(
81-
(o) =>
82-
// it is suprising that sometimes the uid is not unique, so we need to check the apiVersion and kind as well
83-
`${o.object.apiVersion}/${o.object.kind}` ===
84-
`${operation.object.apiVersion}/${operation.object.kind}` &&
85-
o.object.metadata.uid === operation.object.metadata.uid,
86-
);
87-
if (index !== -1) {
88-
PENDING_CHANGES.splice(index, 1);
89-
}
93+
if (updated) {
94+
setObjects(newObjects);
9095
}
91-
92-
setObjects({ ...objects });
9396
};
9497

9598
useEffect(() => {
@@ -104,7 +107,7 @@ export function useKubernetesAtomSyncHook() {
104107
const [kubernetes, setKubernetes] = useAtom(kubernetesAtom);
105108
useEffect(() => {
106109
const interval = setInterval(() => {
107-
for (const operation of PENDING_CHANGES) {
110+
for (const operation of PENDING_CHANGES.values()) {
108111
const { object } = operation;
109112
const { kind, apiVersion } = object;
110113
const gvk = `${apiVersion}/${kind}`;
@@ -135,12 +138,15 @@ export function useServiceEndpointSliceSyncHook() {
135138
const [endpointSlices, setEndpointSlices] = useAtom(endpointSliceAtom);
136139

137140
const sync = () => {
138-
// 1. find all operations that are related to services and endpoint slices
139-
const operations = PENDING_CHANGES.filter(
140-
(operation) =>
141-
operation.object.kind === "Service" ||
142-
operation.object.kind === "EndpointSlice",
143-
);
141+
const operations: _change_operation[] = [];
142+
PENDING_CHANGES.forEach((op, key) => {
143+
if (op.object.kind === "Service" || op.object.kind === "EndpointSlice") {
144+
operations.push(op);
145+
PENDING_CHANGES.delete(key);
146+
}
147+
});
148+
149+
if (operations.length === 0) return;
144150

145151
// 2. update services first
146152
const serviceOperations = operations.filter(
@@ -218,14 +224,6 @@ export function useServiceEndpointSliceSyncHook() {
218224
}
219225
}
220226

221-
// 6. remove operations from PENDING_CHANGES
222-
for (const operation of operations) {
223-
const index = PENDING_CHANGES.findIndex(
224-
(o) => o.object.metadata.uid === operation.object.metadata.uid,
225-
);
226-
if (index !== -1) PENDING_CHANGES.splice(index, 1);
227-
}
228-
229227
setServices({ ...services });
230228
setEndpointSlices({ ...endpointSlices });
231229
};

0 commit comments

Comments
 (0)