2011-12-20 03:52:06 +00:00
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* @file
|
|
|
|
|
* @ingroup FileBackend
|
|
|
|
|
* @author Aaron Schulz
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
class FileBackendMultiWrite extends FileBackendBase {
|
|
|
|
|
/** @var Array Prioritized list of FileBackend objects */
|
2012-01-08 08:40:00 +00:00
|
|
|
protected $backends = array(); // array of (backend index => backends)
|
2011-12-20 03:52:06 +00:00
|
|
|
protected $masterIndex = -1; // index of master backend
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
* FileBackend class, but with these additional settings:
|
|
|
|
|
* 'class' : The name of the backend class
|
|
|
|
|
* 'isMultiMaster' : This must be set for one backend.
|
|
|
|
|
* @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.' );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::doOperationsInternal()
|
|
|
|
|
*/
|
|
|
|
|
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-01-08 08:40:00 +00:00
|
|
|
$filesRead = $filesChanged = array(); // storage paths used
|
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;
|
|
|
|
|
$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...
|
2012-01-08 22:10:53 +00:00
|
|
|
$subStatus = FileOp::attemptBatch( $performOps, $opts );
|
|
|
|
|
|
|
|
|
|
$success = array();
|
|
|
|
|
$failCount = $successCount = 0;
|
|
|
|
|
// 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();
|
|
|
|
|
|
|
|
|
|
$mBackend = $this->backends[$this->masterIndex];
|
|
|
|
|
foreach ( array_unique( $paths ) as $path ) {
|
|
|
|
|
$params = array( 'src' => $path );
|
|
|
|
|
// 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 );
|
|
|
|
|
} elseif ( $cStat['size'] != $mStat['size'] ) { // wrong size
|
|
|
|
|
$status->fatal( 'backend-fail-synced', $path );
|
|
|
|
|
} else {
|
|
|
|
|
$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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} 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
|
|
|
|
|
* @param $backend FileBackend
|
|
|
|
|
* @return Array
|
|
|
|
|
*/
|
2012-01-08 08:40:00 +00:00
|
|
|
protected function substOpBatchPaths( array $ops, FileBackend $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
|
|
|
|
|
* @param $backend FileBackend
|
|
|
|
|
* @return Array
|
|
|
|
|
*/
|
|
|
|
|
protected function substOpPaths( array $ops, FileBackend $backend ) {
|
|
|
|
|
$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
|
|
|
|
|
* @param $backend FileBackend
|
|
|
|
|
* @return Array|string
|
2011-12-20 03:52:06 +00:00
|
|
|
*/
|
2012-01-08 22:10:53 +00:00
|
|
|
protected function substPaths( $paths, FileBackend $backend ) {
|
|
|
|
|
return preg_replace(
|
|
|
|
|
'!^mwstore://' . preg_quote( $this->name ) . '/!',
|
|
|
|
|
'mwstore://' . $backend->getName() . '/',
|
|
|
|
|
$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://([^/]+)!',
|
|
|
|
|
"mwstore://{$this->name}",
|
|
|
|
|
$paths // string or array
|
|
|
|
|
);
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-23 09:43:28 +00:00
|
|
|
/**
|
2012-01-09 00:20:28 +00:00
|
|
|
* @see FileBackendBase::doPrepare()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-09 00:20:28 +00:00
|
|
|
public 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-09 00:20:28 +00:00
|
|
|
* @see FileBackendBase::doSecure()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-09 00:20:28 +00:00
|
|
|
public 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-09 00:20:28 +00:00
|
|
|
* @see FileBackendBase::doClean()
|
2011-12-23 09:43:28 +00:00
|
|
|
*/
|
2012-01-09 00:20:28 +00:00
|
|
|
public 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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileList()
|
|
|
|
|
*/
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::fileExists()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileTimestamp()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileSize()
|
|
|
|
|
*/
|
|
|
|
|
public function getFileSize( array $params ) {
|
|
|
|
|
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
|
|
|
|
|
return $this->backends[$this->masterIndex]->getFileSize( $realParams );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileStat()
|
|
|
|
|
*/
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileContents()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileSha1Base36()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileProps()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::streamFile()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getLocalReference()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getLocalCopy()
|
|
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::getFileList()
|
|
|
|
|
*/
|
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
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @see FileBackendBase::clearCache()
|
|
|
|
|
*/
|
|
|
|
|
public function clearCache( array $paths = null ) {
|
|
|
|
|
foreach ( $this->backends as $backend ) {
|
|
|
|
|
$realPaths = is_array( $paths ) ? $this->substPaths( $paths ) : null;
|
|
|
|
|
$backend->clearCache( $realPaths );
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-12-20 03:52:06 +00:00
|
|
|
}
|