Implement search (message list) caching
authorMichael M Slusarz <slusarz@curecanti.org>
Fri, 20 Mar 2009 15:48:28 +0000 (09:48 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Fri, 20 Mar 2009 17:12:03 +0000 (11:12 -0600)
framework/Imap_Client/lib/Horde/Imap/Client/Base.php
framework/Imap_Client/lib/Horde/Imap/Client/Socket.php

index c2e8e8a..3e40c3d 100644 (file)
@@ -1301,7 +1301,33 @@ abstract class Horde_Imap_Client_Base
             }
         }
 
-        $ret = $this->_search($query, $options);
+        /* If CONDSTORE is available, we can take advantage of search result
+         * caching. We invalidate the cache when the MODSEQ changes. We
+         * store results by hashing the options array - the generated
+         * query is already added to '_query' key above. */
+        $cache = $ret = null;
+        if (isset($this->_init['enabled']['CONDSTORE'])) {
+            ksort($options);
+            $cache = hash('md5', serialize($options));
+            $metadata = $this->_cache->getMetaData($mailbox, array('HICsearch'));
+            if (isset($metadata['HICsearch'][$cache])) {
+                $ret = $metadata['HICsearch'][$cache];
+                if ($this->_debug) {
+                    fwrite($this->_debug, sprintf("Horde_Imap_Client: Retrieved search results from cache (mailbox: %s; id: %s)\n", $mailbox, $cache));
+                }
+            }
+        }
+
+        if (is_null($ret)) {
+            $ret = $this->_search($query, $options);
+            if ($cache) {
+                $metadata['HICsearch'][$cache] = $ret;
+                $this->_updateMetaData($mailbox, $metadata);
+                if ($this->_debug) {
+                    fwrite($this->_debug, sprintf("Horde_Imap_Client: Saved search results to cache (mailbox: %s; id: %s)\n", $mailbox, $cache));
+                }
+            }
+        }
 
         if (!empty($options['reverse'])) {
             if (empty($options['sort'])) {
@@ -1319,7 +1345,8 @@ abstract class Horde_Imap_Client_Base
      *
      * @param object $query   The search query.
      * @param array $options  Additional options. The '_query' key contains
-     *                        the value of $query->build().
+     *                        the value of $query->build(). 'sort' and
+     *                        'reverse' should be ignored.
      *
      * @return array  An array of UIDs (default) or an array of message
      *                sequence numbers (if 'sequence' is true).
@@ -1864,7 +1891,8 @@ abstract class Horde_Imap_Client_Base
                             if (!empty($uids)) {
                                 $this->_fetch(array(Horde_Imap_Client::FETCH_FLAGS => true), array('changedsince' => $metadata['HICmodseq'], 'ids' => $uids));
                             }
-                            $this->_cache->setMetaData($mailbox, array('HICmodseq' => $status_res['highestmodseq']));
+
+                            $this->_updateMetaData($mailbox, array('HICmodseq' => $status_res['highestmodseq']));
                         }
                     }
 
@@ -2453,7 +2481,7 @@ abstract class Horde_Imap_Client_Base
         try {
             $this->_cache->set($mailbox, $tocache, $uidvalid);
             if ($is_flags) {
-                $this->_cache->setMetaData($mailbox, array('HICmodseq' => max($highestmodseq)));
+                $this->_updateMetaData($mailbox, array('HICmodseq' => max($highestmodseq)));
             }
         } catch (Horde_Imap_Client_Exception $e) {
             if ($e->getCode() != Horde_Imap_Client_Exception::CACHEUIDINVALID) {
@@ -2462,4 +2490,21 @@ abstract class Horde_Imap_Client_Base
         }
     }
 
+    /**
+     * Update metadata entries.
+     *
+     * @param string $mailbox  Mailbox to update.
+     * @param array $data      The data to update with.
+     */
+    protected function _updateMetaData($mailbox, $data)
+    {
+        /* If we see that HICmodseq is being updated, we know that we have
+         * to invalidate the search cache. */
+        if (isset($data['HICmodseq']) && !isset($data['HICsearch'])) {
+            $data['HICsearch'] = array();
+        }
+
+        $this->_cache->setMetaData($mailbox, $data);
+    }
+
 }
index 74aecc1..e8df3ca 100644 (file)
@@ -825,7 +825,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             } else {
                 /* We know the mailbox has been updated, so update the
                  * highestmodseq metadata in the cache. */
-                $this->_cache->setMetaData($mailbox, array('HICmodseq' => $this->_temp['mailbox']['highestmodseq']));
+                $this->_updateMetaData($mailbox, array('HICmodseq' => $this->_temp['mailbox']['highestmodseq']));
             }
         } elseif ($condstore) {
             $this->_init['enabled']['CONDSTORE'] = true;
@@ -1400,7 +1400,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             }
 
             if (isset($this->_init['enabled']['QRESYNC'])) {
-                $this->_cache->setMetaData($mailbox, array('HICmodseq' => $this->_temp['mailbox']['highestmodseq']));
+                $this->_updateMetaData($mailbox, array('HICmodseq' => $this->_temp['mailbox']['highestmodseq']));
             }
 
             return $list_msgs ? $expunged : null;