Skip to content

Commit

Permalink
Reduced #repop time dramatically by taking down hundreds of individua…
Browse files Browse the repository at this point in the history
…l SELECT/DELETE/INSERT queries in routines and bringing it down to very few

	See: https://www.youtube.com/watch?v=9kSFbyTBuAk
  • Loading branch information
Akkadius committed Feb 8, 2015
1 parent 1149f04 commit cb81d95
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 43 deletions.
4 changes: 4 additions & 0 deletions 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
Expand Down
4 changes: 2 additions & 2 deletions zone/questmgr.cpp
Expand Up @@ -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());
Expand Down Expand Up @@ -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<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
while (iterator.MoreElements())
Expand Down
109 changes: 84 additions & 25 deletions zone/spawn2.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -348,36 +345,100 @@ 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
}
}

bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {

std::unordered_map<uint32, uint32> 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;

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]));
}

spawn2_list.Insert(newSpawn);
}
for (auto row = results.begin(); row != results.end(); ++row) {

uint32 spawn_time_left = 0;
Spawn2* new_spawn = 0;
bool perl_enabled = atoi(row[11]) == 1 ? true : false;

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;
}
Expand Down Expand Up @@ -427,8 +488,6 @@ bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* z
if (results.RowsAffected() != 1)
return false;

if(client)

return true;
}

Expand Down
3 changes: 3 additions & 0 deletions zone/zone.cpp
Expand Up @@ -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());
Expand Down
42 changes: 27 additions & 15 deletions zone/zonedb.cpp
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion zone/zonedb.h
Expand Up @@ -365,7 +365,7 @@ class ZoneDatabase : public SharedDatabase {
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
Spawn2* LoadSpawn2(LinkedList<Spawn2*> &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);

Expand Down

0 comments on commit cb81d95

Please sign in to comment.