/** * @see FileBackend::doOperationsInternal() */ protected final function doOperationsInternal(array $ops, array $opts) { $status = Status::newGood(); $performOps = array(); // list of FileOp objects $filesRead = $filesChanged = array(); // storage paths used // Build up a list of FileOps. The list will have all the ops // for one backend, then all the ops for the next, and so on. // These batches of ops are all part of a continuous array. // Also build up a list of files read/changed... foreach ($this->backends as $index => $backend) { $backendOps = $this->substOpBatchPaths($ops, $backend); // Add on the operation batch for this backend $performOps = array_merge($performOps, $backend->getOperations($backendOps)); if ($index == 0) { // first batch // Get the files used for these operations. Each backend has a batch of // the same operations, so we only need to get them from the first batch. foreach ($performOps as $fileOp) { $filesRead = array_merge($filesRead, $fileOp->storagePathsRead()); $filesChanged = array_merge($filesChanged, $fileOp->storagePathsChanged()); } // Get the paths under the proxy backend's name $filesRead = $this->unsubstPaths($filesRead); $filesChanged = $this->unsubstPaths($filesChanged); } } // Try to lock those files for the scope of this function... if (empty($opts['nonLocking'])) { $filesLockSh = array_diff($filesRead, $filesChanged); // optimization $filesLockEx = $filesChanged; // Get a shared lock on the parent directory of each path changed $filesLockSh = array_merge($filesLockSh, array_map('dirname', $filesLockEx)); // Try to lock those files for the scope of this function... $scopeLockS = $this->getScopedFileLocks($filesLockSh, LockManager::LOCK_UW, $status); $scopeLockE = $this->getScopedFileLocks($filesLockEx, LockManager::LOCK_EX, $status); if (!$status->isOK()) { return $status; // abort } } // Clear any cache entries (after locks acquired) $this->clearCache(); // Do a consistency check to see if the backends agree if (count($this->backends) > 1) { $status->merge($this->consistencyCheck(array_merge($filesRead, $filesChanged))); if (!$status->isOK()) { return $status; // abort } } // Actually attempt the operation batch... $subStatus = FileOp::attemptBatch($performOps, $opts); $success = array(); $failCount = $successCount = 0; // Make 'success', 'successCount', and 'failCount' fields reflect // the overall operation, rather than all the batches for each backend. // Do this by only using success values from the master backend's batch. $batchStart = $this->masterIndex * count($ops); $batchEnd = $batchStart + count($ops) - 1; for ($i = $batchStart; $i <= $batchEnd; $i++) { if (!isset($subStatus->success[$i])) { break; // failed out before trying this op } elseif ($subStatus->success[$i]) { ++$successCount; } else { ++$failCount; } $success[] = $subStatus->success[$i]; } $subStatus->success = $success; $subStatus->successCount = $successCount; $subStatus->failCount = $failCount; // Merge errors into status fields $status->merge($subStatus); $status->success = $subStatus->success; // not done in merge() return $status; }
/** * @see FileBackend::doOperationsInternal() */ protected function doOperationsInternal(array $ops, array $opts) { wfProfileIn(__METHOD__); $status = Status::newGood(); // Build up a list of FileOps... $performOps = $this->getOperations($ops); // Acquire any locks as needed... if (empty($opts['nonLocking'])) { // Build up a list of files to lock... $filesLockEx = $filesLockSh = array(); foreach ($performOps as $fileOp) { $filesLockSh = array_merge($filesLockSh, $fileOp->storagePathsRead()); $filesLockEx = array_merge($filesLockEx, $fileOp->storagePathsChanged()); } // Optimization: if doing an EX lock anyway, don't also set an SH one $filesLockSh = array_diff($filesLockSh, $filesLockEx); // Get a shared lock on the parent directory of each path changed $filesLockSh = array_merge($filesLockSh, array_map('dirname', $filesLockEx)); // Try to lock those files for the scope of this function... $scopeLockS = $this->getScopedFileLocks($filesLockSh, LockManager::LOCK_UW, $status); $scopeLockE = $this->getScopedFileLocks($filesLockEx, LockManager::LOCK_EX, $status); if (!$status->isOK()) { wfProfileOut(__METHOD__); return $status; // abort } } // Clear any cache entries (after locks acquired) $this->clearCache(); // Actually attempt the operation batch... $subStatus = FileOp::attemptBatch($performOps, $opts); // Merge errors into status fields $status->merge($subStatus); $status->success = $subStatus->success; // not done in merge() wfProfileOut(__METHOD__); return $status; }