Skip to content

Commit

Permalink
feat: cache GUIDs without any unit IDs mappings for later removal (#972)
Browse files Browse the repository at this point in the history
Keep a cache of the last 100 unused GUIDs that no longer have unit
IDs associated with them. Once they are evicted from the cache,
remove all other information tracked by the `guid` module for those
GUIDs.  This prevents the number of GUID-to-name mappings from
growing without bound, and frees up some memory for garbage
collection.
  • Loading branch information
johnnylam88 authored Aug 30, 2021
1 parent 19c7d5b commit 6b70923
Showing 1 changed file with 32 additions and 2 deletions.
34 changes: 32 additions & 2 deletions src/engine/guid.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import aceEvent, { AceEvent } from "@wowts/ace_event-3.0";
import { LuaArray, LuaObj, ipairs, lualength, pairs, unpack } from "@wowts/lua";
import { concat, insert } from "@wowts/table";
import { concat, insert, sort } from "@wowts/table";
import { GetUnitName, UnitGUID, UnitIsUnit } from "@wowts/wow-mock";
import { AceModule } from "@wowts/tsaddon";
import { OvaleClass } from "../Ovale";
import { Tracer, DebugTools } from "./debug";
import { binaryInsertUnique, binaryRemove } from "../tools/array";
import { LRUCache } from "../tools/cache";
import { OptionUiGroup } from "../ui/acegui-helpers";

function dumpMapping(t: LuaObj<LuaArray<string>>, output: LuaArray<string>) {
Expand Down Expand Up @@ -34,15 +35,16 @@ export class Guids {
private nameByGUID: LuaObj<string> = {};
private guidByName: LuaObj<LuaArray<string>> = {};
private ownerGUIDByGUID: LuaObj<string> = {};
private unusedGUIDCache: LRUCache<string>;

private childUnitByUnit: LuaObj<LuaObj<boolean>> = {};
private petUnitByUnit: LuaObj<string> = {};

// eventfulUnits is an ordered array of unit IDs that receive unit events.
private eventfulUnits: LuaArray<string> = {};
private unitPriority: LuaObj<number> = {};
unitAuraUnits: LuaObj<boolean> = {};

unitAuraUnits: LuaObj<boolean> = {};
petGUID: LuaObj<boolean> = {};

private debugGUIDs: OptionUiGroup = {
Expand All @@ -64,6 +66,13 @@ export class Guids {
insert(output, "}\n");
insert(output, "GUID by Name = {");
dumpMapping(this.guidByName, output);
insert(output, "}\n");
insert(output, "Unused GUIDs = {");
const guids = this.unusedGUIDCache.asArray();
sort(guids);
for (const [, guid] of ipairs(guids)) {
insert(output, ` ${guid}`);
}
insert(output, "}");
return concat(output, "\n");
},
Expand All @@ -81,6 +90,10 @@ export class Guids {
aceEvent
);
this.tracer = debug.create(this.module.GetName());
/* Cache the last 100 unreferenced GUIDs to retain their
* name mappings.
*/
this.unusedGUIDCache = new LRUCache<string>(100);

this.petUnitByUnit["player"] = "pet";
insert(this.eventfulUnits, "player");
Expand Down Expand Up @@ -343,6 +356,8 @@ export class Guids {
const t = this.unitByGUID[guid] || {};
binaryInsertUnique(t, unit, this.compareUnit);
this.unitByGUID[guid] = t;
// This GUID has a unit ID, so remove it from the cache.
this.unusedGUIDCache.remove(guid);
};

private unmapGUIDToUnit = (guid: string, unit: string) => {
Expand All @@ -352,6 +367,21 @@ export class Guids {
binaryRemove(t, unit, this.compareUnit);
if (lualength(t) == 0) {
delete this.unitByGUID[unit];

/* This GUID has no more unit IDs associated with it, so
* put it the cache for eventual garbage collection.
*/
const evictedGUID = this.unusedGUIDCache.put(guid);
// Garbage-collect mappings for GUID evicted from cache.
if (evictedGUID) {
const name = this.nameByGUID[evictedGUID];
if (name) {
this.unmapNameToGUID(name, evictedGUID);
}
delete this.ownerGUIDByGUID[evictedGUID];
delete this.petGUID[evictedGUID];
this.module.SendMessage("Ovale_UnusedGUID", evictedGUID);
}
}
}
};
Expand Down

0 comments on commit 6b70923

Please sign in to comment.