From 20eeb0b31a986f15ae552944ba5ea7c70fd7038b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stephan=20Gro=C3=9Fberndt?= <stephan@grossberndt.de>
Date: Tue, 4 Jul 2017 09:51:55 +0200
Subject: [PATCH] [BUGFIX] Cache calls to SchemaManager()->listTableColumns()

Caching the calls SchemaManager()->listTableColumns() during runtime
leads to improved performance when doing operations on multiple files or
multiple extbase Domain/Model objects at once as the same information
does not have to be fetched over and over.

Releases: master, 8.7
Resolves: #81778
Change-Id: Ieebcf5046d007dfea40acf148045807053873ac8
Reviewed-on: https://review.typo3.org/53391
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Reviewed-by: Philipp Gampe <philipp.gampe@typo3.org>
Reviewed-by: Sebastian Fischer <typo3@evoweb.de>
Reviewed-by: Henning Liebe <h.liebe@neusta.de>
Tested-by: Philipp Gampe <philipp.gampe@typo3.org>
Reviewed-by: Joerg Boesche <typo3@joergboesche.de>
Reviewed-by: Steffen Frese <steffenf14@gmail.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
---
 .../Resource/ProcessedFileRepository.php      | 22 +++++++++++++----
 .../Generic/Storage/Typo3DbBackend.php        | 24 +++++++++++++++----
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/typo3/sysext/core/Classes/Resource/ProcessedFileRepository.php b/typo3/sysext/core/Classes/Resource/ProcessedFileRepository.php
index dd63afc66b06..9443c98a2f64 100644
--- a/typo3/sysext/core/Classes/Resource/ProcessedFileRepository.php
+++ b/typo3/sysext/core/Classes/Resource/ProcessedFileRepository.php
@@ -41,6 +41,14 @@ class ProcessedFileRepository extends AbstractRepository
      */
     protected $table = 'sys_file_processedfile';
 
+    /**
+     * As determining the table columns is a costly operation this is done only once during runtime and cached then
+     *
+     * @var array
+     * @see cleanUnavailableColumns()
+     */
+    protected $tableColumns = [];
+
     /**
      * Creates this object.
      */
@@ -291,11 +299,15 @@ class ProcessedFileRepository extends AbstractRepository
      */
     protected function cleanUnavailableColumns(array $data)
     {
-        $tableColumns = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getConnectionForTable($this->table)
-            ->getSchemaManager()
-            ->listTableColumns($this->table);
-        return array_intersect_key($data, $tableColumns);
+        // As determining the table columns is a costly operation this is done only once during runtime and cached then
+        if (empty($this->tableColumns[$this->table])) {
+            $this->tableColumns[$this->table] = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getConnectionForTable($this->table)
+                ->getSchemaManager()
+                ->listTableColumns($this->table);
+        }
+
+        return array_intersect_key($data, $this->tableColumns[$this->table]);
     }
 
     /**
diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
index a7457a3aed90..e7c22579b57f 100644
--- a/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
+++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
@@ -78,6 +78,14 @@ class Typo3DbBackend implements BackendInterface, SingletonInterface
      */
     protected $objectManager;
 
+    /**
+     * As determining the table columns is a costly operation this is done only once per table during runtime and cached then
+     *
+     * @var array
+     * @see clearPageCache()
+     */
+    protected $hasPidColumn = [];
+
     /**
      * @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper $dataMapper
      */
@@ -672,11 +680,17 @@ class Typo3DbBackend implements BackendInterface, SingletonInterface
         }
         $pageIdsToClear = [];
         $storagePage = null;
-        $columns = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getConnectionForTable($tableName)
-            ->getSchemaManager()
-            ->listTableColumns($tableName);
-        if (array_key_exists('pid', $columns)) {
+
+        // As determining the table columns is a costly operation this is done only once per table during runtime and cached then
+        if (!isset($this->hasPidColumn[$tableName])) {
+            $columns = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getConnectionForTable($tableName)
+                ->getSchemaManager()
+                ->listTableColumns($tableName);
+            $this->hasPidColumn[$tableName] = array_key_exists('pid', $columns);
+        }
+
+        if ($this->hasPidColumn[$tableName]) {
             $queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
             $queryBuilder->getRestrictions()->removeAll();
             $result = $queryBuilder
-- 
GitLab