| Index: branches/FileBackend/phase3/includes/filerepo/TempLocalFile.php |
| — | — | @@ -1,60 +0,0 @@ |
| 2 | | -<?php |
| 3 | | - |
| 4 | | -/** |
| 5 | | - * This class is used to hold the location to and do limited manipulation of |
| 6 | | - * files stored temporarily (usually this will be $wgTmpDirectory) |
| 7 | | - * |
| 8 | | - */ |
| 9 | | -class TempLocalFile { |
| 10 | | - |
| 11 | | - /** |
| 12 | | - * Path to local temp file directory |
| 13 | | - * @var String |
| 14 | | - */ |
| 15 | | - private $path; |
| 16 | | - |
| 17 | | - /** |
| 18 | | - * Does this object have authority to remove the temp file |
| 19 | | - * @var Boolean |
| 20 | | - */ |
| 21 | | - private $canDelete; |
| 22 | | - |
| 23 | | - /** |
| 24 | | - * Sets up the temporary file object |
| 25 | | - * @param String $path - Path to temporary file on local disk |
| 26 | | - * @param Boolean $canDelete - Does this object have authority to remove the file |
| 27 | | - */ |
| 28 | | - public function __construct($path, $canDelete = true) { |
| 29 | | - $this->path = $path; |
| 30 | | - $this->canDelete = $canDelete; |
| 31 | | - } |
| 32 | | - |
| 33 | | - /** |
| 34 | | - * Returns the local path to the temp file |
| 35 | | - * @return String |
| 36 | | - */ |
| 37 | | - public function getPath() { |
| 38 | | - return $this->path; |
| 39 | | - } |
| 40 | | - |
| 41 | | - /** |
| 42 | | - * If this object has the authority this method will remove the temp file |
| 43 | | - * from the local disk. This method is called on object destruct, but |
| 44 | | - * may also be called any time a cleanup is needed |
| 45 | | - */ |
| 46 | | - public function cleanup() { |
| 47 | | - if($this->canDelete) { |
| 48 | | - unlink($this->path); |
| 49 | | - } |
| 50 | | - } |
| 51 | | - |
| 52 | | - /** |
| 53 | | - * Object destructor. |
| 54 | | - * |
| 55 | | - * Cleans up after the temporary file. Currently this means removing it |
| 56 | | - * from the local disk |
| 57 | | - */ |
| 58 | | - public function __destruct() { |
| 59 | | - $this->cleanup(); |
| 60 | | - } |
| 61 | | -} // end class |
| \ No newline at end of file |
| Property changes on: branches/FileBackend/phase3/includes/filerepo/file/File.php |
| ___________________________________________________________________ |
| Modified: svn:mergeinfo |
| 62 | 1 | Merged /trunk/phase3/includes/filerepo/file/File.php:r103742 |
| Index: branches/FileBackend/phase3/includes/filerepo/file/TempLocalFile.php |
| — | — | @@ -0,0 +1,46 @@ |
| | 2 | +<?php |
| | 3 | +/** |
| | 4 | + * @file |
| | 5 | + * @ingroup FileRepo |
| | 6 | + */ |
| | 7 | + |
| | 8 | +/** |
| | 9 | + * This class is used to hold the location and do limited manipulation |
| | 10 | + * of files stored temporarily (usually this will be $wgTmpDirectory) |
| | 11 | + */ |
| | 12 | +class TempLocalFile { |
| | 13 | + protected $path; // path to local temp file directory |
| | 14 | + protected $canDelete; // whether this object should garbage collect the temp file |
| | 15 | + |
| | 16 | + /** |
| | 17 | + * Sets up the temporary file object |
| | 18 | + * |
| | 19 | + * @param String $path Path to temporary file on local disk |
| | 20 | + * @param Boolean $canDelete Whether this object should garbage collect the temp file |
| | 21 | + */ |
| | 22 | + public function __construct( $path, $canDelete = true ) { |
| | 23 | + $this->path = $path; |
| | 24 | + $this->canDelete = $canDelete; |
| | 25 | + } |
| | 26 | + |
| | 27 | + /** |
| | 28 | + * Returns the local path to the temp file |
| | 29 | + * |
| | 30 | + * @return String |
| | 31 | + */ |
| | 32 | + public function getPath() { |
| | 33 | + return $this->path; |
| | 34 | + } |
| | 35 | + |
| | 36 | + /** |
| | 37 | + * Cleans up after the temporary file. |
| | 38 | + * Currently this means removing it from the local disk. |
| | 39 | + */ |
| | 40 | + protected function __destruct() { |
| | 41 | + if ( $this->canDelete ) { |
| | 42 | + wfSuppressWarnings(); |
| | 43 | + unlink( $this->path ); |
| | 44 | + wfRestoreWarnings(); |
| | 45 | + } |
| | 46 | + } |
| | 47 | +} |
| Property changes on: branches/FileBackend/phase3/includes/filerepo/file/TempLocalFile.php |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 48 | + native |
| Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php |
| — | — | @@ -28,9 +28,10 @@ |
| 29 | 29 | |
| 30 | 30 | public function __construct( array $config ) { |
| 31 | 31 | $this->name = $config['name']; |
| | 32 | + $this->fileBackends = $config['backends']; |
| 32 | 33 | } |
| 33 | 34 | |
| 34 | | - public function getName() { |
| | 35 | + function getName() { |
| 35 | 36 | return $this->name; |
| 36 | 37 | } |
| 37 | 38 | |
| — | — | @@ -72,32 +73,32 @@ |
| 73 | 74 | return $status; |
| 74 | 75 | } |
| 75 | 76 | |
| 76 | | - public function store( array $params ) { |
| | 77 | + function store( array $params ) { |
| 77 | 78 | $op = array( 'operation' => 'store' ) + $params; |
| 78 | 79 | return $this->doOperation( array( $op ) ); |
| 79 | 80 | } |
| 80 | 81 | |
| 81 | | - public function copy( array $params ) { |
| | 82 | + function copy( array $params ) { |
| 82 | 83 | $op = array( 'operation' => 'copy' ) + $params; |
| 83 | 84 | return $this->doOperation( array( $op ) ); |
| 84 | 85 | } |
| 85 | 86 | |
| 86 | | - public function move( array $params ) { |
| | 87 | + function move( array $params ) { |
| 87 | 88 | $op = array( 'operation' => 'move' ) + $params; |
| 88 | 89 | return $this->doOperation( array( $op ) ); |
| 89 | 90 | } |
| 90 | 91 | |
| 91 | | - public function delete( array $params ){ |
| | 92 | + function delete( array $params ){ |
| 92 | 93 | $op = array( 'operation' => 'delete' ) + $params; |
| 93 | 94 | return $this->doOperation( array( $op ) ); |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | | - public function concatenate( array $params ){ |
| | 97 | + function concatenate( array $params ){ |
| 97 | 98 | $op = array( 'operation' => 'concatenate' ) + $params; |
| 98 | 99 | return $this->doOperation( array( $op ) ); |
| 99 | 100 | } |
| 100 | 101 | |
| 101 | | - public function fileExists( array $params ) { |
| | 102 | + function fileExists( array $params ) { |
| 102 | 103 | foreach ( $this->backends as $backend ) { |
| 103 | 104 | if ( $backend->fileExists( $params ) ) { |
| 104 | 105 | return true; |
| — | — | @@ -105,28 +106,43 @@ |
| 106 | 107 | } |
| 107 | 108 | return false; |
| 108 | 109 | } |
| 109 | | - |
| 110 | | - public function getLocalCopy( array $params ) { |
| | 110 | + |
| | 111 | + function getFileProps( array $params ) { |
| 111 | 112 | foreach ( $this->backends as $backend ) { |
| 112 | | - $tmpPath = $backend->getLocalCopy( $params ); |
| 113 | | - if ( $tmpPath !== null ) { |
| 114 | | - return $tmpPath; |
| | 113 | + $props = $backend->getFileProps( $params ); |
| | 114 | + if ( $props !== null ) { |
| | 115 | + return $props; |
| 115 | 116 | } |
| 116 | 117 | } |
| 117 | 118 | return null; |
| 118 | 119 | } |
| 119 | | - |
| 120 | | - public function getFileProps( array $params ) { |
| | 120 | + |
| | 121 | + function streamFile( array $params ) { |
| | 122 | + if ( !count( $this->backends ) ) { |
| | 123 | + return Status::newFatal( "No file backends are defined." ); |
| | 124 | + } |
| 121 | 125 | foreach ( $this->backends as $backend ) { |
| 122 | | - $props = $backend->getFileProps( $params ); |
| 123 | | - if ( $props !== null ) { |
| 124 | | - return $props; |
| | 126 | + $status = $backend->streamFile( $params ); |
| | 127 | + if ( $status->isOK() ) { |
| | 128 | + return $status; |
| | 129 | + } else { |
| | 130 | + // @TODO: check if we failed mid-stream and return out if so |
| 125 | 131 | } |
| 126 | 132 | } |
| | 133 | + return Status::newFatal( "Could not stream file {$params['source']}." ); |
| | 134 | + } |
| | 135 | + |
| | 136 | + function getLocalCopy( array $params ) { |
| | 137 | + foreach ( $this->backends as $backend ) { |
| | 138 | + $tmpFile = $backend->getLocalCopy( $params ); |
| | 139 | + if ( $tmpFile ) { |
| | 140 | + return $tmpFile; |
| | 141 | + } |
| | 142 | + } |
| 127 | 143 | return null; |
| 128 | 144 | } |
| 129 | 145 | |
| 130 | | - public function lockFiles( array $paths ) { |
| | 146 | + function lockFiles( array $paths ) { |
| 131 | 147 | $status = Status::newGood(); |
| 132 | 148 | foreach ( $this->backends as $index => $backend ) { |
| 133 | 149 | $subStatus = $backend->lockFiles( $paths ); |
| — | — | @@ -143,7 +159,7 @@ |
| 144 | 160 | return $status; |
| 145 | 161 | } |
| 146 | 162 | |
| 147 | | - public function unlockFiles( array $paths ) { |
| | 163 | + function unlockFiles( array $paths ) { |
| 148 | 164 | $status = Status::newGood(); |
| 149 | 165 | foreach ( $this->backends as $backend ) { |
| 150 | 166 | $subStatus = $backend->unlockFile( $paths ); |
| Index: branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php |
| — | — | @@ -18,7 +18,7 @@ |
| 19 | 19 | : 0644; |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | | - public function store( array $params ) { |
| | 22 | + function store( array $params ) { |
| 23 | 23 | $status = Status::newGood(); |
| 24 | 24 | |
| 25 | 25 | if ( file_exists( $params['dest'] ) ) { |
| — | — | @@ -54,11 +54,11 @@ |
| 55 | 55 | return $status; |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | | - public function copy( array $params ) { |
| | 58 | + function copy( array $params ) { |
| 59 | 59 | return $this->store( $params ); // both source and dest are on FS |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | | - public function move( array $params ) { |
| | 62 | + function move( array $params ) { |
| 63 | 63 | $status = Status::newGood(); |
| 64 | 64 | |
| 65 | 65 | if ( file_exists( $params['dest'] ) ) { |
| — | — | @@ -92,7 +92,7 @@ |
| 93 | 93 | return $status; |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | | - public function delete( array $params ) { |
| | 96 | + function delete( array $params ) { |
| 97 | 97 | $status = Status::newGood(); |
| 98 | 98 | |
| 99 | 99 | if ( !file_exists( $params['source'] ) ) { |
| — | — | @@ -113,7 +113,7 @@ |
| 114 | 114 | return $status; |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | | - public function concatenate( array $params ) { |
| | 117 | + function concatenate( array $params ) { |
| 118 | 118 | $status = Status::newGood(); |
| 119 | 119 | |
| 120 | 120 | // Check if the destination file exists and we can't handle that |
| — | — | @@ -196,15 +196,27 @@ |
| 197 | 197 | return $status; |
| 198 | 198 | } |
| 199 | 199 | |
| 200 | | - public function fileExists( array $params ) { |
| | 200 | + function fileExists( array $params ) { |
| 201 | 201 | return file_exists( $params['source'] ); |
| 202 | 202 | } |
| 203 | 203 | |
| 204 | | - public function getFileProps( array $params ) { |
| | 204 | + function getFileProps( array $params ) { |
| 205 | 205 | return File::getPropsFromPath( $params['source'] ); |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | | - public function getLocalCopy( array $params ) { |
| | 208 | + function streamFile( array $params ) { |
| | 209 | + $status = Status::newGood(); |
| | 210 | + |
| | 211 | + $ok = StreamFile::stream( $params['source'], array(), false ); |
| | 212 | + if ( !$ok ) { |
| | 213 | + $status->fatal( "Unable to stream file {$params['source']}." ); |
| | 214 | + return $status; |
| | 215 | + } |
| | 216 | + |
| | 217 | + return $status; |
| | 218 | + } |
| | 219 | + |
| | 220 | + function getLocalCopy( array $params ) { |
| 209 | 221 | // Create a new temporary file... |
| 210 | 222 | wfSuppressWarnings(); |
| 211 | 223 | $tmpPath = tempnam( wfTempDir(), 'file_localcopy' ); |
| — | — | @@ -223,7 +235,7 @@ |
| 224 | 236 | |
| 225 | 237 | $this->chmod( $tmpPath ); |
| 226 | 238 | |
| 227 | | - return $tmpPath; |
| | 239 | + return new TempLocalFile( $tmpPath ); |
| 228 | 240 | } |
| 229 | 241 | |
| 230 | 242 | /** |
| Index: branches/FileBackend/phase3/includes/filerepo/backend/FileLockManager.php |
| — | — | @@ -164,7 +164,7 @@ |
| 165 | 165 | return $status; |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | | - function __destruct() { |
| | 168 | + protected function __destruct() { |
| 169 | 169 | // Make sure remaining files get cleared for sanity |
| 170 | 170 | foreach ( $this->handles as $key => $handler ) { |
| 171 | 171 | flock( $handler, LOCK_UN ); // PHP 5.3 will not do this automatically |
| Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php |
| — | — | @@ -154,12 +154,25 @@ |
| 155 | 155 | public function getFileProps( array $params ); |
| 156 | 156 | |
| 157 | 157 | /** |
| 158 | | - * Get a local copy on dist of the file at a storage path in the backend |
| | 158 | + * Stream the file that exists at a storage path in the backend. |
| | 159 | + * Appropriate HTTP headers (Status, Content-Type, Content-Length) |
| | 160 | + * must be sent on success, while no headers should be sent on failure. |
| | 161 | + * Implementations should flush the output buffer before sending data. |
| 159 | 162 | * $params include: |
| | 163 | + * source : source storage path |
| | 164 | + * |
| | 165 | + * @param Array $params |
| | 166 | + * @return Status |
| | 167 | + */ |
| | 168 | + public function streamFile( array $params ); |
| | 169 | + |
| | 170 | + /** |
| | 171 | + * Get a local copy on disk of the file at a storage path in the backend |
| | 172 | + * $params include: |
| 160 | 173 | * source : source storage path |
| 161 | 174 | * |
| 162 | 175 | * @param Array $params |
| 163 | | - * @return string|null Path to temporary file or null on failure |
| | 176 | + * @return TempLocalFile|null Temporary file or null on failure |
| 164 | 177 | */ |
| 165 | 178 | public function getLocalCopy( array $params ); |
| 166 | 179 | |
| — | — | @@ -440,7 +453,8 @@ |
| 441 | 454 | * overwriteSame : override any existing file at destination |
| 442 | 455 | */ |
| 443 | 456 | class FileStoreOp extends FileOp { |
| 444 | | - protected $tmpDestPath; // temp copy of existing destination file |
| | 457 | + /** @var TempLocalFile|null */ |
| | 458 | + protected $tmpDestFile; // temp copy of existing destination file |
| 445 | 459 | |
| 446 | 460 | function doAttempt() { |
| 447 | 461 | // Create a backup copy of any file that exists at destination |
| — | — | @@ -485,8 +499,8 @@ |
| 486 | 500 | if ( $this->backend->fileExists( $this->params['dest'] ) ) { |
| 487 | 501 | if ( $this->params['overwriteDest'] ) { |
| 488 | 502 | // Create a temporary backup copy... |
| 489 | | - $this->tmpDestPath = $this->getLocalCopy( $this->params['dest'] ); |
| 490 | | - if ( $this->tmpDestPath === null ) { |
| | 503 | + $this->tmpDestFile = $this->getLocalCopy( $this->params['dest'] ); |
| | 504 | + if ( !$this->tmpDestFile ) { |
| 491 | 505 | $status->fatal( "Could not backup destination file." ); |
| 492 | 506 | return $status; |
| 493 | 507 | } |
| — | — | @@ -503,9 +517,9 @@ |
| 504 | 518 | protected function restoreDest() { |
| 505 | 519 | $status = Status::newGood(); |
| 506 | 520 | // Restore any file that was at the destination |
| 507 | | - if ( $this->tmpDestPath !== null ) { |
| | 521 | + if ( $this->tmpDestFile ) { |
| 508 | 522 | $params = array( |
| 509 | | - 'source' => $this->tmpDestPath, |
| | 523 | + 'source' => $this->tmpDestFile->getPath(), |
| 510 | 524 | 'dest' => $this->params['dest'] |
| 511 | 525 | ); |
| 512 | 526 | $status = $this->backend->store( $params ); |