From 5a564dac60a06ce3207d3b94c19c57443f4670e5 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Tue, 29 Jun 2021 09:52:21 +0200 Subject: [PATCH] Improve speed of PIPs to delete files MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit … by fetching all existing database records at once and deleting obsolete records in one transaction. See #4269 See #4289 --- ...eDeletePackageInstallationPlugin.class.php | 85 ++++++++++++------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/wcfsetup/install/files/lib/system/package/plugin/AbstractFileDeletePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/AbstractFileDeletePackageInstallationPlugin.class.php index 42b901729b..678e18ee1f 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/AbstractFileDeletePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/AbstractFileDeletePackageInstallationPlugin.class.php @@ -6,6 +6,7 @@ use wcf\data\application\Application; use wcf\data\package\Package; use wcf\data\package\PackageCache; use wcf\system\application\ApplicationHandler; +use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\devtools\pip\IDevtoolsPipEntryList; use wcf\system\devtools\pip\IGuiPackageInstallationPlugin; use wcf\system\devtools\pip\TXmlGuiPackageInstallationPlugin; @@ -60,18 +61,7 @@ abstract class AbstractFileDeletePackageInstallationPlugin extends AbstractXMLPa */ protected function handleDelete(array $items) { - $sql = "SELECT packageID - FROM {$this->getLogTableName()} - WHERE {$this->getFilenameTableColumn()} = ? - AND application = ? - AND packageID = ?"; - $searchStatement = WCF::getDB()->prepare($sql); - - $sql = "DELETE FROM {$this->getLogTableName()} - WHERE packageID = ? - AND {$this->getFilenameTableColumn()} = ?"; - $deleteStatement = WCF::getDB()->prepare($sql); - + $groupedFiles = []; foreach ($items as $item) { $file = $item['value']; $application = 'wcf'; @@ -81,30 +71,63 @@ abstract class AbstractFileDeletePackageInstallationPlugin extends AbstractXMLPa $application = Package::getAbbreviation($this->installation->getPackage()->package); } - $searchStatement->execute([ - $file, - $application, - $this->installation->getPackageID(), - ]); - - $filePackageID = $searchStatement->fetchSingleColumn(); - if ($filePackageID !== false && $filePackageID != $this->installation->getPackageID()) { - throw new \UnexpectedValueException( - "'{$file}' does not belong to package '{$this->installation->getPackage()->package}' - but to package '" . PackageCache::getInstance()->getPackage($filePackageID)->package . "'." - ); + if (!isset($groupedFiles[$application])) { + $groupedFiles[$application] = []; + } + $groupedFiles[$application][] = $file; + } + + $logFiles = []; + foreach ($groupedFiles as $application => $files) { + $conditions = new PreparedStatementConditionBuilder(); + $conditions->add("{$this->getFilenameTableColumn()} IN (?)", [$files]); + $conditions->add('application = ?', [$application]); + $conditions->add('packageID = ?', [$this->installation->getPackageID()]); + + $sql = "SELECT packageID, application, {$this->getFilenameTableColumn()} + FROM {$this->getLogTableName()} + {$conditions}"; + $searchStatement = WCF::getDB()->prepare($sql); + $searchStatement->execute($conditions->getParameters()); + + while ($row = $searchStatement->fetchArray()) { + if (!isset($logFiles[$row['application']])) { + $logFiles[$row['application']] = []; + } + $logFiles[$row['application']][$row[$this->getFilenameTableColumn()]] = $row['packageID']; } + } - $filePath = $this->getFilePath($file, $application); - if (\file_exists($filePath)) { - \unlink($filePath); + foreach ($groupedFiles as $application => $files) { + foreach ($files as $file) { + $filePackageID = $logFiles[$application][$file] ?? null; + if ($filePackageID !== null && $filePackageID != $this->installation->getPackageID()) { + throw new \UnexpectedValueException( + "'{$file}' does not belong to package '{$this->installation->getPackage()->package}' + but to package '" . PackageCache::getInstance()->getPackage($filePackageID)->package . "'." + ); + } + + $filePath = $this->getFilePath($file, $application); + if (\file_exists($filePath)) { + \unlink($filePath); + } } + } - $deleteStatement->execute([ - $this->installation->getPackageID(), - $file, - ]); + WCF::getDB()->beginTransaction(); + foreach ($logFiles as $application => $files) { + $conditions = new PreparedStatementConditionBuilder(); + $conditions->add("{$this->getFilenameTableColumn()} IN (?)", [\array_keys($files)]); + $conditions->add('application = ?', [$application]); + $conditions->add('packageID = ?', [$this->installation->getPackageID()]); + + $sql = "DELETE FROM {$this->getLogTableName()} + {$conditions}"; + $statement = WCF::getDB()->prepare($sql); + $statement->execute($conditions->getParameters()); } + WCF::getDB()->commitTransaction(); } /** -- 2.20.1