/** * Release the locks when this goes out of scope */ function __destruct() { $wasOk = $this->status->isOK(); $this->status->merge($this->manager->unlockByType($this->pathsByType)); if ($wasOk) { // Make sure StatusValue is OK, despite any unlockFiles() fatals $this->status->setResult(true, $this->status->value); } }
/** * Merge another status object into this one * * @param Status $other Other Status object * @param bool $overwriteValue Whether to override the "value" member */ public function merge($other, $overwriteValue = false) { $this->sv->merge($other->sv, $overwriteValue); }
/** * Attempt a list of file operations sub-batches in series. * * The operations *in* each sub-batch will be done in parallel. * The caller is responsible for making sure the operations * within any given sub-batch do not depend on each other. * This will abort remaining ops on failure. * * @param array $pPerformOps Batches of file ops (batches use original indexes) * @param StatusValue $status */ protected static function runParallelBatches(array $pPerformOps, StatusValue $status) { $aborted = false; // set to true on unexpected errors foreach ($pPerformOps as $performOpsBatch) { /** @var FileOp[] $performOpsBatch */ if ($aborted) { // check batch op abort flag... // We can't continue (even with $ignoreErrors) as $predicates is wrong. // Log the remaining ops as failed for recovery... foreach ($performOpsBatch as $i => $fileOp) { $status->success[$i] = false; ++$status->failCount; $performOpsBatch[$i]->logFailure('attempt_aborted'); } continue; } /** @var StatusValue[] $statuses */ $statuses = []; $opHandles = []; // Get the backend; all sub-batch ops belong to a single backend /** @var FileBackendStore $backend */ $backend = reset($performOpsBatch)->getBackend(); // Get the operation handles or actually do it if there is just one. // If attemptAsync() returns a StatusValue, it was either due to an error // or the backend does not support async ops and did it synchronously. foreach ($performOpsBatch as $i => $fileOp) { if (!isset($status->success[$i])) { // didn't already fail in precheck() // Parallel ops may be disabled in config due to missing dependencies, // (e.g. needing popen()). When they are, $performOpsBatch has size 1. $subStatus = count($performOpsBatch) > 1 ? $fileOp->attemptAsync() : $fileOp->attempt(); if ($subStatus->value instanceof FileBackendStoreOpHandle) { $opHandles[$i] = $subStatus->value; // deferred } else { $statuses[$i] = $subStatus; // done already } } } // Try to do all the operations concurrently... $statuses = $statuses + $backend->executeOpHandlesInternal($opHandles); // Marshall and merge all the responses (blocking)... foreach ($performOpsBatch as $i => $fileOp) { if (!isset($status->success[$i])) { // didn't already fail in precheck() $subStatus = $statuses[$i]; $status->merge($subStatus); if ($subStatus->isOK()) { $status->success[$i] = true; ++$status->successCount; } else { $status->success[$i] = false; ++$status->failCount; $aborted = true; // set abort flag; we can't continue } } } } }