From 9ae29c9525dbd878cff63d691625bb0c6f6cbf5c Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Fri, 29 Oct 2010 14:02:19 -0400
Subject: [PATCH] - Improve performance of message cache status checking when skip_disabled=true

---
 CHANGELOG                              |    1 
 program/include/rcube_imap.php         |   67 +++++++++++++++++++--------------
 program/include/rcube_imap_generic.php |   32 +++++++++++----
 3 files changed, 62 insertions(+), 38 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 94d6d04..dbd9b5a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -57,6 +57,7 @@
 - Plugin API: add possibility to disable plugin in AJAX mode, 'noajax' property
 - Plugin API: add possibility to disable plugin in framed mode, 'noframe' property
 - Improve performance of setting IMAP flags using .SILENT suffix
+- Improve performance of message cache status checking with skip_disabled=true
 
 RELEASE 0.4.2
 -------------
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 028d998..473e914 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -546,9 +546,14 @@
             if ($mode == 'UNSEEN') {
                 $search_str .= " UNSEEN";
             }
-            else if ($status) {
-                $keys[]   = 'MAX';
-                $need_uid = true;
+            else {
+                if ($this->caching_enabled) {
+                    $keys[] = 'ALL';
+                }
+                if ($status) {
+                    $keys[]   = 'MAX';
+                    $need_uid = true;
+                }
             }
 
             // get message count using (E)SEARCH
@@ -557,9 +562,15 @@
 
             $count = is_array($index) ? $index['COUNT'] : 0;
 
-            if ($mode == 'ALL' && $status) {
-                $this->set_folder_stats($mailbox, 'cnt', $count);
-                $this->set_folder_stats($mailbox, 'maxuid', is_array($index) ? $index['MAX'] : 0);
+            if ($mode == 'ALL') {
+                if ($need_uid && $this->caching_enabled) {
+                    // Save messages index for check_cache_status()
+                    $this->icache['all_undeleted_idx'] = $index['ALL'];
+                }
+                if ($status) {
+                    $this->set_folder_stats($mailbox, 'cnt', $count);
+                    $this->set_folder_stats($mailbox, 'maxuid', is_array($index) ? $index['MAX'] : 0);
+                }
             }
         }
         else {
@@ -3646,45 +3657,43 @@
         $cache_count = count($cache_index);
 
         // empty mailbox
-        if (!$msg_count)
+        if (!$msg_count) {
             return $cache_count ? -2 : 1;
+        }
 
         if ($cache_count == $msg_count) {
             if ($this->skip_deleted) {
-	            $h_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", 'UID', $this->skip_deleted);
-
-                // Save index in internal cache, will be used when syncing the cache
-                $this->icache['folder_index'] = $h_index;
-
-                if (empty($h_index))
-                    return -2;
-
-	            if (sizeof($h_index) == $cache_count) {
-	                $cache_index = array_flip($cache_index);
-	                foreach ($h_index as $idx => $uid)
-                        unset($cache_index[$uid]);
-
-	                if (empty($cache_index))
-	                    return 1;
-	            }
-	            return -2;
+                if (!empty($this->icache['all_undeleted_idx'])) {
+                    $uids = rcube_imap_generic::uncompressMessageSet($this->icache['all_undeleted_idx']);
+                    $uids = array_flip($uids);
+                    foreach ($cache_index as $uid) {
+                        unset($uids[$uid]);
+                    }
+                }
+                else {
+                    // get all undeleted messages excluding cached UIDs
+                    $uids = $this->search_once($mailbox, 'ALL UNDELETED NOT UID '.
+                        rcube_imap_generic::compressMessageSet($cache_index));
+                }
+                if (empty($uids)) {
+                    return 1;
+                }
             } else {
                 // get UID of the message with highest index
                 $uid = $this->_id2uid($msg_count, $mailbox);
                 $cache_uid = array_pop($cache_index);
 
                 // uids of highest message matches -> cache seems OK
-                if ($cache_uid == $uid)
+                if ($cache_uid == $uid) {
                     return 1;
+                }
             }
             // cache is dirty
             return -1;
         }
+
         // if cache count differs less than 10% report as dirty
-        else if (abs($msg_count - $cache_count) < $msg_count/10)
-            return -1;
-        else
-            return -2;
+        return (abs($msg_count - $cache_count) < $msg_count/10) ? -1 : -2;
     }
 
 
diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php
index 5d16dc0..a7bfe05 100644
--- a/program/include/rcube_imap_generic.php
+++ b/program/include/rcube_imap_generic.php
@@ -1008,8 +1008,8 @@
 	    }
 
 	    // message IDs
-	    if (is_array($add))
-		    $add = $this->compressMessageSet(join(',', $add));
+	    if (!empty($add))
+		    $add = $this->compressMessageSet($add);
 
 	    list($code, $response) = $this->execute($is_uid ? 'UID SORT' : 'SORT',
 	        array("($field)", $encoding, 'ALL' . (!empty($add) ? ' '.$add : '')));
@@ -1026,7 +1026,7 @@
     function fetchHeaderIndex($mailbox, $message_set, $index_field='', $skip_deleted=true, $uidfetch=false)
     {
 	    if (is_array($message_set)) {
-		    if (!($message_set = $this->compressMessageSet(join(',', $message_set))))
+		    if (!($message_set = $this->compressMessageSet($message_set)))
 			    return false;
 	    } else {
 		    list($from_idx, $to_idx) = explode(':', $message_set);
@@ -1150,12 +1150,12 @@
 	    return $result;
     }
 
-    private function compressMessageSet($messages, $force=false)
+    static function compressMessageSet($messages, $force=false)
     {
 	    // given a comma delimited list of independent mid's,
 	    // compresses by grouping sequences together
 
-        if (!is_array($message_set)) {
+        if (!is_array($messages)) {
 	        // if less than 255 bytes long, let's not bother
 	        if (!$force && strlen($messages)<255) {
 	            return $messages;
@@ -1197,6 +1197,23 @@
 
 	    // return as comma separated string
 	    return implode(',', $result);
+    }
+
+    static function uncompressMessageSet($messages)
+    {
+	    $result   = array();
+	    $messages = explode(',', $messages);
+
+        foreach ($messages as $part) {
+            $items = explode(':', $part);
+            $max   = max($items[0], $items[1]);
+
+            for ($x=$items[0]; $x<=$max; $x++) {
+                $result[] = $x;
+            }
+        }
+
+        return $result;
     }
 
     /**
@@ -1264,9 +1281,6 @@
 	    if (!$this->select($mailbox)) {
 		    return false;
 	    }
-
-	    if (is_array($message_set))
-		    $message_set = join(',', $message_set);
 
 	    $message_set = $this->compressMessageSet($message_set);
 
@@ -1824,7 +1838,7 @@
                     if (in_array('MAX', $items))
                         $result['MAX'] = !empty($response) ? max($response) : 0;
                     if (in_array('ALL', $items))
-                        $result['ALL'] = $this->compressMessageSet(implode(',', $response), true);
+                        $result['ALL'] = $this->compressMessageSet($response, true);
 
                     return $result;                    
                 }

--
Gitblit v1.9.1