Aaron Schulz has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/311203

Change subject: [WIP] Make Status extend StatusValue and start FileBackend 
update
......................................................................

[WIP] Make Status extend StatusValue and start FileBackend update

* This avoids code duplication.
* Callers can safely start type-hinting StatusValue as well.
* The docs and type-hints in /filebackend are updated as an example.
* A migration pattern is to inject a StatusValue wrapper
  into the backend and use it on all returned statuses, so MediaWiki
  will still get Status for message methods.

Change-Id: Iff9255f34870ea6b0c4b91f6ddc69eea95186aba
---
M includes/Status.php
M includes/filebackend/FSFileBackend.php
M includes/filebackend/FileBackend.php
M includes/filebackend/FileBackendMultiWrite.php
M includes/filebackend/FileBackendStore.php
M includes/filebackend/FileOp.php
M includes/filebackend/FileOpBatch.php
M includes/filebackend/MemoryFileBackend.php
M includes/filebackend/SwiftFileBackend.php
M includes/filebackend/filejournal/DBFileJournal.php
M includes/filebackend/filejournal/FileJournal.php
M includes/filebackend/lockmanager/FSLockManager.php
M includes/filebackend/lockmanager/LockManager.php
M includes/filebackend/lockmanager/MemcLockManager.php
M includes/filebackend/lockmanager/MySqlLockManager.php
M includes/filebackend/lockmanager/PostgreSqlLockManager.php
M includes/filebackend/lockmanager/QuorumLockManager.php
M includes/filebackend/lockmanager/ScopedLock.php
18 files changed, 305 insertions(+), 452 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/03/311203/1

diff --git a/includes/Status.php b/includes/Status.php
index e578873..760ab17 100644
--- a/includes/Status.php
+++ b/includes/Status.php
@@ -37,10 +37,7 @@
  * developer of the calling code is reminded that the function can fail, and
  * so that a lack of error-handling will be explicit.
  */
-class Status {
-       /** @var StatusValue */
-       protected $sv;
-
+class Status extends StatusValue {
        /** @var mixed */
        public $value;
        /** @var array Map of (key => bool) to indicate success of each part of 
batch operations */
@@ -57,12 +54,12 @@
         * @param StatusValue $sv [optional]
         */
        public function __construct( StatusValue $sv = null ) {
-               $this->sv = ( $sv === null ) ? new StatusValue() : $sv;
-               // B/C field aliases
-               $this->value =& $this->sv->value;
-               $this->successCount =& $this->sv->successCount;
-               $this->failCount =& $this->sv->failCount;
-               $this->success =& $this->sv->success;
+               if ( $sv ) {
+                       $this->value =& $sv->value;
+                       $this->successCount =& $sv->successCount;
+                       $this->failCount =& $sv->failCount;
+                       $this->success =& $sv->success;
+               }
        }
 
        /**
@@ -81,95 +78,12 @@
        }
 
        /**
-        * Factory function for fatal errors
-        *
-        * @param string|Message $message Message name or object
-        * @return Status
-        */
-       public static function newFatal( $message /*, parameters...*/ ) {
-               return new self( call_user_func_array(
-                       [ 'StatusValue', 'newFatal' ], func_get_args()
-               ) );
-       }
-
-       /**
-        * Factory function for good results
-        *
-        * @param mixed $value
-        * @return Status
-        */
-       public static function newGood( $value = null ) {
-               $sv = new StatusValue();
-               $sv->value = $value;
-
-               return new self( $sv );
-       }
-
-       /**
-        * Change operation result
-        *
-        * @param bool $ok Whether the operation completed
-        * @param mixed $value
-        */
-       public function setResult( $ok, $value = null ) {
-               $this->sv->setResult( $ok, $value );
-       }
-
-       /**
         * Returns the wrapped StatusValue object
         * @return StatusValue
         * @since 1.27
         */
        public function getStatusValue() {
-               return $this->sv;
-       }
-
-       /**
-        * Returns whether the operation completed and didn't have any error or
-        * warnings
-        *
-        * @return bool
-        */
-       public function isGood() {
-               return $this->sv->isGood();
-       }
-
-       /**
-        * Returns whether the operation completed
-        *
-        * @return bool
-        */
-       public function isOK() {
-               return $this->sv->isOK();
-       }
-
-       /**
-        * Add a new warning
-        *
-        * @param string|Message $message Message name or object
-        */
-       public function warning( $message /*, parameters... */ ) {
-               call_user_func_array( [ $this->sv, 'warning' ], func_get_args() 
);
-       }
-
-       /**
-        * Add an error, do not set fatal flag
-        * This can be used for non-fatal errors
-        *
-        * @param string|Message $message Message name or object
-        */
-       public function error( $message /*, parameters... */ ) {
-               call_user_func_array( [ $this->sv, 'error' ], func_get_args() );
-       }
-
-       /**
-        * Add an error and set OK to false, indicating that the operation
-        * as a whole was fatal
-        *
-        * @param string|Message $message Message name or object
-        */
-       public function fatal( $message /*, parameters... */ ) {
-               call_user_func_array( [ $this->sv, 'fatal' ], func_get_args() );
+               return $this;
        }
 
        /**
@@ -217,16 +131,16 @@
        public function getWikiText( $shortContext = false, $longContext = 
false, $lang = null ) {
                $lang = $this->languageFromParam( $lang );
 
-               $rawErrors = $this->sv->getErrors();
+               $rawErrors = $this->getErrors();
                if ( count( $rawErrors ) == 0 ) {
-                       if ( $this->sv->isOK() ) {
-                               $this->sv->fatal( 'internalerror_info',
+                       if ( $this->isOK() ) {
+                               $this->fatal( 'internalerror_info',
                                        __METHOD__ . " called for a good 
result, this is incorrect\n" );
                        } else {
-                               $this->sv->fatal( 'internalerror_info',
+                               $this->fatal( 'internalerror_info',
                                        __METHOD__ . ": Invalid result object: 
no error text but not OK\n" );
                        }
-                       $rawErrors = $this->sv->getErrors(); // just added a 
fatal
+                       $rawErrors = $this->getErrors(); // just added a fatal
                }
                if ( count( $rawErrors ) == 1 ) {
                        $s = $this->getErrorMessage( $rawErrors[0], $lang 
)->plain();
@@ -265,24 +179,24 @@
         *
         * If both parameters are missing, and there is only one error, no 
bullet will be added.
         *
-        * @param string|string[] $shortContext A message name or an array of 
message names.
-        * @param string|string[] $longContext A message name or an array of 
message names.
+        * @param string|string[]|bool $shortContext A message name or an array 
of message names.
+        * @param string|string[]|bool $longContext A message name or an array 
of message names.
         * @param string|Language $lang Language to use for processing messages
         * @return Message
         */
        public function getMessage( $shortContext = false, $longContext = 
false, $lang = null ) {
                $lang = $this->languageFromParam( $lang );
 
-               $rawErrors = $this->sv->getErrors();
+               $rawErrors = $this->getErrors();
                if ( count( $rawErrors ) == 0 ) {
-                       if ( $this->sv->isOK() ) {
-                               $this->sv->fatal( 'internalerror_info',
+                       if ( $this->isOK() ) {
+                               $this->fatal( 'internalerror_info',
                                        __METHOD__ . " called for a good 
result, this is incorrect\n" );
                        } else {
-                               $this->sv->fatal( 'internalerror_info',
+                               $this->fatal( 'internalerror_info',
                                        __METHOD__ . ": Invalid result object: 
no error text but not OK\n" );
                        }
-                       $rawErrors = $this->sv->getErrors(); // just added a 
fatal
+                       $rawErrors = $this->getErrors(); // just added a fatal
                }
                if ( count( $rawErrors ) == 1 ) {
                        $s = $this->getErrorMessage( $rawErrors[0], $lang );
@@ -342,12 +256,11 @@
        }
 
        /**
-        * Get the error message as HTML. This is done by parsing the wikitext 
error
-        * message.
-        * @param string $shortContext A short enclosing context message name, 
to
+        * Get the error message as HTML. This is done by parsing the wikitext 
error message
+        * @param string|bool $shortContext A short enclosing context message 
name, to
         *        be used when there is a single error
-        * @param string $longContext A long enclosing context message name, 
for a list
-        * @param string|Language $lang Language to use for processing messages
+        * @param string|bool $longContext A long enclosing context message 
name, for a list
+        * @param string|Language|null $lang Language to use for processing 
messages
         * @return string
         */
        public function getHTML( $shortContext = false, $longContext = false, 
$lang = null ) {
@@ -368,16 +281,6 @@
                return array_map( function ( $e ) use ( $lang ) {
                        return $this->getErrorMessage( $e, $lang );
                }, $errors );
-       }
-
-       /**
-        * Merge another status object into this one
-        *
-        * @param Status $other Other Status object
-        * @param bool $overwriteValue Whether to override the "value" member
-        */
-       public function merge( $other, $overwriteValue = false ) {
-               $this->sv->merge( $other->sv, $overwriteValue );
        }
 
        /**
@@ -413,7 +316,7 @@
        protected function getStatusArray( $type = false ) {
                $result = [];
 
-               foreach ( $this->sv->getErrors() as $error ) {
+               foreach ( $this->getErrors() as $error ) {
                        if ( $type === false || $error['type'] === $type ) {
                                if ( $error['message'] instanceof 
MessageSpecifier ) {
                                        $result[] = array_merge(
@@ -429,92 +332,6 @@
                }
 
                return $result;
-       }
-
-       /**
-        * Returns a list of status messages of the given type, with message and
-        * params left untouched, like a sane version of getStatusArray
-        *
-        * Each entry is a map of:
-        *   - message: string message key or MessageSpecifier
-        *   - params: array list of parameters
-        *
-        * @param string $type
-        * @return array
-        */
-       public function getErrorsByType( $type ) {
-               return $this->sv->getErrorsByType( $type );
-       }
-
-       /**
-        * Returns true if the specified message is present as a warning or 
error
-        *
-        * @param string|Message $message Message key or object to search for
-        *
-        * @return bool
-        */
-       public function hasMessage( $message ) {
-               return $this->sv->hasMessage( $message );
-       }
-
-       /**
-        * If the specified source message exists, replace it with the specified
-        * destination message, but keep the same parameters as in the original 
error.
-        *
-        * Note, due to the lack of tools for comparing Message objects, this
-        * function will not work when using a Message object as the search 
parameter.
-        *
-        * @param Message|string $source Message key or object to search for
-        * @param Message|string $dest Replacement message key or object
-        * @return bool Return true if the replacement was done, false 
otherwise.
-        */
-       public function replaceMessage( $source, $dest ) {
-               return $this->sv->replaceMessage( $source, $dest );
-       }
-
-       /**
-        * @return mixed
-        */
-       public function getValue() {
-               return $this->sv->getValue();
-       }
-
-       /**
-        * Backwards compatibility logic
-        *
-        * @param string $name
-        */
-       function __get( $name ) {
-               if ( $name === 'ok' ) {
-                       return $this->sv->isOK();
-               } elseif ( $name === 'errors' ) {
-                       return $this->sv->getErrors();
-               }
-               throw new Exception( "Cannot get '$name' property." );
-       }
-
-       /**
-        * Backwards compatibility logic
-        *
-        * @param string $name
-        * @param mixed $value
-        */
-       function __set( $name, $value ) {
-               if ( $name === 'ok' ) {
-                       $this->sv->setOK( $value );
-               } elseif ( !property_exists( $this, $name ) ) {
-                       // Caller is using undeclared ad-hoc properties
-                       $this->$name = $value;
-               } else {
-                       throw new Exception( "Cannot set '$name' property." );
-               }
-       }
-
-       /**
-        * @return string
-        */
-       public function __toString() {
-               return $this->sv->__toString();
        }
 
        /**
diff --git a/includes/filebackend/FSFileBackend.php 
b/includes/filebackend/FSFileBackend.php
index efe78ee..b0e3eee 100644
--- a/includes/filebackend/FSFileBackend.php
+++ b/includes/filebackend/FSFileBackend.php
@@ -32,7 +32,7 @@
  * Having directories with thousands of files will diminish performance.
  * Sharding can be accomplished by using FileRepo-style hash paths.
  *
- * Status messages should avoid mentioning the internal FS paths.
+ * StatusValue messages should avoid mentioning the internal FS paths.
  * PHP warnings are assumed to be logged rather than output.
  *
  * @ingroup FileBackend
@@ -185,7 +185,7 @@
        }
 
        protected function doCreateInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dest = $this->resolveToFSPath( $params['dst'] );
                if ( $dest === null ) {
@@ -214,7 +214,7 @@
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$tempFile->getPath() ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$dest ) )
                        ] );
-                       $handler = function ( $errors, Status $status, array 
$params, $cmd ) {
+                       $handler = function ( $errors, StatusValue $status, 
array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && 
$errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-create', 
$params['dst'] );
                                        trigger_error( "$cmd\n$errors", 
E_USER_WARNING ); // command output
@@ -238,7 +238,7 @@
        }
 
        protected function doStoreInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dest = $this->resolveToFSPath( $params['dst'] );
                if ( $dest === null ) {
@@ -253,7 +253,7 @@
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$params['src'] ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$dest ) )
                        ] );
-                       $handler = function ( $errors, Status $status, array 
$params, $cmd ) {
+                       $handler = function ( $errors, StatusValue $status, 
array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && 
$errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-store', 
$params['src'], $params['dst'] );
                                        trigger_error( "$cmd\n$errors", 
E_USER_WARNING ); // command output
@@ -281,7 +281,7 @@
        }
 
        protected function doCopyInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $source = $this->resolveToFSPath( $params['src'] );
                if ( $source === null ) {
@@ -311,7 +311,7 @@
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$source ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$dest ) )
                        ] );
-                       $handler = function ( $errors, Status $status, array 
$params, $cmd ) {
+                       $handler = function ( $errors, StatusValue $status, 
array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && 
$errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-copy', 
$params['src'], $params['dst'] );
                                        trigger_error( "$cmd\n$errors", 
E_USER_WARNING ); // command output
@@ -341,7 +341,7 @@
        }
 
        protected function doMoveInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $source = $this->resolveToFSPath( $params['src'] );
                if ( $source === null ) {
@@ -371,7 +371,7 @@
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$source ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$dest ) )
                        ] );
-                       $handler = function ( $errors, Status $status, array 
$params, $cmd ) {
+                       $handler = function ( $errors, StatusValue $status, 
array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && 
$errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-move', 
$params['src'], $params['dst'] );
                                        trigger_error( "$cmd\n$errors", 
E_USER_WARNING ); // command output
@@ -394,7 +394,7 @@
        }
 
        protected function doDeleteInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $source = $this->resolveToFSPath( $params['src'] );
                if ( $source === null ) {
@@ -416,7 +416,7 @@
                                wfIsWindows() ? 'DEL' : 'unlink',
                                wfEscapeShellArg( $this->cleanPathSlashes( 
$source ) )
                        ] );
-                       $handler = function ( $errors, Status $status, array 
$params, $cmd ) {
+                       $handler = function ( $errors, StatusValue $status, 
array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && 
$errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-delete', 
$params['src'] );
                                        trigger_error( "$cmd\n$errors", 
E_USER_WARNING ); // command output
@@ -441,10 +441,10 @@
         * @param string $fullCont
         * @param string $dirRel
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doPrepareInternal( $fullCont, $dirRel, array $params 
) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                list( , $shortCont, ) = FileBackend::splitStoragePath( 
$params['dir'] );
                $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // 
must be valid
                $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
@@ -471,7 +471,7 @@
        }
 
        protected function doSecureInternal( $fullCont, $dirRel, array $params 
) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                list( , $shortCont, ) = FileBackend::splitStoragePath( 
$params['dir'] );
                $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // 
must be valid
                $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
@@ -499,7 +499,7 @@
        }
 
        protected function doPublishInternal( $fullCont, $dirRel, array $params 
) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                list( , $shortCont, ) = FileBackend::splitStoragePath( 
$params['dir'] );
                $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // 
must be valid
                $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
@@ -527,7 +527,7 @@
        }
 
        protected function doCleanInternal( $fullCont, $dirRel, array $params ) 
{
-               $status = Status::newGood();
+               $status = $this->newStatus();
                list( , $shortCont, ) = FileBackend::splitStoragePath( 
$params['dir'] );
                $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // 
must be valid
                $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
@@ -682,7 +682,7 @@
        /**
         * @param FSFileOpHandle[] $fileOpHandles
         *
-        * @return Status[]
+        * @return StatusValue[]
         */
        protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
                $statuses = [];
@@ -701,7 +701,7 @@
                }
 
                foreach ( $fileOpHandles as $index => $fileOpHandle ) {
-                       $status = Status::newGood();
+                       $status = $this->newStatus();
                        $function = $fileOpHandle->call;
                        $function( $errs[$index], $status, 
$fileOpHandle->params, $fileOpHandle->cmd );
                        $statuses[$index] = $status;
diff --git a/includes/filebackend/FileBackend.php 
b/includes/filebackend/FileBackend.php
index ed36a1f..b5fe603 100644
--- a/includes/filebackend/FileBackend.php
+++ b/includes/filebackend/FileBackend.php
@@ -104,6 +104,9 @@
        /** @var FileJournal */
        protected $fileJournal;
 
+       /** @var callable */
+       protected $statusWrapper;
+
        /** Bitfield flags for supported features */
        const ATTR_HEADERS = 1; // files can be tagged with standard HTTP 
headers
        const ATTR_METADATA = 2; // files can be stored with metadata key/values
@@ -156,6 +159,10 @@
                $this->concurrency = isset( $config['concurrency'] )
                        ? (int)$config['concurrency']
                        : 50;
+               // @TODO: inject this
+               $this->statusWrapper = function ( StatusValue $sv ) {
+                       return Status::wrap( $sv );
+               };
        }
 
        /**
@@ -359,20 +366,20 @@
         * during the operation. The 'failCount', 'successCount', and 'success' 
members
         * will reflect each operation attempted.
         *
-        * The status will be "OK" unless:
+        * The StatusValue will be "OK" unless:
         *   - a) unexpected operation errors occurred (network partitions, 
disk full...)
         *   - b) significant operation errors occurred and 'force' was not set
         *
         * @param array $ops List of operations to execute in order
         * @param array $opts Batch operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function doOperations( array $ops, array $opts = [] ) {
                if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
-                       return Status::newFatal( 'backend-fail-readonly', 
$this->name, $this->readOnly );
+                       return $this->newStatus( 'backend-fail-readonly', 
$this->name, $this->readOnly );
                }
                if ( !count( $ops ) ) {
-                       return Status::newGood(); // nothing to do
+                       return $this->newStatus(); // nothing to do
                }
 
                $ops = $this->resolveFSFileObjects( $ops );
@@ -402,7 +409,7 @@
         *
         * @param array $op Operation
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function doOperation( array $op, array $opts = [] ) {
                return $this->doOperations( [ $op ], $opts );
@@ -416,7 +423,7 @@
         *
         * @param array $params Operation parameters
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function create( array $params, array $opts = [] ) {
                return $this->doOperation( [ 'op' => 'create' ] + $params, 
$opts );
@@ -430,7 +437,7 @@
         *
         * @param array $params Operation parameters
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function store( array $params, array $opts = [] ) {
                return $this->doOperation( [ 'op' => 'store' ] + $params, $opts 
);
@@ -444,7 +451,7 @@
         *
         * @param array $params Operation parameters
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function copy( array $params, array $opts = [] ) {
                return $this->doOperation( [ 'op' => 'copy' ] + $params, $opts 
);
@@ -458,7 +465,7 @@
         *
         * @param array $params Operation parameters
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function move( array $params, array $opts = [] ) {
                return $this->doOperation( [ 'op' => 'move' ] + $params, $opts 
);
@@ -472,7 +479,7 @@
         *
         * @param array $params Operation parameters
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         */
        final public function delete( array $params, array $opts = [] ) {
                return $this->doOperation( [ 'op' => 'delete' ] + $params, 
$opts );
@@ -486,7 +493,7 @@
         *
         * @param array $params Operation parameters
         * @param array $opts Operation options
-        * @return Status
+        * @return StatusValue
         * @since 1.21
         */
        final public function describe( array $params, array $opts = [] ) {
@@ -597,20 +604,20 @@
         * @par Return value:
         * This returns a Status, which contains all warnings and fatals that 
occurred
         * during the operation. The 'failCount', 'successCount', and 'success' 
members
-        * will reflect each operation attempted for the given files. The 
status will be
+        * will reflect each operation attempted for the given files. The 
StatusValue will be
         * considered "OK" as long as no fatal errors occurred.
         *
         * @param array $ops Set of operations to execute
         * @param array $opts Batch operation options
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function doQuickOperations( array $ops, array $opts = [] ) 
{
                if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
-                       return Status::newFatal( 'backend-fail-readonly', 
$this->name, $this->readOnly );
+                       return $this->newStatus( 'backend-fail-readonly', 
$this->name, $this->readOnly );
                }
                if ( !count( $ops ) ) {
-                       return Status::newGood(); // nothing to do
+                       return $this->newStatus(); // nothing to do
                }
 
                $ops = $this->resolveFSFileObjects( $ops );
@@ -638,7 +645,7 @@
         * @see FileBackend::doQuickOperations()
         *
         * @param array $op Operation
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function doQuickOperation( array $op ) {
@@ -652,7 +659,7 @@
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickCreate( array $params ) {
@@ -666,7 +673,7 @@
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickStore( array $params ) {
@@ -680,7 +687,7 @@
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickCopy( array $params ) {
@@ -694,7 +701,7 @@
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickMove( array $params ) {
@@ -708,7 +715,7 @@
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickDelete( array $params ) {
@@ -722,7 +729,7 @@
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.21
         */
        final public function quickDescribe( array $params ) {
@@ -739,7 +746,7 @@
         *   - srcs        : ordered source storage paths (e.g. chunk1, chunk2, 
...)
         *   - dst         : file system path to 0-byte temp file
         *   - parallelize : try to do operations in parallel when possible
-        * @return Status
+        * @return StatusValue
         */
        abstract public function concatenate( array $params );
 
@@ -759,11 +766,11 @@
         *   - noAccess       : try to deny file access (since 1.20)
         *   - noListing      : try to deny file listing (since 1.20)
         *   - bypassReadOnly : allow writes in read-only mode (since 1.20)
-        * @return Status
+        * @return StatusValue
         */
        final public function prepare( array $params ) {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() 
) {
-                       return Status::newFatal( 'backend-fail-readonly', 
$this->name, $this->readOnly );
+                       return $this->newStatus( 'backend-fail-readonly', 
$this->name, $this->readOnly );
                }
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore 
client aborts
@@ -790,11 +797,11 @@
         *   - noAccess       : try to deny file access
         *   - noListing      : try to deny file listing
         *   - bypassReadOnly : allow writes in read-only mode (since 1.20)
-        * @return Status
+        * @return StatusValue
         */
        final public function secure( array $params ) {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() 
) {
-                       return Status::newFatal( 'backend-fail-readonly', 
$this->name, $this->readOnly );
+                       return $this->newStatus( 'backend-fail-readonly', 
$this->name, $this->readOnly );
                }
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore 
client aborts
@@ -822,12 +829,12 @@
         *   - access         : try to allow file access
         *   - listing        : try to allow file listing
         *   - bypassReadOnly : allow writes in read-only mode (since 1.20)
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function publish( array $params ) {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() 
) {
-                       return Status::newFatal( 'backend-fail-readonly', 
$this->name, $this->readOnly );
+                       return $this->newStatus( 'backend-fail-readonly', 
$this->name, $this->readOnly );
                }
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore 
client aborts
@@ -849,11 +856,11 @@
         *   - dir            : storage directory
         *   - recursive      : recursively delete empty subdirectories first 
(since 1.20)
         *   - bypassReadOnly : allow writes in read-only mode (since 1.20)
-        * @return Status
+        * @return StatusValue
         */
        final public function clean( array $params ) {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() 
) {
-                       return Status::newFatal( 'backend-fail-readonly', 
$this->name, $this->readOnly );
+                       return $this->newStatus( 'backend-fail-readonly', 
$this->name, $this->readOnly );
                }
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore 
client aborts
@@ -1020,7 +1027,7 @@
         *   - headless : only include the body (and headers from "headers") 
(since 1.28)
         *   - latest   : use the latest available data
         *   - allowOB  : preserve any output buffers (since 1.28)
-        * @return Status
+        * @return StatusValue
         */
        abstract public function streamFile( array $params );
 
@@ -1250,7 +1257,7 @@
         * @param array $paths Storage paths
         * @param int $type LockManager::LOCK_* constant
         * @param int $timeout Timeout in seconds (0 means non-blocking) (since 
1.24)
-        * @return Status
+        * @return StatusValue
         */
        final public function lockFiles( array $paths, $type, $timeout = 0 ) {
                $paths = array_map( 'FileBackend::normalizeStoragePath', $paths 
);
@@ -1263,7 +1270,7 @@
         *
         * @param array $paths Storage paths
         * @param int $type LockManager::LOCK_* constant
-        * @return Status
+        * @return StatusValue
         */
        final public function unlockFiles( array $paths, $type ) {
                $paths = array_map( 'FileBackend::normalizeStoragePath', $paths 
);
@@ -1274,20 +1281,20 @@
        /**
         * Lock the files at the given storage paths in the backend.
         * This will either lock all the files or none (on failure).
-        * On failure, the status object will be updated with errors.
+        * On failure, the StatusValue object will be updated with errors.
         *
         * Once the return value goes out scope, the locks will be released and
-        * the status updated. Unlock fatals will not change the status "OK" 
value.
+        * the StatusValue updated. Unlock fatals will not change the 
StatusValue "OK" value.
         *
         * @see ScopedLock::factory()
         *
         * @param array $paths List of storage paths or map of lock types to 
path lists
         * @param int|string $type LockManager::LOCK_* constant or "mixed"
-        * @param Status $status Status to update on lock/unlock
+        * @param StatusValue $status StatusValue to update on lock/unlock
         * @param int $timeout Timeout in seconds (0 means non-blocking) (since 
1.24)
         * @return ScopedLock|null Returns null on failure
         */
-       final public function getScopedFileLocks( array $paths, $type, Status 
$status, $timeout = 0 ) {
+       final public function getScopedFileLocks( array $paths, $type, 
StatusValue $status, $timeout = 0 ) {
                if ( $type === 'mixed' ) {
                        foreach ( $paths as &$typePaths ) {
                                $typePaths = array_map( 
'FileBackend::normalizeStoragePath', $typePaths );
@@ -1311,11 +1318,11 @@
         * @see FileBackend::doOperations()
         *
         * @param array $ops List of file operations to 
FileBackend::doOperations()
-        * @param Status $status Status to update on lock/unlock
+        * @param StatusValue $status StatusValue to update on lock/unlock
         * @return ScopedLock|null
         * @since 1.20
         */
-       abstract public function getScopedLocksForOps( array $ops, Status 
$status );
+       abstract public function getScopedLocksForOps( array $ops, StatusValue 
$status );
 
        /**
         * Get the root storage path of this backend.
@@ -1530,6 +1537,33 @@
 
                return $path;
        }
+
+       /**
+        * Yields the result of the status wrapper callback on either:
+        *   - StatusValue::newGood() if this method is called without 
parameters
+        *   - StatusValue::newFatal() with all parameters to this method if 
passed in
+        *
+        * @param ... string
+        * @return StatusValue
+        */
+       final protected function newStatus() {
+               $args = func_get_args();
+               if ( count( $args ) ) {
+                       $sv = call_user_func_array( [ 'StatusValue', 'newFatal' 
], $args );
+               } else {
+                       $sv = StatusValue::newGood();
+               }
+
+               return $this->wrapStatus( $sv );
+       }
+
+       /**
+        * @param StatusValue $sv
+        * @return StatusValue Modified status or StatusValue subclass
+        */
+       final protected function wrapStatus( StatusValue $sv ) {
+               return $this->statusWrapper ? call_user_func( 
$this->statusWrapper, $sv ) : $sv;
+       }
 }
 
 /**
diff --git a/includes/filebackend/FileBackendMultiWrite.php 
b/includes/filebackend/FileBackendMultiWrite.php
index 3b20048..c1cc7bb 100644
--- a/includes/filebackend/FileBackendMultiWrite.php
+++ b/includes/filebackend/FileBackendMultiWrite.php
@@ -148,7 +148,7 @@
        }
 
        final protected function doOperationsInternal( array $ops, array $opts 
) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $mbe = $this->backends[$this->masterIndex]; // convenience
 
@@ -233,10 +233,10 @@
         * Check that a set of files are consistent across all internal backends
         *
         * @param array $paths List of storage paths
-        * @return Status
+        * @return StatusValue
         */
        public function consistencyCheck( array $paths ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                if ( $this->syncChecks == 0 || count( $this->backends ) <= 1 ) {
                        return $status; // skip checks
                }
@@ -305,10 +305,10 @@
         * Check that a set of file paths are usable across all internal 
backends
         *
         * @param array $paths List of storage paths
-        * @return Status
+        * @return StatusValue
         */
        public function accessibilityCheck( array $paths ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                if ( count( $this->backends ) <= 1 ) {
                        return $status; // skip checks
                }
@@ -331,10 +331,10 @@
         *
         * @param array $paths List of storage paths
         * @param string|bool $resyncMode False, True, or "conservative"; see 
__construct()
-        * @return Status
+        * @return StatusValue
         */
        public function resyncFiles( array $paths, $resyncMode = true ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $mBackend = $this->backends[$this->masterIndex];
                foreach ( $paths as $path ) {
@@ -502,8 +502,8 @@
        }
 
        protected function doQuickOperationsInternal( array $ops ) {
-               $status = Status::newGood();
-               // Do the operations on the master backend; setting Status 
fields...
+               $status = $this->newStatus();
+               // Do the operations on the master backend; setting StatusValue 
fields...
                $realOps = $this->substOpBatchPaths( $ops, 
$this->backends[$this->masterIndex] );
                $masterStatus = 
$this->backends[$this->masterIndex]->doQuickOperations( $realOps );
                $status->merge( $masterStatus );
@@ -553,10 +553,10 @@
        /**
         * @param string $method One of (doPrepare,doSecure,doPublish,doClean)
         * @param array $params Method arguments
-        * @return Status
+        * @return StatusValue
         */
        protected function doDirectoryOp( $method, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $realParams = $this->substOpPaths( $params, 
$this->backends[$this->masterIndex] );
                $masterStatus = $this->backends[$this->masterIndex]->$method( 
$realParams );
@@ -736,7 +736,7 @@
                return $this->backends[$index]->preloadFileStat( $realParams );
        }
 
-       public function getScopedLocksForOps( array $ops, Status $status ) {
+       public function getScopedLocksForOps( array $ops, StatusValue $status ) 
{
                $realOps = $this->substOpBatchPaths( $ops, 
$this->backends[$this->masterIndex] );
                $fileOps = 
$this->backends[$this->masterIndex]->getOperationsInternal( $realOps );
                // Get the paths to lock from the master backend
diff --git a/includes/filebackend/FileBackendStore.php 
b/includes/filebackend/FileBackendStore.php
index bc4d81d..4a8c30d 100644
--- a/includes/filebackend/FileBackendStore.php
+++ b/includes/filebackend/FileBackendStore.php
@@ -106,19 +106,19 @@
         *   - content     : the raw file contents
         *   - dst         : destination storage path
         *   - headers     : HTTP header name/value map
-        *   - async       : Status will be returned immediately if supported.
-        *                   If the status is OK, then its value field will be
+        *   - async       : StatusValue will be returned immediately if 
supported.
+        *                   If the StatusValue is OK, then its value field 
will be
         *                   set to a FileBackendStoreOpHandle object.
         *   - dstExists   : Whether a file exists at the destination 
(optimization).
         *                   Callers can use "false" if no existing file is 
being changed.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function createInternal( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
                if ( strlen( $params['content'] ) > 
$this->maxFileSizeInternal() ) {
-                       $status = Status::newFatal( 'backend-fail-maxsize',
+                       $status = $this->newStatus( 'backend-fail-maxsize',
                                $params['dst'], $this->maxFileSizeInternal() );
                } else {
                        $status = $this->doCreateInternal( $params );
@@ -134,7 +134,7 @@
        /**
         * @see FileBackendStore::createInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doCreateInternal( array $params );
 
@@ -147,19 +147,19 @@
         *   - src         : source path on disk
         *   - dst         : destination storage path
         *   - headers     : HTTP header name/value map
-        *   - async       : Status will be returned immediately if supported.
-        *                   If the status is OK, then its value field will be
+        *   - async       : StatusValue will be returned immediately if 
supported.
+        *                   If the StatusValue is OK, then its value field 
will be
         *                   set to a FileBackendStoreOpHandle object.
         *   - dstExists   : Whether a file exists at the destination 
(optimization).
         *                   Callers can use "false" if no existing file is 
being changed.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function storeInternal( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
                if ( filesize( $params['src'] ) > $this->maxFileSizeInternal() 
) {
-                       $status = Status::newFatal( 'backend-fail-maxsize',
+                       $status = $this->newStatus( 'backend-fail-maxsize',
                                $params['dst'], $this->maxFileSizeInternal() );
                } else {
                        $status = $this->doStoreInternal( $params );
@@ -175,7 +175,7 @@
        /**
         * @see FileBackendStore::storeInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doStoreInternal( array $params );
 
@@ -189,14 +189,14 @@
         *   - dst                 : destination storage path
         *   - ignoreMissingSource : do nothing if the source file does not 
exist
         *   - headers             : HTTP header name/value map
-        *   - async               : Status will be returned immediately if 
supported.
-        *                           If the status is OK, then its value field 
will be
+        *   - async               : StatusValue will be returned immediately 
if supported.
+        *                           If the StatusValue is OK, then its value 
field will be
         *                           set to a FileBackendStoreOpHandle object.
         *   - dstExists           : Whether a file exists at the destination 
(optimization).
         *                           Callers can use "false" if no existing 
file is being changed.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function copyInternal( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
@@ -212,7 +212,7 @@
        /**
         * @see FileBackendStore::copyInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doCopyInternal( array $params );
 
@@ -223,12 +223,12 @@
         * $params include:
         *   - src                 : source storage path
         *   - ignoreMissingSource : do nothing if the source file does not 
exist
-        *   - async               : Status will be returned immediately if 
supported.
-        *                           If the status is OK, then its value field 
will be
+        *   - async               : StatusValue will be returned immediately 
if supported.
+        *                           If the StatusValue is OK, then its value 
field will be
         *                           set to a FileBackendStoreOpHandle object.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function deleteInternal( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
@@ -241,7 +241,7 @@
        /**
         * @see FileBackendStore::deleteInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doDeleteInternal( array $params );
 
@@ -255,14 +255,14 @@
         *   - dst                 : destination storage path
         *   - ignoreMissingSource : do nothing if the source file does not 
exist
         *   - headers             : HTTP header name/value map
-        *   - async               : Status will be returned immediately if 
supported.
-        *                           If the status is OK, then its value field 
will be
+        *   - async               : StatusValue will be returned immediately 
if supported.
+        *                           If the StatusValue is OK, then its value 
field will be
         *                           set to a FileBackendStoreOpHandle object.
         *   - dstExists           : Whether a file exists at the destination 
(optimization).
         *                           Callers can use "false" if no existing 
file is being changed.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function moveInternal( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
@@ -279,7 +279,7 @@
        /**
         * @see FileBackendStore::moveInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doMoveInternal( array $params ) {
                unset( $params['async'] ); // two steps, won't work here :)
@@ -303,12 +303,12 @@
         * $params include:
         *   - src           : source storage path
         *   - headers       : HTTP header name/value map
-        *   - async         : Status will be returned immediately if supported.
-        *                     If the status is OK, then its value field will be
+        *   - async         : StatusValue will be returned immediately if 
supported.
+        *                     If the StatusValue is OK, then its value field 
will be
         *                     set to a FileBackendStoreOpHandle object.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function describeInternal( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
@@ -317,7 +317,7 @@
                        $this->clearCache( [ $params['src'] ] );
                        $this->deleteFileCache( $params['src'] ); // persistent 
cache
                } else {
-                       $status = Status::newGood(); // nothing to do
+                       $status = $this->newStatus(); // nothing to do
                }
 
                return $status;
@@ -326,10 +326,10 @@
        /**
         * @see FileBackendStore::describeInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doDescribeInternal( array $params ) {
-               return Status::newGood();
+               return $this->newStatus();
        }
 
        /**
@@ -337,15 +337,15 @@
         * Do not call this function from places outside FileBackend and FileOp.
         *
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        final public function nullInternal( array $params ) {
-               return Status::newGood();
+               return $this->newStatus();
        }
 
        final public function concatenate( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // Try to lock the source files for the scope of this function
                $scopeLockS = $this->getScopedFileLocks( $params['srcs'], 
LockManager::LOCK_UW, $status );
@@ -366,10 +366,10 @@
        /**
         * @see FileBackendStore::concatenate()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doConcatenate( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                $tmpPath = $params['dst']; // convenience
                unset( $params['latest'] ); // sanity
 
@@ -438,7 +438,7 @@
 
        final protected function doPrepare( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( 
$params['dir'] );
                if ( $dir === null ) {
@@ -465,15 +465,15 @@
         * @param string $container
         * @param string $dir
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doPrepareInternal( $container, $dir, array $params ) 
{
-               return Status::newGood();
+               return $this->newStatus();
        }
 
        final protected function doSecure( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( 
$params['dir'] );
                if ( $dir === null ) {
@@ -500,15 +500,15 @@
         * @param string $container
         * @param string $dir
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doSecureInternal( $container, $dir, array $params ) {
-               return Status::newGood();
+               return $this->newStatus();
        }
 
        final protected function doPublish( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( 
$params['dir'] );
                if ( $dir === null ) {
@@ -535,15 +535,15 @@
         * @param string $container
         * @param string $dir
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doPublishInternal( $container, $dir, array $params ) 
{
-               return Status::newGood();
+               return $this->newStatus();
        }
 
        final protected function doClean( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // Recursive: first delete all empty subdirs recursively
                if ( !empty( $params['recursive'] ) && 
!$this->directoriesAreVirtual() ) {
@@ -591,10 +591,10 @@
         * @param string $container
         * @param string $dir
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doCleanInternal( $container, $dir, array $params ) {
-               return Status::newGood();
+               return $this->newStatus();
        }
 
        final public function fileExists( array $params ) {
@@ -842,7 +842,7 @@
 
        final public function streamFile( array $params ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // Always set some fields for subclass convenience
                $params['options'] = isset( $params['options'] ) ? 
$params['options'] : [];
@@ -863,10 +863,10 @@
        /**
         * @see FileBackendStore::streamFile()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function doStreamFile( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $flags = 0;
                $flags |= !empty( $params['headless'] ) ? 
StreamFile::STREAM_HEADLESS : 0;
@@ -992,7 +992,7 @@
         * An exception is thrown if an unsupported operation is requested.
         *
         * @param array $ops Same format as doOperations()
-        * @return array List of FileOp objects
+        * @return FileOp[] List of FileOp objects
         * @throws FileBackendError
         */
        final public function getOperationsInternal( array $ops ) {
@@ -1052,7 +1052,7 @@
                ];
        }
 
-       public function getScopedLocksForOps( array $ops, Status $status ) {
+       public function getScopedLocksForOps( array $ops, StatusValue $status ) 
{
                $paths = $this->getPathsToLockForOpsInternal( 
$this->getOperationsInternal( $ops ) );
 
                return $this->getScopedFileLocks( $paths, 'mixed', $status );
@@ -1060,7 +1060,7 @@
 
        final protected function doOperationsInternal( array $ops, array $opts 
) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // Fix up custom header name/value pairs...
                $ops = array_map( [ $this, 'sanitizeOpHeaders' ], $ops );
@@ -1106,7 +1106,7 @@
                        $subStatus = FileOpBatch::attempt( $performOps, $opts, 
$this->fileJournal );
                } else {
                        // If we could not even stat some files, then bail 
out...
-                       $subStatus = Status::newFatal( 'backend-fail-internal', 
$this->name );
+                       $subStatus = $this->newStatus( 'backend-fail-internal', 
$this->name );
                        foreach ( $ops as $i => $op ) { // mark each op as 
failed
                                $subStatus->success[$i] = false;
                                ++$subStatus->failCount;
@@ -1115,7 +1115,7 @@
                                " stat failure; aborted operations: " . 
FormatJson::encode( $ops ) );
                }
 
-               // Merge errors into status fields
+               // Merge errors into StatusValue fields
                $status->merge( $subStatus );
                $status->success = $subStatus->success; // not done in merge()
 
@@ -1127,7 +1127,7 @@
 
        final protected function doQuickOperationsInternal( array $ops ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // Fix up custom header name/value pairs...
                $ops = array_map( [ $this, 'sanitizeOpHeaders' ], $ops );
@@ -1184,13 +1184,13 @@
 
        /**
         * Execute a list of FileBackendStoreOpHandle handles in parallel.
-        * The resulting Status object fields will correspond
+        * The resulting StatusValue object fields will correspond
         * to the order in which the handles where given.
         *
         * @param FileBackendStoreOpHandle[] $fileOpHandles
         *
         * @throws FileBackendError
-        * @return array Map of Status objects
+        * @return array Map of StatusValue objects
         */
        final public function executeOpHandlesInternal( array $fileOpHandles ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . 
"-{$this->name}" );
@@ -1216,7 +1216,7 @@
         * @param FileBackendStoreOpHandle[] $fileOpHandles
         *
         * @throws FileBackendError
-        * @return Status[] List of corresponding Status objects
+        * @return StatusValue[] List of corresponding StatusValue objects
         */
        protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
                if ( count( $fileOpHandles ) ) {
@@ -1844,7 +1844,7 @@
  * FileBackendStore helper class for performing asynchronous file operations.
  *
  * For example, calling FileBackendStore::createInternal() with the "async"
- * param flag may result in a Status that contains this object as a value.
+ * param flag may result in a StatusValue that contains this object as a value.
  * This class is largely backend-specific and is mostly just "magic" to be
  * passed to FileBackendStore::executeOpHandlesInternal().
  */
diff --git a/includes/filebackend/FileOp.php b/includes/filebackend/FileOp.php
index 56a4073..916366c 100644
--- a/includes/filebackend/FileOp.php
+++ b/includes/filebackend/FileOp.php
@@ -239,14 +239,14 @@
        /**
         * Check preconditions of the operation without writing anything.
         * This must update $predicates for each path that the op can change
-        * except when a failing status object is returned.
+        * except when a failing StatusValue object is returned.
         *
         * @param array $predicates
-        * @return Status
+        * @return StatusValue
         */
        final public function precheck( array &$predicates ) {
                if ( $this->state !== self::STATE_NEW ) {
-                       return Status::newFatal( 'fileop-fail-state', 
self::STATE_NEW, $this->state );
+                       return StatusValue::newFatal( 'fileop-fail-state', 
self::STATE_NEW, $this->state );
                }
                $this->state = self::STATE_CHECKED;
                $status = $this->doPrecheck( $predicates );
@@ -259,22 +259,22 @@
 
        /**
         * @param array $predicates
-        * @return Status
+        * @return StatusValue
         */
        protected function doPrecheck( array &$predicates ) {
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        /**
         * Attempt the operation
         *
-        * @return Status
+        * @return StatusValue
         */
        final public function attempt() {
                if ( $this->state !== self::STATE_CHECKED ) {
-                       return Status::newFatal( 'fileop-fail-state', 
self::STATE_CHECKED, $this->state );
+                       return StatusValue::newFatal( 'fileop-fail-state', 
self::STATE_CHECKED, $this->state );
                } elseif ( $this->failed ) { // failed precheck
-                       return Status::newFatal( 'fileop-fail-attempt-precheck' 
);
+                       return StatusValue::newFatal( 
'fileop-fail-attempt-precheck' );
                }
                $this->state = self::STATE_ATTEMPTED;
                if ( $this->doOperation ) {
@@ -284,23 +284,23 @@
                                $this->logFailure( 'attempt' );
                        }
                } else { // no-op
-                       $status = Status::newGood();
+                       $status = StatusValue::newGood();
                }
 
                return $status;
        }
 
        /**
-        * @return Status
+        * @return StatusValue
         */
        protected function doAttempt() {
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        /**
         * Attempt the operation in the background
         *
-        * @return Status
+        * @return StatusValue
         */
        final public function attemptAsync() {
                $this->async = true;
@@ -350,13 +350,13 @@
        /**
         * Check for errors with regards to the destination file already 
existing.
         * Also set the destExists, overwriteSameCase and sourceSha1 member 
variables.
-        * A bad status will be returned if there is no chance it can be 
overwritten.
+        * A bad StatusValue will be returned if there is no chance it can be 
overwritten.
         *
         * @param array $predicates
-        * @return Status
+        * @return StatusValue
         */
        protected function precheckDestExistence( array $predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Get hash of source file/string and the destination file
                $this->sourceSha1 = $this->getSourceSha1Base36(); // FS file or 
data string
                if ( $this->sourceSha1 === null ) { // file in storage?
@@ -476,7 +476,7 @@
        }
 
        protected function doPrecheck( array &$predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Check if the source data is too big
                if ( strlen( $this->getParam( 'content' ) ) > 
$this->backend->maxFileSizeInternal() ) {
                        $status->fatal( 'backend-fail-maxsize',
@@ -509,7 +509,7 @@
                        return $this->backend->createInternal( $this->setFlags( 
$this->params ) );
                }
 
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        protected function getSourceSha1Base36() {
@@ -535,7 +535,7 @@
        }
 
        protected function doPrecheck( array &$predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Check if the source file exists on the file system
                if ( !is_file( $this->params['src'] ) ) {
                        $status->fatal( 'backend-fail-notexists', 
$this->params['src'] );
@@ -573,7 +573,7 @@
                        return $this->backend->storeInternal( $this->setFlags( 
$this->params ) );
                }
 
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        protected function getSourceSha1Base36() {
@@ -606,7 +606,7 @@
        }
 
        protected function doPrecheck( array &$predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Check if the source file exists
                if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
                        if ( $this->getParam( 'ignoreMissingSource' ) ) {
@@ -642,7 +642,7 @@
 
        protected function doAttempt() {
                if ( $this->overwriteSameCase ) {
-                       $status = Status::newGood(); // nothing to do
+                       $status = StatusValue::newGood(); // nothing to do
                } elseif ( $this->params['src'] === $this->params['dst'] ) {
                        // Just update the destination file headers
                        $headers = $this->getParam( 'headers' ) ?: [];
@@ -680,7 +680,7 @@
        }
 
        protected function doPrecheck( array &$predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Check if the source file exists
                if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
                        if ( $this->getParam( 'ignoreMissingSource' ) ) {
@@ -720,7 +720,7 @@
                if ( $this->overwriteSameCase ) {
                        if ( $this->params['src'] === $this->params['dst'] ) {
                                // Do nothing to the destination (which is also 
the source)
-                               $status = Status::newGood();
+                               $status = StatusValue::newGood();
                        } else {
                                // Just delete the source as the destination 
file needs no changes
                                $status = $this->backend->deleteInternal( 
$this->setFlags(
@@ -760,7 +760,7 @@
        }
 
        protected function doPrecheck( array &$predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Check if the source file exists
                if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
                        if ( $this->getParam( 'ignoreMissingSource' ) ) {
@@ -809,7 +809,7 @@
        }
 
        protected function doPrecheck( array &$predicates ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                // Check if the source file exists
                if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
                        $status->fatal( 'backend-fail-notexists', 
$this->params['src'] );
diff --git a/includes/filebackend/FileOpBatch.php 
b/includes/filebackend/FileOpBatch.php
index 78209d8..c40a737 100644
--- a/includes/filebackend/FileOpBatch.php
+++ b/includes/filebackend/FileOpBatch.php
@@ -45,17 +45,17 @@
         *   - nonJournaled : Don't log this operation batch in the file 
journal.
         *   - concurrency  : Try to do this many operations in parallel when 
possible.
         *
-        * The resulting Status will be "OK" unless:
+        * The resulting StatusValue will be "OK" unless:
         *   - a) unexpected operation errors occurred (network partitions, 
disk full...)
         *   - b) significant operation errors occurred and 'force' was not set
         *
         * @param FileOp[] $performOps List of FileOp operations
         * @param array $opts Batch operation options
         * @param FileJournal $journal Journal to log operations to
-        * @return Status
+        * @return StatusValue
         */
        public static function attempt( array $performOps, array $opts, 
FileJournal $journal ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
 
                $n = count( $performOps );
                if ( $n > self::MAX_BATCH_SIZE ) {
@@ -119,7 +119,9 @@
                if ( count( $entries ) ) {
                        $subStatus = $journal->logChangeBatch( $entries, 
$batchId );
                        if ( !$subStatus->isOK() ) {
-                               return $subStatus; // abort
+                               $status->merge( $subStatus );
+
+                               return $status; // abort
                        }
                }
 
@@ -142,9 +144,9 @@
         * This will abort remaining ops on failure.
         *
         * @param array $pPerformOps Batches of file ops (batches use original 
indexes)
-        * @param Status $status
+        * @param StatusValue $status
         */
-       protected static function runParallelBatches( array $pPerformOps, 
Status $status ) {
+       protected static function runParallelBatches( array $pPerformOps, 
StatusValue $status ) {
                $aborted = false; // set to true on unexpected errors
                foreach ( $pPerformOps as $performOpsBatch ) {
                        /** @var FileOp[] $performOpsBatch */
diff --git a/includes/filebackend/MemoryFileBackend.php 
b/includes/filebackend/MemoryFileBackend.php
index e2c1ede..74a0068 100644
--- a/includes/filebackend/MemoryFileBackend.php
+++ b/includes/filebackend/MemoryFileBackend.php
@@ -44,7 +44,7 @@
        }
 
        protected function doCreateInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dst = $this->resolveHashKey( $params['dst'] );
                if ( $dst === null ) {
@@ -62,7 +62,7 @@
        }
 
        protected function doStoreInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dst = $this->resolveHashKey( $params['dst'] );
                if ( $dst === null ) {
@@ -89,7 +89,7 @@
        }
 
        protected function doCopyInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $src = $this->resolveHashKey( $params['src'] );
                if ( $src === null ) {
@@ -122,7 +122,7 @@
        }
 
        protected function doDeleteInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $src = $this->resolveHashKey( $params['src'] );
                if ( $src === null ) {
diff --git a/includes/filebackend/SwiftFileBackend.php 
b/includes/filebackend/SwiftFileBackend.php
index 2adf934..a0027e4 100644
--- a/includes/filebackend/SwiftFileBackend.php
+++ b/includes/filebackend/SwiftFileBackend.php
@@ -26,7 +26,7 @@
 /**
  * @brief Class for an OpenStack Swift (or Ceph RGW) based file backend.
  *
- * Status messages should avoid mentioning the Swift account name.
+ * StatusValue messages should avoid mentioning the Swift account name.
  * Likewise, error suppression should be used to avoid path disclosure.
  *
  * @ingroup FileBackend
@@ -252,7 +252,7 @@
        }
 
        protected function doCreateInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $dstCont, $dstRel ) = $this->resolveStoragePathReal( 
$params['dst'] );
                if ( $dstRel === null ) {
@@ -279,7 +279,7 @@
                ] ];
 
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( 
$method, $params ) {
+               $handler = function ( array $request, StatusValue $status ) use 
( $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = 
$request['response'];
                        if ( $rcode === 201 ) {
                                // good
@@ -301,7 +301,7 @@
        }
 
        protected function doStoreInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $dstCont, $dstRel ) = $this->resolveStoragePathReal( 
$params['dst'] );
                if ( $dstRel === null ) {
@@ -343,7 +343,7 @@
                ] ];
 
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( 
$method, $params ) {
+               $handler = function ( array $request, StatusValue $status ) use 
( $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = 
$request['response'];
                        if ( $rcode === 201 ) {
                                // good
@@ -365,7 +365,7 @@
        }
 
        protected function doCopyInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( 
$params['src'] );
                if ( $srcRel === null ) {
@@ -391,7 +391,7 @@
                ] ];
 
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( 
$method, $params ) {
+               $handler = function ( array $request, StatusValue $status ) use 
( $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = 
$request['response'];
                        if ( $rcode === 201 ) {
                                // good
@@ -413,7 +413,7 @@
        }
 
        protected function doMoveInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( 
$params['src'] );
                if ( $srcRel === null ) {
@@ -448,7 +448,7 @@
                }
 
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( 
$method, $params ) {
+               $handler = function ( array $request, StatusValue $status ) use 
( $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = 
$request['response'];
                        if ( $request['method'] === 'PUT' && $rcode === 201 ) {
                                // good
@@ -472,7 +472,7 @@
        }
 
        protected function doDeleteInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( 
$params['src'] );
                if ( $srcRel === null ) {
@@ -488,7 +488,7 @@
                ] ];
 
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( 
$method, $params ) {
+               $handler = function ( array $request, StatusValue $status ) use 
( $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = 
$request['response'];
                        if ( $rcode === 204 ) {
                                // good
@@ -512,7 +512,7 @@
        }
 
        protected function doDescribeInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( 
$params['src'] );
                if ( $srcRel === null ) {
@@ -546,7 +546,7 @@
                ] ];
 
                $method = __METHOD__;
-               $handler = function ( array $request, Status $status ) use ( 
$method, $params ) {
+               $handler = function ( array $request, StatusValue $status ) use 
( $method, $params ) {
                        list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = 
$request['response'];
                        if ( $rcode === 202 ) {
                                // good
@@ -568,7 +568,7 @@
        }
 
        protected function doPrepareInternal( $fullCont, $dir, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // (a) Check if container already exists
                $stat = $this->getContainerStat( $fullCont );
@@ -591,7 +591,7 @@
        }
 
        protected function doSecureInternal( $fullCont, $dir, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                if ( empty( $params['noAccess'] ) ) {
                        return $status; // nothing to do
                }
@@ -615,7 +615,7 @@
        }
 
        protected function doPublishInternal( $fullCont, $dir, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $stat = $this->getContainerStat( $fullCont );
                if ( is_array( $stat ) ) {
@@ -636,7 +636,7 @@
        }
 
        protected function doCleanInternal( $fullCont, $dir, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                // Only containers themselves can be removed, all else is 
virtual
                if ( $dir != '' ) {
@@ -719,7 +719,7 @@
                // Find prior metadata headers
                $postHeaders += $this->getMetadataHeaders( $objHdrs );
 
-               $status = Status::newGood();
+               $status = $this->newStatus();
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scopeLockS = $this->getScopedFileLocks( [ $path ], 
LockManager::LOCK_UW, $status );
                if ( $status->isOK() ) {
@@ -1043,7 +1043,7 @@
        }
 
        protected function doStreamFile( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $flags = !empty( $params['headless'] ) ? 
StreamFile::STREAM_HEADLESS : 0;
 
@@ -1254,7 +1254,7 @@
        /**
         * @param FileBackendStoreOpHandle[] $fileOpHandles
         *
-        * @return Status[]
+        * @return StatusValue[]
         */
        protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
                $statuses = [];
@@ -1262,7 +1262,7 @@
                $auth = $this->getAuthentication();
                if ( !$auth ) {
                        foreach ( $fileOpHandles as $index => $fileOpHandle ) {
-                               $statuses[$index] = Status::newFatal( 
'backend-fail-connect', $this->name );
+                               $statuses[$index] = $this->newStatus( 
'backend-fail-connect', $this->name );
                        }
 
                        return $statuses;
@@ -1280,7 +1280,7 @@
                                $req['headers'] = $this->authTokenHeaders( 
$auth ) + $req['headers'];
                                $httpReqsByStage[$stage][$index] = $req;
                        }
-                       $statuses[$index] = Status::newGood();
+                       $statuses[$index] = $this->newStatus();
                }
 
                // Run all requests for the first stage, then the next, and so 
on
@@ -1325,10 +1325,10 @@
         * @param array $writeGrps A list of the possible criteria for a 
request to have
         * access to write to a container. Each item is of the following format:
         *   - account:user       : Grants access if the request is by the 
given user
-        * @return Status
+        * @return StatusValue
         */
        protected function setContainerAccess( $container, array $readGrps, 
array $writeGrps ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
                $auth = $this->getAuthentication();
 
                if ( !$auth ) {
@@ -1411,10 +1411,10 @@
         *
         * @param string $container Container name
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function createContainer( $container, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $auth = $this->getAuthentication();
                if ( !$auth ) {
@@ -1456,10 +1456,10 @@
         *
         * @param string $container Container name
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        protected function deleteContainer( $container, array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $auth = $this->getAuthentication();
                if ( !$auth ) {
@@ -1497,12 +1497,12 @@
         * @param string|null $after
         * @param string|null $prefix
         * @param string|null $delim
-        * @return Status With the list as value
+        * @return StatusValue With the list as value
         */
        private function objectListing(
                $fullCont, $type, $limit, $after = null, $prefix = null, $delim 
= null
        ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $auth = $this->getAuthentication();
                if ( !$auth ) {
@@ -1739,17 +1739,17 @@
 
        /**
         * Log an unexpected exception for this backend.
-        * This also sets the Status object to have a fatal error.
+        * This also sets the StatusValue object to have a fatal error.
         *
-        * @param Status|null $status
+        * @param StatusValue|null $status
         * @param string $func
         * @param array $params
         * @param string $err Error string
         * @param int $code HTTP status
-        * @param string $desc HTTP status description
+        * @param string $desc HTTP StatusValue description
         */
        public function onError( $status, $func, array $params, $err = '', 
$code = 0, $desc = '' ) {
-               if ( $status instanceof Status ) {
+               if ( $status instanceof StatusValue ) {
                        $status->fatal( 'backend-fail-internal', $this->name );
                }
                if ( $code == 401 ) { // possibly a stale token
diff --git a/includes/filebackend/filejournal/DBFileJournal.php 
b/includes/filebackend/filejournal/DBFileJournal.php
index 7efb3a1..2e06c40 100644
--- a/includes/filebackend/filejournal/DBFileJournal.php
+++ b/includes/filebackend/filejournal/DBFileJournal.php
@@ -48,10 +48,10 @@
         * @see FileJournal::logChangeBatch()
         * @param array $entries
         * @param string $batchId
-        * @return Status
+        * @return StatusValue
         */
        protected function doLogChangeBatch( array $entries, $batchId ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
 
                try {
                        $dbw = $this->getMasterDB();
@@ -151,11 +151,11 @@
 
        /**
         * @see FileJournal::purgeOldLogs()
-        * @return Status
+        * @return StatusValue
         * @throws DBError
         */
        protected function doPurgeOldLogs() {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
                if ( $this->ttlDays <= 0 ) {
                        return $status; // nothing to do
                }
diff --git a/includes/filebackend/filejournal/FileJournal.php 
b/includes/filebackend/filejournal/FileJournal.php
index b84e195..f0bb92d 100644
--- a/includes/filebackend/filejournal/FileJournal.php
+++ b/includes/filebackend/filejournal/FileJournal.php
@@ -95,11 +95,11 @@
         *     newSha1 : The final base 36 SHA-1 of the file
         *   Note that 'false' should be used as the SHA-1 for non-existing 
files.
         * @param string $batchId UUID string that identifies the operation 
batch
-        * @return Status
+        * @return StatusValue
         */
        final public function logChangeBatch( array $entries, $batchId ) {
                if ( !count( $entries ) ) {
-                       return Status::newGood();
+                       return StatusValue::newGood();
                }
 
                return $this->doLogChangeBatch( $entries, $batchId );
@@ -110,7 +110,7 @@
         *
         * @param array $entries List of file operations (each an array of 
parameters)
         * @param string $batchId UUID string that identifies the operation 
batch
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doLogChangeBatch( array $entries, $batchId 
);
 
@@ -186,7 +186,7 @@
        /**
         * Purge any old log entries
         *
-        * @return Status
+        * @return StatusValue
         */
        final public function purgeOldLogs() {
                return $this->doPurgeOldLogs();
@@ -194,7 +194,7 @@
 
        /**
         * @see FileJournal::purgeOldLogs()
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doPurgeOldLogs();
 }
@@ -208,10 +208,10 @@
         * @see FileJournal::doLogChangeBatch()
         * @param array $entries
         * @param string $batchId
-        * @return Status
+        * @return StatusValue
         */
        protected function doLogChangeBatch( array $entries, $batchId ) {
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        /**
@@ -243,9 +243,9 @@
 
        /**
         * @see FileJournal::doPurgeOldLogs()
-        * @return Status
+        * @return StatusValue
         */
        protected function doPurgeOldLogs() {
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 }
diff --git a/includes/filebackend/lockmanager/FSLockManager.php 
b/includes/filebackend/lockmanager/FSLockManager.php
index 2b660ec..8e149d6 100644
--- a/includes/filebackend/lockmanager/FSLockManager.php
+++ b/includes/filebackend/lockmanager/FSLockManager.php
@@ -62,7 +62,7 @@
         * @see LockManager::doLock()
         * @param array $paths
         * @param int $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doLock( array $paths, $type ) {
                $status = Status::newGood();
@@ -87,7 +87,7 @@
         * @see LockManager::doUnlock()
         * @param array $paths
         * @param int $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doUnlock( array $paths, $type ) {
                $status = Status::newGood();
@@ -104,7 +104,7 @@
         *
         * @param string $path
         * @param int $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doSingleLock( $path, $type ) {
                $status = Status::newGood();
@@ -149,7 +149,7 @@
         *
         * @param string $path
         * @param int $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doSingleUnlock( $path, $type ) {
                $status = Status::newGood();
@@ -192,7 +192,7 @@
        /**
         * @param string $path
         * @param array $handlesToClose
-        * @return Status
+        * @return StatusValue
         */
        private function closeLockHandles( $path, array $handlesToClose ) {
                $status = Status::newGood();
@@ -210,7 +210,7 @@
 
        /**
         * @param string $path
-        * @return Status
+        * @return StatusValue
         */
        private function pruneKeyLockFiles( $path ) {
                $status = Status::newGood();
diff --git a/includes/filebackend/lockmanager/LockManager.php 
b/includes/filebackend/lockmanager/LockManager.php
index a3cb3b1..eff031b 100644
--- a/includes/filebackend/lockmanager/LockManager.php
+++ b/includes/filebackend/lockmanager/LockManager.php
@@ -87,7 +87,7 @@
         * @param array $paths List of resource names
         * @param int $type LockManager::LOCK_* constant
         * @param int $timeout Timeout in seconds (0 means non-blocking) (since 
1.21)
-        * @return Status
+        * @return StatusValue
         */
        final public function lock( array $paths, $type = self::LOCK_EX, 
$timeout = 0 ) {
                return $this->lockByType( [ $type => $paths ], $timeout );
@@ -98,7 +98,7 @@
         *
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
         * @param int $timeout Timeout in seconds (0 means non-blocking) (since 
1.21)
-        * @return Status
+        * @return StatusValue
         * @since 1.22
         */
        final public function lockByType( array $pathsByType, $timeout = 0 ) {
@@ -123,7 +123,7 @@
         *
         * @param array $paths List of paths
         * @param int $type LockManager::LOCK_* constant
-        * @return Status
+        * @return StatusValue
         */
        final public function unlock( array $paths, $type = self::LOCK_EX ) {
                return $this->unlockByType( [ $type => $paths ] );
@@ -133,7 +133,7 @@
         * Unlock the resources at the given abstract paths
         *
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         * @since 1.22
         */
        final public function unlockByType( array $pathsByType ) {
@@ -187,7 +187,7 @@
        /**
         * @see LockManager::lockByType()
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         * @since 1.22
         */
        protected function doLockByType( array $pathsByType ) {
@@ -214,14 +214,14 @@
         *
         * @param array $paths List of paths
         * @param int $type LockManager::LOCK_* constant
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doLock( array $paths, $type );
 
        /**
         * @see LockManager::unlockByType()
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         * @since 1.22
         */
        protected function doUnlockByType( array $pathsByType ) {
@@ -238,7 +238,7 @@
         *
         * @param array $paths List of paths
         * @param int $type LockManager::LOCK_* constant
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doUnlock( array $paths, $type );
 }
diff --git a/includes/filebackend/lockmanager/MemcLockManager.php 
b/includes/filebackend/lockmanager/MemcLockManager.php
index 2f17e27..2e2d0a3 100644
--- a/includes/filebackend/lockmanager/MemcLockManager.php
+++ b/includes/filebackend/lockmanager/MemcLockManager.php
@@ -126,7 +126,7 @@
         * @param string $lockSrv
         * @param array $paths
         * @param string $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
                $status = Status::newGood();
@@ -202,7 +202,7 @@
         * @param string $lockSrv
         * @param array $paths
         * @param string $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doFreeLocksOnServer( $lockSrv, array $paths, $type ) 
{
                $status = Status::newGood();
@@ -254,7 +254,7 @@
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
                return Status::newGood(); // not supported
diff --git a/includes/filebackend/lockmanager/MySqlLockManager.php 
b/includes/filebackend/lockmanager/MySqlLockManager.php
index 0536091..896e0ff 100644
--- a/includes/filebackend/lockmanager/MySqlLockManager.php
+++ b/includes/filebackend/lockmanager/MySqlLockManager.php
@@ -35,7 +35,7 @@
         * @param string $lockSrv
         * @param array $paths
         * @param string $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
                $status = Status::newGood();
@@ -105,7 +105,7 @@
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
                $status = Status::newGood();
diff --git a/includes/filebackend/lockmanager/PostgreSqlLockManager.php 
b/includes/filebackend/lockmanager/PostgreSqlLockManager.php
index d55b5ae..307c1644 100644
--- a/includes/filebackend/lockmanager/PostgreSqlLockManager.php
+++ b/includes/filebackend/lockmanager/PostgreSqlLockManager.php
@@ -61,7 +61,7 @@
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
                $status = Status::newGood();
diff --git a/includes/filebackend/lockmanager/QuorumLockManager.php 
b/includes/filebackend/lockmanager/QuorumLockManager.php
index 108b846..0db9e81 100644
--- a/includes/filebackend/lockmanager/QuorumLockManager.php
+++ b/includes/filebackend/lockmanager/QuorumLockManager.php
@@ -124,7 +124,7 @@
         *
         * @param int $bucket
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         */
        final protected function doLockingRequestBucket( $bucket, array 
$pathsByType ) {
                $status = Status::newGood();
@@ -166,7 +166,7 @@
         *
         * @param int $bucket
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         */
        final protected function doUnlockingRequestBucket( $bucket, array 
$pathsByType ) {
                $status = Status::newGood();
@@ -189,7 +189,7 @@
                                }
                        }
                }
-               // Set a bad status if the quorum was not met.
+               // Set a bad StatusValue if the quorum was not met.
                // Assumes the same "up" servers as during the acquire step.
                $status->setResult( $yesVotes >= $quorum );
 
@@ -222,7 +222,7 @@
         *
         * @param string $lockSrv
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function getLocksOnServer( $lockSrv, array 
$pathsByType );
 
@@ -233,7 +233,7 @@
         *
         * @param string $lockSrv
         * @param array $pathsByType Map of LockManager::LOCK_* constants to 
lists of paths
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function freeLocksOnServer( $lockSrv, array 
$pathsByType );
 
@@ -242,7 +242,7 @@
         *
         * Subclasses must effectively implement this or freeLocksOnServer().
         *
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function releaseAllLocks();
 }
diff --git a/includes/filebackend/lockmanager/ScopedLock.php 
b/includes/filebackend/lockmanager/ScopedLock.php
index e1a600c..05ab289 100644
--- a/includes/filebackend/lockmanager/ScopedLock.php
+++ b/includes/filebackend/lockmanager/ScopedLock.php
@@ -35,7 +35,7 @@
        /** @var LockManager */
        protected $manager;
 
-       /** @var Status */
+       /** @var StatusValue */
        protected $status;
 
        /** @var array Map of lock types to resource paths */
@@ -44,9 +44,9 @@
        /**
         * @param LockManager $manager
         * @param array $pathsByType Map of lock types to path lists
-        * @param Status $status
+        * @param StatusValue $status
         */
-       protected function __construct( LockManager $manager, array 
$pathsByType, Status $status ) {
+       protected function __construct( LockManager $manager, array 
$pathsByType, StatusValue $status ) {
                $this->manager = $manager;
                $this->pathsByType = $pathsByType;
                $this->status = $status;
@@ -55,19 +55,19 @@
        /**
         * Get a ScopedLock object representing a lock on resource paths.
         * Any locks are released once this object goes out of scope.
-        * The status object is updated with any errors or warnings.
+        * The StatusValue object is updated with any errors or warnings.
         *
         * @param LockManager $manager
         * @param array $paths List of storage paths or map of lock types to 
path lists
         * @param int|string $type LockManager::LOCK_* constant or "mixed" and 
$paths
         *   can be a map of types to paths (since 1.22). Otherwise $type 
should be an
         *   integer and $paths should be a list of paths.
-        * @param Status $status
+        * @param StatusValue $status
         * @param int $timeout Timeout in seconds (0 means non-blocking) (since 
1.22)
         * @return ScopedLock|null Returns null on failure
         */
        public static function factory(
-               LockManager $manager, array $paths, $type, Status $status, 
$timeout = 0
+               LockManager $manager, array $paths, $type, StatusValue $status, 
$timeout = 0
        ) {
                $pathsByType = is_integer( $type ) ? [ $type => $paths ] : 
$paths;
                $lockStatus = $manager->lockByType( $pathsByType, $timeout );
@@ -80,7 +80,7 @@
        }
 
        /**
-        * Release a scoped lock and set any errors in the attatched Status 
object.
+        * Release a scoped lock and set any errors in the attatched 
StatusValue object.
         * This is useful for early release of locks before function scope is 
destroyed.
         * This is the same as setting the lock object to null.
         *
@@ -98,7 +98,7 @@
                $wasOk = $this->status->isOK();
                $this->status->merge( $this->manager->unlockByType( 
$this->pathsByType ) );
                if ( $wasOk ) {
-                       // Make sure status is OK, despite any unlockFiles() 
fatals
+                       // Make sure StatusValue is OK, despite any 
unlockFiles() fatals
                        $this->status->setResult( true, $this->status->value );
                }
        }

-- 
To view, visit https://gerrit.wikimedia.org/r/311203
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iff9255f34870ea6b0c4b91f6ddc69eea95186aba
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <asch...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to