MediaWiki  1.29.2
FileBackendMultiWrite.php
Go to the documentation of this file.
1 <?php
46  protected $backends = [];
47 
49  protected $masterIndex = -1;
51  protected $readIndex = -1;
52 
54  protected $syncChecks = 0;
56  protected $autoResync = false;
57 
59  protected $asyncWrites = false;
60 
61  /* Possible internal backend consistency checks */
62  const CHECK_SIZE = 1;
63  const CHECK_TIME = 2;
64  const CHECK_SHA1 = 4;
65 
94  public function __construct( array $config ) {
95  parent::__construct( $config );
96  $this->syncChecks = isset( $config['syncChecks'] )
97  ? $config['syncChecks']
99  $this->autoResync = isset( $config['autoResync'] )
100  ? $config['autoResync']
101  : false;
102  $this->asyncWrites = isset( $config['replication'] ) && $config['replication'] === 'async';
103  // Construct backends here rather than via registration
104  // to keep these backends hidden from outside the proxy.
105  $namesUsed = [];
106  foreach ( $config['backends'] as $index => $config ) {
107  $name = $config['name'];
108  if ( isset( $namesUsed[$name] ) ) { // don't break FileOp predicates
109  throw new LogicException( "Two or more backends defined with the name $name." );
110  }
111  $namesUsed[$name] = 1;
112  // Alter certain sub-backend settings for sanity
113  unset( $config['readOnly'] ); // use proxy backend setting
114  unset( $config['fileJournal'] ); // use proxy backend journal
115  unset( $config['lockManager'] ); // lock under proxy backend
116  $config['domainId'] = $this->domainId; // use the proxy backend wiki ID
117  if ( !empty( $config['isMultiMaster'] ) ) {
118  if ( $this->masterIndex >= 0 ) {
119  throw new LogicException( 'More than one master backend defined.' );
120  }
121  $this->masterIndex = $index; // this is the "master"
122  $config['fileJournal'] = $this->fileJournal; // log under proxy backend
123  }
124  if ( !empty( $config['readAffinity'] ) ) {
125  $this->readIndex = $index; // prefer this for reads
126  }
127  // Create sub-backend object
128  if ( !isset( $config['class'] ) ) {
129  throw new InvalidArgumentException( 'No class given for a backend config.' );
130  }
131  $class = $config['class'];
132  $this->backends[$index] = new $class( $config );
133  }
134  if ( $this->masterIndex < 0 ) { // need backends and must have a master
135  throw new LogicException( 'No master backend defined.' );
136  }
137  if ( $this->readIndex < 0 ) {
138  $this->readIndex = $this->masterIndex; // default
139  }
140  }
141 
142  final protected function doOperationsInternal( array $ops, array $opts ) {
143  $status = $this->newStatus();
144 
145  $mbe = $this->backends[$this->masterIndex]; // convenience
146 
147  // Try to lock those files for the scope of this function...
148  $scopeLock = null;
149  if ( empty( $opts['nonLocking'] ) ) {
150  // Try to lock those files for the scope of this function...
152  $scopeLock = $this->getScopedLocksForOps( $ops, $status );
153  if ( !$status->isOK() ) {
154  return $status; // abort
155  }
156  }
157  // Clear any cache entries (after locks acquired)
158  $this->clearCache();
159  $opts['preserveCache'] = true; // only locked files are cached
160  // Get the list of paths to read/write...
161  $relevantPaths = $this->fileStoragePathsForOps( $ops );
162  // Check if the paths are valid and accessible on all backends...
163  $status->merge( $this->accessibilityCheck( $relevantPaths ) );
164  if ( !$status->isOK() ) {
165  return $status; // abort
166  }
167  // Do a consistency check to see if the backends are consistent...
168  $syncStatus = $this->consistencyCheck( $relevantPaths );
169  if ( !$syncStatus->isOK() ) {
170  wfDebugLog( 'FileOperation', static::class .
171  " failed sync check: " . FormatJson::encode( $relevantPaths ) );
172  // Try to resync the clone backends to the master on the spot...
173  if ( $this->autoResync === false
174  || !$this->resyncFiles( $relevantPaths, $this->autoResync )->isOK()
175  ) {
176  $status->merge( $syncStatus );
177 
178  return $status; // abort
179  }
180  }
181  // Actually attempt the operation batch on the master backend...
182  $realOps = $this->substOpBatchPaths( $ops, $mbe );
183  $masterStatus = $mbe->doOperations( $realOps, $opts );
184  $status->merge( $masterStatus );
185  // Propagate the operations to the clone backends if there were no unexpected errors
186  // and if there were either no expected errors or if the 'force' option was used.
187  // However, if nothing succeeded at all, then don't replicate any of the operations.
188  // If $ops only had one operation, this might avoid backend sync inconsistencies.
189  if ( $masterStatus->isOK() && $masterStatus->successCount > 0 ) {
190  foreach ( $this->backends as $index => $backend ) {
191  if ( $index === $this->masterIndex ) {
192  continue; // done already
193  }
194 
195  $realOps = $this->substOpBatchPaths( $ops, $backend );
196  if ( $this->asyncWrites && !$this->hasVolatileSources( $ops ) ) {
197  // Bind $scopeLock to the callback to preserve locks
199  function() use ( $backend, $realOps, $opts, $scopeLock, $relevantPaths ) {
200  wfDebugLog( 'FileOperationReplication',
201  "'{$backend->getName()}' async replication; paths: " .
202  FormatJson::encode( $relevantPaths ) );
203  $backend->doOperations( $realOps, $opts );
204  }
205  );
206  } else {
207  wfDebugLog( 'FileOperationReplication',
208  "'{$backend->getName()}' sync replication; paths: " .
209  FormatJson::encode( $relevantPaths ) );
210  $status->merge( $backend->doOperations( $realOps, $opts ) );
211  }
212  }
213  }
214  // Make 'success', 'successCount', and 'failCount' fields reflect
215  // the overall operation, rather than all the batches for each backend.
216  // Do this by only using success values from the master backend's batch.
217  $status->success = $masterStatus->success;
218  $status->successCount = $masterStatus->successCount;
219  $status->failCount = $masterStatus->failCount;
220 
221  return $status;
222  }
223 
230  public function consistencyCheck( array $paths ) {
231  $status = $this->newStatus();
232  if ( $this->syncChecks == 0 || count( $this->backends ) <= 1 ) {
233  return $status; // skip checks
234  }
235 
236  // Preload all of the stat info in as few round trips as possible...
237  foreach ( $this->backends as $backend ) {
238  $realPaths = $this->substPaths( $paths, $backend );
239  $backend->preloadFileStat( [ 'srcs' => $realPaths, 'latest' => true ] );
240  }
241 
242  $mBackend = $this->backends[$this->masterIndex];
243  foreach ( $paths as $path ) {
244  $params = [ 'src' => $path, 'latest' => true ];
245  $mParams = $this->substOpPaths( $params, $mBackend );
246  // Stat the file on the 'master' backend
247  $mStat = $mBackend->getFileStat( $mParams );
248  if ( $this->syncChecks & self::CHECK_SHA1 ) {
249  $mSha1 = $mBackend->getFileSha1Base36( $mParams );
250  } else {
251  $mSha1 = false;
252  }
253  // Check if all clone backends agree with the master...
254  foreach ( $this->backends as $index => $cBackend ) {
255  if ( $index === $this->masterIndex ) {
256  continue; // master
257  }
258  $cParams = $this->substOpPaths( $params, $cBackend );
259  $cStat = $cBackend->getFileStat( $cParams );
260  if ( $mStat ) { // file is in master
261  if ( !$cStat ) { // file should exist
262  $status->fatal( 'backend-fail-synced', $path );
263  continue;
264  }
265  if ( $this->syncChecks & self::CHECK_SIZE ) {
266  if ( $cStat['size'] != $mStat['size'] ) { // wrong size
267  $status->fatal( 'backend-fail-synced', $path );
268  continue;
269  }
270  }
271  if ( $this->syncChecks & self::CHECK_TIME ) {
272  $mTs = wfTimestamp( TS_UNIX, $mStat['mtime'] );
273  $cTs = wfTimestamp( TS_UNIX, $cStat['mtime'] );
274  if ( abs( $mTs - $cTs ) > 30 ) { // outdated file somewhere
275  $status->fatal( 'backend-fail-synced', $path );
276  continue;
277  }
278  }
279  if ( $this->syncChecks & self::CHECK_SHA1 ) {
280  if ( $cBackend->getFileSha1Base36( $cParams ) !== $mSha1 ) { // wrong SHA1
281  $status->fatal( 'backend-fail-synced', $path );
282  continue;
283  }
284  }
285  } else { // file is not in master
286  if ( $cStat ) { // file should not exist
287  $status->fatal( 'backend-fail-synced', $path );
288  }
289  }
290  }
291  }
292 
293  return $status;
294  }
295 
302  public function accessibilityCheck( array $paths ) {
303  $status = $this->newStatus();
304  if ( count( $this->backends ) <= 1 ) {
305  return $status; // skip checks
306  }
307 
308  foreach ( $paths as $path ) {
309  foreach ( $this->backends as $backend ) {
310  $realPath = $this->substPaths( $path, $backend );
311  if ( !$backend->isPathUsableInternal( $realPath ) ) {
312  $status->fatal( 'backend-fail-usable', $path );
313  }
314  }
315  }
316 
317  return $status;
318  }
319 
328  public function resyncFiles( array $paths, $resyncMode = true ) {
329  $status = $this->newStatus();
330 
331  $mBackend = $this->backends[$this->masterIndex];
332  foreach ( $paths as $path ) {
333  $mPath = $this->substPaths( $path, $mBackend );
334  $mSha1 = $mBackend->getFileSha1Base36( [ 'src' => $mPath, 'latest' => true ] );
335  $mStat = $mBackend->getFileStat( [ 'src' => $mPath, 'latest' => true ] );
336  if ( $mStat === null || ( $mSha1 !== false && !$mStat ) ) { // sanity
337  $status->fatal( 'backend-fail-internal', $this->name );
338  wfDebugLog( 'FileOperation', __METHOD__
339  . ': File is not available on the master backend' );
340  continue; // file is not available on the master backend...
341  }
342  // Check of all clone backends agree with the master...
343  foreach ( $this->backends as $index => $cBackend ) {
344  if ( $index === $this->masterIndex ) {
345  continue; // master
346  }
347  $cPath = $this->substPaths( $path, $cBackend );
348  $cSha1 = $cBackend->getFileSha1Base36( [ 'src' => $cPath, 'latest' => true ] );
349  $cStat = $cBackend->getFileStat( [ 'src' => $cPath, 'latest' => true ] );
350  if ( $cStat === null || ( $cSha1 !== false && !$cStat ) ) { // sanity
351  $status->fatal( 'backend-fail-internal', $cBackend->getName() );
352  wfDebugLog( 'FileOperation', __METHOD__ .
353  ': File is not available on the clone backend' );
354  continue; // file is not available on the clone backend...
355  }
356  if ( $mSha1 === $cSha1 ) {
357  // already synced; nothing to do
358  } elseif ( $mSha1 !== false ) { // file is in master
359  if ( $resyncMode === 'conservative'
360  && $cStat && $cStat['mtime'] > $mStat['mtime']
361  ) {
362  $status->fatal( 'backend-fail-synced', $path );
363  continue; // don't rollback data
364  }
365  $fsFile = $mBackend->getLocalReference(
366  [ 'src' => $mPath, 'latest' => true ] );
367  $status->merge( $cBackend->quickStore(
368  [ 'src' => $fsFile->getPath(), 'dst' => $cPath ]
369  ) );
370  } elseif ( $mStat === false ) { // file is not in master
371  if ( $resyncMode === 'conservative' ) {
372  $status->fatal( 'backend-fail-synced', $path );
373  continue; // don't delete data
374  }
375  $status->merge( $cBackend->quickDelete( [ 'src' => $cPath ] ) );
376  }
377  }
378  }
379 
380  if ( !$status->isOK() ) {
381  wfDebugLog( 'FileOperation', static::class .
382  " failed to resync: " . FormatJson::encode( $paths ) );
383  }
384 
385  return $status;
386  }
387 
394  protected function fileStoragePathsForOps( array $ops ) {
395  $paths = [];
396  foreach ( $ops as $op ) {
397  if ( isset( $op['src'] ) ) {
398  // For things like copy/move/delete with "ignoreMissingSource" and there
399  // is no source file, nothing should happen and there should be no errors.
400  if ( empty( $op['ignoreMissingSource'] )
401  || $this->fileExists( [ 'src' => $op['src'] ] )
402  ) {
403  $paths[] = $op['src'];
404  }
405  }
406  if ( isset( $op['srcs'] ) ) {
407  $paths = array_merge( $paths, $op['srcs'] );
408  }
409  if ( isset( $op['dst'] ) ) {
410  $paths[] = $op['dst'];
411  }
412  }
413 
414  return array_values( array_unique( array_filter( $paths, 'FileBackend::isStoragePath' ) ) );
415  }
416 
425  protected function substOpBatchPaths( array $ops, FileBackendStore $backend ) {
426  $newOps = []; // operations
427  foreach ( $ops as $op ) {
428  $newOp = $op; // operation
429  foreach ( [ 'src', 'srcs', 'dst', 'dir' ] as $par ) {
430  if ( isset( $newOp[$par] ) ) { // string or array
431  $newOp[$par] = $this->substPaths( $newOp[$par], $backend );
432  }
433  }
434  $newOps[] = $newOp;
435  }
436 
437  return $newOps;
438  }
439 
447  protected function substOpPaths( array $ops, FileBackendStore $backend ) {
448  $newOps = $this->substOpBatchPaths( [ $ops ], $backend );
449 
450  return $newOps[0];
451  }
452 
460  protected function substPaths( $paths, FileBackendStore $backend ) {
461  return preg_replace(
462  '!^mwstore://' . preg_quote( $this->name, '!' ) . '/!',
463  StringUtils::escapeRegexReplacement( "mwstore://{$backend->getName()}/" ),
464  $paths // string or array
465  );
466  }
467 
474  protected function unsubstPaths( $paths ) {
475  return preg_replace(
476  '!^mwstore://([^/]+)!',
477  StringUtils::escapeRegexReplacement( "mwstore://{$this->name}" ),
478  $paths // string or array
479  );
480  }
481 
486  protected function hasVolatileSources( array $ops ) {
487  foreach ( $ops as $op ) {
488  if ( $op['op'] === 'store' && !isset( $op['srcRef'] ) ) {
489  return true; // source file might be deleted anytime after do*Operations()
490  }
491  }
492 
493  return false;
494  }
495 
496  protected function doQuickOperationsInternal( array $ops ) {
497  $status = $this->newStatus();
498  // Do the operations on the master backend; setting StatusValue fields...
499  $realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
500  $masterStatus = $this->backends[$this->masterIndex]->doQuickOperations( $realOps );
501  $status->merge( $masterStatus );
502  // Propagate the operations to the clone backends...
503  foreach ( $this->backends as $index => $backend ) {
504  if ( $index === $this->masterIndex ) {
505  continue; // done already
506  }
507 
508  $realOps = $this->substOpBatchPaths( $ops, $backend );
509  if ( $this->asyncWrites && !$this->hasVolatileSources( $ops ) ) {
511  function() use ( $backend, $realOps ) {
512  $backend->doQuickOperations( $realOps );
513  }
514  );
515  } else {
516  $status->merge( $backend->doQuickOperations( $realOps ) );
517  }
518  }
519  // Make 'success', 'successCount', and 'failCount' fields reflect
520  // the overall operation, rather than all the batches for each backend.
521  // Do this by only using success values from the master backend's batch.
522  $status->success = $masterStatus->success;
523  $status->successCount = $masterStatus->successCount;
524  $status->failCount = $masterStatus->failCount;
525 
526  return $status;
527  }
528 
529  protected function doPrepare( array $params ) {
530  return $this->doDirectoryOp( 'prepare', $params );
531  }
532 
533  protected function doSecure( array $params ) {
534  return $this->doDirectoryOp( 'secure', $params );
535  }
536 
537  protected function doPublish( array $params ) {
538  return $this->doDirectoryOp( 'publish', $params );
539  }
540 
541  protected function doClean( array $params ) {
542  return $this->doDirectoryOp( 'clean', $params );
543  }
544 
550  protected function doDirectoryOp( $method, array $params ) {
551  $status = $this->newStatus();
552 
553  $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
554  $masterStatus = $this->backends[$this->masterIndex]->$method( $realParams );
555  $status->merge( $masterStatus );
556 
557  foreach ( $this->backends as $index => $backend ) {
558  if ( $index === $this->masterIndex ) {
559  continue; // already done
560  }
561 
562  $realParams = $this->substOpPaths( $params, $backend );
563  if ( $this->asyncWrites ) {
565  function() use ( $backend, $method, $realParams ) {
566  $backend->$method( $realParams );
567  }
568  );
569  } else {
570  $status->merge( $backend->$method( $realParams ) );
571  }
572  }
573 
574  return $status;
575  }
576 
577  public function concatenate( array $params ) {
578  $status = $this->newStatus();
579  // We are writing to an FS file, so we don't need to do this per-backend
580  $index = $this->getReadIndexFromParams( $params );
581  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
582 
583  $status->merge( $this->backends[$index]->concatenate( $realParams ) );
584 
585  return $status;
586  }
587 
588  public function fileExists( array $params ) {
589  $index = $this->getReadIndexFromParams( $params );
590  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
591 
592  return $this->backends[$index]->fileExists( $realParams );
593  }
594 
595  public function getFileTimestamp( array $params ) {
596  $index = $this->getReadIndexFromParams( $params );
597  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
598 
599  return $this->backends[$index]->getFileTimestamp( $realParams );
600  }
601 
602  public function getFileSize( array $params ) {
603  $index = $this->getReadIndexFromParams( $params );
604  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
605 
606  return $this->backends[$index]->getFileSize( $realParams );
607  }
608 
609  public function getFileStat( array $params ) {
610  $index = $this->getReadIndexFromParams( $params );
611  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
612 
613  return $this->backends[$index]->getFileStat( $realParams );
614  }
615 
616  public function getFileXAttributes( array $params ) {
617  $index = $this->getReadIndexFromParams( $params );
618  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
619 
620  return $this->backends[$index]->getFileXAttributes( $realParams );
621  }
622 
623  public function getFileContentsMulti( array $params ) {
624  $index = $this->getReadIndexFromParams( $params );
625  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
626 
627  $contentsM = $this->backends[$index]->getFileContentsMulti( $realParams );
628 
629  $contents = []; // (path => FSFile) mapping using the proxy backend's name
630  foreach ( $contentsM as $path => $data ) {
631  $contents[$this->unsubstPaths( $path )] = $data;
632  }
633 
634  return $contents;
635  }
636 
637  public function getFileSha1Base36( array $params ) {
638  $index = $this->getReadIndexFromParams( $params );
639  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
640 
641  return $this->backends[$index]->getFileSha1Base36( $realParams );
642  }
643 
644  public function getFileProps( array $params ) {
645  $index = $this->getReadIndexFromParams( $params );
646  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
647 
648  return $this->backends[$index]->getFileProps( $realParams );
649  }
650 
651  public function streamFile( array $params ) {
652  $index = $this->getReadIndexFromParams( $params );
653  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
654 
655  return $this->backends[$index]->streamFile( $realParams );
656  }
657 
658  public function getLocalReferenceMulti( array $params ) {
659  $index = $this->getReadIndexFromParams( $params );
660  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
661 
662  $fsFilesM = $this->backends[$index]->getLocalReferenceMulti( $realParams );
663 
664  $fsFiles = []; // (path => FSFile) mapping using the proxy backend's name
665  foreach ( $fsFilesM as $path => $fsFile ) {
666  $fsFiles[$this->unsubstPaths( $path )] = $fsFile;
667  }
668 
669  return $fsFiles;
670  }
671 
672  public function getLocalCopyMulti( array $params ) {
673  $index = $this->getReadIndexFromParams( $params );
674  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
675 
676  $tempFilesM = $this->backends[$index]->getLocalCopyMulti( $realParams );
677 
678  $tempFiles = []; // (path => TempFSFile) mapping using the proxy backend's name
679  foreach ( $tempFilesM as $path => $tempFile ) {
680  $tempFiles[$this->unsubstPaths( $path )] = $tempFile;
681  }
682 
683  return $tempFiles;
684  }
685 
686  public function getFileHttpUrl( array $params ) {
687  $index = $this->getReadIndexFromParams( $params );
688  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
689 
690  return $this->backends[$index]->getFileHttpUrl( $realParams );
691  }
692 
693  public function directoryExists( array $params ) {
694  $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
695 
696  return $this->backends[$this->masterIndex]->directoryExists( $realParams );
697  }
698 
699  public function getDirectoryList( array $params ) {
700  $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
701 
702  return $this->backends[$this->masterIndex]->getDirectoryList( $realParams );
703  }
704 
705  public function getFileList( array $params ) {
706  $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
707 
708  return $this->backends[$this->masterIndex]->getFileList( $realParams );
709  }
710 
711  public function getFeatures() {
712  return $this->backends[$this->masterIndex]->getFeatures();
713  }
714 
715  public function clearCache( array $paths = null ) {
716  foreach ( $this->backends as $backend ) {
717  $realPaths = is_array( $paths ) ? $this->substPaths( $paths, $backend ) : null;
718  $backend->clearCache( $realPaths );
719  }
720  }
721 
722  public function preloadCache( array $paths ) {
723  $realPaths = $this->substPaths( $paths, $this->backends[$this->readIndex] );
724  $this->backends[$this->readIndex]->preloadCache( $realPaths );
725  }
726 
727  public function preloadFileStat( array $params ) {
728  $index = $this->getReadIndexFromParams( $params );
729  $realParams = $this->substOpPaths( $params, $this->backends[$index] );
730 
731  return $this->backends[$index]->preloadFileStat( $realParams );
732  }
733 
734  public function getScopedLocksForOps( array $ops, StatusValue $status ) {
735  $realOps = $this->substOpBatchPaths( $ops, $this->backends[$this->masterIndex] );
736  $fileOps = $this->backends[$this->masterIndex]->getOperationsInternal( $realOps );
737  // Get the paths to lock from the master backend
738  $paths = $this->backends[$this->masterIndex]->getPathsToLockForOpsInternal( $fileOps );
739  // Get the paths under the proxy backend's name
740  $pbPaths = [
743  ];
744 
745  // Actually acquire the locks
746  return $this->getScopedFileLocks( $pbPaths, 'mixed', $status );
747  }
748 
753  protected function getReadIndexFromParams( array $params ) {
754  return !empty( $params['latest'] ) ? $this->masterIndex : $this->readIndex;
755  }
756 }
FileBackendMultiWrite\unsubstPaths
unsubstPaths( $paths)
Substitute the backend of internal storage paths with the proxy backend's name.
Definition: FileBackendMultiWrite.php:474
FileBackendMultiWrite\getFileList
getFileList(array $params)
Get an iterator to list all stored files under a storage directory.
Definition: FileBackendMultiWrite.php:705
StatusValue
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: StatusValue.php:42
FileBackendMultiWrite\doClean
doClean(array $params)
Definition: FileBackendMultiWrite.php:541
FileBackendMultiWrite\getFileXAttributes
getFileXAttributes(array $params)
Get metadata about a file at a storage path in the backend.
Definition: FileBackendMultiWrite.php:616
FileBackend
Base class for all file backend classes (including multi-write backends).
Definition: FileBackend.php:93
captcha-old.count
count
Definition: captcha-old.py:225
FileBackendMultiWrite\hasVolatileSources
hasVolatileSources(array $ops)
Definition: FileBackendMultiWrite.php:486
FileBackendMultiWrite\getLocalCopyMulti
getLocalCopyMulti(array $params)
Like getLocalCopy() except it takes an array of storage paths and returns a map of storage paths to T...
Definition: FileBackendMultiWrite.php:672
LockManager\LOCK_UW
const LOCK_UW
Definition: LockManager.php:69
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1994
FileBackendMultiWrite\$autoResync
string bool $autoResync
Definition: FileBackendMultiWrite.php:56
FileBackend\getScopedFileLocks
getScopedFileLocks(array $paths, $type, StatusValue $status, $timeout=0)
Lock the files at the given storage paths in the backend.
Definition: FileBackend.php:1344
$status
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1049
FileBackendMultiWrite\doPublish
doPublish(array $params)
Definition: FileBackendMultiWrite.php:537
FileBackendMultiWrite\$masterIndex
int $masterIndex
Index of master backend.
Definition: FileBackendMultiWrite.php:49
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
FileBackendMultiWrite\getFileProps
getFileProps(array $params)
Get the properties of the file at a storage path in the backend.
Definition: FileBackendMultiWrite.php:644
StringUtils\escapeRegexReplacement
static escapeRegexReplacement( $string)
Escape a string to make it suitable for inclusion in a preg_replace() replacement parameter.
Definition: StringUtils.php:322
$params
$params
Definition: styleTest.css.php:40
FileBackendMultiWrite\substPaths
substPaths( $paths, FileBackendStore $backend)
Substitute the backend of storage paths with an internal backend's name.
Definition: FileBackendMultiWrite.php:460
FileBackendMultiWrite\directoryExists
directoryExists(array $params)
Check if a directory exists at a given storage path.
Definition: FileBackendMultiWrite.php:693
FileBackendMultiWrite\getFileStat
getFileStat(array $params)
Get quick information about a file at a storage path in the backend.
Definition: FileBackendMultiWrite.php:609
FileBackendMultiWrite\CHECK_TIME
const CHECK_TIME
Definition: FileBackendMultiWrite.php:63
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1092
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
FileBackendMultiWrite\doOperationsInternal
doOperationsInternal(array $ops, array $opts)
Definition: FileBackendMultiWrite.php:142
FileBackendMultiWrite\getFileSize
getFileSize(array $params)
Get the size (bytes) of a file at a storage path in the backend.
Definition: FileBackendMultiWrite.php:602
DeferredUpdates\addCallableUpdate
static addCallableUpdate( $callable, $stage=self::POSTSEND, IDatabase $dbw=null)
Add a callable update.
Definition: DeferredUpdates.php:111
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:127
FileBackendMultiWrite\getLocalReferenceMulti
getLocalReferenceMulti(array $params)
Like getLocalReference() except it takes an array of storage paths and returns a map of storage paths...
Definition: FileBackendMultiWrite.php:658
FileBackendMultiWrite\clearCache
clearCache(array $paths=null)
Invalidate any in-process file stat and property cache.
Definition: FileBackendMultiWrite.php:715
FileBackendMultiWrite\preloadFileStat
preloadFileStat(array $params)
Preload file stat information (concurrently if possible) into in-process cache.
Definition: FileBackendMultiWrite.php:727
FileBackendMultiWrite\doDirectoryOp
doDirectoryOp( $method, array $params)
Definition: FileBackendMultiWrite.php:550
FileBackendMultiWrite\doQuickOperationsInternal
doQuickOperationsInternal(array $ops)
Definition: FileBackendMultiWrite.php:496
FileBackendMultiWrite\fileExists
fileExists(array $params)
Check if a file exists at a storage path in the backend.
Definition: FileBackendMultiWrite.php:588
FileBackendMultiWrite\CHECK_SHA1
const CHECK_SHA1
Definition: FileBackendMultiWrite.php:64
FileBackendMultiWrite\getFeatures
getFeatures()
Get the a bitfield of extra features supported by the backend medium.
Definition: FileBackendMultiWrite.php:711
FileBackendMultiWrite\getFileSha1Base36
getFileSha1Base36(array $params)
Get a SHA-1 hash of the file at a storage path in the backend.
Definition: FileBackendMultiWrite.php:637
FileBackendMultiWrite\concatenate
concatenate(array $params)
Concatenate a list of storage files into a single file system file.
Definition: FileBackendMultiWrite.php:577
FileBackendStore
Base class for all backends using particular storage medium.
Definition: FileBackendStore.php:39
FileBackendMultiWrite
Proxy backend that mirrors writes to several internal backends.
Definition: FileBackendMultiWrite.php:44
FileBackendMultiWrite\getDirectoryList
getDirectoryList(array $params)
Get an iterator to list all directories under a storage directory.
Definition: FileBackendMultiWrite.php:699
FileBackendMultiWrite\getFileHttpUrl
getFileHttpUrl(array $params)
Return an HTTP URL to a given file that requires no authentication to use.
Definition: FileBackendMultiWrite.php:686
FileBackendMultiWrite\CHECK_SIZE
const CHECK_SIZE
Definition: FileBackendMultiWrite.php:62
FileBackendMultiWrite\$asyncWrites
bool $asyncWrites
Definition: FileBackendMultiWrite.php:59
FileBackendMultiWrite\doPrepare
doPrepare(array $params)
Definition: FileBackendMultiWrite.php:529
FileBackendMultiWrite\fileStoragePathsForOps
fileStoragePathsForOps(array $ops)
Get a list of file storage paths to read or write for a list of operations.
Definition: FileBackendMultiWrite.php:394
FileBackendMultiWrite\substOpPaths
substOpPaths(array $ops, FileBackendStore $backend)
Same as substOpBatchPaths() but for a single operation.
Definition: FileBackendMultiWrite.php:447
FileBackend\$name
string $name
Unique backend name.
Definition: FileBackend.php:95
FileBackendMultiWrite\getFileContentsMulti
getFileContentsMulti(array $params)
Like getFileContents() except it takes an array of storage paths and returns a map of storage paths t...
Definition: FileBackendMultiWrite.php:623
$path
$path
Definition: NoLocalSettings.php:26
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
FileBackendMultiWrite\__construct
__construct(array $config)
Construct a proxy backend that consists of several internal backends.
Definition: FileBackendMultiWrite.php:94
FileBackendMultiWrite\getReadIndexFromParams
getReadIndexFromParams(array $params)
Definition: FileBackendMultiWrite.php:753
true
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1956
FileBackendMultiWrite\consistencyCheck
consistencyCheck(array $paths)
Check that a set of files are consistent across all internal backends.
Definition: FileBackendMultiWrite.php:230
FileBackendMultiWrite\getScopedLocksForOps
getScopedLocksForOps(array $ops, StatusValue $status)
Get an array of scoped locks needed for a batch of file operations.
Definition: FileBackendMultiWrite.php:734
name
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
Definition: design.txt:12
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
FileBackend\$fileJournal
FileJournal $fileJournal
Definition: FileBackend.php:115
FileBackendMultiWrite\accessibilityCheck
accessibilityCheck(array $paths)
Check that a set of file paths are usable across all internal backends.
Definition: FileBackendMultiWrite.php:302
FileBackendMultiWrite\$syncChecks
int $syncChecks
Bitfield.
Definition: FileBackendMultiWrite.php:54
LockManager\LOCK_EX
const LOCK_EX
Definition: LockManager.php:70
FileBackendMultiWrite\doSecure
doSecure(array $params)
Definition: FileBackendMultiWrite.php:533
FileBackendMultiWrite\$backends
FileBackendStore[] $backends
Prioritized list of FileBackendStore objects.
Definition: FileBackendMultiWrite.php:46
FileBackendMultiWrite\streamFile
streamFile(array $params)
Stream the file at a storage path in the backend.
Definition: FileBackendMultiWrite.php:651
FileBackendMultiWrite\preloadCache
preloadCache(array $paths)
Preload persistent file stat cache and property cache into in-process cache.
Definition: FileBackendMultiWrite.php:722
FileBackendMultiWrite\resyncFiles
resyncFiles(array $paths, $resyncMode=true)
Check that a set of files are consistent across all internal backends and re-synchronize those files ...
Definition: FileBackendMultiWrite.php:328
FileBackend\newStatus
newStatus()
Yields the result of the status wrapper callback on either:
Definition: FileBackend.php:1598
array
the array() calling protocol came about after MediaWiki 1.4rc1.
FileBackend\$domainId
string $domainId
Unique domain name.
Definition: FileBackend.php:98
FileBackendMultiWrite\getFileTimestamp
getFileTimestamp(array $params)
Get the last-modified timestamp of the file at a storage path.
Definition: FileBackendMultiWrite.php:595
FileBackendMultiWrite\substOpBatchPaths
substOpBatchPaths(array $ops, FileBackendStore $backend)
Substitute the backend name in storage path parameters for a set of operations with that of a given i...
Definition: FileBackendMultiWrite.php:425
FileBackendMultiWrite\$readIndex
int $readIndex
Index of read affinity backend.
Definition: FileBackendMultiWrite.php:51