Core/InstanceSaveMgr: Optimize instance packing and cleaning up

--HG--
branch : trunk
This commit is contained in:
linencloth
2010-12-18 23:43:44 +01:00
parent 454444a1af
commit a8214a682a
3 changed files with 33 additions and 110 deletions
+30 -103
View File
@@ -246,120 +246,47 @@ void InstanceSaveManager::_DelHelper(const char *fields, const char *table, cons
}
}
void InstanceSaveManager::CleanupInstances()
void InstanceSaveManager::CleanupAndPackInstances()
{
barGoLink bar(2);
bar.step();
// load reset times and clean expired instances
sInstanceSaveMgr.LoadResetTimes();
// clean character/group - instance binds with invalid group/characters
_DelHelper("character_instance.guid, instance", "character_instance", "LEFT JOIN characters ON character_instance.guid = characters.guid WHERE characters.guid IS NULL");
_DelHelper("group_instance.guid, instance", "group_instance", "LEFT JOIN groups ON group_instance.guid = groups.guid LEFT JOIN characters ON groups.leaderGuid = characters.guid WHERE characters.guid IS NULL OR groups.guid IS NULL");
// Delete invalid character_instance and group_instance references
CharacterDatabase.DirectExecute("DELETE ci.* FROM character_instance AS ci LEFT JOIN characters AS c ON ci.guid = c.guid WHERE c.guid IS NULL");
CharacterDatabase.DirectExecute("DELETE gi.* FROM group_instance AS gi LEFT JOIN groups AS g ON gi.guid = g.guid WHERE g.guid IS NULL");
// clean instances that do not have any players or groups bound to them
_DelHelper("id, map, difficulty", "instance", "LEFT JOIN character_instance ON character_instance.instance = id LEFT JOIN group_instance ON group_instance.instance = id WHERE character_instance.instance IS NULL AND group_instance.instance IS NULL");
// Delete invalid instance references
CharacterDatabase.DirectExecute("DELETE i.* FROM instance AS i LEFT JOIN character_instance AS ci ON i.id = ci.instance LEFT JOIN group_instance AS gi ON i.id = gi.instance WHERE ci.guid IS NULL AND gi.guid IS NULL");
// clean invalid instance references in other tables
_DelHelper("character_instance.guid, instance", "character_instance", "LEFT JOIN instance ON character_instance.instance = instance.id WHERE instance.id IS NULL");
_DelHelper("guid, instance", "group_instance", "LEFT JOIN instance ON group_instance.instance = instance.id WHERE instance.id IS NULL");
// Delete invalid references to instance
CharacterDatabase.DirectExecute("DELETE tmp.* FROM creature_respawn AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
CharacterDatabase.DirectExecute("DELETE tmp.* FROM gameobject_respawn AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
CharacterDatabase.DirectExecute("DELETE tmp.* FROM character_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
CharacterDatabase.DirectExecute("DELETE tmp.* FROM group_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
// Clean respawn data from non existing instances
CharacterDatabase.PExecute("DELETE FROM creature_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)");
CharacterDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)");
// Clean invalid references to instance
CharacterDatabase.DirectExecute("UPDATE corpse AS tmp LEFT JOIN instance ON tmp.instance = instance.id SET tmp.instance = 0 WHERE tmp.instance > 0 AND instance.id IS NULL");
CharacterDatabase.DirectExecute("UPDATE characters AS tmp LEFT JOIN instance ON tmp.instance_id = instance.id SET tmp.instance_id = 0 WHERE tmp.instance_id > 0 AND instance.id IS NULL");
// first, obtain total instance set
std::set<uint32> InstanceSet;
QueryResult result = CharacterDatabase.Query("SELECT id FROM instance");
if (result)
{
do
{
Field *fields = result->Fetch();
InstanceSet.insert(fields[0].GetUInt32());
}
while (result->NextRow());
}
// Create new index
CharacterDatabase.DirectExecute("ALTER TABLE instance ADD newid INT UNSIGNED AUTO_INCREMENT, ADD INDEX(newid)");
// characters
result = CharacterDatabase.Query("SELECT DISTINCT(instance_id) FROM characters WHERE instance_id <> 0");
if (result)
{
do
{
Field *fields = result->Fetch();
if (InstanceSet.find(fields[0].GetUInt32()) == InstanceSet.end())
CharacterDatabase.PExecute("UPDATE characters SET instance_id = '0' WHERE instance_id = '%u'", fields[0].GetUInt32());
}
while (result->NextRow());
}
// Update old ids
CharacterDatabase.DirectExecute("UPDATE corpse AS tmp LEFT JOIN instance ON tmp.instance = instance.id SET tmp.instance = instance.newid WHERE tmp.instance > 0");
CharacterDatabase.DirectExecute("UPDATE character_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id SET tmp.instance = instance.newid WHERE tmp.instance > 0");
CharacterDatabase.DirectExecute("UPDATE group_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id SET tmp.instance = instance.newid WHERE tmp.instance > 0");
CharacterDatabase.DirectExecute("UPDATE characters AS tmp LEFT JOIN instance ON tmp.instance_id = instance.id SET tmp.instance_id = instance.newid WHERE tmp.instance_id > 0");
CharacterDatabase.DirectExecute("UPDATE creature_respawn AS tmp LEFT JOIN instance ON tmp.instance = instance.id SET tmp.instance = instance.newid WHERE tmp.instance > 0");
CharacterDatabase.DirectExecute("UPDATE gameobject_respawn AS tmp LEFT JOIN instance ON tmp.instance = instance.id SET tmp.instance = instance.newid WHERE tmp.instance > 0");
// corpse
result = CharacterDatabase.Query("SELECT DISTINCT(instance) FROM corpse WHERE instance <> 0");
if (result)
{
do
{
Field *fields = result->Fetch();
if (InstanceSet.find(fields[0].GetUInt32()) == InstanceSet.end())
CharacterDatabase.PExecute("UPDATE corpse SET instance = '0' WHERE instance = '%u'", fields[0].GetUInt32());
}
while (result->NextRow());
}
// Update instance too
CharacterDatabase.Query("UPDATE instance SET id = newid");
bar.step();
sLog.outString();
sLog.outString(">> Initialized %u instances", (uint32)InstanceSet.size());
}
void InstanceSaveManager::PackInstances()
{
// this routine renumbers player instance associations in such a way so they start from 1 and go up
// TODO: this can be done a LOT more efficiently
// obtain set of all associations
std::set<uint32> InstanceSet;
// all valid ids are in the instance table
// any associations to ids not in this table are assumed to be
// cleaned already in CleanupInstances
QueryResult result = CharacterDatabase.Query("SELECT id FROM instance");
if (result)
{
do
{
Field *fields = result->Fetch();
InstanceSet.insert(fields[0].GetUInt32());
}
while (result->NextRow());
}
barGoLink bar(InstanceSet.size() + 1);
bar.step();
uint32 InstanceNumber = 1;
// we do assume std::set is sorted properly on integer value
for (std::set<uint32>::iterator i = InstanceSet.begin(); i != InstanceSet.end(); ++i)
{
if (*i != InstanceNumber)
{
// remap instance id
CharacterDatabase.PExecute("UPDATE creature_respawn SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE gameobject_respawn SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE characters SET instance_id = '%u' WHERE instance_id = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE corpse SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE character_instance SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE instance SET id = '%u' WHERE id = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i);
}
++InstanceNumber;
bar.step();
}
sLog.outString();
sLog.outString(">> Instance numbers remapped, next instance id is %u", InstanceNumber);
// Finally drop the no longer needed column
CharacterDatabase.Query("ALTER TABLE instance DROP COLUMN newid");
// Bake some cookies for click
sLog.outString(">> Cleaned up and packed instances");
}
void InstanceSaveManager::LoadResetTimes()