From a7c5ff1323c5b72bedd54bd57c1279e780be7232 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Tue, 4 Jun 2013 02:29:41 -0400 Subject: [PATCH] Implement template PreCache-ing in the TemplateLoader. FileCacheBackend still needs to implement it, and tests need to be written. --- views/cache_backend.php | 11 +++++++++++ views/pdo_cache_backend.php | 29 +++++++++++++++++++++++++++++ views/template_loader.php | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/views/cache_backend.php b/views/cache_backend.php index c6fe4a8..9b92883 100644 --- a/views/cache_backend.php +++ b/views/cache_backend.php @@ -44,4 +44,15 @@ interface CacheBackend @param int The UNIX timestamp the uncompiled template was last modified. */ public function StoreCompiledTemplate($name, $modification_time, $data); + + /*! + Gets a set of templates from the cache in bulk. If the backend doesn't + support bulk fetch operations, just loop over GetTemplateDataForName. + + @param array Map of template names to modification times. + + @return array Map of template names to data for templates that are present + and valid in the cache. + */ + public function GetMultipleTemplates(Array $templates); } diff --git a/views/pdo_cache_backend.php b/views/pdo_cache_backend.php index 3ccb01c..9ca0a60 100644 --- a/views/pdo_cache_backend.php +++ b/views/pdo_cache_backend.php @@ -24,6 +24,9 @@ require_once HOPLITE_ROOT . '/views/cache_backend.php'; */ class PDOCacheBackend implements CacheBackend { + /*! @var \PDO The dat abase to use. */ + protected $db = NULL; + /*! @var \PDOStatement Used to query for cached templates. */ protected $fetch_statement = NULL; @@ -33,6 +36,9 @@ class PDOCacheBackend implements CacheBackend /*! @var \PDOStatement Used to expire out-of-date templates. */ protected $delete_statement = NULL; + /*! @var string Base query for a multi-fetch operation. */ + protected $fetch_multi_query = ""; + /*! Constructor that prepares the database statements. @@ -48,6 +54,8 @@ class PDOCacheBackend implements CacheBackend $data_column_name = 'template', $timestamp_column_name = 'timestamp') { + $this->db = $db; + $this->fetch_statement = $db->Prepare(" SELECT `$data_column_name` AS template, `$timestamp_column_name` AS timestamp @@ -66,6 +74,13 @@ class PDOCacheBackend implements CacheBackend DELETE FROM `$table_name` WHERE `$name_column_name` = :name "); + + $this->fetch_multi_query = " + SELECT `$name_column_name` AS name, + `$data_column_name` AS template, + `$timestamp_column_name` AS timestamp + FROM $table_name + WHERE `$name_column_name` IN "; } public function GetTemplateDataForName($name, $modification_time) @@ -91,4 +106,18 @@ class PDOCacheBackend implements CacheBackend 'template' => $data, )); } + + public function GetMultipleTemplates(Array $fetch_templates) + { + $placeholders = array_fill(0, count($fetch_templates), '?'); + $stmt = $this->db->Prepare($this->fetch_multi_query . '(' . implode(',', $placeholders) . ')'); + $stmt->Execute(array_keys($fetch_templates)); + + $templates = array(); + while (($template = $stmt->FetchObject())) { + if ($template->timestamp >= $fetch_templates[$template->name]) + $templates[$template->name] = $template->template; + } + return $templates; + } } diff --git a/views/template_loader.php b/views/template_loader.php index 58138f5..84d461e 100644 --- a/views/template_loader.php +++ b/views/template_loader.php @@ -105,6 +105,35 @@ class TemplateLoader return clone $template; } + /*! + Warms up the template cache with a set of templates. If the cache backend + supports multiple simultaneous fetches, this can greatly improve performance. + */ + public function PreCache(Array $templates) + { + if (!$this->cache_backend) + return; + + $fetch_templates = array(); + foreach ($templates AS $name) { + // Do not re-cache templates that have already been cached. + if (isset($this->cache[$name])) + continue; + + $tpl_path = $this->_TemplatePath($name); + $fetch_templates[$name] = filemtime($tpl_path); + } + + $profile = Profiling::IsProfilingEnabled(); + + $cached_templates = $this->cache_backend->GetMultipleTemplates($fetch_templates); + foreach ($cached_templates AS $name => $data) { + $this->cache[$name] = Template::NewWithCompiledData($name, $data); + if ($profile) + $this->usage[$name] = 0; + } + } + /*! Convenience function for loading templates. */ static public function Fetch($name) { -- 2.22.5