* Refactored the forking code from runJobs.php to a new class called ForkController...
authorTim Starling <tstarling@users.mediawiki.org>
Thu, 26 Feb 2009 06:02:32 +0000 (06:02 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Thu, 26 Feb 2009 06:02:32 +0000 (06:02 +0000)
* Fixed debugging code left in in gearmanRefreshLinks.php

includes/AutoLoader.php
includes/ForkController.php [new file with mode: 0644]
maintenance/gearman/gearmanRefreshLinks.php
maintenance/gearman/gearmanWorker.php
maintenance/runJobs.php

index 5438ff2..9d310b1 100644 (file)
@@ -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 (file)
index 0000000..689b9c8
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * Class for managing forking command line scripts.
+ * Currently just does forking and process control, but it could easily be extended 
+ * to provide IPC and job dispatch.
+ */
+class ForkController {
+       var $children = array();
+       var $termReceived = false;
+
+       public function __construct() {
+               if ( php_sapi_name() != 'cli' ) {
+                       throw new MWException( "MultiProcess cannot be used from the web." );
+               }
+       }
+
+       protected function prepareEnvironment() {
+               global $wgCaches, $wgMemc;
+               // Don't share DB or memcached connections
+               wfGetLBFactory()->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;
+       }
+}
index dc11fb4..7f93eca 100644 (file)
@@ -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(
index 1e2f384..711ec4a 100644 (file)
@@ -1,9 +1,22 @@
 <?php
 
-$optionsWithArgs = array( 'fake-job' );
+$optionsWithArgs = array( 'fake-job', 'procs' );
 require( dirname(__FILE__).'/../commandLine.inc' );
 require( dirname(__FILE__).'/gearman.inc' );
 
+if ( isset( $options['procs'] ) ) {
+       $procs = $options['procs'];
+       if ( $procs < 1 || $procs > 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' );
 }
index 68efb74..63dddeb 100644 (file)
@@ -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;
-}