Merge "Remove unused 'XMPGetInfo' and 'XMPGetResults' hooks"
[lhc/web/wiklou.git] / includes / deferred / DeferredUpdates.php
index 2178281..082d435 100644 (file)
@@ -34,13 +34,17 @@ interface DeferrableUpdate {
 }
 
 /**
- * Class for managing the deferred updates.
+ * Class for managing the deferred updates
+ *
+ * Deferred updates can be run at the end of the request,
+ * after the HTTP response has been sent. In CLI mode, updates
+ * are only deferred until there is no local master DB transaction.
  *
  * @since 1.19
  */
 class DeferredUpdates {
        /**
-        * Store of updates to be deferred until the end of the request.
+        * @var array Updates to be deferred until the end of the request.
         */
        private static $updates = array();
 
@@ -49,7 +53,28 @@ class DeferredUpdates {
         * @param DeferrableUpdate $update Some object that implements doUpdate()
         */
        public static function addUpdate( DeferrableUpdate $update ) {
+               global $wgCommandLineMode;
+
                array_push( self::$updates, $update );
+
+               // CLI scripts may forget to periodically flush these updates,
+               // so try to handle that rather than OOMing and losing them.
+               // Try to run the updates as soon as there is no local transaction.
+               static $waitingOnTrx = false; // de-duplicate callback
+               if ( $wgCommandLineMode && !$waitingOnTrx ) {
+                       $lb = wfGetLB();
+                       $dbw = $lb->getAnyOpenConnection( $lb->getWriterIndex() );
+                       // Do the update as soon as there is no transaction
+                       if ( $dbw && $dbw->trxLevel() ) {
+                               $waitingOnTrx = true;
+                               $dbw->onTransactionIdle( function() use ( &$waitingOnTrx ) {
+                                       DeferredUpdates::doUpdates();
+                                       $waitingOnTrx = false;
+                               } );
+                       } else {
+                               self::doUpdates();
+                       }
+               }
        }
 
        /**
@@ -82,43 +107,31 @@ class DeferredUpdates {
        public static function doUpdates( $commit = '' ) {
                global $wgDeferredUpdateList;
 
-               wfProfileIn( __METHOD__ );
-
                $updates = array_merge( $wgDeferredUpdateList, self::$updates );
 
-               // No need to get master connections in case of empty updates array
-               if ( !count( $updates ) ) {
-                       wfProfileOut( __METHOD__ );
+               while ( count( $updates ) ) {
+                       self::clearPendingUpdates();
 
-                       return;
-               }
+                       /** @var DeferrableUpdate $update */
+                       foreach ( $updates as $update ) {
+                               try {
+                                       $update->doUpdate();
 
-               $dbw = false;
-               $doCommit = $commit == 'commit';
-               if ( $doCommit ) {
-                       $dbw = wfGetDB( DB_MASTER );
-               }
-
-               /** @var DeferrableUpdate $update */
-               foreach ( $updates as $update ) {
-                       try {
-                               $update->doUpdate();
-
-                               if ( $doCommit && $dbw->trxLevel() ) {
-                                       $dbw->commit( __METHOD__, 'flush' );
-                               }
-                       } catch ( MWException $e ) {
-                               // We don't want exceptions thrown during deferred updates to
-                               // be reported to the user since the output is already sent.
-                               // Instead we just log them.
-                               if ( !$e instanceof ErrorPageError ) {
-                                       MWExceptionHandler::logException( $e );
+                                       if ( $commit === 'commit' ) {
+                                               wfGetLBFactory()->commitMasterChanges();
+                                       }
+                               } catch ( Exception $e ) {
+                                       // We don't want exceptions thrown during deferred updates to
+                                       // be reported to the user since the output is already sent.
+                                       // Instead we just log them.
+                                       if ( !$e instanceof ErrorPageError ) {
+                                               MWExceptionHandler::logException( $e );
+                                       }
                                }
                        }
-               }
 
-               self::clearPendingUpdates();
-               wfProfileOut( __METHOD__ );
+                       $updates = array_merge( $wgDeferredUpdateList, self::$updates );
+               }
        }
 
        /**