}
$name = $config['name'];
if ( isset( $namesUsed[$name] ) ) { // don't break FileOp predicates
- throw new FileBackendError( "Two or more backends defined with the name $name." );
+ throw new LogicException( "Two or more backends defined with the name $name." );
}
$namesUsed[$name] = 1;
// Alter certain sub-backend settings for sanity
$config['wikiId'] = $this->wikiId; // use the proxy backend wiki ID
if ( !empty( $config['isMultiMaster'] ) ) {
if ( $this->masterIndex >= 0 ) {
- throw new FileBackendError( 'More than one master backend defined.' );
+ throw new LogicException( 'More than one master backend defined.' );
}
$this->masterIndex = $index; // this is the "master"
$config['fileJournal'] = $this->fileJournal; // log under proxy backend
}
// Create sub-backend object
if ( !isset( $config['class'] ) ) {
- throw new FileBackendError( 'No class given for a backend config.' );
+ throw new InvalidArgumentException( 'No class given for a backend config.' );
}
$class = $config['class'];
$this->backends[$index] = new $class( $config );
}
if ( $this->masterIndex < 0 ) { // need backends and must have a master
- throw new FileBackendError( 'No master backend defined.' );
+ throw new LogicException( 'No master backend defined.' );
}
if ( $this->readIndex < 0 ) {
$this->readIndex = $this->masterIndex; // default
}
final protected function doOperationsInternal( array $ops, array $opts ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$mbe = $this->backends[$this->masterIndex]; // convenience
wfDebugLog( 'FileOperation', get_class( $this ) .
" failed sync check: " . FormatJson::encode( $relevantPaths ) );
// Try to resync the clone backends to the master on the spot...
- if ( !$this->autoResync || !$this->resyncFiles( $relevantPaths )->isOK() ) {
+ if ( $this->autoResync === false
+ || !$this->resyncFiles( $relevantPaths, $this->autoResync )->isOK()
+ ) {
$status->merge( $syncStatus );
return $status; // abort
* Check that a set of files are consistent across all internal backends
*
* @param array $paths List of storage paths
- * @return Status
+ * @return StatusValue
*/
public function consistencyCheck( array $paths ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
if ( $this->syncChecks == 0 || count( $this->backends ) <= 1 ) {
return $status; // skip checks
}
+ // Preload all of the stat info in as few round trips as possible...
+ foreach ( $this->backends as $backend ) {
+ $realPaths = $this->substPaths( $paths, $backend );
+ $backend->preloadFileStat( [ 'srcs' => $realPaths, 'latest' => true ] );
+ }
+
$mBackend = $this->backends[$this->masterIndex];
foreach ( $paths as $path ) {
$params = [ 'src' => $path, 'latest' => true ];
* Check that a set of file paths are usable across all internal backends
*
* @param array $paths List of storage paths
- * @return Status
+ * @return StatusValue
*/
public function accessibilityCheck( array $paths ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
if ( count( $this->backends ) <= 1 ) {
return $status; // skip checks
}
* and re-synchronize those files against the "multi master" if needed.
*
* @param array $paths List of storage paths
- * @return Status
+ * @param string|bool $resyncMode False, True, or "conservative"; see __construct()
+ * @return StatusValue
*/
- public function resyncFiles( array $paths ) {
- $status = Status::newGood();
+ public function resyncFiles( array $paths, $resyncMode = true ) {
+ $status = $this->newStatus();
$mBackend = $this->backends[$this->masterIndex];
foreach ( $paths as $path ) {
if ( $mSha1 === $cSha1 ) {
// already synced; nothing to do
} elseif ( $mSha1 !== false ) { // file is in master
- if ( $this->autoResync === 'conservative'
+ if ( $resyncMode === 'conservative'
&& $cStat && $cStat['mtime'] > $mStat['mtime']
) {
$status->fatal( 'backend-fail-synced', $path );
[ 'src' => $fsFile->getPath(), 'dst' => $cPath ]
) );
} elseif ( $mStat === false ) { // file is not in master
- if ( $this->autoResync === 'conservative' ) {
+ if ( $resyncMode === 'conservative' ) {
$status->fatal( 'backend-fail-synced', $path );
continue; // don't delete data
}
}
}
+ if ( !$status->isOK() ) {
+ wfDebugLog( 'FileOperation', get_class( $this ) .
+ " failed to resync: " . FormatJson::encode( $paths ) );
+ }
+
return $status;
}
}
protected function doQuickOperationsInternal( array $ops ) {
- $status = Status::newGood();
- // Do the operations on the master backend; setting Status fields...
+ $status = $this->newStatus();
+ // Do the operations on the master backend; setting StatusValue fields...
$realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
$masterStatus = $this->backends[$this->masterIndex]->doQuickOperations( $realOps );
$status->merge( $masterStatus );
/**
* @param string $method One of (doPrepare,doSecure,doPublish,doClean)
* @param array $params Method arguments
- * @return Status
+ * @return StatusValue
*/
protected function doDirectoryOp( $method, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
$masterStatus = $this->backends[$this->masterIndex]->$method( $realParams );
return $this->backends[$index]->preloadFileStat( $realParams );
}
- public function getScopedLocksForOps( array $ops, Status $status ) {
+ public function getScopedLocksForOps( array $ops, StatusValue $status ) {
$realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
$fileOps = $this->backends[$this->masterIndex]->getOperationsInternal( $realOps );
// Get the paths to lock from the master backend