Implement template PreCache-ing in the TemplateLoader.
authorRobert Sesek <rsesek@bluestatic.org>
Tue, 4 Jun 2013 06:29:41 +0000 (02:29 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Tue, 4 Jun 2013 06:29:41 +0000 (02:29 -0400)
FileCacheBackend still needs to implement it, and tests need to be written.

views/cache_backend.php
views/pdo_cache_backend.php
views/template_loader.php

index c6fe4a899c34790587ab0026c78da0d23a5518ec..9b92883cb39299d55afa0842b82f2a6691420061 100644 (file)
@@ -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);
 }
index 3ccb01cef89dba9eb0c2868b713b9c2dc14eca00..9ca0a608a2a5de5c76a289d3da11f9d34adc88b4 100644 (file)
@@ -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;
+  }
 }
index 58138f54c1661aaeaea1487bb2934ce37178b523..84d461e1f0be21cb2df261a675bcbd1c31b2cc2c 100644 (file)
@@ -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)
   {