X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Fiomaster.php;h=7072761f2d2a03be6f34e5a66aae6eb445826044;hb=refs%2Fheads%2Fupstream-changes%2Fgoogle-analytics-removal;hp=979f73e75381800ad67aaf4e3c3685cc3d7af4d1;hpb=bd72e8b96e1bc360ba46a1864c6121f3b5f11235;p=quix0rs-gnu-social.git diff --git a/lib/iomaster.php b/lib/iomaster.php index 979f73e753..7072761f2d 100644 --- a/lib/iomaster.php +++ b/lib/iomaster.php @@ -27,18 +27,20 @@ * @link http://status.net/ */ -class IoMaster +abstract class IoMaster { public $id; protected $multiSite = false; - protected $includeGlobalSingletons = true; protected $managers = array(); protected $singletons = array(); protected $pollTimeouts = array(); protected $lastPoll = array(); + public $shutdown = false; // Did we do a graceful shutdown? + public $respawn = true; // Should we respawn after shutdown? + /** * @param string $id process ID to use in logging/monitoring */ @@ -48,105 +50,53 @@ class IoMaster $this->monitor = new QueueMonitor(); } - public function init($multiSite=null, $includeGlobalSingletons = true) + public function init($multiSite=null) { - $this->includeGlobalSingletons = $includeGlobalSingletons; if ($multiSite !== null) { $this->multiSite = $multiSite; } - if ($this->multiSite) { - $this->sites = $this->findAllSites(); - } else { - $this->sites = array(common_config('site', 'server')); - } - - if (empty($this->sites)) { - throw new Exception("Empty status_network table, cannot init"); - } - - foreach ($this->sites as $site) { - if ($site != common_config('site', 'server')) { - StatusNet::init($site); - } - - $classes = array(); - if (Event::handle('StartIoManagerClasses', array(&$classes))) { - $classes[] = 'QueueManager'; - if (common_config('xmpp', 'enabled') && !defined('XMPP_EMERGENCY_FLAG')) { - $classes[] = 'XmppManager'; // handles pings/reconnects - $classes[] = 'XmppConfirmManager'; // polls for outgoing confirmations - } - } - Event::handle('EndIoManagerClasses', array(&$classes)); - foreach ($classes as $class) { - $this->instantiate($class); - } - } + $this->initManagers(); } /** - * Pull all local sites from status_network table. - * @return array of hostnames + * Initialize IoManagers which are appropriate to this instance; + * pass class names or instances into $this->instantiate(). + * + * If setup and configuration may vary between sites in multi-site + * mode, it's the subclass's responsibility to set them up here. + * + * Switching site configurations is an acceptable side effect. */ - protected function findAllSites() - { - $hosts = array(); - $sn = new Status_network(); - $sn->find(); - while ($sn->fetch()) { - $hosts[] = $sn->hostname; - } - return $hosts; - } + abstract function initManagers(); /** * Instantiate an i/o manager class for the current site. * If a multi-site capable handler is already present, * we don't need to build a new one. * - * @param string $class + * @param mixed $manager class name (to run $class::get()) or object */ - protected function instantiate($class) + protected function instantiate($manager) { - if (is_string($class) && isset($this->singletons[$class])) { - // Already instantiated a multi-site-capable handler. - // Just let it know it should listen to this site too! - $this->singletons[$class]->addSite(common_config('site', 'server')); - return; + if (is_string($manager)) { + $manager = call_user_func(array($class, 'get')); } - $manager = $this->getManager($class); - $caps = $manager->multiSite(); - if ($this->multiSite) { - if ($caps == IoManager::SINGLE_ONLY) { + if ($caps == IoManager::SINGLE_ONLY) { + if ($this->multiSite) { throw new Exception("$class can't run with --all; aborting."); } - if ($caps == IoManager::INSTANCE_PER_PROCESS || - ( $this->includeGlobalSingletons && $caps == IoManager::GLOBAL_SINGLE_ONLY )) { - // Save this guy for later! - // We'll only need the one to cover multiple sites. - if (is_string($class)){ - $this->singletons[$class] = $manager; - } - $manager->addSite(common_config('site', 'server')); - } + } else if ($caps == IoManager::INSTANCE_PER_PROCESS) { + $manager->addSite(); } - if( $this->includeGlobalSingletons || $caps != IoManager::GLOBAL_SINGLE_ONLY ) { + if (!in_array($manager, $this->managers, true)) { + // Only need to save singletons once $this->managers[] = $manager; } } - - protected function getManager($class) - { - if(is_object($class)){ - return $class; - }else{ - return call_user_func(array($class, 'get')); - } - } /** * Basic run loop... @@ -159,8 +109,9 @@ class IoMaster { $this->logState('init'); $this->start(); + $this->checkMemory(false); - while (true) { + while (!$this->shutdown) { $timeouts = array_values($this->pollTimeouts); $timeouts[] = 60; // default max timeout @@ -181,7 +132,7 @@ class IoMaster $write = array(); $except = array(); $this->logState('listening'); - common_log(LOG_INFO, "Waiting up to $timeout seconds for socket data..."); + //common_debug("Waiting up to $timeout seconds for socket data..."); $ready = stream_select($read, $write, $except, $timeout, 0); if ($ready === false) { @@ -201,7 +152,7 @@ class IoMaster if ($timeout > 0 && empty($sockets)) { // If we had no listeners, sleep until the pollers' next requested wakeup. - common_log(LOG_INFO, "Sleeping $timeout seconds until next poll cycle..."); + common_log(LOG_DEBUG, "Sleeping $timeout seconds until next poll cycle..."); $this->logState('sleep'); sleep($timeout); } @@ -212,20 +163,38 @@ class IoMaster $this->logState('idle'); $this->idle(); - $memoryLimit = $this->softMemoryLimit(); - if ($memoryLimit > 0) { - $usage = memory_get_usage(); - if ($usage > $memoryLimit) { - common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting."); - break; - } - } + $this->checkMemory(); } $this->logState('shutdown'); $this->finish(); } + /** + * Check runtime memory usage, possibly triggering a graceful shutdown + * and thread respawn if we've crossed the soft limit. + * + * @param boolean $respawn if false we'll shut down instead of respawning + */ + protected function checkMemory($respawn=true) + { + $memoryLimit = $this->softMemoryLimit(); + if ($memoryLimit > 0) { + $usage = memory_get_usage(); + if ($usage > $memoryLimit) { + common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting."); + if ($respawn) { + $this->requestRestart(); + } else { + $this->requestShutdown(); + } + } else if (common_config('queue', 'debug_memory')) { + $fmt = number_format($usage); + common_log(LOG_DEBUG, "Memory usage $fmt"); + } + } + } + /** * Return fully-parsed soft memory limit in bytes. * @return intval 0 or -1 if not set @@ -234,8 +203,7 @@ class IoMaster { $softLimit = trim(common_config('queue', 'softlimit')); if (substr($softLimit, -1) == '%') { - $limit = trim(ini_get('memory_limit')); - $limit = $this->parseMemoryLimit($limit); + $limit = $this->parseMemoryLimit(ini_get('memory_limit')); if ($limit > 0) { return intval(substr($softLimit, 0, -1) * $limit / 100); } else { @@ -253,9 +221,10 @@ class IoMaster * @param string $mem * @return int */ - protected function parseMemoryLimit($mem) + public function parseMemoryLimit($mem) { // http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes + $mem = strtolower(trim($mem)); $size = array('k' => 1024, 'm' => 1024*1024, 'g' => 1024*1024*1024); @@ -264,7 +233,7 @@ class IoMaster } else if (is_numeric($mem)) { return intval($mem); } else { - $mult = strtolower(substr($mem, -1)); + $mult = substr($mem, -1); if (isset($size[$mult])) { return substr($mem, 0, -1) * $size[$mult]; } else { @@ -361,12 +330,31 @@ class IoMaster * for per-queue and per-site records. * * @param string $key counter name - * @param array $owners list of owner keys like 'queue:jabber' or 'site:stat01' + * @param array $owners list of owner keys like 'queue:xmpp' or 'site:stat01' */ public function stats($key, $owners=array()) { $owners[] = "thread:" . $this->id; $this->monitor->stats($key, $owners); } + + /** + * For IoManagers to request a graceful shutdown at end of event loop. + */ + public function requestShutdown() + { + $this->shutdown = true; + $this->respawn = false; + } + + /** + * For IoManagers to request a graceful restart at end of event loop. + */ + public function requestRestart() + { + $this->shutdown = true; + $this->respawn = true; + } + }