Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php |
— | — | @@ -27,6 +27,8 @@ |
28 | 28 | /** @var Array List of FileBackend object informations */ |
29 | 29 | protected $fileBackendsInfo = array(); // array (backend index => array of settings) |
30 | 30 | |
| 31 | + protected $masterIndex; // index of master backend |
| 32 | + |
31 | 33 | /** |
32 | 34 | * Construct a proxy backend that consist of several internal backends. |
33 | 35 | * $config contains: |
— | — | @@ -39,10 +41,9 @@ |
40 | 42 | * @param $config Array |
41 | 43 | */ |
42 | 44 | public function __construct( array $config ) { |
43 | | - $this->name = $config['name']; |
44 | | - $this->lockManager = $config['lockManger']; |
| 45 | + parent::__construct( $config ); |
45 | 46 | |
46 | | - $hasMaster = false; |
| 47 | + $this->masterIndex = -1; |
47 | 48 | foreach ( $config['backends'] as $index => $info ) { |
48 | 49 | list( $backend, $settings ) = $info; |
49 | 50 | $this->fileBackends[$index] = $backend; |
— | — | @@ -51,13 +52,13 @@ |
52 | 53 | // Apply custom backend settings to defaults |
53 | 54 | $this->fileBackendsInfo[$index] = $info + $defaults; |
54 | 55 | if ( $info['isMaster'] ) { |
55 | | - if ( $hasMaster ) { |
| 56 | + if ( $this->masterIndex >= 0 ) { |
56 | 57 | throw new MWException( 'More than one master backend defined.' ); |
57 | 58 | } |
58 | | - $hasMaster = true; |
| 59 | + $this->masterIndex = $index; |
59 | 60 | } |
60 | 61 | } |
61 | | - if ( !$hasMaster ) { |
| 62 | + if ( $this->masterIndex < 0 ) { // need backends and must have a master |
62 | 63 | throw new MWException( 'No master backend defined.' ); |
63 | 64 | } |
64 | 65 | } |
— | — | @@ -127,40 +128,6 @@ |
128 | 129 | return $status; |
129 | 130 | } |
130 | 131 | |
131 | | - function store( array $params ) { |
132 | | - $op = array( 'operation' => 'store' ) + $params; |
133 | | - return $this->doOperation( array( $op ) ); |
134 | | - } |
135 | | - |
136 | | - function copy( array $params ) { |
137 | | - $op = array( 'operation' => 'copy' ) + $params; |
138 | | - return $this->doOperation( array( $op ) ); |
139 | | - } |
140 | | - |
141 | | - function canMove( array $params ) { |
142 | | - return true; // this is irrelevant |
143 | | - } |
144 | | - |
145 | | - function move( array $params ) { |
146 | | - $op = array( 'operation' => 'move' ) + $params; |
147 | | - return $this->doOperation( array( $op ) ); |
148 | | - } |
149 | | - |
150 | | - function delete( array $params ){ |
151 | | - $op = array( 'operation' => 'delete' ) + $params; |
152 | | - return $this->doOperation( array( $op ) ); |
153 | | - } |
154 | | - |
155 | | - function concatenate( array $params ){ |
156 | | - $op = array( 'operation' => 'concatenate' ) + $params; |
157 | | - return $this->doOperation( array( $op ) ); |
158 | | - } |
159 | | - |
160 | | - function create( array $params ) { |
161 | | - $op = array( 'operation' => 'create' ) + $params; |
162 | | - return $this->doOperation( array( $op ) ); |
163 | | - } |
164 | | - |
165 | 132 | function prepare( array $params ) { |
166 | 133 | $status = Status::newGood(); |
167 | 134 | foreach ( $this->backends as $backend ) { |
— | — | @@ -179,23 +146,13 @@ |
180 | 147 | } |
181 | 148 | |
182 | 149 | function getFileHash( array $params ) { |
183 | | - foreach ( $this->backends as $backend ) { |
184 | | - // Skip non-master for consistent hash formats |
185 | | - if ( $this->fileBackendsInfo[$index]['isMaster'] ) { |
186 | | - return $backend->getFileHash( $params ); |
187 | | - } |
188 | | - } |
189 | | - return false; |
| 150 | + // Skip non-master for consistent hash formats |
| 151 | + return $this->backends[$this->masterIndex]->getFileHash( $params ); |
190 | 152 | } |
191 | 153 | |
192 | 154 | function getHashType() { |
193 | | - foreach ( $this->backends as $backend ) { |
194 | | - // Skip non-master for consistent hash formats |
195 | | - if ( $this->fileBackendsInfo[$index]['isMaster'] ) { |
196 | | - return $backend->getHashType(); |
197 | | - } |
198 | | - } |
199 | | - return null; // shouldn't happen |
| 155 | + // Skip non-master for consistent hash formats |
| 156 | + return $this->backends[$this->masterIndex]->getHashType(); |
200 | 157 | } |
201 | 158 | |
202 | 159 | function getFileProps( array $params ) { |
— | — | @@ -209,9 +166,6 @@ |
210 | 167 | } |
211 | 168 | |
212 | 169 | function streamFile( array $params ) { |
213 | | - if ( !count( $this->backends ) ) { |
214 | | - return Status::newFatal( "No file backends are defined." ); |
215 | | - } |
216 | 170 | foreach ( $this->backends as $backend ) { |
217 | 171 | $status = $backend->streamFile( $params ); |
218 | 172 | if ( $status->isOK() ) { |
— | — | @@ -220,7 +174,7 @@ |
221 | 175 | return $status; // died mid-stream...so this is already fubar |
222 | 176 | } |
223 | 177 | } |
224 | | - return Status::newFatal( "Could not stream file {$params['source']}." ); |
| 178 | + return Status::newFatal( 'backend-fail-stream', $params['source'] ); |
225 | 179 | } |
226 | 180 | |
227 | 181 | function getLocalCopy( array $params ) { |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileOp.php |
— | — | @@ -181,8 +181,7 @@ |
182 | 182 | } |
183 | 183 | // Give an error if the files are not identical |
184 | 184 | if ( $shash !== $dhash ) { |
185 | | - $status->fatal( 'backend-fail-notsame', |
186 | | - $this->params['source'], $this->params['dest'] ); |
| 185 | + $status->fatal( 'backend-fail-notsame', $this->params['dest'] ); |
187 | 186 | } |
188 | 187 | return $status; // do nothing; either OK or bad status |
189 | 188 | } |
— | — | @@ -361,7 +360,7 @@ |
362 | 361 | * overwriteDest : do nothing and pass if an identical file exists at destination |
363 | 362 | * overwriteSame : override any existing file at destination |
364 | 363 | */ |
365 | | -class CopyFileOp extends StoreFileOp { |
| 364 | +class CopyFileOp extends FileOp { |
366 | 365 | function doPrecheck() { |
367 | 366 | $status = Status::newGood(); |
368 | 367 | // Check if the source files exists on disk |
— | — | @@ -507,11 +506,6 @@ |
508 | 507 | } |
509 | 508 | |
510 | 509 | function doAttempt() { |
511 | | - // Create a backup copy of any file that exists at destination |
512 | | - $status = $this->checkAndBackupDest(); |
513 | | - if ( !$status->isOK() ) { |
514 | | - return $status; |
515 | | - } |
516 | 510 | // Concatenate the file at the destination |
517 | 511 | $status = $this->backend->concatenate( $this->params ); |
518 | 512 | return $status; |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php |
— | — | @@ -45,11 +45,6 @@ |
46 | 46 | $status->fatal( 'backend-fail-delete', $param['dest'] ); |
47 | 47 | return $status; |
48 | 48 | } |
49 | | - } elseif ( isset( $params['overwriteSame'] ) ) { |
50 | | - if ( !$this->filesAreSame( $params['source'], $dest ) ) { |
51 | | - $status->fatal( 'backend-fail-notsame', $params['source'], $params['dest'] ); |
52 | | - } |
53 | | - return $status; // do nothing; either OK or bad status |
54 | 49 | } else { |
55 | 50 | $status->fatal( 'backend-fail-alreadyexists', $params['dest'] ); |
56 | 51 | return $status; |
— | — | @@ -106,11 +101,6 @@ |
107 | 102 | return $status; |
108 | 103 | } |
109 | 104 | } |
110 | | - } elseif ( isset( $params['overwriteSame'] ) ) { |
111 | | - if ( !$this->filesAreSame( $source, $dest ) ) { |
112 | | - $status->fatal( 'backend-fail-notsame', $params['source'], $params['dest'] ); |
113 | | - } |
114 | | - return $status; // do nothing; either OK or bad status |
115 | 105 | } else { |
116 | 106 | $status->fatal( 'backend-fail-alreadyexists', $params['dest'] ); |
117 | 107 | return $status; |
— | — | @@ -234,7 +224,7 @@ |
235 | 225 | } |
236 | 226 | } elseif ( isset( $params['overwriteSame'] ) ) { |
237 | 227 | if ( !$this->filesAreSame( $tmpPath, $dest ) ) { |
238 | | - $status->fatal( 'backend-fail-notsame', $tmpPath, $params['dest'] ); |
| 228 | + $status->fatal( 'backend-fail-notsame', $params['dest'] ); |
239 | 229 | } |
240 | 230 | return $status; // do nothing; either OK or bad status |
241 | 231 | } |
— | — | @@ -276,11 +266,6 @@ |
277 | 267 | $status->fatal( 'backend-fail-delete', $param['dest'] ); |
278 | 268 | return $status; |
279 | 269 | } |
280 | | - } elseif ( isset( $params['overwriteSame'] ) ) { |
281 | | - if ( !$this->fileAndDataAreSame( $dest, $params['content'] ) ) { |
282 | | - $status->fatal( 'backend-fail-notsame-raw', $params['dest'] ); |
283 | | - } |
284 | | - return $status; // do nothing; either OK or bad status |
285 | 270 | } else { |
286 | 271 | $status->fatal( 'backend-fail-alreadyexists', $params['dest'] ); |
287 | 272 | return $status; |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileLockManager.php |
— | — | @@ -214,13 +214,13 @@ |
215 | 215 | * This is meant for multi-wiki systems that may share share files. |
216 | 216 | * One or several database servers are set up having a `file_locking` |
217 | 217 | * table with one field, fl_key, the PRIMARY KEY. The table engine should |
218 | | - * have row-level locking. All lock requests for a resource, identified by |
219 | | - * a hash string, will map to one bucket. Each bucket maps to a single server. |
| 218 | + * have row-level locking. All lock requests for a resource, identified |
| 219 | + * by a hash string, will map to one bucket. |
220 | 220 | * |
221 | | - * Each bucket can also have several fallback servers. |
222 | | - * Fallback servers get the same lock statements as the primary bucket server. |
223 | | - * This propagation is only best-effort; lock requests will not be blocked just |
224 | | - * because a fallback server cannot be contacted. |
| 221 | + * Each bucket maps to one or several pier servers. |
| 222 | + * All pier servers must agree to a lock in order for it to be acquired. |
| 223 | + * As long as one pier server is up, lock requests will not be blocked |
| 224 | + * just because another pier server cannot be contacted. |
225 | 225 | * |
226 | 226 | * For performance, deadlock detection should be disabled and a small |
227 | 227 | * lock-wait timeout should be set via server config. In innoDB, this can |
— | — | @@ -228,19 +228,31 @@ |
229 | 229 | */ |
230 | 230 | class DBFileLockManager extends FileLockManager { |
231 | 231 | /** @var Array Map of bucket indexes to server names */ |
232 | | - protected $serverMap = array(); // (index => (server1,server2,...)) |
| 232 | + protected $serverMap; // (index => (server1, server2, ...)) |
| 233 | + protected $webTimeout; // integer number of seconds |
| 234 | + protected $cliTimeout; // integer number of seconds |
| 235 | + protected $resetDelay; // integer number of seconds |
233 | 236 | /** @var Array Map of (locked key => lock type => 1) */ |
234 | 237 | protected $locksHeld = array(); |
235 | | - /** $var Array Map Lock-active database connections (name => Database) */ |
| 238 | + /** $var Array Map Lock-active database connections (server name => Database) */ |
236 | 239 | protected $activeConns = array(); |
237 | 240 | |
238 | 241 | /** |
239 | 242 | * Construct a new instance from configuration. |
240 | 243 | * $config paramaters include: |
241 | | - * 'serverMap' : Array of no more than 16 consecutive integer keys, |
242 | | - * starting from 0, with a list of servers as values. |
243 | | - * The first server in each list is the main server and |
244 | | - * the others are fallback servers. |
| 244 | + * 'serverMap' : Array of no more than 16 consecutive integer keys, |
| 245 | + * starting from 0, with a list of servers as values. |
| 246 | + * The first server in each list is the main server and |
| 247 | + * the others are pier servers. |
| 248 | + * 'webTimeout' : Connection timeout (seconds) for non-CLI scripts. |
| 249 | + * This tells the DB server how long to wait before giving up |
| 250 | + * and releasing all the locks made in a session transaction. |
| 251 | + * 'cliTimeout' : Connection timeout (seconds) for CLI scripts. |
| 252 | + * This tells the DB server how long to wait before giving up |
| 253 | + * and releasing all the locks made in a session transaction. |
| 254 | + * 'resetDelay' : How long (seconds) to avoid using a DB server after it restarted. |
| 255 | + * This should reflect the highest max_execution_time that a PHP |
| 256 | + * script might use on this wiki. Locks are lost on server restart. |
245 | 257 | * |
246 | 258 | * @param Array $config |
247 | 259 | */ |
— | — | @@ -257,6 +269,19 @@ |
258 | 270 | wfWarn( "No key for bucket $i in serverMap or server list is empty." ); |
259 | 271 | } |
260 | 272 | } |
| 273 | + if ( !empty( $config['webTimeout'] ) ) { // disallow 0 |
| 274 | + $this->webTimeout = $config['webTimeout']; |
| 275 | + } elseif ( ini_get( 'max_execution_time' ) > 0 ) { |
| 276 | + $this->webTimeout = ini_get( 'max_execution_time' ); |
| 277 | + } else { // cli? |
| 278 | + $this->webTimeout = 60; // some sane number |
| 279 | + } |
| 280 | + $this->cliTimeout = !empty( $config['cliTimeout'] ) // disallow 0 |
| 281 | + ? $config['cliTimeout'] |
| 282 | + : 60; // some sane number |
| 283 | + $this->resetDelay = isset( $config['resetDelay'] ) |
| 284 | + ? $config['resetDelay'] |
| 285 | + : max( $this->cliTimeout, $this->webTimeout ); |
261 | 286 | } |
262 | 287 | |
263 | 288 | function doLock( array $keys, $type ) { |
— | — | @@ -284,8 +309,8 @@ |
285 | 310 | foreach ( $keysToLock as $bucket => $keys ) { |
286 | 311 | // Acquire the locks for this server. Three main cases can happen: |
287 | 312 | // (a) First server is up; common case |
288 | | - // (b) First server is down but a fallback is up |
289 | | - // (c) First server is down and no fallbacks are up (or none defined) |
| 313 | + // (b) First server is down but a pier is up |
| 314 | + // (c) First server is down and no pier are up (or none defined) |
290 | 315 | $count = $this->doLockingSelectAll( $bucket, $keys, $type ); |
291 | 316 | if ( $count == -1 ) { |
292 | 317 | // Resources already locked by another process. |
— | — | @@ -300,7 +325,7 @@ |
301 | 326 | $status->merge( $this->doUnlock( $lockedKeys, $type ) ); |
302 | 327 | return $status; // error |
303 | 328 | } |
304 | | - // Record locks as active |
| 329 | + // Record these locks as active |
305 | 330 | foreach ( $keys as $key ) { |
306 | 331 | $this->locksHeld[$key][$type] = 1; // locked |
307 | 332 | } |
— | — | @@ -326,6 +351,9 @@ |
327 | 352 | } |
328 | 353 | unset( $this->locksHeld[$key][$lockType] ); |
329 | 354 | } |
| 355 | + if ( !count( $this->locksHeld[$key] ) ) { |
| 356 | + unset( $this->locksHeld[$key] ); // no SH or EX locks left for key |
| 357 | + } |
330 | 358 | } |
331 | 359 | } |
332 | 360 | |
— | — | @@ -354,9 +382,9 @@ |
355 | 383 | # This won't handle the case of server reboots however. |
356 | 384 | $options = array(); |
357 | 385 | if ( php_sapi_name() == 'cli' ) { // maintenance scripts |
358 | | - $options['connTimeout'] = 60; // some sane amount |
| 386 | + $options['connTimeout'] = $this->cliTimeout; |
359 | 387 | } else { // web requests |
360 | | - $options['connTimeout'] = ini_get( 'max_execution_time' ); |
| 388 | + $options['connTimeout'] = $this->webTimeout; |
361 | 389 | } |
362 | 390 | $this->activeConns[$server]->setSessionOptions( $options ); |
363 | 391 | } |
— | — | @@ -375,9 +403,9 @@ |
376 | 404 | |
377 | 405 | /** |
378 | 406 | * Attept to acquire a lock on the primary server as well |
379 | | - * as all fallback servers for a bucket. Returns the number |
380 | | - * of servers with locks made or -1 if any of them claimed |
381 | | - * that any of the keys were already locked by another process. |
| 407 | + * as all pier servers for a bucket. Returns the number of |
| 408 | + * servers with locks made or -1 if any of them claimed that |
| 409 | + * any of the keys were already locked by another process. |
382 | 410 | * This should avoid throwing any exceptions. |
383 | 411 | * |
384 | 412 | * @param $bucket integer |
— | — | @@ -391,12 +419,14 @@ |
392 | 420 | $server = $this->serverMap[$bucket][$i]; |
393 | 421 | try { |
394 | 422 | $this->doLockingSelect( $server, $keys, $type ); |
395 | | - ++$locksMade; // success for this fallback |
| 423 | + if ( $this->checkServerUptime( $server ) ) { |
| 424 | + ++$locksMade; // success for this pier |
| 425 | + } |
396 | 426 | } catch ( DBError $e ) { |
397 | 427 | if ( $this->lastErrorIndicatesLocked( $server ) ) { |
398 | 428 | return -1; // resource locked |
399 | 429 | } |
400 | | - // oh well; best effort (@TODO: logging?) |
| 430 | + // oh well; logged via wfLogDBError() |
401 | 431 | } |
402 | 432 | } |
403 | 433 | return $locksMade; |
— | — | @@ -413,7 +443,7 @@ |
414 | 444 | try { |
415 | 445 | $db->commit(); // finish transaction |
416 | 446 | } catch ( DBError $e ) { |
417 | | - // oh well; best effort (@TODO: logging?) |
| 447 | + // oh well; best effort |
418 | 448 | } |
419 | 449 | } |
420 | 450 | $this->activeConns = array(); |
— | — | @@ -436,6 +466,22 @@ |
437 | 467 | } |
438 | 468 | |
439 | 469 | /** |
| 470 | + * Check if the DB server has been up long enough to be safe |
| 471 | + * to use. This is to get around the problems of locks falling |
| 472 | + * off when servers restart. |
| 473 | + * |
| 474 | + * @param $server string |
| 475 | + * @return bool |
| 476 | + */ |
| 477 | + protected function checkServerUptime( $server ) { |
| 478 | + if ( isset( $this->activeConns[$server] ) ) { // sanity |
| 479 | + $db = $this->activeConns[$server]; |
| 480 | + return ( $db->getServerUptime() >= $this->resetDelay ); |
| 481 | + } |
| 482 | + return false; |
| 483 | + } |
| 484 | + |
| 485 | + /** |
440 | 486 | * Get the bucket for lock key. |
441 | 487 | * This should avoid throwing any exceptions. |
442 | 488 | * |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php |
— | — | @@ -6,14 +6,16 @@ |
7 | 7 | |
8 | 8 | /** |
9 | 9 | * Base class for all file backend classes (including multi-write backends). |
10 | | - * This class defines the methods as abstract that must be implemented subclasses. |
| 10 | + * This class defines the methods as abstract that subclasses must implement. |
| 11 | + * |
| 12 | + * Outside callers can assume that all backends will have these functions. |
11 | 13 | * |
12 | 14 | * All "storage paths" are of the format "mwstore://backend/container/path". |
13 | 15 | * The paths use typical file system notation, though any particular backend may |
14 | 16 | * not actually be using a local filesystem. Therefore, the paths are only virtual. |
15 | 17 | * |
16 | | - * All functions should avoid throwing exceptions at all costs. |
17 | | - * As a corollary, external dependencies should be kept to a minimal. |
| 18 | + * Methods should avoid throwing exceptions at all costs. |
| 19 | + * As a corollary, external dependencies should be kept to a minimum. |
18 | 20 | */ |
19 | 21 | abstract class FileBackendBase { |
20 | 22 | protected $name; // unique backend name |
— | — | @@ -82,107 +84,26 @@ |
83 | 85 | abstract public function prepare( array $params ); |
84 | 86 | |
85 | 87 | /** |
86 | | - * Store a file into the backend from a file on disk. |
| 88 | + * Check if a file exits at a storage path in the backend. |
87 | 89 | * Do not call this function from places outside FileBackend and FileOp. |
88 | 90 | * $params include: |
89 | | - * source : source path on disk |
90 | | - * dest : destination storage path |
91 | | - * overwriteDest : do nothing and pass if an identical file exists at destination |
| 91 | + * source : source storage path |
92 | 92 | * |
93 | 93 | * @param Array $params |
94 | | - * @return Status |
95 | | - */ |
96 | | - abstract public function store( array $params ); |
97 | | - |
98 | | - /** |
99 | | - * Copy a file from one storage path to another in the backend. |
100 | | - * Do not call this function from places outside FileBackend and FileOp. |
101 | | - * $params include: |
102 | | - * source : source storage path |
103 | | - * dest : destination storage path |
104 | | - * overwriteDest : do nothing and pass if an identical file exists at destination |
105 | | - * |
106 | | - * @param Array $params |
107 | | - * @return Status |
108 | | - */ |
109 | | - abstract public function copy( array $params ); |
110 | | - |
111 | | - /** |
112 | | - * Copy a file from one storage path to another in the backend. |
113 | | - * This can be left as a dummy function as long as hasMove() returns false. |
114 | | - * Do not call this function from places outside FileBackend and FileOp. |
115 | | - * $params include: |
116 | | - * source : source storage path |
117 | | - * dest : destination storage path |
118 | | - * overwriteDest : do nothing and pass if an identical file exists at destination |
119 | | - * |
120 | | - * @param Array $params |
121 | | - * @return Status |
122 | | - */ |
123 | | - abstract public function move( array $params ); |
124 | | - |
125 | | - /** |
126 | | - * Delete a file at the storage path. |
127 | | - * Do not call this function from places outside FileBackend and FileOp. |
128 | | - * $params include: |
129 | | - * source : source storage path |
130 | | - * |
131 | | - * @param Array $params |
132 | | - * @return Status |
133 | | - */ |
134 | | - abstract public function delete( array $params ); |
135 | | - |
136 | | - /** |
137 | | - * Combines files from severals storage paths into a new file in the backend. |
138 | | - * Do not call this function from places outside FileBackend and FileOp. |
139 | | - * $params include: |
140 | | - * source : source storage path |
141 | | - * dest : destination storage path |
142 | | - * overwriteDest : do nothing and pass if an identical file exists at destination |
143 | | - * overwriteSame : override any existing file at destination |
144 | | - * |
145 | | - * @param Array $params |
146 | | - * @return Status |
147 | | - */ |
148 | | - abstract public function concatenate( array $params ); |
149 | | - |
150 | | - /** |
151 | | - * Create a file in the backend with the given contents. |
152 | | - * Do not call this function from places outside FileBackend and FileOp. |
153 | | - * $params include: |
154 | | - * contents : the raw file contents |
155 | | - * dest : destination storage path |
156 | | - * overwriteDest : do nothing and pass if an identical file exists at destination |
157 | | - * |
158 | | - * @param Array $params |
159 | | - * @return Status |
160 | | - */ |
161 | | - abstract public function create( array $params ); |
162 | | - |
163 | | - /** |
164 | | - * Whether this backend implements move() and is applies to a potential |
165 | | - * move from one storage path to another. No backends hits are required. |
166 | | - * For example, moving objects accross containers may not be supported. |
167 | | - * Do not call this function from places outside FileBackend and FileOp. |
168 | | - * $params include: |
169 | | - * source : source storage path |
170 | | - * dest : destination storage path |
171 | | - * |
172 | | - * @param Array $params |
173 | 94 | * @return bool |
174 | 95 | */ |
175 | | - abstract public function canMove( array $params ); |
| 96 | + abstract public function fileExists( array $params ); |
176 | 97 | |
177 | 98 | /** |
178 | | - * Check if a file exits at a storage path in the backend. |
179 | | - * Do not call this function from places outside FileBackend and FileOp. |
| 99 | + * Get a hash of the file that exists at a storage path in the backend. |
| 100 | + * Typically this will be a SHA-1 hash, MD5 hash, or something similar. |
180 | 101 | * $params include: |
181 | 102 | * source : source storage path |
182 | 103 | * |
183 | 104 | * @param Array $params |
184 | | - * @return bool |
| 105 | + * @return string|null Gives null if the file does not exist |
185 | 106 | */ |
186 | | - abstract public function fileExists( array $params ); |
| 107 | + abstract public function getFileHash( array $params ); |
187 | 108 | |
188 | 109 | /** |
189 | 110 | * Get the format of the hash that getFileHash() uses |
— | — | @@ -194,17 +115,6 @@ |
195 | 116 | } |
196 | 117 | |
197 | 118 | /** |
198 | | - * Get a hash of the file that exists at a storage path in the backend. |
199 | | - * Typically this will be a SHA-1 hash, MD5 hash, or something similar. |
200 | | - * $params include: |
201 | | - * source : source storage path |
202 | | - * |
203 | | - * @param Array $params |
204 | | - * @return string|null Gives null if the file does not exist |
205 | | - */ |
206 | | - abstract public function getFileHash( array $params ); |
207 | | - |
208 | | - /** |
209 | 119 | * Get the properties of the file that exists at a storage path in the backend |
210 | 120 | * $params include: |
211 | 121 | * source : source storage path |
— | — | @@ -275,18 +185,107 @@ |
276 | 186 | } |
277 | 187 | |
278 | 188 | /** |
279 | | - * Base class for all single-write backends |
| 189 | + * Base class for all single-write backends. |
| 190 | + * This class defines the methods as abstract that subclasses must implement. |
280 | 191 | */ |
281 | 192 | abstract class FileBackend extends FileBackendBase { |
282 | | - function canMove( array $params ) { |
283 | | - return false; // not implemented |
284 | | - } |
| 193 | + /** |
| 194 | + * Store a file into the backend from a file on disk. |
| 195 | + * Do not call this function from places outside FileBackend and FileOp. |
| 196 | + * $params include: |
| 197 | + * source : source path on disk |
| 198 | + * dest : destination storage path |
| 199 | + * overwriteDest : do nothing and pass if an identical file exists at destination |
| 200 | + * |
| 201 | + * @param Array $params |
| 202 | + * @return Status |
| 203 | + */ |
| 204 | + abstract public function store( array $params ); |
285 | 205 | |
286 | | - function move( array $params ) { |
| 206 | + /** |
| 207 | + * Copy a file from one storage path to another in the backend. |
| 208 | + * Do not call this function from places outside FileBackend and FileOp. |
| 209 | + * $params include: |
| 210 | + * source : source storage path |
| 211 | + * dest : destination storage path |
| 212 | + * overwriteDest : do nothing and pass if an identical file exists at destination |
| 213 | + * |
| 214 | + * @param Array $params |
| 215 | + * @return Status |
| 216 | + */ |
| 217 | + abstract public function copy( array $params ); |
| 218 | + |
| 219 | + /** |
| 220 | + * Copy a file from one storage path to another in the backend. |
| 221 | + * This can be left as a dummy function as long as hasMove() returns false. |
| 222 | + * Do not call this function from places outside FileBackend and FileOp. |
| 223 | + * $params include: |
| 224 | + * source : source storage path |
| 225 | + * dest : destination storage path |
| 226 | + * overwriteDest : do nothing and pass if an identical file exists at destination |
| 227 | + * |
| 228 | + * @param Array $params |
| 229 | + * @return Status |
| 230 | + */ |
| 231 | + public function move( array $params ) { |
287 | 232 | throw new MWException( "This function is not implemented." ); |
288 | 233 | } |
289 | 234 | |
290 | 235 | /** |
| 236 | + * Delete a file at the storage path. |
| 237 | + * Do not call this function from places outside FileBackend and FileOp. |
| 238 | + * $params include: |
| 239 | + * source : source storage path |
| 240 | + * |
| 241 | + * @param Array $params |
| 242 | + * @return Status |
| 243 | + */ |
| 244 | + abstract public function delete( array $params ); |
| 245 | + |
| 246 | + /** |
| 247 | + * Combines files from severals storage paths into a new file in the backend. |
| 248 | + * Do not call this function from places outside FileBackend and FileOp. |
| 249 | + * $params include: |
| 250 | + * source : source storage path |
| 251 | + * dest : destination storage path |
| 252 | + * overwriteDest : do nothing and pass if an identical file exists at destination |
| 253 | + * overwriteSame : override any existing file at destination |
| 254 | + * |
| 255 | + * @param Array $params |
| 256 | + * @return Status |
| 257 | + */ |
| 258 | + abstract public function concatenate( array $params ); |
| 259 | + |
| 260 | + /** |
| 261 | + * Create a file in the backend with the given contents. |
| 262 | + * Do not call this function from places outside FileBackend and FileOp. |
| 263 | + * $params include: |
| 264 | + * contents : the raw file contents |
| 265 | + * dest : destination storage path |
| 266 | + * overwriteDest : do nothing and pass if an identical file exists at destination |
| 267 | + * |
| 268 | + * @param Array $params |
| 269 | + * @return Status |
| 270 | + */ |
| 271 | + abstract public function create( array $params ); |
| 272 | + |
| 273 | + /** |
| 274 | + * Whether this backend implements move() and is applies to a potential |
| 275 | + * move from one storage path to another. No backends hits are required. |
| 276 | + * For example, moving objects accross containers may not be supported. |
| 277 | + * Do not call this function from places outside FileBackend and FileOp. |
| 278 | + * $params include: |
| 279 | + * source : source storage path |
| 280 | + * dest : destination storage path |
| 281 | + * |
| 282 | + * @param Array $params |
| 283 | + * @return bool |
| 284 | + */ |
| 285 | + public function canMove( array $params ) { |
| 286 | + return false; // not implemented |
| 287 | + } |
| 288 | + |
| 289 | + /** |
291 | 290 | * Get the list of supported operations and their corresponding FileOp classes. |
292 | 291 | * |
293 | 292 | * @return Array |