2011-12-20 03:52:06 +00:00
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* @file
|
|
|
|
|
* @ingroup FileBackend
|
|
|
|
|
* @author Aaron Schulz
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
2012-02-19 23:40:02 +00:00
|
|
|
* @brief Proxy backend that mirrors writes to several internal backends.
|
|
|
|
|
*
|
2011-12-20 03:52:06 +00:00
|
|
|
* This class defines a multi-write backend. Multiple backends can be
|
|
|
|
|
* registered to this proxy backend and it will act as a single backend.
|
|
|
|
|
* Use this when all access to those backends is through this proxy backend.
|
|
|
|
|
* At least one of the backends must be declared the "master" backend.
|
2011-12-23 09:43:28 +00:00
|
|
|
*
|
|
|
|
|
* Only use this class when transitioning from one storage system to another.
|
2012-01-08 08:40:00 +00:00
|
|
|
*
|
|
|
|
|
* Read operations are only done on the 'master' backend for consistency.
|
2012-01-08 22:10:53 +00:00
|
|
|
* Write operations are performed on all backends, in the order defined.
|
2011-12-20 03:52:06 +00:00
|
|
|
* If an operation fails on one backend it will be rolled back from the others.
|
|
|
|
|
*
|
|
|
|
|
* @ingroup FileBackend
|
2012-01-13 23:30:46 +00:00
|
|
|
* @since 1.19
|
2011-12-20 03:52:06 +00:00
|
|
|
*/
|
2012-01-29 22:22:28 +00:00
|
|
|
class FileBackendMultiWrite extends FileBackend {
|
|
|
|
|
/** @var Array Prioritized list of FileBackendStore objects */
|
2012-01-08 08:40:00 +00:00
|
|
|
protected $backends = array(); // array of (backend index => backends)
|
2012-01-29 22:22:28 +00:00
|
|
|
protected $masterIndex = -1; // integer; index of master backend
|
2012-01-30 08:00:19 +00:00
|
|
|
protected $syncChecks = 0; // integer bitfield
|
|
|
|
|
|
|
|
|
|
/* Possible internal backend consistency checks */
|
|
|
|
|
const CHECK_SIZE = 1;
|
|
|
|
|
const CHECK_TIME = 2;
|
2011-12-20 03:52:06 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Construct a proxy backend that consists of several internal backends.
|
2012-01-05 06:18:36 +00:00
|
|
|
* Additional $config params include:
|
2011-12-20 03:52:06 +00:00
|
|
|
* 'backends' : Array of backend config and multi-backend settings.
|
|
|
|
|
* Each value is the config used in the constructor of a
|
2012-01-29 22:22:28 +00:00
|
|
|
* FileBackendStore class, but with these additional settings:
|
2011-12-20 03:52:06 +00:00
|
|
|
* 'class' : The name of the backend class
|
|
|
|
|
* 'isMultiMaster' : This must be set for one backend.
|
2012-01-30 08:00:19 +00:00
|
|
|
* 'syncChecks' : Integer bitfield of internal backend sync checks to perform.
|
|
|
|
|
* Possible bits include self::CHECK_SIZE and self::CHECK_TIME.
|
|
|
|
|
* The checks are done before allowing any file operations.
|
2011-12-20 03:52:06 +00:00
|
|
|
* @param $config Array
|
|
|
|
|
*/
|
|
|
|
|
public function __construct( array $config ) {
|
|
|
|
|
parent::__construct( $config );
|
2012-01-08 09:25:15 +00:00
|
|
|
$namesUsed = array();
|
2011-12-20 03:52:06 +00:00
|
|
|
// Construct backends here rather than via registration
|
|
|
|
|
// to keep these backends hidden from outside the proxy.
|
|
|
|
|
foreach ( $config['backends'] as $index => $config ) {
|
2012-01-08 09:25:15 +00:00
|
|
|
$name = $config['name'];
|
|
|
|
|
if ( isset( $namesUsed[$name] ) ) { // don't break FileOp predicates
|
|
|
|
|
throw new MWException( "Two or more backends defined with the name $name." );
|
|
|
|
|
}
|
|
|
|
|
$namesUsed[$name] = 1;
|
2011-12-20 03:52:06 +00:00
|
|
|
if ( !isset( $config['class'] ) ) {
|
|
|
|
|
throw new MWException( 'No class given for a backend config.' );
|
|
|
|
|
}
|
|
|
|
|
$class = $config['class'];
|
2012-01-08 08:40:00 +00:00
|
|
|
$this->backends[$index] = new $class( $config );
|
2011-12-20 03:52:06 +00:00
|
|
|
if ( !empty( $config['isMultiMaster'] ) ) {
|
|
|
|
|
if ( $this->masterIndex >= 0 ) {
|
|
|
|
|
throw new MWException( 'More than one master backend defined.' );
|
|
|
|
|
}
|
|
|
|
|
$this->masterIndex = $index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( $this->masterIndex < 0 ) { // need backends and must have a master
|
|
|
|
|
throw new MWException( 'No master backend defined.' );
|
|
|
|
|
}
|
2012-01-30 08:00:19 +00:00
|
|
|
$this->syncChecks = isset( $config['syncChecks'] )
|
|
|
|
|
? $config['syncChecks']
|
|
|
|
|
: self::CHECK_SIZE;
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::doOperationsInternal()
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return Status
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
|
|
|
|
final protected function doOperationsInternal( array $ops, array $opts ) {
|
2011-12-20 03:52:06 +00:00
|
|
|
$status = Status::newGood();
|
|
|
|
|
|
|
|
|
|
$performOps = array(); // list of FileOp objects
|
2012-02-19 23:40:02 +00:00
|
|
|
$filesRead = array(); // storage paths read from
|
|
|
|
|
$filesChanged = array(); // storage paths written to
|
2011-12-20 03:52:06 +00:00
|
|
|
// Build up a list of FileOps. The list will have all the ops
|
|
|
|
|
// for one backend, then all the ops for the next, and so on.
|
|
|
|
|
// These batches of ops are all part of a continuous array.
|
2012-01-08 08:40:00 +00:00
|
|
|
// Also build up a list of files read/changed...
|
|
|
|
|
foreach ( $this->backends as $index => $backend ) {
|
|
|
|
|
$backendOps = $this->substOpBatchPaths( $ops, $backend );
|
|
|
|
|
// Add on the operation batch for this backend
|
2011-12-20 03:52:06 +00:00
|
|
|
$performOps = array_merge( $performOps, $backend->getOperations( $backendOps ) );
|
2012-01-08 08:40:00 +00:00
|
|
|
if ( $index == 0 ) { // first batch
|
|
|
|
|
// Get the files used for these operations. Each backend has a batch of
|
|
|
|
|
// the same operations, so we only need to get them from the first batch.
|
2012-01-01 23:35:08 +00:00
|
|
|
foreach ( $performOps as $fileOp ) {
|
2012-01-08 08:40:00 +00:00
|
|
|
$filesRead = array_merge( $filesRead, $fileOp->storagePathsRead() );
|
|
|
|
|
$filesChanged = array_merge( $filesChanged, $fileOp->storagePathsChanged() );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
2012-01-08 08:40:00 +00:00
|
|
|
// Get the paths under the proxy backend's name
|
2012-01-08 22:10:53 +00:00
|
|
|
$filesRead = $this->unsubstPaths( $filesRead );
|
|
|
|
|
$filesChanged = $this->unsubstPaths( $filesChanged );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to lock those files for the scope of this function...
|
2012-01-08 08:40:00 +00:00
|
|
|
if ( empty( $opts['nonLocking'] ) ) {
|
|
|
|
|
$filesLockSh = array_diff( $filesRead, $filesChanged ); // optimization
|
|
|
|
|
$filesLockEx = $filesChanged;
|
2012-01-19 23:18:03 +00:00
|
|
|
// Get a shared lock on the parent directory of each path changed
|
|
|
|
|
$filesLockSh = array_merge( $filesLockSh, array_map( 'dirname', $filesLockEx ) );
|
|
|
|
|
// Try to lock those files for the scope of this function...
|
2012-01-08 08:40:00 +00:00
|
|
|
$scopeLockS = $this->getScopedFileLocks( $filesLockSh, LockManager::LOCK_UW, $status );
|
|
|
|
|
$scopeLockE = $this->getScopedFileLocks( $filesLockEx, LockManager::LOCK_EX, $status );
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status; // abort
|
|
|
|
|
}
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear any cache entries (after locks acquired)
|
2012-01-08 22:10:53 +00:00
|
|
|
$this->clearCache();
|
2012-01-08 08:40:00 +00:00
|
|
|
|
|
|
|
|
// Do a consistency check to see if the backends agree
|
|
|
|
|
if ( count( $this->backends ) > 1 ) {
|
|
|
|
|
$status->merge( $this->consistencyCheck( array_merge( $filesRead, $filesChanged ) ) );
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status; // abort
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-20 03:52:06 +00:00
|
|
|
// Actually attempt the operation batch...
|
Revert r107309, r113601, r113704, r113742, r113792, r113838, r113859, r113893, r113894, r113952, r114047, r114252, r114256, r114257. This reverts the remaining 'new' revisions in core.
All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-21 00:16:50 +00:00
|
|
|
$subStatus = FileOp::attemptBatch( $performOps, $opts );
|
2012-01-08 22:10:53 +00:00
|
|
|
|
|
|
|
|
$success = array();
|
2012-02-19 23:40:02 +00:00
|
|
|
$failCount = 0;
|
|
|
|
|
$successCount = 0;
|
2012-01-08 22:10:53 +00:00
|
|
|
// Make 'success', 'successCount', and 'failCount' fields reflect
|
|
|
|
|
// the overall operation, rather than all the batches for each backend.
|
|
|
|
|
// Do this by only using success values from the master backend's batch.
|
|
|
|
|
$batchStart = $this->masterIndex * count( $ops );
|
|
|
|
|
$batchEnd = $batchStart + count( $ops ) - 1;
|
|
|
|
|
for ( $i = $batchStart; $i <= $batchEnd; $i++ ) {
|
|
|
|
|
if ( !isset( $subStatus->success[$i] ) ) {
|
|
|
|
|
break; // failed out before trying this op
|
|
|
|
|
} elseif ( $subStatus->success[$i] ) {
|
|
|
|
|
++$successCount;
|
|
|
|
|
} else {
|
|
|
|
|
++$failCount;
|
|
|
|
|
}
|
|
|
|
|
$success[] = $subStatus->success[$i];
|
|
|
|
|
}
|
|
|
|
|
$subStatus->success = $success;
|
|
|
|
|
$subStatus->successCount = $successCount;
|
|
|
|
|
$subStatus->failCount = $failCount;
|
|
|
|
|
|
|
|
|
|
// Merge errors into status fields
|
|
|
|
|
$status->merge( $subStatus );
|
|
|
|
|
$status->success = $subStatus->success; // not done in merge()
|
2011-12-20 03:52:06 +00:00
|
|
|
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-08 08:40:00 +00:00
|
|
|
/**
|
|
|
|
|
* Check that a set of files are consistent across all internal backends
|
|
|
|
|
*
|
|
|
|
|
* @param $paths Array
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
public function consistencyCheck( array $paths ) {
|
|
|
|
|
$status = Status::newGood();
|
2012-01-30 08:00:19 +00:00
|
|
|
if ( $this->syncChecks == 0 ) {
|
|
|
|
|
return $status; // skip checks
|
|
|
|
|
}
|
2012-01-08 08:40:00 +00:00
|
|
|
|
|
|
|
|
$mBackend = $this->backends[$this->masterIndex];
|
|
|
|
|
foreach ( array_unique( $paths ) as $path ) {
|
2012-01-19 23:18:03 +00:00
|
|
|
$params = array( 'src' => $path, 'latest' => true );
|
2012-01-08 08:40:00 +00:00
|
|
|
// Stat the file on the 'master' backend
|
|
|
|
|
$mStat = $mBackend->getFileStat( $this->substOpPaths( $params, $mBackend ) );
|
|
|
|
|
// Check of all clone backends agree with the master...
|
|
|
|
|
foreach ( $this->backends as $index => $cBackend ) {
|
|
|
|
|
if ( $index === $this->masterIndex ) {
|
|
|
|
|
continue; // master
|
|
|
|
|
}
|
|
|
|
|
$cStat = $cBackend->getFileStat( $this->substOpPaths( $params, $cBackend ) );
|
|
|
|
|
if ( $mStat ) { // file is in master
|
|
|
|
|
if ( !$cStat ) { // file should exist
|
|
|
|
|
$status->fatal( 'backend-fail-synced', $path );
|
2012-01-30 08:00:19 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ( $this->syncChecks & self::CHECK_SIZE ) {
|
|
|
|
|
if ( $cStat['size'] != $mStat['size'] ) { // wrong size
|
|
|
|
|
$status->fatal( 'backend-fail-synced', $path );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( $this->syncChecks & self::CHECK_TIME ) {
|
2012-01-08 08:40:00 +00:00
|
|
|
$mTs = wfTimestamp( TS_UNIX, $mStat['mtime'] );
|
|
|
|
|
$cTs = wfTimestamp( TS_UNIX, $cStat['mtime'] );
|
|
|
|
|
if ( abs( $mTs - $cTs ) > 30 ) { // outdated file somewhere
|
|
|
|
|
$status->fatal( 'backend-fail-synced', $path );
|
2012-01-30 08:00:19 +00:00
|
|
|
continue;
|
2012-01-08 08:40:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else { // file is not in master
|
|
|
|
|
if ( $cStat ) { // file should not exist
|
|
|
|
|
$status->fatal( 'backend-fail-synced', $path );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-20 03:52:06 +00:00
|
|
|
/**
|
|
|
|
|
* Substitute the backend name in storage path parameters
|
2012-01-08 22:10:53 +00:00
|
|
|
* for a set of operations with that of a given internal backend.
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
|
|
|
|
* @param $ops Array List of file operation arrays
|
2012-01-29 22:22:28 +00:00
|
|
|
* @param $backend FileBackendStore
|
2011-12-20 03:52:06 +00:00
|
|
|
* @return Array
|
|
|
|
|
*/
|
2012-01-29 22:22:28 +00:00
|
|
|
protected function substOpBatchPaths( array $ops, FileBackendStore $backend ) {
|
2011-12-20 03:52:06 +00:00
|
|
|
$newOps = array(); // operations
|
|
|
|
|
foreach ( $ops as $op ) {
|
|
|
|
|
$newOp = $op; // operation
|
2012-01-08 08:40:00 +00:00
|
|
|
foreach ( array( 'src', 'srcs', 'dst', 'dir' ) as $par ) {
|
2012-01-08 22:10:53 +00:00
|
|
|
if ( isset( $newOp[$par] ) ) { // string or array
|
|
|
|
|
$newOp[$par] = $this->substPaths( $newOp[$par], $backend );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$newOps[] = $newOp;
|
|
|
|
|
}
|
|
|
|
|
return $newOps;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-08 08:40:00 +00:00
|
|
|
/**
|
|
|
|
|
* Same as substOpBatchPaths() but for a single operation
|
|
|
|
|
*
|
|
|
|
|
* @param $op File operation array
|
2012-01-29 22:22:28 +00:00
|
|
|
* @param $backend FileBackendStore
|
2012-01-08 08:40:00 +00:00
|
|
|
* @return Array
|
|
|
|
|
*/
|
2012-01-29 22:22:28 +00:00
|
|
|
protected function substOpPaths( array $ops, FileBackendStore $backend ) {
|
2012-01-08 08:40:00 +00:00
|
|
|
$newOps = $this->substOpBatchPaths( array( $ops ), $backend );
|
|
|
|
|
return $newOps[0];
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-20 03:52:06 +00:00
|
|
|
/**
|
2012-01-08 22:10:53 +00:00
|
|
|
* Substitute the backend of storage paths with an internal backend's name
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
2012-01-08 22:10:53 +00:00
|
|
|
* @param $paths Array|string List of paths or single string path
|
2012-01-29 22:22:28 +00:00
|
|
|
* @param $backend FileBackendStore
|
2012-01-08 22:10:53 +00:00
|
|
|
* @return Array|string
|
2011-12-20 03:52:06 +00:00
|
|
|
*/
|
2012-01-29 22:22:28 +00:00
|
|
|
protected function substPaths( $paths, FileBackendStore $backend ) {
|
2012-01-08 22:10:53 +00:00
|
|
|
return preg_replace(
|
|
|
|
|
'!^mwstore://' . preg_quote( $this->name ) . '/!',
|
2012-02-03 18:05:33 +00:00
|
|
|
StringUtils::escapeRegexReplacement( "mwstore://{$backend->getName()}/" ),
|
2012-01-08 22:10:53 +00:00
|
|
|
$paths // string or array
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Substitute the backend of internal storage paths with the proxy backend's name
|
|
|
|
|
*
|
|
|
|
|
* @param $paths Array|string List of paths or single string path
|
|
|
|
|
* @return Array|string
|
|
|
|
|
*/
|
|
|
|
|
protected function unsubstPaths( $paths ) {
|
|
|
|
|
return preg_replace(
|
|
|
|
|
'!^mwstore://([^/]+)!',
|
2012-02-03 18:05:33 +00:00
|
|
|
StringUtils::escapeRegexReplacement( "mwstore://{$this->name}" ),
|
2012-01-08 22:10:53 +00:00
|
|
|
$paths // string or array
|
|
|
|
|
);
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::doPrepare()
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return Status
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-02-19 23:40:02 +00:00
|
|
|
protected function doPrepare( array $params ) {
|
2011-12-20 03:52:06 +00:00
|
|
|
$status = Status::newGood();
|
|
|
|
|
foreach ( $this->backends as $backend ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $backend );
|
2012-01-09 00:20:28 +00:00
|
|
|
$status->merge( $backend->doPrepare( $realParams ) );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::doSecure()
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return Status
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-02-19 23:40:02 +00:00
|
|
|
protected function doSecure( array $params ) {
|
2011-12-20 03:52:06 +00:00
|
|
|
$status = Status::newGood();
|
|
|
|
|
foreach ( $this->backends as $backend ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $backend );
|
2012-01-09 00:20:28 +00:00
|
|
|
$status->merge( $backend->doSecure( $realParams ) );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::doClean()
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return Status
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-02-19 23:40:02 +00:00
|
|
|
protected function doClean( array $params ) {
|
2011-12-20 03:52:06 +00:00
|
|
|
$status = Status::newGood();
|
|
|
|
|
foreach ( $this->backends as $backend ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $backend );
|
2012-01-09 00:20:28 +00:00
|
|
|
$status->merge( $backend->doClean( $realParams ) );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-08 09:25:15 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileList()
|
2012-01-08 09:25:15 +00:00
|
|
|
*/
|
|
|
|
|
public function concatenate( array $params ) {
|
|
|
|
|
// We are writing to an FS file, so we don't need to do this per-backend
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->concatenate( $realParams );
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::fileExists()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function fileExists( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->fileExists( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileTimestamp()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getFileTimestamp( array $params ) {
|
2011-12-25 23:17:30 +00:00
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
2011-12-20 03:52:06 +00:00
|
|
|
return $this->backends[$this->masterIndex]->getFileTimestamp( $realParams );
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-08 08:40:00 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileSize()
|
2012-01-08 08:40:00 +00:00
|
|
|
*/
|
|
|
|
|
public function getFileSize( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileSize( $realParams );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileStat()
|
2012-01-08 08:40:00 +00:00
|
|
|
*/
|
|
|
|
|
public function getFileStat( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileStat( $realParams );
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-04 02:15:07 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileContents()
|
2012-01-04 02:15:07 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getFileContents( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileContents( $realParams );
|
2012-01-04 02:15:07 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileSha1Base36()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getFileSha1Base36( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileSha1Base36( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileProps()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getFileProps( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileProps( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::streamFile()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function streamFile( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->streamFile( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getLocalReference()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getLocalReference( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getLocalReference( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getLocalCopy()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getLocalCopy( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getLocalCopy( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::getFileList()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
public function getFileList( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileList( $realParams );
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
2012-01-08 22:10:53 +00:00
|
|
|
|
|
|
|
|
/**
|
2012-01-29 22:22:28 +00:00
|
|
|
* @see FileBackend::clearCache()
|
2012-01-08 22:10:53 +00:00
|
|
|
*/
|
|
|
|
|
public function clearCache( array $paths = null ) {
|
|
|
|
|
foreach ( $this->backends as $backend ) {
|
2012-01-27 14:29:29 +00:00
|
|
|
$realPaths = is_array( $paths ) ? $this->substPaths( $paths, $backend ) : null;
|
2012-01-08 22:10:53 +00:00
|
|
|
$backend->clearCache( $realPaths );
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|