Make Status extend StatusValue and start FileBackend update
authorAaron Schulz <aschulz@wikimedia.org>
Fri, 16 Sep 2016 22:55:40 +0000 (15:55 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Sat, 17 Sep 2016 22:45:40 +0000 (15:45 -0700)
* This avoids code duplication.
* Callers can safely start type-hinting StatusValue as well.
* Also moved the wrap() logic out of Status::__construct(), which
  only wrap() was (and should have been) using. Use "static" as
  well, so subclass behave properly.
* 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

20 files changed:
includes/Status.php
includes/filebackend/FSFileBackend.php
includes/filebackend/FileBackend.php
includes/filebackend/FileBackendMultiWrite.php
includes/filebackend/FileBackendStore.php
includes/filebackend/FileOp.php
includes/filebackend/FileOpBatch.php
includes/filebackend/MemoryFileBackend.php
includes/filebackend/SwiftFileBackend.php
includes/filebackend/filejournal/DBFileJournal.php
includes/filebackend/filejournal/FileJournal.php
includes/filebackend/lockmanager/FSLockManager.php
includes/filebackend/lockmanager/LockManager.php
includes/filebackend/lockmanager/MemcLockManager.php
includes/filebackend/lockmanager/MySqlLockManager.php
includes/filebackend/lockmanager/PostgreSqlLockManager.php
includes/filebackend/lockmanager/QuorumLockManager.php
includes/filebackend/lockmanager/ScopedLock.php
includes/filerepo/FileBackendDBRepoWrapper.php
includes/libs/StatusValue.php

index a6348b7..07828fe 100644 (file)
  * 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;
-
-       /** @var mixed */
-       public $value;
-       /** @var array Map of (key => bool) to indicate success of each part of batch operations */
-       public $success = [];
-       /** @var int Counter for batch operations */
-       public $successCount = 0;
-       /** @var int Counter for batch operations */
-       public $failCount = 0;
-
+class Status extends StatusValue {
        /** @var callable */
        public $cleanCallback = false;
 
-       /**
-        * @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;
-       }
-
        /**
         * Succinct helper method to wrap a StatusValue
         *
@@ -77,119 +53,83 @@ class Status {
         * @return Status
         */
        public static function wrap( $sv ) {
-               return $sv instanceof Status ? $sv : new self( $sv );
+               if ( $sv instanceof static ) {
+                       return $sv;
+               }
+
+               $result = new static();
+               $result->ok =& $sv->ok;
+               $result->errors =& $sv->errors;
+               $result->value =& $sv->value;
+               $result->successCount =& $sv->successCount;
+               $result->failCount =& $sv->failCount;
+               $result->success =& $sv->success;
+
+               return $result;
        }
 
        /**
-        * Factory function for fatal errors
+        * Backwards compatibility logic
         *
-        * @param string|Message $message Message name or object
-        * @return Status
+        * @param string $name
+        * @return mixed
+        * @throws RuntimeException
         */
-       public static function newFatal( $message /*, parameters...*/ ) {
-               return new self( call_user_func_array(
-                       [ 'StatusValue', 'newFatal' ], func_get_args()
-               ) );
+       function __get( $name ) {
+               if ( $name === 'ok' ) {
+                       return $this->isOK();
+               } elseif ( $name === 'errors' ) {
+                       return $this->getErrors();
+               }
+
+               throw new RuntimeException( "Cannot get '$name' property." );
        }
 
        /**
-        * Factory function for good results
+        * Change operation result
+        * Backwards compatibility logic
         *
+        * @param string $name
         * @param mixed $value
-        * @return Status
+        * @throws RuntimeException
         */
-       public static function newGood( $value = null ) {
-               $sv = new StatusValue();
-               $sv->value = $value;
-
-               return new self( $sv );
+       function __set( $name, $value ) {
+               if ( $name === 'ok' ) {
+                       $this->setOK( $value );
+               } elseif ( !property_exists( $this, $name ) ) {
+                       // Caller is using undeclared ad-hoc properties
+                       $this->$name = $value;
+               } else {
+                       throw new RuntimeException( "Cannot set '$name' property." );
+               }
        }
 
        /**
         * Splits this Status object into two new Status objects, one which contains only
         * the error messages, and one that contains the warnings, only. The returned array is
         * defined as:
-        * array(
-        *      0 => object(Status) # the Status with error messages, only
-        *      1 => object(Status) # The Status with warning messages, only
-        * )
+        * [
+        *     0 => object(Status) # the Status with error messages, only
+        *     1 => object(Status) # The Status with warning messages, only
+        * ]
         *
         * @return array
         */
        public function splitByErrorType() {
-               list( $errorsOnlyStatusValue, $warningsOnlyStatusValue ) = $this->sv->splitByErrorType();
-               $errorsOnlyStatus = new Status( $errorsOnlyStatusValue );
-               $warningsOnlyStatus = new Status( $warningsOnlyStatusValue );
-               $errorsOnlyStatus->cleanCallback = $warningsOnlyStatus->cleanCallback = $this->cleanCallback;
+               list( $errorsOnlyStatus, $warningsOnlyStatus ) = parent::splitByErrorType();
+               $errorsOnlyStatus->cleanCallback =
+                       $warningsOnlyStatus->cleanCallback = $this->cleanCallback;
 
                return [ $errorsOnlyStatus, $warningsOnlyStatus ];
        }
 
-       /**
-        * 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;
        }
 
        /**
@@ -237,16 +177,16 @@ class Status {
        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();
@@ -285,24 +225,24 @@ class Status {
         *
         * 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 );
@@ -333,12 +273,12 @@ class Status {
        }
 
        /**
-        * Return the message for a single error.
+        * Return the message for a single error
         *
-        * @param mixed $error With an array & two values keyed by
-        * 'message' and 'params', use those keys-value pairs.
-        * Otherwise, if its an array, just use the first value as the
-        * message and the remaining items as the params.
+        * The code string can be used a message key with per-language versions.
+        * If $error is an array, the "params" field is a list of parameters for the message.
+        *
+        * @param array|string $error Code string or (key: code string, params: string[]) map
         * @param string|Language $lang Language to use for processing messages
         * @return Message
         */
@@ -354,8 +294,10 @@ class Status {
                                $msg = wfMessage( $msgName,
                                        array_map( 'wfEscapeWikiText', $this->cleanParams( $error ) ) );
                        }
-               } else {
+               } elseif ( is_string( $error ) ) {
                        $msg = wfMessage( $error );
+               } else {
+                       throw new UnexpectedValueException( "Got " . get_class( $error ) . " for key." );
                }
 
                $msg->inLanguage( $this->languageFromParam( $lang ) );
@@ -363,12 +305,11 @@ class Status {
        }
 
        /**
-        * 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 ) {
@@ -391,16 +332,6 @@ class Status {
                }, $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 );
-       }
-
        /**
         * Get the list of errors (but not warnings)
         *
@@ -434,7 +365,7 @@ class Status {
        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(
@@ -452,92 +383,6 @@ class Status {
                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();
-       }
-
        /**
         * Don't save the callback when serializing, because Closures can't be
         * serialized and we're going to clear it in __wakeup anyway.
index efe78ee..b0e3eee 100644 (file)
@@ -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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        protected function doCreateInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dest = $this->resolveToFSPath( $params['dst'] );
                if ( $dest === null ) {
@@ -214,7 +214,7 @@ class FSFileBackend extends FileBackendStore {
                                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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        protected function doStoreInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dest = $this->resolveToFSPath( $params['dst'] );
                if ( $dest === null ) {
@@ -253,7 +253,7 @@ class FSFileBackend extends FileBackendStore {
                                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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        protected function doCopyInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $source = $this->resolveToFSPath( $params['src'] );
                if ( $source === null ) {
@@ -311,7 +311,7 @@ class FSFileBackend extends FileBackendStore {
                                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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        protected function doMoveInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $source = $this->resolveToFSPath( $params['src'] );
                if ( $source === null ) {
@@ -371,7 +371,7 @@ class FSFileBackend extends FileBackendStore {
                                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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        protected function doDeleteInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $source = $this->resolveToFSPath( $params['src'] );
                if ( $source === null ) {
@@ -416,7 +416,7 @@ class FSFileBackend extends FileBackendStore {
                                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 @@ class FSFileBackend extends FileBackendStore {
         * @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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        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 @@ class FSFileBackend extends FileBackendStore {
        }
 
        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 @@ class FSFileBackend extends FileBackendStore {
        /**
         * @param FSFileOpHandle[] $fileOpHandles
         *
-        * @return Status[]
+        * @return StatusValue[]
         */
        protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
                $statuses = [];
@@ -701,7 +701,7 @@ class FSFileBackend extends FileBackendStore {
                }
 
                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;
index ed36a1f..1f91b3f 100644 (file)
@@ -104,6 +104,9 @@ abstract class FileBackend {
        /** @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,8 @@ abstract class FileBackend {
                $this->concurrency = isset( $config['concurrency'] )
                        ? (int)$config['concurrency']
                        : 50;
+               // @TODO: dependency inject this
+               $this->statusWrapper = [ 'Status', 'wrap' ];
        }
 
        /**
@@ -359,20 +364,20 @@ abstract class FileBackend {
         * 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 +407,7 @@ abstract class FileBackend {
         *
         * @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 +421,7 @@ abstract class FileBackend {
         *
         * @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 +435,7 @@ abstract class FileBackend {
         *
         * @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 +449,7 @@ abstract class FileBackend {
         *
         * @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 +463,7 @@ abstract class FileBackend {
         *
         * @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 +477,7 @@ abstract class FileBackend {
         *
         * @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 +491,7 @@ abstract class FileBackend {
         *
         * @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 +602,20 @@ abstract class FileBackend {
         * @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 +643,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperations()
         *
         * @param array $op Operation
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function doQuickOperation( array $op ) {
@@ -652,7 +657,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickCreate( array $params ) {
@@ -666,7 +671,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickStore( array $params ) {
@@ -680,7 +685,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickCopy( array $params ) {
@@ -694,7 +699,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickMove( array $params ) {
@@ -708,7 +713,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.20
         */
        final public function quickDelete( array $params ) {
@@ -722,7 +727,7 @@ abstract class FileBackend {
         * @see FileBackend::doQuickOperation()
         *
         * @param array $params Operation parameters
-        * @return Status
+        * @return StatusValue
         * @since 1.21
         */
        final public function quickDescribe( array $params ) {
@@ -739,7 +744,7 @@ abstract class FileBackend {
         *   - 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 +764,11 @@ abstract class FileBackend {
         *   - 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 +795,11 @@ abstract class FileBackend {
         *   - 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 +827,12 @@ abstract class FileBackend {
         *   - 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 +854,11 @@ abstract class FileBackend {
         *   - 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 +1025,7 @@ abstract class FileBackend {
         *   - 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 +1255,7 @@ abstract class FileBackend {
         * @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 +1268,7 @@ abstract class FileBackend {
         *
         * @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 +1279,22 @@ abstract class FileBackend {
        /**
         * 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 @@ abstract class FileBackend {
         * @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 @@ abstract class FileBackend {
 
                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;
+       }
 }
 
 /**
index 3b20048..c1cc7bb 100644 (file)
@@ -148,7 +148,7 @@ class FileBackendMultiWrite extends FileBackend {
        }
 
        final protected function doOperationsInternal( array $ops, array $opts ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $mbe = $this->backends[$this->masterIndex]; // convenience
 
@@ -233,10 +233,10 @@ class FileBackendMultiWrite extends FileBackend {
         * 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 @@ class FileBackendMultiWrite extends FileBackend {
         * 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 @@ class FileBackendMultiWrite extends FileBackend {
         *
         * @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 @@ class FileBackendMultiWrite extends FileBackend {
        }
 
        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 @@ class FileBackendMultiWrite extends FileBackend {
        /**
         * @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 @@ class FileBackendMultiWrite extends FileBackend {
                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
index bc4d81d..4e25ce7 100644 (file)
@@ -106,19 +106,19 @@ abstract class FileBackendStore extends FileBackend {
         *   - 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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @see FileBackendStore::createInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doCreateInternal( array $params );
 
@@ -147,19 +147,19 @@ abstract class FileBackendStore extends FileBackend {
         *   - 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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @see FileBackendStore::storeInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doStoreInternal( array $params );
 
@@ -189,14 +189,14 @@ abstract class FileBackendStore extends FileBackend {
         *   - 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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @see FileBackendStore::copyInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doCopyInternal( array $params );
 
@@ -223,12 +223,12 @@ abstract class FileBackendStore extends FileBackend {
         * $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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @see FileBackendStore::deleteInternal()
         * @param array $params
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doDeleteInternal( array $params );
 
@@ -255,14 +255,14 @@ abstract class FileBackendStore extends FileBackend {
         *   - 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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @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 @@ abstract class FileBackendStore extends FileBackend {
         * $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 @@ abstract class FileBackendStore extends FileBackend {
                        $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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @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 @@ abstract class FileBackendStore extends FileBackend {
         * 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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @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 @@ abstract class FileBackendStore extends FileBackend {
 
        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 @@ abstract class FileBackendStore extends FileBackend {
         * @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 @@ abstract class FileBackendStore extends FileBackend {
         * @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 @@ abstract class FileBackendStore extends FileBackend {
         * @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 @@ abstract class FileBackendStore extends FileBackend {
         * @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 @@ abstract class FileBackendStore extends FileBackend {
 
        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 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * @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 @@ abstract class FileBackendStore extends FileBackend {
         * 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 @@ abstract class FileBackendStore extends FileBackend {
                ];
        }
 
-       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 @@ abstract class FileBackendStore extends FileBackend {
 
        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 @@ abstract class FileBackendStore extends FileBackend {
                        $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 @@ abstract class FileBackendStore extends FileBackend {
                                " 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 @@ abstract class FileBackendStore extends FileBackend {
 
        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 );
@@ -1139,8 +1139,8 @@ abstract class FileBackendStore extends FileBackend {
                // Parallel ops may be disabled in config due to dependencies (e.g. needing popen())
                $async = ( $this->parallelize === 'implicit' && count( $ops ) > 1 );
                $maxConcurrency = $this->concurrency; // throttle
-
-               $statuses = []; // array of (index => Status)
+               /** @var StatusValue[] $statuses */
+               $statuses = []; // array of (index => StatusValue)
                $fileOpHandles = []; // list of (index => handle) arrays
                $curFileOpHandles = []; // current handle batch
                // Perform the sync-only ops and build up op handles for the async ops...
@@ -1184,13 +1184,13 @@ abstract class FileBackendStore extends FileBackend {
 
        /**
         * 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 StatusValue[] Map of StatusValue objects
         */
        final public function executeOpHandlesInternal( array $fileOpHandles ) {
                $ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
@@ -1216,7 +1216,7 @@ abstract class FileBackendStore extends FileBackend {
         * @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 @@ abstract class FileBackendStore extends FileBackend {
  * 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().
  */
index 56a4073..916366c 100644 (file)
@@ -239,14 +239,14 @@ abstract class FileOp {
        /**
         * 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 @@ abstract class FileOp {
 
        /**
         * @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 @@ abstract class FileOp {
                                $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 @@ abstract class FileOp {
        /**
         * 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 @@ class CreateFileOp extends FileOp {
        }
 
        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 @@ class CreateFileOp extends FileOp {
                        return $this->backend->createInternal( $this->setFlags( $this->params ) );
                }
 
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        protected function getSourceSha1Base36() {
@@ -535,7 +535,7 @@ class StoreFileOp extends FileOp {
        }
 
        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 @@ class StoreFileOp extends FileOp {
                        return $this->backend->storeInternal( $this->setFlags( $this->params ) );
                }
 
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 
        protected function getSourceSha1Base36() {
@@ -606,7 +606,7 @@ class CopyFileOp extends FileOp {
        }
 
        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 @@ class CopyFileOp extends FileOp {
 
        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 @@ class MoveFileOp extends FileOp {
        }
 
        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 @@ class MoveFileOp extends FileOp {
                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 @@ class DeleteFileOp extends FileOp {
        }
 
        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 @@ class DescribeFileOp extends FileOp {
        }
 
        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'] );
index 78209d8..e34ad8c 100644 (file)
@@ -45,17 +45,17 @@ class FileOpBatch {
         *   - 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 @@ class FileOpBatch {
                if ( count( $entries ) ) {
                        $subStatus = $journal->logChangeBatch( $entries, $batchId );
                        if ( !$subStatus->isOK() ) {
-                               return $subStatus; // abort
+                               $status->merge( $subStatus );
+
+                               return $status; // abort
                        }
                }
 
@@ -142,9 +144,9 @@ class FileOpBatch {
         * 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 */
@@ -158,13 +160,13 @@ class FileOpBatch {
                                }
                                continue;
                        }
-                       /** @var Status[] $statuses */
+                       /** @var StatusValue[] $statuses */
                        $statuses = [];
                        $opHandles = [];
                        // Get the backend; all sub-batch ops belong to a single backend
                        $backend = reset( $performOpsBatch )->getBackend();
                        // Get the operation handles or actually do it if there is just one.
-                       // If attemptAsync() returns a Status, it was either due to an error
+                       // If attemptAsync() returns a StatusValue, it was either due to an error
                        // or the backend does not support async ops and did it synchronously.
                        foreach ( $performOpsBatch as $i => $fileOp ) {
                                if ( !isset( $status->success[$i] ) ) { // didn't already fail in precheck()
index e2c1ede..74a0068 100644 (file)
@@ -44,7 +44,7 @@ class MemoryFileBackend extends FileBackendStore {
        }
 
        protected function doCreateInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dst = $this->resolveHashKey( $params['dst'] );
                if ( $dst === null ) {
@@ -62,7 +62,7 @@ class MemoryFileBackend extends FileBackendStore {
        }
 
        protected function doStoreInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $dst = $this->resolveHashKey( $params['dst'] );
                if ( $dst === null ) {
@@ -89,7 +89,7 @@ class MemoryFileBackend extends FileBackendStore {
        }
 
        protected function doCopyInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $src = $this->resolveHashKey( $params['src'] );
                if ( $src === null ) {
@@ -122,7 +122,7 @@ class MemoryFileBackend extends FileBackendStore {
        }
 
        protected function doDeleteInternal( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $src = $this->resolveHashKey( $params['src'] );
                if ( $src === null ) {
index 2adf934..a0027e4 100644 (file)
@@ -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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                ] ];
 
                $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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                ] ];
 
                $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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                ] ];
 
                $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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                }
 
                $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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                ] ];
 
                $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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                ] ];
 
                $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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        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 @@ class SwiftFileBackend extends FileBackendStore {
                // 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 @@ class SwiftFileBackend extends FileBackendStore {
        }
 
        protected function doStreamFile( array $params ) {
-               $status = Status::newGood();
+               $status = $this->newStatus();
 
                $flags = !empty( $params['headless'] ) ? StreamFile::STREAM_HEADLESS : 0;
 
@@ -1254,7 +1254,7 @@ class SwiftFileBackend extends FileBackendStore {
        /**
         * @param FileBackendStoreOpHandle[] $fileOpHandles
         *
-        * @return Status[]
+        * @return StatusValue[]
         */
        protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
                $statuses = [];
@@ -1262,7 +1262,7 @@ class SwiftFileBackend extends FileBackendStore {
                $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 @@ class SwiftFileBackend extends FileBackendStore {
                                $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 @@ class SwiftFileBackend extends FileBackendStore {
         * @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 @@ class SwiftFileBackend extends FileBackendStore {
         *
         * @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 @@ class SwiftFileBackend extends FileBackendStore {
         *
         * @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 @@ class SwiftFileBackend extends FileBackendStore {
         * @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 @@ class SwiftFileBackend extends FileBackendStore {
 
        /**
         * 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
index 7efb3a1..2e06c40 100644 (file)
@@ -48,10 +48,10 @@ class DBFileJournal extends FileJournal {
         * @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 @@ class DBFileJournal extends FileJournal {
 
        /**
         * @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
                }
index b84e195..f0bb92d 100644 (file)
@@ -95,11 +95,11 @@ abstract class FileJournal {
         *     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 @@ abstract class FileJournal {
         *
         * @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 @@ abstract class FileJournal {
        /**
         * Purge any old log entries
         *
-        * @return Status
+        * @return StatusValue
         */
        final public function purgeOldLogs() {
                return $this->doPurgeOldLogs();
@@ -194,7 +194,7 @@ abstract class FileJournal {
 
        /**
         * @see FileJournal::purgeOldLogs()
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doPurgeOldLogs();
 }
@@ -208,10 +208,10 @@ class NullFileJournal extends FileJournal {
         * @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 @@ class NullFileJournal extends FileJournal {
 
        /**
         * @see FileJournal::doPurgeOldLogs()
-        * @return Status
+        * @return StatusValue
         */
        protected function doPurgeOldLogs() {
-               return Status::newGood();
+               return StatusValue::newGood();
        }
 }
index 2b660ec..8e149d6 100644 (file)
@@ -62,7 +62,7 @@ class FSLockManager extends LockManager {
         * @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 @@ class FSLockManager extends LockManager {
         * @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 @@ class FSLockManager extends LockManager {
         *
         * @param string $path
         * @param int $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doSingleLock( $path, $type ) {
                $status = Status::newGood();
@@ -149,7 +149,7 @@ class FSLockManager extends LockManager {
         *
         * @param string $path
         * @param int $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doSingleUnlock( $path, $type ) {
                $status = Status::newGood();
@@ -192,7 +192,7 @@ class FSLockManager extends LockManager {
        /**
         * @param string $path
         * @param array $handlesToClose
-        * @return Status
+        * @return StatusValue
         */
        private function closeLockHandles( $path, array $handlesToClose ) {
                $status = Status::newGood();
@@ -210,7 +210,7 @@ class FSLockManager extends LockManager {
 
        /**
         * @param string $path
-        * @return Status
+        * @return StatusValue
         */
        private function pruneKeyLockFiles( $path ) {
                $status = Status::newGood();
index a3cb3b1..eff031b 100644 (file)
@@ -87,7 +87,7 @@ abstract class LockManager {
         * @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 @@ abstract class LockManager {
         *
         * @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 @@ abstract class LockManager {
         *
         * @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 @@ abstract class LockManager {
         * 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 @@ abstract class LockManager {
        /**
         * @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 @@ abstract class LockManager {
         *
         * @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 @@ abstract class LockManager {
         *
         * @param array $paths List of paths
         * @param int $type LockManager::LOCK_* constant
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function doUnlock( array $paths, $type );
 }
index 2f17e27..2e2d0a3 100644 (file)
@@ -126,7 +126,7 @@ class MemcLockManager extends QuorumLockManager {
         * @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 @@ class MemcLockManager extends QuorumLockManager {
         * @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 @@ class MemcLockManager extends QuorumLockManager {
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
                return Status::newGood(); // not supported
index 0536091..896e0ff 100644 (file)
@@ -35,7 +35,7 @@ class MySqlLockManager extends DBLockManager {
         * @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 @@ class MySqlLockManager extends DBLockManager {
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
                $status = Status::newGood();
index d55b5ae..307c164 100644 (file)
@@ -61,7 +61,7 @@ class PostgreSqlLockManager extends DBLockManager {
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
                $status = Status::newGood();
index 108b846..0db9e81 100644 (file)
@@ -124,7 +124,7 @@ abstract class QuorumLockManager extends LockManager {
         *
         * @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 @@ abstract class QuorumLockManager extends LockManager {
         *
         * @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 @@ abstract class QuorumLockManager extends LockManager {
                                }
                        }
                }
-               // 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 @@ abstract class QuorumLockManager extends LockManager {
         *
         * @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 @@ abstract class QuorumLockManager extends LockManager {
         *
         * @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 @@ abstract class QuorumLockManager extends LockManager {
         *
         * Subclasses must effectively implement this or freeLocksOnServer().
         *
-        * @return Status
+        * @return StatusValue
         */
        abstract protected function releaseAllLocks();
 }
index e1a600c..05ab289 100644 (file)
@@ -35,7 +35,7 @@ class ScopedLock {
        /** @var LockManager */
        protected $manager;
 
-       /** @var Status */
+       /** @var StatusValue */
        protected $status;
 
        /** @var array Map of lock types to resource paths */
@@ -44,9 +44,9 @@ class ScopedLock {
        /**
         * @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 @@ class ScopedLock {
        /**
         * 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 @@ class ScopedLock {
        }
 
        /**
-        * 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 @@ class ScopedLock {
                $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 );
                }
        }
index 596dbde..5bc60a0 100644 (file)
@@ -50,8 +50,10 @@ class FileBackendDBRepoWrapper extends FileBackend {
        protected $dbs;
 
        public function __construct( array $config ) {
-               $config['name'] = $config['backend']->getName();
-               $config['wikiId'] = $config['backend']->getWikiId();
+               /** @var FileBackend $backend */
+               $backend = $config['backend'];
+               $config['name'] = $backend->getName();
+               $config['wikiId'] = $backend->getWikiId();
                parent::__construct( $config );
                $this->backend = $config['backend'];
                $this->repoName = $config['repoName'];
@@ -256,7 +258,7 @@ class FileBackendDBRepoWrapper extends FileBackend {
                return $this->translateSrcParams( __FUNCTION__, $params );
        }
 
-       public function getScopedLocksForOps( array $ops, Status $status ) {
+       public function getScopedLocksForOps( array $ops, StatusValue $status ) {
                return $this->backend->getScopedLocksForOps( $ops, $status );
        }
 
index 7f41f55..45185c5 100644 (file)
@@ -83,10 +83,10 @@ class StatusValue {
         * Splits this StatusValue object into two new StatusValue objects, one which contains only
         * the error messages, and one that contains the warnings, only. The returned array is
         * defined as:
-        * array(
-        *      0 => object(StatusValue) # the StatusValue with error messages, only
-        *      1 => object(StatusValue) # The StatusValue with warning messages, only
-        * )
+        * [
+        *     0 => object(StatusValue) # the StatusValue with error messages, only
+        *         1 => object(StatusValue) # The StatusValue with warning messages, only
+        * ]
         *
         * @return array
         */