From 6455336013211f663b633c1803d3653cb08964eb Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Thu, 12 Jul 2012 12:48:16 -0700 Subject: [PATCH] [FileBackend] Added "bypassReadOnly" flag. * Added flag to bypass read-only checks to the 6 write functions. * Made backend copy and sync scripts pass in this new flag. * Also made sync script use doQuickOperations() since its faster. Change-Id: Iee47f79ed7ab002cfc2d0adb5321c3a8520f971d --- includes/filerepo/backend/FileBackend.php | 47 ++++++++++++++--------- maintenance/copyFileBackend.php | 6 +-- maintenance/syncFileBackend.php | 6 +-- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/includes/filerepo/backend/FileBackend.php b/includes/filerepo/backend/FileBackend.php index de61ef6b22..efafbd1c84 100644 --- a/includes/filerepo/backend/FileBackend.php +++ b/includes/filerepo/backend/FileBackend.php @@ -244,7 +244,8 @@ abstract class FileBackend { * This has no effect unless the 'force' flag is set. * - nonJournaled : Don't log this operation batch in the file journal. * This limits the ability of recovery scripts. - * - parallelize' : Try to do operations in parallel when possible. + * - parallelize : Try to do operations in parallel when possible. + * - bypassReadOnly : Allow writes in read-only mode (@since 1.20). * * @remarks Remarks on locking: * File system paths given to operations should refer to files that are @@ -266,7 +267,7 @@ abstract class FileBackend { * @return Status */ final public function doOperations( array $ops, array $opts = array() ) { - if ( $this->isReadOnly() ) { + if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) { return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); } if ( empty( $opts['force'] ) ) { // sanity @@ -441,6 +442,9 @@ abstract class FileBackend { * - ignoreMissingSource : The operation will simply succeed and do * nothing if the source file does not exist. * + * $opts is an associative of boolean flags, including: + * - bypassReadOnly : Allow writes in read-only mode (@since 1.20) + * * @par Return value: * This returns a Status, which contains all warnings and fatals that occured * during the operation. The 'failCount', 'successCount', and 'success' members @@ -448,11 +452,12 @@ abstract class FileBackend { * considered "OK" as long as no fatal errors occured. * * @param $ops Array Set of operations to execute + * @param $opts Array Batch operation options * @return Status * @since 1.20 */ - final public function doQuickOperations( array $ops ) { - if ( $this->isReadOnly() ) { + final public function doQuickOperations( array $ops, array $opts = array() ) { + if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) { return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); } foreach ( $ops as &$op ) { @@ -575,15 +580,16 @@ abstract class FileBackend { * These flags should always be set for directories that have private files. * * $params include: - * - dir : storage directory - * - noAccess : try to deny file access (@since 1.20) - * - noListing : try to deny file listing (@since 1.20) + * - dir : storage directory + * - 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) * * @param $params Array * @return Status */ final public function prepare( array $params ) { - if ( $this->isReadOnly() ) { + if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) { return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); } return $this->doPrepare( $params ); @@ -603,13 +609,14 @@ abstract class FileBackend { * * @param $params Array * $params include: - * - dir : storage directory - * - noAccess : try to deny file access - * - noListing : try to deny file listing + * - dir : storage directory + * - noAccess : try to deny file access + * - noListing : try to deny file listing + * - bypassReadOnly : allow writes in read-only mode (@since 1.20) * @return Status */ final public function secure( array $params ) { - if ( $this->isReadOnly() ) { + if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) { return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); } return $this->doSecure( $params ); @@ -628,16 +635,17 @@ abstract class FileBackend { * This essentially can undo the result of secure() calls. * * $params include: - * - dir : storage directory - * - access : try to allow file access - * - listing : try to allow file listing + * - dir : storage directory + * - access : try to allow file access + * - listing : try to allow file listing + * - bypassReadOnly : allow writes in read-only mode (@since 1.20) * * @param $params Array * @return Status * @since 1.20 */ final public function publish( array $params ) { - if ( $this->isReadOnly() ) { + if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) { return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); } return $this->doPublish( $params ); @@ -655,12 +663,13 @@ abstract class FileBackend { * * @param $params Array * $params include: - * - dir : storage directory - * - recursive : recursively delete empty subdirectories first (@since 1.20) + * - dir : storage directory + * - recursive : recursively delete empty subdirectories first (@since 1.20) + * - bypassReadOnly : allow writes in read-only mode (@since 1.20) * @return Status */ final public function clean( array $params ) { - if ( $this->isReadOnly() ) { + if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) { return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); } return $this->doClean( $params ); diff --git a/maintenance/copyFileBackend.php b/maintenance/copyFileBackend.php index 548a33b358..544f48b6c7 100644 --- a/maintenance/copyFileBackend.php +++ b/maintenance/copyFileBackend.php @@ -141,7 +141,7 @@ class CopyFileBackend extends Maintenance { } $fsFiles[] = $fsFile; // keep TempFSFile objects alive as needed // Note: prepare() is usually fast for key/value backends - $status = $dst->prepare( array( 'dir' => dirname( $dstPath ) ) ); + $status = $dst->prepare( array( 'dir' => dirname( $dstPath ), 'bypassReadOnly' => 1 ) ); if ( !$status->isOK() ) { $this->error( print_r( $status->getErrorsArray(), true ) ); $this->error( "Could not copy $srcPath to $dstPath.", 1 ); // die @@ -152,10 +152,10 @@ class CopyFileBackend extends Maintenance { } $t_start = microtime( true ); - $status = $dst->doQuickOperations( $ops ); + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); if ( !$status->isOK() ) { sleep( 10 ); // wait and retry copy again - $status = $dst->doQuickOperations( $ops ); + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); } $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); if ( !$status->isOK() ) { diff --git a/maintenance/syncFileBackend.php b/maintenance/syncFileBackend.php index 1af33e6ed4..c4ba66e14c 100644 --- a/maintenance/syncFileBackend.php +++ b/maintenance/syncFileBackend.php @@ -185,7 +185,8 @@ class SyncFileBackend extends Maintenance { } $fsFiles[] = $fsFile; // keep TempFSFile objects alive as needed // Note: prepare() is usually fast for key/value backends - $status->merge( $dst->prepare( array( 'dir' => dirname( $dPath ) ) ) ); + $status->merge( $dst->prepare( array( + 'dir' => dirname( $dPath ), 'bypassReadOnly' => 1 ) ) ); if ( !$status->isOK() ) { return $status; } @@ -201,8 +202,7 @@ class SyncFileBackend extends Maintenance { } $t_start = microtime( true ); - $status->merge( $dst->doOperations( $ops, - array( 'nonLocking' => 1, 'nonJournaled' => 1 ) ) ); + $status->merge( $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ) ); $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); if ( $status->isOK() && $this->getOption( 'verbose' ) ) { $this->output( "Synchronized these file(s) [{$ellapsed_ms}ms]:\n" . -- 2.20.1