From: Aaron Schulz Date: Fri, 1 Feb 2013 20:12:58 +0000 (-0800) Subject: [FileBackend] Set ignore_user_abort() in file operations. X-Git-Tag: 1.31.0-rc.0~20805^2 X-Git-Url: http://git.cyclocoop.org/%24image?a=commitdiff_plain;h=dce693efdc71de4b91f154ce6d69ffa9a201c1d4;p=lhc%2Fweb%2Fwiklou.git [FileBackend] Set ignore_user_abort() in file operations. * This reduces the change of partial operations. WMF sites already set ignore_user_abort() in configuration, but this makes sure that it always happens during file changes. Change-Id: I702c27fc3c19aca0cdd39b793a3250ead40bfe71 --- diff --git a/includes/filebackend/FileBackend.php b/includes/filebackend/FileBackend.php index 0e61d0c4b3..a3e1de3019 100644 --- a/includes/filebackend/FileBackend.php +++ b/includes/filebackend/FileBackend.php @@ -314,6 +314,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 ); } @@ -544,6 +545,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 ); } @@ -687,6 +689,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 +717,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 +746,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 +771,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 +780,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.