/**
  * @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;
 }
Пример #2
0
 /**
  * @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;
 }