refactor(ui): speed up updates with large number of alerts

Comparing group dicts with large number of alerts is expensive, doing it per group and using hash checks will speed up updates, especially when alerts don't change often
This commit is contained in:
Łukasz Mierzwa
2018-10-14 11:16:08 +01:00
parent e6715d8ea1
commit bbd9edab26
2 changed files with 74 additions and 7 deletions

View File

@@ -285,13 +285,7 @@ class AlertStore {
let updates = {};
// update data dicts if they changed
for (const key of [
"colors",
"counters",
"groups",
"silences",
"upstreams"
]) {
for (const key of ["colors", "counters", "silences", "upstreams"]) {
if (!equal(this.data[key], result[key])) {
updates[key] = result[key];
}
@@ -300,6 +294,27 @@ class AlertStore {
this.data = Object.assign(this.data, updates);
}
// update groups, it can be huge so we have custom logic with cheaper
// comparision logic running per group using content hashes from the API
// response
for (const key of Object.keys(result.groups)) {
// set/update each group if:
// * it's not yet stored in AlertStore
// * it's stored but hash is different than in the API response
if (
!(key in this.data.groups) ||
(key in this.data.groups &&
result.groups[key].hash !== this.data.groups[key].hash)
) {
this.data.groups[key] = result.groups[key];
}
}
for (const key of Object.keys(this.data.groups).filter(
k => !(k in result.groups)
)) {
delete this.data.groups[key];
}
// before storing new version check if we need to reload
if (
this.info.version !== "unknown" &&

View File

@@ -333,4 +333,56 @@ describe("AlertStore.fetch", () => {
await expect(store.fetch()).resolves.toBeUndefined();
expect(store.info.upgradeNeeded).toBe(true);
});
it("adds new groups to the store after fetch", () => {
const response = EmptyAPIResponse();
response.groups = { foo: "foo", bar: "bar" };
const store = new AlertStore(["label=value"]);
store.parseAPIResponse(response);
expect(Object.keys(store.data.groups)).toHaveLength(2);
expect(store.data.groups).toMatchObject({ foo: "foo", bar: "bar" });
});
it("is no-op for groups that didn't change", () => {
const store = new AlertStore(["label=value"]);
store.data.groups = { foo: { hash: "foo" }, bar: { hash: "bar" } };
const response = EmptyAPIResponse();
response.groups = { foo: { hash: "foo" }, bar: { hash: "bar" } };
store.parseAPIResponse(response);
expect(Object.keys(store.data.groups)).toHaveLength(2);
expect(store.data.groups).toMatchObject({
foo: { hash: "foo" },
bar: { hash: "bar" }
});
});
it("removes old groups from the store after fetch", () => {
const store = new AlertStore(["label=value"]);
store.data.groups = { foo: "foo", delete: "me", bar: "bar" };
expect(Object.keys(store.data.groups)).toHaveLength(3);
const response = EmptyAPIResponse();
response.groups = { foo: "foo", bar: "bar" };
store.parseAPIResponse(response);
expect(Object.keys(store.data.groups)).toHaveLength(2);
expect(store.data.groups).toMatchObject({ foo: "foo", bar: "bar" });
});
it("updates groups with new hash after fetch", () => {
const store = new AlertStore(["label=value"]);
store.data.groups = { foo: { hash: "foo" }, bar: { hash: "bar" } };
const response = EmptyAPIResponse();
response.groups = { foo: { hash: "newFoo" }, bar: { hash: "newBar" } };
store.parseAPIResponse(response);
expect(Object.keys(store.data.groups)).toHaveLength(2);
expect(store.data.groups).toMatchObject({
foo: { hash: "newFoo" },
bar: { hash: "newBar" }
});
});
});