From cb81d956f62b75cf6cfbb7e5e9e328a24ea52d65 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 8 Feb 2015 05:01:58 -0600 Subject: [PATCH] Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few See: https://www.youtube.com/watch?v=9kSFbyTBuAk --- changelog.txt | 4 ++ zone/questmgr.cpp | 4 +- zone/spawn2.cpp | 105 ++++++++++++++++++++++++++++++++++++---------- zone/zone.cpp | 3 ++ zone/zonedb.cpp | 42 ++++++++++++------- zone/zonedb.h | 2 +- 6 files changed, 119 insertions(+), 41 deletions(-) diff --git a/changelog.txt b/changelog.txt index 65941f885..38b9d5719 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/06/2015 == +Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few + See: https://www.youtube.com/watch?v=9kSFbyTBuAk + == 02/06/2015 == Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const) Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 6c181bf1e..7dcb4e457 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -297,7 +297,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) } } - database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0); + database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), 0); found_spawn->SetCurrentNPCID(npcid); auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading()); @@ -2388,7 +2388,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime) { bool found = false; - database.UpdateSpawn2Timeleft(id, 0, (newTime/1000)); + database.UpdateRespawnTime(id, 0, (newTime/1000)); LinkedListIterator iterator(zone->spawn2_list); iterator.Reset(); while (iterator.MoreElements()) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index f3440f127..068774091 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -214,9 +214,6 @@ bool Spawn2::Process() { if(IsDespawned) return true; - if(spawn2_id) - database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0); - currentnpcid = npcid; NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3); @@ -348,7 +345,7 @@ void Spawn2::DeathReset(bool realdeath) //if we have a valid spawn id if(spawn2_id) { - database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), (cur/1000)); + database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), (cur/1000)); Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn reset by death, repop in %d ms", spawn2_id, timer.GetRemainingTime()); //store it to database too } @@ -356,28 +353,92 @@ void Spawn2::DeathReset(bool realdeath) bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay) { + std::unordered_map spawn_times; + + timeval tv; + gettimeofday(&tv, nullptr); + + std::string spawn_query = StringFormat( + "SELECT " + "respawn_times.id, " + "respawn_times.`start`, " + "respawn_times.duration " + "FROM " + "respawn_times " + "WHERE instance_id = %u", + zone->GetInstanceID() + ); + auto results = QueryDatabase(spawn_query); + for (auto row = results.begin(); row != results.end(); ++row) { + uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0; + uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0; + + /* Our current time was expired */ + if ((start_duration + end_duration) <= tv.tv_sec) { + spawn_times[atoi(row[0])] = 0; + } + /* We still have time left on this timer */ + else { + spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000; + } + } + const char *zone_name = database.GetZoneName(zoneid); - std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, " - "respawntime, variance, pathgrid, _condition, " - "cond_value, enabled, animation FROM spawn2 " - "WHERE zone = '%s' AND version = %u", - zone_name, version); - auto results = QueryDatabase(query); - if (!results.Success()) { + std::string query = StringFormat( + "SELECT " + "id, " + "spawngroupID, " + "x, " + "y, " + "z, " + "heading, " + "respawntime, " + "variance, " + "pathgrid, " + "_condition, " + "cond_value, " + "enabled, " + "animation " + "FROM " + "spawn2 " + "WHERE zone = '%s' AND version = %u", + zone_name, + version + ); + results = QueryDatabase(query); + + if (!results.Success()) { return false; - } + } - for (auto row = results.begin(); row != results.end(); ++row) { - Spawn2* newSpawn = 0; + for (auto row = results.begin(); row != results.end(); ++row) { - bool perl_enabled = atoi(row[11]) == 1? true: false; - uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000); - newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), - atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), - atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); + uint32 spawn_time_left = 0; + Spawn2* new_spawn = 0; + bool perl_enabled = atoi(row[11]) == 1 ? true : false; - spawn2_list.Insert(newSpawn); - } + if (spawn_times.count(atoi(row[0])) != 0) + spawn_time_left = spawn_times[atoi(row[0])]; + + new_spawn = new Spawn2( // + atoi(row[0]), // uint32 in_spawn2_id + atoi(row[1]), // uint32 spawngroup_id + atof(row[2]), // float in_x + atof(row[3]), // float in_y + atof(row[4]), // float in_z + atof(row[5]), // float in_heading + atoi(row[6]), // uint32 respawn + atoi(row[7]), // uint32 variance + spawn_time_left, // uint32 timeleft + atoi(row[8]), // uint32 grid + atoi(row[9]), // uint16 in_cond_id + atoi(row[10]), // int16 in_min_value + perl_enabled, // bool in_enabled + (EmuAppearance)atoi(row[12]) // EmuAppearance anim + ); + + spawn2_list.Insert(new_spawn); + } return true; } @@ -427,8 +488,6 @@ bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* z if (results.RowsAffected() != 1) return false; - if(client) - return true; } diff --git a/zone/zone.cpp b/zone/zone.cpp index 444e217da..e79a9f9af 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -931,6 +931,9 @@ bool Zone::Init(bool iStaticZone) { Log.Out(Logs::General, Logs::Error, "Loading World Objects failed. continuing."); } + Log.Out(Logs::General, Logs::Status, "Flushing old respawn timers..."); + database.QueryDatabase("DELETE FROM `respawn_times` WHERE (`start` + `duration`) < UNIX_TIMESTAMP(NOW())"); + //load up the zone's doors (prints inside) zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion()); zone->LoadBlockedSpells(zone->GetZoneID()); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index cfde2ff19..165282f3d 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -185,28 +185,40 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct return true; } -//updates or clears the respawn time in the database for the current spawn id -void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 timeleft) +void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint32 time_left) { + timeval tv; gettimeofday(&tv, nullptr); - uint32 cur = tv.tv_sec; + uint32 current_time = tv.tv_sec; - //if we pass timeleft as 0 that means we clear from respawn time - //otherwise we update with a REPLACE INTO - if(timeleft == 0) { - std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id); - auto results = QueryDatabase(query); - + /* If we pass timeleft as 0 that means we clear from respawn time + otherwise we update with a REPLACE INTO + */ + + if(time_left == 0) { + std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id); + QueryDatabase(query); return; } - std::string query = StringFormat("REPLACE INTO respawn_times (id, start, duration, instance_id) " - "VALUES (%lu, %lu, %lu, %lu)", - (unsigned long)id, (unsigned long)cur, - (unsigned long)timeleft, (unsigned long)instance_id); - auto results = QueryDatabase(query); - if (!results.Success()) + std::string query = StringFormat( + "REPLACE INTO `respawn_times` " + "(id, " + "start, " + "duration, " + "instance_id) " + "VALUES " + "(%u, " + "%u, " + "%u, " + "%u)", + spawn2_id, + current_time, + time_left, + instance_id + ); + QueryDatabase(query); return; } diff --git a/zone/zonedb.h b/zone/zonedb.h index 5e1a55248..70c732878 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -365,7 +365,7 @@ public: bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft); bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); - void UpdateSpawn2Timeleft(uint32 id, uint16 instance_id,uint32 timeleft); + void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft); uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id); void UpdateSpawn2Status(uint32 id, uint8 new_status);