plugins/libkolab

Aleksander Machniak machniak at kolabsys.com
Tue Jan 7 16:28:30 CET 2014


 plugins/libkolab/lib/kolab_storage_cache.php |  219 +++++++++++++--------------
 1 file changed, 106 insertions(+), 113 deletions(-)

New commits:
commit 05003d05969938165161a78f20cb70362bc759b5
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Tue Jan 7 16:28:06 2014 +0100

    Fixes/improvements for use with kolab_cache=false

diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
index 8c38614..186f261 100644
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -29,7 +29,6 @@ class kolab_storage_cache
     protected $folder;
     protected $uid2msg;
     protected $objects;
-    protected $index = null;
     protected $metadata = array();
     protected $folder_id;
     protected $resource_uri;
@@ -139,65 +138,71 @@ class kolab_storage_cache
         // increase time limit
         @set_time_limit($this->max_sync_lock_time);
 
-        // read cached folder metadata
-        $this->_read_folder_data();
+        if (!$this->ready) {
+            // kolab cache is disabled, synchronize IMAP mailbox cache only
+            $this->imap->folder_sync($this->folder->name);
+        }
+        else {
+            // read cached folder metadata
+            $this->_read_folder_data();
 
-        // check cache status hash first ($this->metadata is set in _read_folder_data())
-        if ($this->metadata['ctag'] != $this->folder->get_ctag()) {
+            // check cache status hash first ($this->metadata is set in _read_folder_data())
+            if ($this->metadata['ctag'] != $this->folder->get_ctag()) {
+                // lock synchronization for this folder or wait if locked
+                $this->_sync_lock();
 
-            // lock synchronization for this folder or wait if locked
-            $this->_sync_lock();
+                // disable messages cache if configured to do so
+                $this->bypass(true);
 
-            // disable messages cache if configured to do so
-            $this->bypass(true);
+                // synchronize IMAP mailbox cache
+                $this->imap->folder_sync($this->folder->name);
 
-            // synchronize IMAP mailbox cache
-            $this->imap->folder_sync($this->folder->name);
+                // compare IMAP index with object cache index
+                $imap_index = $this->imap->index($this->folder->name, null, null, true, true);
 
-            // compare IMAP index with object cache index
-            $imap_index = $this->imap->index($this->folder->name);
-            $this->index = $imap_index->get();
+                // determine objects to fetch or to invalidate
+                if (!$imap_index->is_error()) {
+                    $imap_index = $imap_index->get();
 
-            // determine objects to fetch or to invalidate
-            if ($this->ready) {
-                // read cache index
-                $sql_result = $this->db->query(
-                    "SELECT msguid, uid FROM $this->cache_table WHERE folder_id=?",
-                    $this->folder_id
-                );
+                    // read cache index
+                    $sql_result = $this->db->query(
+                        "SELECT msguid, uid FROM $this->cache_table WHERE folder_id=?",
+                        $this->folder_id
+                    );
 
-                $old_index = array();
-                while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
-                    $old_index[] = $sql_arr['msguid'];
-                    $this->uid2msg[$sql_arr['uid']] = $sql_arr['msguid'];
-                }
+                    $old_index = array();
+                    while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
+                        $old_index[] = $sql_arr['msguid'];
+                        $this->uid2msg[$sql_arr['uid']] = $sql_arr['msguid'];
+                    }
 
-                // fetch new objects from imap
-                foreach (array_diff($this->index, $old_index) as $msguid) {
-                    if ($object = $this->folder->read_object($msguid, '*')) {
-                        $this->_extended_insert($msguid, $object);
+                    // fetch new objects from imap
+                    foreach (array_diff($imap_index, $old_index) as $msguid) {
+                        if ($object = $this->folder->read_object($msguid, '*')) {
+                            $this->_extended_insert($msguid, $object);
+                        }
+                    }
+                    $this->_extended_insert(0, null);
+
+                    // delete invalid entries from local DB
+                    $del_index = array_diff($old_index, $imap_index);
+                    if (!empty($del_index)) {
+                        $quoted_ids = join(',', array_map(array($this->db, 'quote'), $del_index));
+                        $this->db->query(
+                            "DELETE FROM $this->cache_table WHERE folder_id=? AND msguid IN ($quoted_ids)",
+                            $this->folder_id
+                        );
                     }
-                }
-                $this->_extended_insert(0, null);
-
-                // delete invalid entries from local DB
-                $del_index = array_diff($old_index, $this->index);
-                if (!empty($del_index)) {
-                    $quoted_ids = join(',', array_map(array($this->db, 'quote'), $del_index));
-                    $this->db->query(
-                        "DELETE FROM $this->cache_table WHERE folder_id=? AND msguid IN ($quoted_ids)",
-                        $this->folder_id
-                    );
-                }
 
-                // update ctag value (will be written to database in _sync_unlock())
-                $this->metadata['ctag'] = $this->folder->get_ctag();
-            }
+                    // update ctag value (will be written to database in _sync_unlock())
+                    $this->metadata['ctag'] = $this->folder->get_ctag();
+                }
 
-            $this->bypass(false);
+                $this->bypass(false);
 
-            // remove lock
-            $this->_sync_unlock();
+                // remove lock
+                $this->_sync_unlock();
+            }
         }
 
         $this->synched = time();
@@ -351,22 +356,27 @@ class kolab_storage_cache
      */
     public function move($msguid, $uid, $target_folder)
     {
-        $target = kolab_storage::get_folder($target_folder);
+        if ($this->ready) {
+            $target = kolab_storage::get_folder($target_folder);
 
-        // resolve new message UID in target folder
-        if ($new_msguid = $target->cache->uid2msguid($uid)) {
-            $this->_read_folder_data();
+            // resolve new message UID in target folder
+            if ($new_msguid = $target->cache->uid2msguid($uid)) {
+                $this->_read_folder_data();
 
-            $this->db->query(
-                "UPDATE $this->cache_table SET folder_id=?, msguid=? ".
-                "WHERE folder_id=? AND msguid=?",
-                $target->cache->get_folder_id(),
-                $new_msguid,
-                $this->folder_id,
-                $msguid
-            );
+                $this->db->query(
+                    "UPDATE $this->cache_table SET folder_id=?, msguid=? ".
+                    "WHERE folder_id=? AND msguid=?",
+                    $target->cache->get_folder_id(),
+                    $new_msguid,
+                    $this->folder_id,
+                    $msguid
+                );
+
+                $result = $this->db->affected_rows();
+            }
         }
-        else {
+
+        if (empty($result)) {
             // just clear cache entry
             $this->set($msguid, false);
         }
@@ -380,12 +390,17 @@ class kolab_storage_cache
      */
     public function purge($type = null)
     {
+        if (!$this->ready) {
+            return true;
+        }
+
         $this->_read_folder_data();
 
         $result = $this->db->query(
             "DELETE FROM $this->cache_table WHERE folder_id=?",
             $this->folder_id
         );
+
         return $this->db->affected_rows($result);
     }
 
@@ -396,6 +411,10 @@ class kolab_storage_cache
      */
     public function rename($new_folder)
     {
+        if (!$this->ready) {
+            return;
+        }
+
         $target = kolab_storage::get_folder($new_folder);
 
         // resolve new message UID in target folder
@@ -443,21 +462,24 @@ class kolab_storage_cache
                 }
             }
         }
+        // use IMAP
         else {
-            // extract object type from query parameter
             $filter = $this->_query2assoc($query);
 
-            // use 'list' for folder's default objects
-            if (is_array($this->index) && $filter['type'] == $this->type) {
-                $index = $this->index;
-            }
-            else {  // search by object type
+            if ($filter['type']) {
                 $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_format::KTYPE_PREFIX . $filter['type'];
-                $index  = $this->imap->search_once($this->folder->name, $search)->get();
+                $index  = $this->imap->search_once($this->folder->name, $search);
+            }
+            else {
+                $index = $this->imap->index($this->folder->name, null, null, true, true);
             }
 
-            // fetch all messages in $index from IMAP
-            $result = $uids ? $this->_fetch_uids($index, $filter['type']) : $this->_fetch($index, $filter['type']);
+            if ($index->is_error()) {
+                return null;
+            }
+
+            $index  = $index->get();
+            $result = $uids ? $index : $this->_fetch($index, $filter['type']);
 
             // TODO: post-filter result according to query
         }
@@ -483,8 +505,8 @@ class kolab_storage_cache
      */
     public function count($query = array())
     {
-        // cache is in sync, we can count records in local DB
-        if ($this->synched) {
+        // read from local cache DB (assume it to be synchronized)
+        if ($this->ready) {
             $this->_read_folder_data();
 
             $sql_result = $this->db->query(
@@ -500,16 +522,24 @@ class kolab_storage_cache
             $sql_arr = $this->db->fetch_assoc($sql_result);
             $count   = intval($sql_arr['numrows']);
         }
+        // use IMAP
         else {
-            // search IMAP by object type
             $filter = $this->_query2assoc($query);
-            $ctype  = kolab_format::KTYPE_PREFIX . $filter['type'];
-            $index  = $this->imap->search_once($this->folder->name, 'UNDELETED HEADER X-Kolab-Type ' . $ctype);
+
+            if ($filter['type']) {
+                $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_format::KTYPE_PREFIX . $filter['type'];
+                $index  = $this->imap->search_once($this->folder->name, $search);
+            }
+            else {
+                $index = $this->imap->index($this->folder->name, null, null, true, true);
+            }
 
             if ($index->is_error()) {
                 return null;
             }
 
+            // TODO: post-filter result according to query
+
             $count = $index->count();
         }
 
@@ -597,43 +627,6 @@ class kolab_storage_cache
         return $results;
     }
 
-
-    /**
-     * Fetch object UIDs (aka message subjects) from IMAP
-     *
-     * @param array List of message UIDs to fetch
-     * @param string Requested object type or * for all
-     * @param string IMAP folder to read from
-     * @return array List of parsed Kolab objects
-     */
-    protected function _fetch_uids($index, $type = null)
-    {
-        if (!$type)
-            $type = $this->folder->type;
-
-        $this->bypass(true);
-
-        $results = array();
-        $headers = $this->imap->fetch_headers($this->folder->name, $index, false);
-
-        $this->bypass(false);
-
-        foreach ((array)$headers as $msguid => $headers) {
-            $object_type = kolab_format::mime2object_type($headers->others['x-kolab-type']);
-
-            // check object type header and abort on mismatch
-            if ($type != '*' && $object_type != $type)
-                return false;
-
-            $uid = $headers->subject;
-            $this->uid2msg[$uid] = $msguid;
-            $results[] = $uid;
-        }
-
-        return $results;
-    }
-
-
     /**
      * Helper method to convert the given Kolab object into a dataset to be written to cache
      */
@@ -789,7 +782,7 @@ class kolab_storage_cache
     protected function _read_folder_data()
     {
         // already done
-        if (!empty($this->folder_id))
+        if (!empty($this->folder_id) || !$this->ready)
             return;
 
         $sql_arr = $this->db->fetch_assoc($this->db->query("SELECT folder_id, synclock, ctag FROM $this->folders_table WHERE resource=?", $this->resource_uri));




More information about the commits mailing list