From abbf76b7b1782d6484519fa3e2d308981560b59e Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Thu, 26 Feb 2009 06:02:32 +0000 Subject: [PATCH] * Refactored the forking code from runJobs.php to a new class called ForkController. Implemented the same sort of forking in gearmanWorker.php. * Fixed debugging code left in in gearmanRefreshLinks.php --- includes/AutoLoader.php | 1 + includes/ForkController.php | 103 ++++++++++++++++++++ maintenance/gearman/gearmanRefreshLinks.php | 3 +- maintenance/gearman/gearmanWorker.php | 15 ++- maintenance/runJobs.php | 57 +---------- 5 files changed, 122 insertions(+), 57 deletions(-) create mode 100644 includes/ForkController.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 5438ff248a..9d310b1fff 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -75,6 +75,7 @@ $wgAutoloadLocalClasses = array( 'FileDependency' => 'includes/CacheDependency.php', 'FileRevertForm' => 'includes/FileRevertForm.php', 'FileStore' => 'includes/FileStore.php', + 'ForkController' => 'includes/ForkController.php', 'FormatExif' => 'includes/Exif.php', 'FormOptions' => 'includes/FormOptions.php', 'FSException' => 'includes/FileStore.php', diff --git a/includes/ForkController.php b/includes/ForkController.php new file mode 100644 index 0000000000..689b9c8de2 --- /dev/null +++ b/includes/ForkController.php @@ -0,0 +1,103 @@ +destroyInstance(); + $wgCaches = array(); + unset( $wgMemc ); + } + + /** + * Fork a number of worker processes. + * + * This should only be called from the command line. It should be called + * as early as possible during execution. It will return 'child' in the + * child processes and 'parent' in the parent process. The parent process + * should then call monitor(). + * + * This function requires the posix and pcntl extensions. + */ + public function forkWorkers( $numProcs ) { + global $wgMemc, $wgCaches, $wgMainCacheType; + + $this->prepareEnvironment(); + + // Create the child processes + for ( $i = 0; $i < $numProcs; $i++ ) { + // Do the fork + $pid = pcntl_fork(); + if ( $pid === -1 || $pid === false ) { + echo "Error creating child processes\n"; + exit( 1 ); + } + + if ( !$pid ) { + $this->initChild(); + $this->children = null; + return 'child'; + } else { + // This is the parent process + $this->children[$pid] = true; + } + } + + return 'parent'; + } + + /** + * The parent process main loop + */ + public function runParent() { + // Trap SIGTERM + pcntl_signal( SIGTERM, array( $this, 'handleTermSignal' ), false ); + + do { + $status = false; + $deadPid = pcntl_wait( $status ); + + if ( $deadPid > 0 ) { + unset( $this->children[$deadPid] ); + } + + // Run signal handlers + if ( function_exists( 'pcntl_signal_dispatch' ) ) { + pcntl_signal_dispatch(); + } else { + declare (ticks=1) { $status = $status; } + } + // Respond to TERM signal + if ( $this->termReceived ) { + foreach ( $this->children as $childPid => $unused ) { + posix_kill( $childPid, SIGTERM ); + } + $this->termReceived = false; + } + } while ( count( $this->children ) ); + pcntl_signal( SIGTERM, SIG_DFL ); + } + + protected function initChild() { + global $wgMemc, $wgMainCacheType; + $wgMemc = wfGetCache( $wgMainCacheType ); + } + + protected function handleTermSignal( $signal ) { + $this->termReceived = true; + } +} diff --git a/maintenance/gearman/gearmanRefreshLinks.php b/maintenance/gearman/gearmanRefreshLinks.php index dc11fb4650..7f93ecafc6 100644 --- a/maintenance/gearman/gearmanRefreshLinks.php +++ b/maintenance/gearman/gearmanRefreshLinks.php @@ -11,8 +11,7 @@ if ( !$args ) { $client = new Net_Gearman_Client( $args ); $dbr = wfGetDB( DB_SLAVE ); -$res = $dbr->select( 'page', array( 'page_namespace', 'page_title' ), false, - __METHOD__, array( 'LIMIT' => 2 ) ); +$res = $dbr->select( 'page', array( 'page_namespace', 'page_title' ), false, __METHOD__ ); foreach ( $res as $row ) { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); $params = array( diff --git a/maintenance/gearman/gearmanWorker.php b/maintenance/gearman/gearmanWorker.php index 1e2f384c33..711ec4aa64 100644 --- a/maintenance/gearman/gearmanWorker.php +++ b/maintenance/gearman/gearmanWorker.php @@ -1,9 +1,22 @@ 1000 ) { + echo "Invalid number of processes, please specify a number between 1 and 1000\n"; + exit( 1 ); + } + $fc = new ForkController; + if ( $fc->forkWorkers( $procs ) == 'parent' ) { + $fc->runParent(); + exit( 0 ); + } +} + if ( !$args ) { $args = array( 'localhost' ); } diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php index 68efb74914..63dddeba1e 100644 --- a/maintenance/runJobs.php +++ b/maintenance/runJobs.php @@ -20,59 +20,11 @@ if ( isset( $options['procs'] ) ) { echo "Invalid argument to --procs\n"; exit( 1 ); } - - // Don't share DB or memcached connections - $lb = wfGetLB(); - $lb->closeAll(); - $wgCaches = array(); - unset( $wgMemc ); - - // Create the child processes - $children = array(); - for ( $childId = 0; $childId < $procs; $childId++ ) { - $pid = pcntl_fork(); - if ( $pid === -1 || $pid === false ) { - echo "Error creating child processes\n"; - exit( 1 ); - } - if ( !$pid ) { - break; - } - - $children[$pid] = true; - } - if ( $pid ) { - // Parent process - // Trap SIGTERM - pcntl_signal( SIGTERM, 'handleTermSignal', false ); - // Wait for a child to exit - $status = false; - $termReceived = false; - do { - $deadPid = pcntl_wait( $status ); - // Run signal handlers - if ( function_exists( 'pcntl_signal_dispatch' ) ) { - pcntl_signal_dispatch(); - } else { - declare (ticks=1) { $status = $status; } - } - if ( $deadPid > 0 ) { - unset( $children[$deadPid] ); - } - // Respond to TERM signal - if ( $termReceived ) { - foreach ( $children as $childPid => $unused ) { - posix_kill( $childPid, SIGTERM ); - } - $termReceived = false; - } - } while ( count( $children ) ); - // All done + $fc = new ForkController; + if ( $fc->forkWorkers( $procs ) == 'parent' ) { + $fc->runParent(); exit( 0 ); } - - // Set up this child - $wgMemc = wfGetCache( $wgMainCacheType ); } if ( isset( $options['maxjobs'] ) ) { @@ -126,7 +78,4 @@ function runJobsLog( $msg ) { wfDebugLog( 'runJobs', $msg ); } -function handleTermSignal( $signal ) { - $GLOBALS['termReceived'] = true; -} -- 2.20.1