MediaWiki REL1_28
FileOpBatch.php
Go to the documentation of this file.
1<?php
35 /* Timeout related parameters */
36 const MAX_BATCH_SIZE = 1000; // integer
37
57 public static function attempt( array $performOps, array $opts, FileJournal $journal ) {
58 $status = StatusValue::newGood();
59
60 $n = count( $performOps );
61 if ( $n > self::MAX_BATCH_SIZE ) {
62 $status->fatal( 'backend-fail-batchsize', $n, self::MAX_BATCH_SIZE );
63
64 return $status;
65 }
66
67 $batchId = $journal->getTimestampedUUID();
68 $ignoreErrors = !empty( $opts['force'] );
69 $journaled = empty( $opts['nonJournaled'] );
70 $maxConcurrency = isset( $opts['concurrency'] ) ? $opts['concurrency'] : 1;
71
72 $entries = []; // file journal entry list
73 $predicates = FileOp::newPredicates(); // account for previous ops in prechecks
74 $curBatch = []; // concurrent FileOp sub-batch accumulation
75 $curBatchDeps = FileOp::newDependencies(); // paths used in FileOp sub-batch
76 $pPerformOps = []; // ordered list of concurrent FileOp sub-batches
77 $lastBackend = null; // last op backend name
78 // Do pre-checks for each operation; abort on failure...
79 foreach ( $performOps as $index => $fileOp ) {
80 $backendName = $fileOp->getBackend()->getName();
81 $fileOp->setBatchId( $batchId ); // transaction ID
82 // Decide if this op can be done concurrently within this sub-batch
83 // or if a new concurrent sub-batch must be started after this one...
84 if ( $fileOp->dependsOn( $curBatchDeps )
85 || count( $curBatch ) >= $maxConcurrency
86 || ( $backendName !== $lastBackend && count( $curBatch ) )
87 ) {
88 $pPerformOps[] = $curBatch; // push this batch
89 $curBatch = []; // start a new sub-batch
90 $curBatchDeps = FileOp::newDependencies();
91 }
92 $lastBackend = $backendName;
93 $curBatch[$index] = $fileOp; // keep index
94 // Update list of affected paths in this batch
95 $curBatchDeps = $fileOp->applyDependencies( $curBatchDeps );
96 // Simulate performing the operation...
97 $oldPredicates = $predicates;
98 $subStatus = $fileOp->precheck( $predicates ); // updates $predicates
99 $status->merge( $subStatus );
100 if ( $subStatus->isOK() ) {
101 if ( $journaled ) { // journal log entries
102 $entries = array_merge( $entries,
103 $fileOp->getJournalEntries( $oldPredicates, $predicates ) );
104 }
105 } else { // operation failed?
106 $status->success[$index] = false;
107 ++$status->failCount;
108 if ( !$ignoreErrors ) {
109 return $status; // abort
110 }
111 }
112 }
113 // Push the last sub-batch
114 if ( count( $curBatch ) ) {
115 $pPerformOps[] = $curBatch;
116 }
117
118 // Log the operations in the file journal...
119 if ( count( $entries ) ) {
120 $subStatus = $journal->logChangeBatch( $entries, $batchId );
121 if ( !$subStatus->isOK() ) {
122 $status->merge( $subStatus );
123
124 return $status; // abort
125 }
126 }
127
128 if ( $ignoreErrors ) { // treat precheck() fatals as mere warnings
129 $status->setResult( true, $status->value );
130 }
131
132 // Attempt each operation (in parallel if allowed and possible)...
133 self::runParallelBatches( $pPerformOps, $status );
134
135 return $status;
136 }
137
149 protected static function runParallelBatches( array $pPerformOps, StatusValue $status ) {
150 $aborted = false; // set to true on unexpected errors
151 foreach ( $pPerformOps as $performOpsBatch ) {
153 if ( $aborted ) { // check batch op abort flag...
154 // We can't continue (even with $ignoreErrors) as $predicates is wrong.
155 // Log the remaining ops as failed for recovery...
156 foreach ( $performOpsBatch as $i => $fileOp ) {
157 $status->success[$i] = false;
158 ++$status->failCount;
159 $performOpsBatch[$i]->logFailure( 'attempt_aborted' );
160 }
161 continue;
162 }
164 $statuses = [];
165 $opHandles = [];
166 // Get the backend; all sub-batch ops belong to a single backend
168 $backend = reset( $performOpsBatch )->getBackend();
169 // Get the operation handles or actually do it if there is just one.
170 // If attemptAsync() returns a StatusValue, it was either due to an error
171 // or the backend does not support async ops and did it synchronously.
172 foreach ( $performOpsBatch as $i => $fileOp ) {
173 if ( !isset( $status->success[$i] ) ) { // didn't already fail in precheck()
174 // Parallel ops may be disabled in config due to missing dependencies,
175 // (e.g. needing popen()). When they are, $performOpsBatch has size 1.
176 $subStatus = ( count( $performOpsBatch ) > 1 )
177 ? $fileOp->attemptAsync()
178 : $fileOp->attempt();
179 if ( $subStatus->value instanceof FileBackendStoreOpHandle ) {
180 $opHandles[$i] = $subStatus->value; // deferred
181 } else {
182 $statuses[$i] = $subStatus; // done already
183 }
184 }
185 }
186 // Try to do all the operations concurrently...
187 $statuses = $statuses + $backend->executeOpHandlesInternal( $opHandles );
188 // Marshall and merge all the responses (blocking)...
189 foreach ( $performOpsBatch as $i => $fileOp ) {
190 if ( !isset( $status->success[$i] ) ) { // didn't already fail in precheck()
191 $subStatus = $statuses[$i];
192 $status->merge( $subStatus );
193 if ( $subStatus->isOK() ) {
194 $status->success[$i] = true;
195 ++$status->successCount;
196 } else {
197 $status->success[$i] = false;
198 ++$status->failCount;
199 $aborted = true; // set abort flag; we can't continue
200 }
201 }
202 }
203 }
204 }
205}
FileBackendStore helper class for performing asynchronous file operations.
Class for handling file operation journaling.
logChangeBatch(array $entries, $batchId)
Log changes made by a batch file operation.
getTimestampedUUID()
Get a statistically unique ID string.
Helper class for representing batch file operations.
static runParallelBatches(array $pPerformOps, StatusValue $status)
Attempt a list of file operations sub-batches in series.
const MAX_BATCH_SIZE
static attempt(array $performOps, array $opts, FileJournal $journal)
Attempt to perform a series of file operations.
static newDependencies()
Get a new empty dependency tracking array for paths read/written to.
Definition FileOp.php:167
static newPredicates()
Get a new empty predicates array for precheck()
Definition FileOp.php:158
Generic operation result class Has warning/error list, boolean status and arbitrary value.
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
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist 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
the array() calling protocol came about after MediaWiki 1.4rc1.
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:37