WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Maintaining a sortable database, garbage creation (https://www.wowinterface.com/forums/showthread.php?t=32310)

corveroth 05-03-10 11:59 PM

Maintaining a sortable database, garbage creation
 
I have an issue, to the tune of 80 KB of junk every time COMPANION_UPDATE fires.

For my addon, I find it necessary to keep up to date information on your companions. Beyond simply registering COMPANION_UPDATE and calling GetCompanionInfo, I also pull some extra data from tooltips and hard-coded tables, in order to offer more information to the user (such as mount speed).

The issues arose when I added in the capacity to sort that data. Three columns appear in the display, and the tabs at the top of each enable sorting, much like the Guild or Who frames. To allow for this behavior, I found it necessary to store several pieces of information in a table, which I could later sort, and whenever the display needed to be refreshed, I read off the appropriate rows from the table. The problem appears to lie in the need to rebuild the entire table every time that COMPANION_UPDATE fires (very common in cities, as it fires for nearby players as well).

What recommendations might you have to offer to cut down on the garbage generation inherent to this approach? What alternative approaches might exist?

lua Code:
  1. local MountData = {}
  2. local function UpdateMountData()
  3.     MountData = {}
  4.     local creatureName, spellID, icon, active
  5.     local speed, mountType, numPassengers, isUsable, varies
  6.     local notes
  7.    
  8.     for i=1, GetNumCompanions("MOUNT") do
  9.         notes = ""
  10.         _, creatureName, spellID, icon, active = GetCompanionInfo("MOUNT", i)
  11.         -- GetExtraCompanionData is my function that does the tooltip scanning and such
  12.         speed, mountType, numPassengers, isUsable, varies = unpack(GetExtraCompanionData("MOUNT", spellID),1,5)
  13.        
  14.         if numPassengers > 0 then
  15.             -- NOTE: addLine is just a utility function to insert newlines as appropriate
  16.             notes = addLine(notes, format(L["Passengers: %d"], numPassengers))
  17.         end
  18.        
  19.         if varies then
  20.             notes = addLine(notes, L["Varies"])
  21.         end
  22.        
  23.         if not strfind(notes, "\n") then
  24.             if mountType == MOUNTTYPE_LAND then
  25.                 notes = addLine(notes, L["Ground"])
  26.             elseif mountType == MOUNTTYPE_FLYING then
  27.                 notes = addLine(notes, L["Flying"])
  28.             elseif mountType == MOUNTTYPE_AQUATIC then
  29.                 notes = addLine(notes, L["Aquatic"])
  30.             end
  31.         end
  32.        
  33.         tinsert(MountData, {NAME = creatureName, NOTES = notes, SPEED = speed, ICON = icon, ACTIVE = active, ISUSABLE = isUsable, ID = i})
  34.     end
  35. end

Torhal 05-04-10 12:51 AM

Get rid of the assignment of a new table to MountData inside of the function. Just call wipe(MountData) at the beginning of your function.

Shadowed 05-04-10 01:01 AM

Quote:

Originally Posted by Torhal (Post 187023)
Get rid of the assignment of a new table to MountData inside of the function. Just call wipe(MountData) at the beginning of your function.

That isn't what is causing the garbage, it's due to creating a new table for every mount. Because you never actually lose a mount, you can do this pretty easily, where you just reuse the table and only add new data when necessary. Change it to something like this:

lua Code:
  1. local MountData = {}
  2. local function UpdateMountData()
  3.     local creatureName, spellID, icon, active
  4.     local speed, mountType, numPassengers, isUsable, varies
  5.     local notes
  6.    
  7.     for i=1, GetNumCompanions("MOUNT") do
  8.         notes = ""
  9.         _, creatureName, spellID, icon, active = GetCompanionInfo("MOUNT", i)
  10.         -- GetExtraCompanionData is my function that does the tooltip scanning and such
  11.         speed, mountType, numPassengers, isUsable, varies = unpack(GetExtraCompanionData("MOUNT", spellID),1,5)
  12.        
  13.         if numPassengers > 0 then
  14.             -- NOTE: addLine is just a utility function to insert newlines as appropriate
  15.             notes = addLine(notes, format(L["Passengers: %d"], numPassengers))
  16.         end
  17.        
  18.         if varies then
  19.             notes = addLine(notes, L["Varies"])
  20.         end
  21.        
  22.         if not strfind(notes, "\n") then
  23.             if mountType == MOUNTTYPE_LAND then
  24.                 notes = addLine(notes, L["Ground"])
  25.             elseif mountType == MOUNTTYPE_FLYING then
  26.                 notes = addLine(notes, L["Flying"])
  27.             elseif mountType == MOUNTTYPE_AQUATIC then
  28.                 notes = addLine(notes, L["Aquatic"])
  29.             end
  30.         end
  31.         mount = MountData[spellID] or {NAME = creatureName, NOTES = notes, SPEED = speed, ICON = icon, ACTIVE = active, ISUSABLE = isUsable, ID = i}
  32.         mount.active = active
  33.         MountData[spellID] = mount
  34.         tinsert(MountData, mount)
  35.     end
  36. end

That way you're only creating a new table if you see a new mount, the only thing to keep in mind with this method is you can't do for id, mount in pairs(MountData) for looping without getting extra data, you want to do for id=1, #(MountData) do local mount = MountData[id] end.

corveroth 05-04-10 01:03 AM

Quote:

Originally Posted by Torhal (Post 187023)
Get rid of the assignment of a new table to MountData inside of the function. Just call wipe(MountData) at the beginning of your function.

I'd had it that way for a while; changing it back, there's no appreciable difference in the rate of memory growth.

corveroth 05-04-10 01:06 AM

Quote:

Originally Posted by Shadowed (Post 187025)
That way you're only creating a new table if you see a new mount

Unfortunately, that reasoning is fallacious. For many mounts, that's true, and the only piece of data that needs to be changed is the active state. However, there are now a number of variable-speed or -type mounts in game which must be rechecked every time the event fires.

EDIT: Hold on. Pause. Your changes make sense; let me edit them as appropriate and see how that goes.

Torhal 05-04-10 01:15 AM

Quote:

Originally Posted by Shadowed (Post 187025)
That isn't what is causing the garbage, it's due to creating a new table for every mount.

Ah. That's what I get for spouting off after merely glancing :)

corveroth 05-04-10 01:20 AM

Many thanks, Shadowed. That change, with a couple of tweaks, has cut growth by an order of magnitude, and I think I can find the rest in cleanup. Thank you greatly. :)

Shadowed 05-04-10 01:28 AM

Quote:

Originally Posted by corveroth (Post 187027)
Unfortunately, that reasoning is fallacious. For many mounts, that's true, and the only piece of data that needs to be changed is the active state. However, there are now a number of variable-speed or -type mounts in game which must be rechecked every time the event fires.

EDIT: Hold on. Pause. Your changes make sense; let me edit them as appropriate and see how that goes.

Ah, yea in that case you'll want to just update the notes or whatnot on update. The companion events fire semi-frequently from what I can recall, so you might also want to bucket them every 0.5-1 seconds.

Quote:

Originally Posted by Torhal (Post 187029)
Ah. That's what I get for spouting off after merely glancing :)

Yea I was a bit puzzled how a single table was making 80KB of garbage for a minute!

corveroth 05-04-10 01:32 AM

Quote:

Originally Posted by Shadowed (Post 187031)
The companion events fire semi-frequently from what I can recall, so you might also want to bucket them every 0.5-1 seconds

They're horribly unpredictable, really. If you're in Dalaran at prime time, you might see them that often, but if you're out questing, you'll hardly get any at all.

nightcracker 05-04-10 03:51 AM

The only situation in which you lose mounts is by Blizzard removing them and a faction change with faction-only mounts I think.


All times are GMT -6. The time now is 06:56 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI