Fixed @param tags to conform with Doxygen format.
[lhc/web/wiklou.git] / includes / filebackend / FileBackend.php
index 0e61d0c..00fd6fb 100644 (file)
  * Outside callers can assume that all backends will have these functions.
  *
  * All "storage paths" are of the format "mwstore://<backend>/<container>/<path>".
- * The "<path>" portion is a relative path that uses UNIX file system (FS)
- * notation, though any particular backend may not actually be using a local
- * filesystem. Therefore, the relative paths are only virtual.
+ * The "backend" portion is unique name for MediaWiki to refer to a backend, while
+ * the "container" portion is a top-level directory of the backend. The "path" portion
+ * is a relative path that uses UNIX file system (FS) notation, though any particular
+ * backend may not actually be using a local filesystem. Therefore, the relative paths
+ * are only virtual.
  *
  * Backend contents are stored under wiki-specific container names by default.
- * For legacy reasons, this has no effect for the FS backend class, and per-wiki
- * segregation must be done by setting the container paths appropriately.
+ * Global (qualified) backends are achieved by configuring the "wiki ID" to a constant.
+ * For legacy reasons, the FSFileBackend class allows manually setting the paths of
+ * containers to ones that do not respect the "wiki ID".
  *
+ * In key/value stores, the container is the only hierarchy (the rest is emulated).
  * FS-based backends are somewhat more restrictive due to the existence of real
  * directory files; a regular file cannot have the same name as a directory. Other
  * backends with virtual directories may not have this limitation. Callers should
@@ -75,10 +79,13 @@ abstract class FileBackend {
         * $config includes:
         *   - name        : The unique name of this backend.
         *                   This should consist of alphanumberic, '-', and '_' characters.
-        *                   This name should not be changed after use.
-        *   - wikiId      : Prefix to container names that is unique to this wiki.
+        *                   This name should not be changed after use (e.g. with journaling).
+        *                   Note that the name is *not* used in actual container names.
+        *   - wikiId      : Prefix to container names that is unique to this backend.
         *                   If not provided, this defaults to the current wiki ID.
         *                   It should only consist of alphanumberic, '-', and '_' characters.
+        *                   This ID is what avoids collisions if multiple logical backends
+        *                   use the same storage system, so this should be set carefully.
         *   - lockManager : Registered name of a file lock manager to use.
         *   - fileJournal : File journal configuration; see FileJournal::factory().
         *                   Journals simply log changes to files stored in the backend.
@@ -276,7 +283,7 @@ abstract class FileBackend {
         * $opts is an associative of boolean flags, including:
         *   - force               : Operation precondition errors no longer trigger an abort.
         *                           Any remaining operations are still attempted. Unexpected
-        *                           failures may still cause remaning operations to be aborted.
+        *                           failures may still cause remaining operations to be aborted.
         *   - nonLocking          : No locks are acquired for the operations.
         *                           This can increase performance for non-critical writes.
         *                           This has no effect unless the 'force' flag is set.
@@ -303,8 +310,8 @@ abstract class FileBackend {
         *   - a) unexpected operation errors occurred (network partitions, disk full...)
         *   - b) significant operation errors occurred and 'force' was not set
         *
-        * @param $ops Array List of operations to execute in order
-        * @param $opts Array Batch operation options
+        * @param array $ops List of operations to execute in order
+        * @param array $opts Batch operation options
         * @return Status
         */
        final public function doOperations( array $ops, array $opts = array() ) {
@@ -314,6 +321,7 @@ abstract class FileBackend {
                if ( empty( $opts['force'] ) ) { // sanity
                        unset( $opts['nonLocking'] );
                }
+               $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
                return $this->doOperationsInternal( $ops, $opts );
        }
 
@@ -329,8 +337,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperations()
         *
-        * @param $op Array Operation
-        * @param $opts Array Operation options
+        * @param array $op Operation
+        * @param array $opts Operation options
         * @return Status
         */
        final public function doOperation( array $op, array $opts = array() ) {
@@ -343,8 +351,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperation()
         *
-        * @param $params Array Operation parameters
-        * @param $opts Array Operation options
+        * @param array $params Operation parameters
+        * @param array $opts Operation options
         * @return Status
         */
        final public function create( array $params, array $opts = array() ) {
@@ -357,8 +365,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperation()
         *
-        * @param $params Array Operation parameters
-        * @param $opts Array Operation options
+        * @param array $params Operation parameters
+        * @param array $opts Operation options
         * @return Status
         */
        final public function store( array $params, array $opts = array() ) {
@@ -371,8 +379,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperation()
         *
-        * @param $params Array Operation parameters
-        * @param $opts Array Operation options
+        * @param array $params Operation parameters
+        * @param array $opts Operation options
         * @return Status
         */
        final public function copy( array $params, array $opts = array() ) {
@@ -385,8 +393,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperation()
         *
-        * @param $params Array Operation parameters
-        * @param $opts Array Operation options
+        * @param array $params Operation parameters
+        * @param array $opts Operation options
         * @return Status
         */
        final public function move( array $params, array $opts = array() ) {
@@ -399,8 +407,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperation()
         *
-        * @param $params Array Operation parameters
-        * @param $opts Array Operation options
+        * @param array $params Operation parameters
+        * @param array $opts Operation options
         * @return Status
         */
        final public function delete( array $params, array $opts = array() ) {
@@ -413,8 +421,8 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperation()
         *
-        * @param $params Array Operation parameters
-        * @param $opts Array Operation options
+        * @param array $params Operation parameters
+        * @param array $opts Operation options
         * @return Status
         * @since 1.21
         */
@@ -532,8 +540,8 @@ abstract class FileBackend {
         * will reflect each operation attempted for the given files. The status will be
         * considered "OK" as long as no fatal errors occurred.
         *
-        * @param $ops Array Set of operations to execute
-        * @param $opts Array Batch operation options
+        * @param array $ops Set of operations to execute
+        * @param array $opts Batch operation options
         * @return Status
         * @since 1.20
         */
@@ -544,6 +552,7 @@ abstract class FileBackend {
                foreach ( $ops as &$op ) {
                        $op['overwrite'] = true; // avoids RTTs in key/value stores
                }
+               $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
                return $this->doQuickOperationsInternal( $ops );
        }
 
@@ -559,7 +568,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperations()
         *
-        * @param $op Array Operation
+        * @param array $op Operation
         * @return Status
         * @since 1.20
         */
@@ -573,7 +582,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperation()
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * @return Status
         * @since 1.20
         */
@@ -587,7 +596,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperation()
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * @return Status
         * @since 1.20
         */
@@ -601,7 +610,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperation()
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * @return Status
         * @since 1.20
         */
@@ -615,7 +624,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperation()
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * @return Status
         * @since 1.20
         */
@@ -629,7 +638,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperation()
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * @return Status
         * @since 1.20
         */
@@ -643,7 +652,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doQuickOperation()
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * @return Status
         * @since 1.21
         */
@@ -657,7 +666,7 @@ abstract class FileBackend {
         * otherwise safe from modification from other processes. Normally,
         * the file will be a new temp file, which should be adequate.
         *
-        * @param $params Array Operation parameters
+        * @param array $params Operation parameters
         * $params include:
         *   - srcs        : ordered source storage paths (e.g. chunk1, chunk2, ...)
         *   - dst         : file system path to 0-byte temp file
@@ -687,6 +696,7 @@ abstract class FileBackend {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
                        return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
                }
+               $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
                return $this->doPrepare( $params );
        }
 
@@ -714,6 +724,7 @@ abstract class FileBackend {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
                        return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
                }
+               $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
                return $this->doSecure( $params );
        }
 
@@ -742,6 +753,7 @@ abstract class FileBackend {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
                        return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
                }
+               $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
                return $this->doPublish( $params );
        }
 
@@ -766,6 +778,7 @@ abstract class FileBackend {
                if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
                        return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
                }
+               $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
                return $this->doClean( $params );
        }
 
@@ -774,6 +787,21 @@ abstract class FileBackend {
         */
        abstract protected function doClean( array $params );
 
+       /**
+        * Enter file operation scope.
+        * This just makes PHP ignore user aborts/disconnects until the return
+        * value leaves scope. This returns null and does nothing in CLI mode.
+        *
+        * @return ScopedCallback|null
+        */
+       final protected function getScopedPHPBehaviorForOps() {
+               if ( php_sapi_name() != 'cli' ) { // http://bugs.php.net/bug.php?id=47540
+                       $old = ignore_user_abort( true ); // avoid half-finished operations
+                       return new ScopedCallback( function() use ( $old ) { ignore_user_abort( $old ); } );
+               }
+               return null;
+       }
+
        /**
         * Check if a file exists at a storage path in the backend.
         * This returns false if only a directory exists at the path.
@@ -988,6 +1016,7 @@ abstract class FileBackend {
         * @param $params Array
         * $params include:
         *   - src : source storage path
+        *   - ttl : lifetime (seconds) if pre-authenticated; default is 1 day
         * @return string|null
         * @since 1.21
         */
@@ -1081,7 +1110,7 @@ abstract class FileBackend {
         * Preload persistent file stat and property cache into in-process cache.
         * This should be used when stat calls will be made on a known list of a many files.
         *
-        * @param $paths Array Storage paths
+        * @param array $paths Storage paths
         * @return void
         */
        public function preloadCache( array $paths ) {}
@@ -1090,7 +1119,7 @@ abstract class FileBackend {
         * Invalidate any in-process file stat and property cache.
         * If $paths is given, then only the cache for those files will be cleared.
         *
-        * @param $paths Array Storage paths (optional)
+        * @param array $paths Storage paths (optional)
         * @return void
         */
        public function clearCache( array $paths = null ) {}
@@ -1101,7 +1130,7 @@ abstract class FileBackend {
         *
         * Callers should consider using getScopedFileLocks() instead.
         *
-        * @param $paths Array Storage paths
+        * @param array $paths Storage paths
         * @param $type integer LockManager::LOCK_* constant
         * @return Status
         */
@@ -1112,7 +1141,7 @@ abstract class FileBackend {
        /**
         * Unlock the files at the given storage paths in the backend.
         *
-        * @param $paths Array Storage paths
+        * @param array $paths Storage paths
         * @param $type integer LockManager::LOCK_* constant
         * @return Status
         */
@@ -1128,7 +1157,7 @@ abstract class FileBackend {
         * 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.
         *
-        * @param $paths Array Storage paths
+        * @param array $paths Storage paths
         * @param $type integer LockManager::LOCK_* constant
         * @param $status Status Status to update on lock/unlock
         * @return ScopedLock|null Returns null on failure
@@ -1148,7 +1177,7 @@ abstract class FileBackend {
         *
         * @see FileBackend::doOperations()
         *
-        * @param $ops Array List of file operations to FileBackend::doOperations()
+        * @param array $ops List of file operations to FileBackend::doOperations()
         * @param $status Status Status to update on lock/unlock
         * @return Array List of ScopedFileLocks or null values
         * @since 1.20
@@ -1169,7 +1198,7 @@ abstract class FileBackend {
        /**
         * Get the storage path for the given container for this backend
         *
-        * @param $container string Container name
+        * @param string $container Container name
         * @return string Storage path
         * @since 1.21
         */
@@ -1250,7 +1279,7 @@ abstract class FileBackend {
         */
        final public static function parentStoragePath( $storagePath ) {
                $storagePath = dirname( $storagePath );
-               list( $b, $cont, $rel ) = self::splitStoragePath( $storagePath );
+               list( , $rel ) = self::splitStoragePath( $storagePath );
                return ( $rel === null ) ? null : $storagePath;
        }
 
@@ -1279,8 +1308,8 @@ abstract class FileBackend {
        /**
         * Build a Content-Disposition header value per RFC 6266.
         *
-        * @param $type string One of (attachment, inline)
-        * @param $filename string Suggested file name (should not contain slashes)
+        * @param string $type One of (attachment, inline)
+        * @param string $filename Suggested file name (should not contain slashes)
         * @throws MWException
         * @return string
         * @since 1.20
@@ -1308,7 +1337,7 @@ abstract class FileBackend {
         *
         * This uses the same traversal protection as Title::secureAndSplit().
         *
-        * @param $path string Storage path relative to a container
+        * @param string $path Storage path relative to a container
         * @return string|null
         */
        final protected static function normalizeContainerPath( $path ) {