98 parent::__construct( $config );
99 $this->syncChecks = isset( $config[
'syncChecks'] )
100 ? $config[
'syncChecks']
102 $this->autoResync = isset( $config[
'autoResync'] )
103 ? $config[
'autoResync']
105 $this->noPushQuickOps = isset( $config[
'noPushQuickOps'] )
106 ? $config[
'noPushQuickOps']
108 $this->noPushDirConts = isset( $config[
'noPushDirConts'] )
109 ? $config[
'noPushDirConts']
113 $namesUsed =
array();
114 foreach ( $config[
'backends']
as $index => $config ) {
115 if ( isset( $config[
'template'] ) ) {
120 $name = $config[
'name'];
121 if ( isset( $namesUsed[
$name] ) ) {
122 throw new FileBackendError(
"Two or more backends defined with the name $name." );
124 $namesUsed[
$name] = 1;
126 unset( $config[
'readOnly'] );
127 unset( $config[
'fileJournal'] );
128 unset( $config[
'lockManager'] );
130 if ( !empty( $config[
'isMultiMaster'] ) ) {
131 if ( $this->masterIndex >= 0 ) {
134 $this->masterIndex = $index;
138 if ( !isset( $config[
'class'] ) ) {
141 $class = $config[
'class'];
142 $this->backends[$index] =
new $class( $config );
144 if ( $this->masterIndex < 0 ) {
155 if ( empty( $opts[
'nonLocking'] ) ) {
158 if ( !$status->isOK() ) {
164 $opts[
'preserveCache'] =
true;
169 if ( !$status->isOK() ) {
174 if ( !$syncStatus->isOK() ) {
175 wfDebugLog(
'FileOperation', get_class( $this ) .
178 if ( !$this->autoResync || !$this->
resyncFiles( $relevantPaths )->isOK() ) {
179 $status->merge( $syncStatus );
186 $masterStatus = $mbe->doOperations( $realOps, $opts );
187 $status->merge( $masterStatus );
192 if ( $masterStatus->isOK() && $masterStatus->successCount > 0 ) {
193 foreach ( $this->backends
as $index => $backend ) {
194 if ( $index !== $this->masterIndex ) {
196 $status->merge( $backend->doOperations( $realOps, $opts ) );
203 $status->success = $masterStatus->success;
204 $status->successCount = $masterStatus->successCount;
205 $status->failCount = $masterStatus->failCount;
218 if ( $this->syncChecks == 0 || count( $this->backends ) <= 1 ) {
227 $mStat = $mBackend->getFileStat( $mParams );
228 if ( $this->syncChecks & self::CHECK_SHA1 ) {
229 $mSha1 = $mBackend->getFileSha1Base36( $mParams );
234 foreach ( $this->backends
as $index => $cBackend ) {
235 if ( $index === $this->masterIndex ) {
239 $cStat = $cBackend->getFileStat( $cParams );
242 $status->fatal(
'backend-fail-synced',
$path );
245 if ( $this->syncChecks & self::CHECK_SIZE ) {
246 if ( $cStat[
'size'] != $mStat[
'size'] ) {
247 $status->fatal(
'backend-fail-synced',
$path );
251 if ( $this->syncChecks & self::CHECK_TIME ) {
254 if ( abs( $mTs - $cTs ) > 30 ) {
255 $status->fatal(
'backend-fail-synced',
$path );
259 if ( $this->syncChecks & self::CHECK_SHA1 ) {
260 if ( $cBackend->getFileSha1Base36( $cParams ) !== $mSha1 ) {
261 $status->fatal(
'backend-fail-synced',
$path );
267 $status->fatal(
'backend-fail-synced',
$path );
284 if ( count( $this->backends ) <= 1 ) {
289 foreach ( $this->backends
as $backend ) {
290 $realPath = $this->
substPaths( $path, $backend );
291 if ( !$backend->isPathUsableInternal( $realPath ) ) {
292 $status->fatal(
'backend-fail-usable',
$path );
312 $mPath = $this->
substPaths( $path, $mBackend );
313 $mSha1 = $mBackend->getFileSha1Base36(
array(
'src' => $mPath,
'latest' =>
true ) );
314 $mStat = $mBackend->getFileStat(
array(
'src' => $mPath,
'latest' =>
true ) );
315 if ( $mStat ===
null || ( $mSha1 !==
false && !$mStat ) ) {
316 $status->fatal(
'backend-fail-internal', $this->
name );
320 foreach ( $this->backends
as $index => $cBackend ) {
321 if ( $index === $this->masterIndex ) {
324 $cPath = $this->
substPaths( $path, $cBackend );
325 $cSha1 = $cBackend->getFileSha1Base36(
array(
'src' => $cPath,
'latest' =>
true ) );
326 $cStat = $cBackend->getFileStat(
array(
'src' => $cPath,
'latest' =>
true ) );
327 if ( $cStat ===
null || ( $cSha1 !==
false && !$cStat ) ) {
328 $status->fatal(
'backend-fail-internal', $cBackend->getName() );
331 if ( $mSha1 === $cSha1 ) {
333 } elseif ( $mSha1 !==
false ) {
334 if ( $this->autoResync ===
'conservative'
335 && $cStat && $cStat[
'mtime'] > $mStat[
'mtime']
337 $status->fatal(
'backend-fail-synced',
$path );
340 $fsFile = $mBackend->getLocalReference(
341 array(
'src' => $mPath,
'latest' =>
true ) );
342 $status->merge( $cBackend->quickStore(
343 array(
'src' => $fsFile->getPath(),
'dst' => $cPath )
345 } elseif ( $mStat ===
false ) {
346 if ( $this->autoResync ===
'conservative' ) {
347 $status->fatal(
'backend-fail-synced',
$path );
350 $status->merge( $cBackend->quickDelete(
array(
'src' => $cPath ) ) );
366 foreach ( $ops
as $op ) {
367 if ( isset( $op[
'src'] ) ) {
370 if ( empty( $op[
'ignoreMissingSource'] )
373 $paths[] = $op[
'src'];
376 if ( isset( $op[
'srcs'] ) ) {
377 $paths = array_merge( $paths, $op[
'srcs'] );
379 if ( isset( $op[
'dst'] ) ) {
380 $paths[] = $op[
'dst'];
384 return array_values( array_unique( array_filter( $paths,
'FileBackend::isStoragePath' ) ) );
397 foreach ( $ops
as $op ) {
399 foreach (
array(
'src',
'srcs',
'dst',
'dir' )
as $par ) {
400 if ( isset( $newOp[$par] ) ) {
401 $newOp[$par] = $this->
substPaths( $newOp[$par], $backend );
432 '!^mwstore://' . preg_quote( $this->
name ) .
'/!',
446 '!^mwstore://([^/]+)!',
455 $realOps = $this->
substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
457 $status->merge( $masterStatus );
459 if ( !$this->noPushQuickOps ) {
460 foreach ( $this->backends
as $index => $backend ) {
461 if ( $index !== $this->masterIndex ) {
470 $status->success = $masterStatus->success;
471 $status->successCount = $masterStatus->successCount;
472 $status->failCount = $masterStatus->failCount;
484 return !in_array( $shortCont, $this->noPushDirConts );
490 foreach ( $this->backends
as $index => $backend ) {
491 if ( $replicate || $index == $this->masterIndex ) {
493 $status->merge( $backend->
doPrepare( $realParams ) );
503 foreach ( $this->backends
as $index => $backend ) {
504 if ( $replicate || $index == $this->masterIndex ) {
506 $status->merge( $backend->
doSecure( $realParams ) );
516 foreach ( $this->backends
as $index => $backend ) {
517 if ( $replicate || $index == $this->masterIndex ) {
519 $status->merge( $backend->
doPublish( $realParams ) );
529 foreach ( $this->backends
as $index => $backend ) {
530 if ( $replicate || $index == $this->masterIndex ) {
532 $status->merge( $backend->
doClean( $realParams ) );
541 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
547 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
553 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
559 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
565 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
571 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
577 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
578 $contentsM = $this->backends[
$this->masterIndex]->getFileContentsMulti( $realParams );
581 foreach ( $contentsM
as $path => $data ) {
589 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
595 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
601 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
607 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
608 $fsFilesM = $this->backends[
$this->masterIndex]->getLocalReferenceMulti( $realParams );
611 foreach ( $fsFilesM
as $path => $fsFile ) {
619 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
622 $tempFiles =
array();
623 foreach ( $tempFilesM
as $path => $tempFile ) {
631 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
637 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
643 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
649 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
659 foreach ( $this->backends
as $backend ) {
660 $realPaths = is_array( $paths ) ? $this->
substPaths( $paths, $backend ) :
null;
661 $backend->clearCache( $realPaths );
666 $realPaths = $this->
substPaths( $paths, $this->backends[$this->masterIndex] );
671 $realParams = $this->
substOpPaths( $params, $this->backends[$this->masterIndex] );
676 $realOps = $this->
substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
679 $paths = $this->backends[
$this->masterIndex]->getPathsToLockForOpsInternal( $fileOps );