/** * Run the transaction * @return FileRepoStatus */ public function execute() { $repo = $this->file->getRepo(); $this->file->lock(); // Prepare deletion batch $hashes = $this->getHashes(); $this->deletionBatch = array(); $ext = $this->file->getExtension(); $dotExt = $ext === '' ? '' : ".{$ext}"; foreach ($this->srcRels as $name => $srcRel) { // Skip files that have no hash (e.g. missing DB record, or sha1 field and file source) if (isset($hashes[$name])) { $hash = $hashes[$name]; $key = $hash . $dotExt; $dstRel = $repo->getDeletedHashPath($key) . $key; $this->deletionBatch[$name] = array($srcRel, $dstRel); } } // Lock the filearchive rows so that the files don't get deleted by a cleanup operation // We acquire this lock by running the inserts now, before the file operations. // This potentially has poor lock contention characteristics -- an alternative // scheme would be to insert stub filearchive entries with no fa_name and commit // them in a separate transaction, then run the file ops, then update the fa_name fields. $this->doDBInserts(); if (!$repo->hasSha1Storage()) { // Removes non-existent file from the batch, so we don't get errors. // This also handles files in the 'deleted' zone deleted via revision deletion. $checkStatus = $this->removeNonexistentFiles($this->deletionBatch); if (!$checkStatus->isGood()) { $this->status->merge($checkStatus); return $this->status; } $this->deletionBatch = $checkStatus->value; // Execute the file deletion batch $status = $this->file->repo->deleteBatch($this->deletionBatch); if (!$status->isGood()) { $this->status->merge($status); } } if (!$this->status->isOK()) { // Critical file deletion error // Roll back inserts, release lock and abort // TODO: delete the defunct filearchive rows if we are using a non-transactional DB $this->file->unlockAndRollback(); return $this->status; } // Delete image/oldimage rows $this->doDBDeletes(); // Commit and return $this->file->unlock(); return $this->status; }
/** * Run the transaction * @return FileRepoStatus */ function execute() { wfProfileIn(__METHOD__); $this->file->lock(); // Leave private files alone $privateFiles = array(); list($oldRels, ) = $this->getOldRels(); $dbw = $this->file->repo->getMasterDB(); if (!empty($oldRels)) { $res = $dbw->select('oldimage', array('oi_archive_name'), array('oi_name' => $this->file->getName(), 'oi_archive_name' => array_keys($oldRels), $dbw->bitAnd('oi_deleted', File::DELETED_FILE) => File::DELETED_FILE), __METHOD__); foreach ($res as $row) { $privateFiles[$row->oi_archive_name] = 1; } } // Prepare deletion batch $hashes = $this->getHashes(); $this->deletionBatch = array(); $ext = $this->file->getExtension(); $dotExt = $ext === '' ? '' : ".{$ext}"; foreach ($this->srcRels as $name => $srcRel) { // Skip files that have no hash (missing source). // Keep private files where they are. if (isset($hashes[$name]) && !array_key_exists($name, $privateFiles)) { $hash = $hashes[$name]; $key = $hash . $dotExt; $dstRel = $this->file->repo->getDeletedHashPath($key) . $key; $this->deletionBatch[$name] = array($srcRel, $dstRel); } } // Lock the filearchive rows so that the files don't get deleted by a cleanup operation // We acquire this lock by running the inserts now, before the file operations. // // This potentially has poor lock contention characteristics -- an alternative // scheme would be to insert stub filearchive entries with no fa_name and commit // them in a separate transaction, then run the file ops, then update the fa_name fields. $this->doDBInserts(); // Removes non-existent file from the batch, so we don't get errors. $this->deletionBatch = $this->removeNonexistentFiles($this->deletionBatch); // Execute the file deletion batch $status = $this->file->repo->deleteBatch($this->deletionBatch); if (!$status->isGood()) { $this->status->merge($status); } if (!$this->status->isOK()) { // Critical file deletion error // Roll back inserts, release lock and abort // TODO: delete the defunct filearchive rows if we are using a non-transactional DB $this->file->unlockAndRollback(); wfProfileOut(__METHOD__); return $this->status; } // Delete image/oldimage rows $this->doDBDeletes(); // Commit and return $this->file->unlock(); wfProfileOut(__METHOD__); return $this->status; }
/** * Run the transaction * @return Status */ public function execute() { $repo = $this->file->getRepo(); $this->file->lock(); // Prepare deletion batch $hashes = $this->getHashes(); $this->deletionBatch = []; $ext = $this->file->getExtension(); $dotExt = $ext === '' ? '' : ".{$ext}"; foreach ($this->srcRels as $name => $srcRel) { // Skip files that have no hash (e.g. missing DB record, or sha1 field and file source) if (isset($hashes[$name])) { $hash = $hashes[$name]; $key = $hash . $dotExt; $dstRel = $repo->getDeletedHashPath($key) . $key; $this->deletionBatch[$name] = [$srcRel, $dstRel]; } } if (!$repo->hasSha1Storage()) { // Removes non-existent file from the batch, so we don't get errors. // This also handles files in the 'deleted' zone deleted via revision deletion. $checkStatus = $this->removeNonexistentFiles($this->deletionBatch); if (!$checkStatus->isGood()) { $this->status->merge($checkStatus); return $this->status; } $this->deletionBatch = $checkStatus->value; // Execute the file deletion batch $status = $this->file->repo->deleteBatch($this->deletionBatch); if (!$status->isGood()) { $this->status->merge($status); } } if (!$this->status->isOK()) { // Critical file deletion error; abort $this->file->unlock(); return $this->status; } // Copy the image/oldimage rows to filearchive $this->doDBInserts(); // Delete image/oldimage rows $this->doDBDeletes(); // Commit and return $this->file->unlock(); return $this->status; }