From a4ce48ca388234684641c139bdcddeef1f2325fa Mon Sep 17 00:00:00 2001 From: Martin Ambrus Date: Mon, 20 Nov 2017 14:11:45 +0100 Subject: [PATCH] refactor: s1_vdata sometimes didn't get cached #313 --- GameEngine/Automation.php | 58 +++++++++++++++++++++++++++---- GameEngine/Database.php | 72 +++++++++++++++++++++++++++++++++++++-- GameEngine/Village.php | 31 ++++++++++++++--- 3 files changed, 147 insertions(+), 14 deletions(-) diff --git a/GameEngine/Automation.php b/GameEngine/Automation.php index 9198c321..3fac173c 100755 --- a/GameEngine/Automation.php +++ b/GameEngine/Automation.php @@ -249,8 +249,7 @@ class Automation { fclose($ourFileHandle); global $database; $array = array(); - $q = "SELECT wref, loyalty, lastupdate2 FROM ".TB_PREFIX."vdata WHERE loyalty < 100"; - $array = $database->query_return($q); + $array = $database->getProfileVillages(0, 6); if(!empty($array)) { foreach($array as $loyalty) { if (($t25_level = $this->getTypeLevel(25, $loyalty['wref'])) >= 1) { @@ -613,7 +612,14 @@ class Automation { timestamp < $time and master = 0" ); - // complete each of them + // preload village data + $vilIDs = []; + foreach($res as $indi) { + $vilIDs[$indi['wid']] = true; + } + $database->getProfileVillages(array_keys($vilIDs), 5); + + // complete buildings foreach($res as $indi) { // store village ID for later for statistical updates $villageData = $database->getVillageFields($indi['wid'],'owner, maxcrop, maxstore, starv, pop'); @@ -1207,6 +1213,15 @@ class Automation { $data_num = 0; if ($dataarray && count($dataarray)) { + // preload village data + $vilIDs = []; + foreach($dataarray as $data) { + $vilIDs[$data['from']] = true; + $vilIDs[$data['to']] = true; + } + $database->getProfileVillages(array_keys($vilIDs), 5); + + // calculate battles foreach($dataarray as $data) { //set base things $isoasis = $data['oasistype']; @@ -3355,9 +3370,16 @@ class Automation { $dataarray = $database->query_return($q); if ($dataarray && count($dataarray)) { + // preload village data + $vilIDs = []; + foreach($dataarray as $data) { + $vilIDs[$data['from']] = true; + $vilIDs[$data['to']] = true; + } + $database->getProfileVillages(array_keys($vilIDs), 5); + // calculate reinforcements data $movementProcIDs = []; - foreach($dataarray as $data) { $isoasis = $database->isVillageOases($data['to']); if($isoasis == 0){ @@ -3536,6 +3558,14 @@ class Automation { if ($dataarray && count($dataarray)) { + // preload village data + $vilIDs = []; + foreach($dataarray as $data) { + $vilIDs[$data['from']] = true; + $vilIDs[$data['to']] = true; + } + $database->getProfileVillages(array_keys($vilIDs), 5); + $movementProcIDs = []; foreach($dataarray as $data) { if (!isset($wavesData[$data['from'].$data['to'].$data['starttime'].$data['endtime']])) { @@ -3656,6 +3686,14 @@ class Automation { $times = []; $endtimes = []; + // preload village data + $vilIDs = []; + foreach($dataarray as $data) { + $vilIDs[$data['from']] = true; + $vilIDs[$data['to']] = true; + } + $database->getProfileVillages(array_keys($vilIDs), 5); + foreach($dataarray as $data) { $ownerID = $database->getUserField($database->getVillageField($data['from'],"owner"),"id",0); if ($session->uid==$ownerID) $reload=true; @@ -4217,6 +4255,14 @@ class Automation { fclose($ourFileHandle); $trainlist = $database->getTrainingList(); if(count($trainlist) > 0){ + // preload village data + $vilIDs = []; + foreach($trainlist as $train){ + $vilIDs[$train['vref']] = true; + } + $database->getProfileVillages(array_keys($vilIDs), 5); + + // calculate training updates foreach($trainlist as $train){ $timepast = $train['timestamp2'] - $time; $pop = $train['pop']; @@ -4240,9 +4286,9 @@ class Automation { if($train['amt'] == 0){ $database->trainUnit($train['id'],0,0,0,0,1,1); } - $crop = $database->getCropProdstarv($train['vref'], false); + $crop = $database->getCropProdstarv($train['vref']); $unitarrays = $this->getAllUnits($train['vref'], false); - $village = $database->getVillage($train['vref'], 0, false); + $village = $database->getVillage($train['vref'], 0); $upkeep = $village['pop'] + $this->getUpkeep($unitarrays, 0); $starv = $database->getVillageField($train['vref'],"starv"); if ($crop < $upkeep){ diff --git a/GameEngine/Database.php b/GameEngine/Database.php index 7ad2dcbf..965538e3 100755 --- a/GameEngine/Database.php +++ b/GameEngine/Database.php @@ -680,7 +680,7 @@ class MYSQLi_DB implements IDbConnection { * to be displayed in the front-end. */ public static function clearVillageCache() { - self::$villageFieldsCache = []; + self::$villageFieldsCache = []; self::$villageFieldsCacheByWorldID = []; } @@ -1688,7 +1688,7 @@ class MYSQLi_DB implements IDbConnection { function getVillage($vid, $mode = 0, $use_cache = true) { // first of all, check if we should be using cache and whether the field // required is already cached - if ($use_cache && ($cachedValue = self::returnCachedContent(self::$villageFieldsCache, $vid.$mode)) && !is_null($cachedValue)) { + if ($use_cache && ($cachedValue = self::returnCachedContent(self::$villageFieldsCache, ((int) $vid).$mode)) && !is_null($cachedValue)) { return $cachedValue; } @@ -1749,6 +1749,17 @@ class MYSQLi_DB implements IDbConnection { return $cachedValue; } + // if we've given a number of villages to preload, remove those that already are + if ($use_cache && $arrayPassed) { + $newIDs = []; + foreach ($uid as $id) { + if (!isset(self::$userVillagesCache[$id])) { + $newIDs[] = $id; + } + } + $uid = $newIDs; + } + switch ($mode) { // by owner ID case 0: $q = "SELECT * FROM " . TB_PREFIX . "vdata WHERE owner IN(".implode(', ', $uid).") ORDER BY capital DESC,pop DESC"; @@ -1769,6 +1780,14 @@ class MYSQLi_DB implements IDbConnection { // villages in need of celebration data update case 4: $q = "SELECT * FROM " . TB_PREFIX . "vdata WHERE celebration < ".$uid[0]." AND celebration != 0"; break; + + // by vref ID + case 5: $q = "SELECT * FROM " . TB_PREFIX . "vdata WHERE wref IN(".implode(', ', $uid).")"; + break; + + // by loyalty updates required + case 6: $q = "SELECT * FROM " . TB_PREFIX . "vdata WHERE loyalty < 100"; + break; } $result = mysqli_query($this->dblink,$q); @@ -1776,15 +1795,23 @@ class MYSQLi_DB implements IDbConnection { if (!$arrayPassed) { $result = $this->mysqli_fetch_all($result); self::$userVillagesCache[ $uid[0] ] = $result; + + // cache each village individually into the fields cache as well + foreach ($result as $v) { + $amode = 0; + self::$villageFieldsCache[((int) $v['wref']).$amode] = $v; + } } else { // we're preloading, cache all the data individually if (mysqli_num_rows($result)) { + $amode = 0; while ( $row = mysqli_fetch_array( $result, MYSQLI_ASSOC ) ) { if ( ! isset( self::$userVillagesCache[ $row['owner'] ] ) ) { self::$userVillagesCache[ $row['owner'] ] = []; } self::$userVillagesCache[ $row['owner'] ][] = $row; + self::$villageFieldsCache[((int) $row['wref']).$amode] = $row; } // just return the full cache if we've given an array of IDs to load villages for @@ -1795,6 +1822,39 @@ class MYSQLi_DB implements IDbConnection { return $result; } + function cacheVillageByWorldIDs($uid, $mode = 0) { + if (!is_array($uid)) { + $uid = [(int) $uid]; + } else { + foreach ($uid as $index => $uidValue) { + $uid[$index] = (int) $uidValue; + } + } + + $result = mysqli_query($this->dblink, " + SELECT + * + FROM + " . TB_PREFIX . "wdata as wdata + LEFT JOIN " . TB_PREFIX . "vdata as vdata ON wdata.id = vdata.wref + WHERE vdata.owner IN(".implode('', $uid).")" + ); + + if (mysqli_num_rows($result)) { + $result = $this->mysqli_fetch_all($result); + + $amode = 0; + foreach ($result as $row) { + self::$villageFieldsCacheByWorldID[$row['id']] = $row; + + // cache village fields by wref as well, for future use + if (!isset(self::$villageFieldsCache[((int) $row['wref']).$amode])) { + self::$villageFieldsCache[ ( (int) $row['wref'] ) . $amode ] = $row; + } + } + } + } + function getVillageByWorldID($vid, $use_cache = true) { $vid = (int) $vid; @@ -2313,6 +2373,12 @@ class MYSQLi_DB implements IDbConnection { function checkVilExist($wref) { list($wref) = $this->escape_input((int) $wref); + // first of all, check if this exists in our cache already - and if so, we don't need an extra query + $mode = 0; + if (isset(self::$villageFieldsCache[((int) $wref).$mode])) { + return true; + } + $q = "SELECT Count(*) as Total FROM " . TB_PREFIX . "vdata where wref = '$wref'"; $result = mysqli_fetch_array(mysqli_query($this->dblink,$q), MYSQLI_ASSOC); if ($result['Total']) { @@ -5961,7 +6027,7 @@ References: User ID/Message ID, Mode $vinfo = $this->getVillage($id); $vtribe = $this->getUserField($vinfo['owner'], "tribe", 0); - $movingunits = array(); + $movingunits = array(); $outgoingarray = $this->getMovement(3, $id, 0); if(!empty($outgoingarray)) { foreach($outgoingarray as $out) { diff --git a/GameEngine/Village.php b/GameEngine/Village.php index 11ac577a..edbfd92b 100755 --- a/GameEngine/Village.php +++ b/GameEngine/Village.php @@ -35,6 +35,9 @@ class Village { else { $this->wid = $session->villages[0]; } + + $this->preloadVillagesData(); + //add new line code //check exist village if from village destroy to avoid error msg. if ( !$database->checkVilExist($this->wid) ) { @@ -48,6 +51,16 @@ class Village { $this->ActionControl(); } + private function preloadVillagesData() { + global $database, $session; + + // preload villages for this user account + $database->getProfileVillages($session->uid, 5); + + // preload villages world data records + $database->cacheVillageByWorldIDs($session->uid); + } + public function getProd($type) { return $this->production[$type]; } @@ -57,7 +70,7 @@ class Village { return $technology->getUnits($database->getUnit($vid),$database->getEnforceVillage($vid,0)); } - private function LoadTown() { + private function LoadTown($second_run = false) { global $database,$session,$logging,$technology; $this->infoarray = $database->getVillage($this->wid); if($this->infoarray['owner'] != $session->uid && !$session->isAdmin) { @@ -102,16 +115,24 @@ class Village { if($this->airon>$this->maxstore){ $this->airon=$this->maxstore; $resourceUpdates['iron'] = $this->maxstore; } if($this->acrop>$this->maxcrop){ $this->acrop=$this->maxcrop; $resourceUpdates['crop'] = $this->maxcrop; } - // update DB values - if (count($resourceUpdates)) { - call_user_func(get_class($database).'::clearVillageCache'); + if (count($resourceUpdates)) { $database->updateResource( $this->wid, array_keys( $resourceUpdates ), array_values($resourceUpdates) ); + + // reload cache if we've updated resources and the like + if ($second_run) { + // update DB cache + call_user_func(get_class($database).'::clearVillageCache'); + $this->preloadVillagesData(); + } + } else if ($second_run) { + $this->preloadVillagesData(); } } private function calculateProduction() { global $technology,$database,$session; + // clear cache, since we're updating village data call_user_func(get_class($database).'::clearVillageCache'); $normalA = $database->getOwnArtefactInfoByType($_SESSION['wid'],4); $largeA = $database->getOwnUniqueArtefactInfo($session->uid,4,2); @@ -145,7 +166,7 @@ class Village { $database->modifyResource($this->wid,$nwood,$nclay,$niron,$ncrop,1); $database->updateVillage($this->wid); - $this->LoadTown(); + $this->LoadTown(true); } private function getWoodProd() {