Changeset 5557 in subversion for trunk/roundcubemail/program/include/rcube_imap_cache.php
- Timestamp:
- Dec 7, 2011 3:44:48 AM (18 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail/program/include/rcube_imap_cache.php
r5357 r5557 109 109 110 110 /** 111 * Return (sorted) messages index .111 * Return (sorted) messages index (UIDs). 112 112 * If index doesn't exist or is invalid, will be updated. 113 113 * … … 123 123 if (empty($this->icache[$mailbox])) 124 124 $this->icache[$mailbox] = array(); 125 125 console('cache::get_index'); 126 126 $sort_order = strtoupper($sort_order) == 'ASC' ? 'ASC' : 'DESC'; 127 127 … … 129 129 if (array_key_exists('index', $this->icache[$mailbox])) { 130 130 // The index was fetched from database already, but not validated yet 131 if (!array_key_exists(' result', $this->icache[$mailbox]['index'])) {131 if (!array_key_exists('object', $this->icache[$mailbox]['index'])) { 132 132 $index = $this->icache[$mailbox]['index']; 133 133 } 134 134 // We've got a valid index 135 else if ($sort_field == 'ANY' || $this->icache[$mailbox]['index']['sort_field'] == $sort_field 136 ) {137 if ($ this->icache[$mailbox]['index']['sort_order'] == $sort_order)138 return $this->icache[$mailbox]['index']['result'];139 else140 return array_reverse($this->icache[$mailbox]['index']['result'], true);135 else if ($sort_field == 'ANY' || $this->icache[$mailbox]['index']['sort_field'] == $sort_field) { 136 $result = $this->icache[$mailbox]['index']['object']; 137 if ($result->getParameters('ORDER') != $sort_order) { 138 $result->revert(); 139 } 140 return $result; 141 141 } 142 142 } … … 174 174 $is_valid = $this->validate($mailbox, $index, $exists); 175 175 } 176 176 console("valid:".$is_valid); 177 177 if ($is_valid) { 178 // build index, assign sequence IDs to unique IDs 179 $data = array_combine($index['seq'], $index['uid']); 178 $data = $index['object']; 180 179 // revert the order if needed 181 if ($index['sort_order'] != $sort_order) 182 $data = array_reverse($data, true); 180 if ($data->getParameters('ORDER') != $sort_order) { 181 $data->revert(); 182 } 183 183 } 184 184 } … … 202 202 203 203 // insert/update 204 $this->add_index_row($mailbox, $sort_field, $sort_order, $data, $mbox_data, 205 $exists, $index['modseq']); 204 $this->add_index_row($mailbox, $sort_field, $data, $mbox_data, $exists, $index['modseq']); 206 205 } 207 206 208 207 $this->icache[$mailbox]['index'] = array( 209 ' result' => $data,208 'object' => $data, 210 209 'sort_field' => $sort_field, 211 'sort_order' => $sort_order,212 210 'modseq' => !empty($index['modseq']) ? $index['modseq'] : $mbox_data['HIGHESTMODSEQ'] 213 211 ); … … 234 232 // Seek in internal cache 235 233 if (array_key_exists('thread', $this->icache[$mailbox])) { 236 return array( 237 $this->icache[$mailbox]['thread']['tree'], 238 $this->icache[$mailbox]['thread']['depth'], 239 $this->icache[$mailbox]['thread']['children'], 240 ); 234 return $this->icache[$mailbox]['thread']['object']; 241 235 } 242 236 … … 251 245 } 252 246 253 $data = null;254 255 247 // Entry exist, check cache status 256 248 if (!empty($index)) { … … 270 262 if ($mbox_data['EXISTS']) { 271 263 // get all threads (default sort order) 272 list ($thread_tree, $msg_depth, $has_children) = $this->imap->fetch_threads($mailbox, true); 273 } 274 275 $index = array( 276 'tree' => !empty($thread_tree) ? $thread_tree : array(), 277 'depth' => !empty($msg_depth) ? $msg_depth : array(), 278 'children' => !empty($has_children) ? $has_children : array(), 279 ); 264 $threads = $this->imap->fetch_threads($mailbox, true); 265 } 266 else { 267 $threads = new rcube_imap_result($mailbox, ''); 268 } 269 270 $index['object'] = $threads; 280 271 281 272 // insert/update 282 $this->add_thread_row($mailbox, $ index, $mbox_data, $exists);273 $this->add_thread_row($mailbox, $threads, $mbox_data, $exists); 283 274 } 284 275 285 276 $this->icache[$mailbox]['thread'] = $index; 286 277 287 return array($index['tree'], $index['depth'], $index['children']);278 return $index['object']; 288 279 } 289 280 … … 293 284 * 294 285 * @param string $mailbox Folder name 295 * @param array $msgs Message sequence numbers 296 * @param bool $is_uid True if $msgs contains message UIDs 286 * @param array $msgs Message UIDs 297 287 * 298 288 * @return array The list of messages (rcube_mail_header) indexed by UID 299 289 */ 300 function get_messages($mailbox, $msgs = array() , $is_uid = true)290 function get_messages($mailbox, $msgs = array()) 301 291 { 302 292 if (empty($msgs)) { 303 293 return array(); 304 }305 306 // @TODO: it would be nice if we could work with UIDs only307 // then index would be not needed. For now we need it to308 // map id to uid here and to update message id for cached message309 310 // Convert IDs to UIDs311 $index = $this->get_index($mailbox, 'ANY');312 if (!$is_uid) {313 foreach ($msgs as $idx => $msgid)314 if ($uid = $index[$msgid])315 $msgs[$idx] = $uid;316 294 } 317 295 … … 335 313 $result[$uid]->body = null; 336 314 337 // update message ID according to index data338 if (!empty($index) && ($id = array_search($uid, $index)))339 $result[$uid]->id = $id;340 341 315 if (!empty($result[$uid])) { 342 316 unset($msgs[$uid]); … … 346 320 // Fetch not found messages from IMAP server 347 321 if (!empty($msgs)) { 348 $messages = $this->imap->fetch_headers($mailbox, array_keys($msgs), true, true);322 $messages = $this->imap->fetch_headers($mailbox, array_keys($msgs), false, true); 349 323 350 324 // Insert to DB and add to result list … … 392 366 $message = $this->build_message($sql_arr); 393 367 $found = true; 394 395 // update message ID according to index data396 $index = $this->get_index($mailbox, 'ANY');397 if (!empty($index) && ($id = array_search($uid, $index)))398 $message->id = $id;399 368 } 400 369 … … 618 587 619 588 /** 620 * @param string $mailbox Folder name621 * @param int $id Message (sequence) ID622 *623 * @return int Message UID624 */625 function id2uid($mailbox, $id)626 {627 if (!empty($this->icache['pending_index_update']))628 return null;629 630 // get index if it exists631 $index = $this->get_index($mailbox, 'ANY', null, true);632 633 return $index[$id];634 }635 636 637 /**638 * @param string $mailbox Folder name639 * @param int $uid Message UID640 *641 * @return int Message (sequence) ID642 */643 function uid2id($mailbox, $uid)644 {645 if (!empty($this->icache['pending_index_update']))646 return null;647 648 // get index if it exists649 $index = $this->get_index($mailbox, 'ANY', null, true);650 651 return array_search($uid, (array)$index);652 }653 654 /**655 589 * Fetches index data from database 656 590 */ 657 591 private function get_index_row($mailbox) 658 592 { 593 console('cache::get_index_row'); 659 594 // Get index from DB 660 595 $sql_result = $this->db->query( … … 666 601 667 602 if ($sql_arr = $this->db->fetch_assoc($sql_result)) { 668 $data = explode('@', $sql_arr['data']); 603 $data = explode('@', $sql_arr['data']); 604 $index = @unserialize($data[0]); 605 unset($data[0]); 606 607 if (empty($index)) { 608 $index = new rcube_result_index($mailbox); 609 } 669 610 670 611 return array( 671 612 'valid' => $sql_arr['valid'], 672 'seq' => explode(',', $data[0]), 673 'uid' => explode(',', $data[1]), 674 'sort_field' => $data[2], 675 'sort_order' => $data[3], 676 'deleted' => $data[4], 677 'validity' => $data[5], 678 'uidnext' => $data[6], 679 'modseq' => $data[7], 613 'object' => $index, 614 'sort_field' => $data[1], 615 'deleted' => $data[2], 616 'validity' => $data[3], 617 'uidnext' => $data[4], 618 'modseq' => $data[5], 680 619 ); 681 620 } … … 699 638 700 639 if ($sql_arr = $this->db->fetch_assoc($sql_result)) { 701 $data = explode('@', $sql_arr['data']); 702 703 // Uncompress data, see add_thread_row() 704 // $data[0] = str_replace(array('*', '^', '#'), array(';a:0:{}', 'i:', ';a:1:'), $data[0]); 705 $data[0] = unserialize($data[0]); 706 707 // build 'depth' and 'children' arrays 708 $depth = $children = array(); 709 $this->build_thread_data($data[0], $depth, $children); 640 $data = explode('@', $sql_arr['data']); 641 $thread = @unserialize($data[0]); 642 unset($data[0]); 643 644 if (empty($thread)) { 645 $thread = new rcube_imap_result($mailbox); 646 } 710 647 711 648 return array( 712 'tree' => $data[0], 713 'depth' => $depth, 714 'children' => $children, 649 'object' => $thread, 715 650 'deleted' => $data[1], 716 651 'validity' => $data[2], … … 726 661 * Saves index data into database 727 662 */ 728 private function add_index_row($mailbox, $sort_field, $sort_order,729 $data = array(), $mbox_data = array(), $exists = false, $modseq = null)663 private function add_index_row($mailbox, $sort_field, 664 $data, $mbox_data = array(), $exists = false, $modseq = null) 730 665 { 731 666 $data = array( 732 implode(',', array_keys($data)), 733 implode(',', array_values($data)), 667 serialize($data), 734 668 $sort_field, 735 $sort_order,736 669 (int) $this->skip_deleted, 737 670 (int) $mbox_data['UIDVALIDITY'], … … 760 693 * Saves thread data into database 761 694 */ 762 private function add_thread_row($mailbox, $data = array(), $mbox_data = array(), $exists = false) 763 { 764 $tree = serialize($data['tree']); 765 // This significantly reduces data length 766 // $tree = str_replace(array(';a:0:{}', 'i:', ';a:1:'), array('*', '^', '#'), $tree); 767 695 private function add_thread_row($mailbox, $data, $mbox_data = array(), $exists = false) 696 { 768 697 $data = array( 769 $tree,698 serialize($data), 770 699 (int) $this->skip_deleted, 771 700 (int) $mbox_data['UIDVALIDITY'], … … 795 724 private function validate($mailbox, $index, &$exists = true) 796 725 { 797 $is_thread = isset($index['tree']); 726 $object = $index['object']; 727 $is_thread = is_a($object, 'rcube_result_thread'); 798 728 799 729 // Get mailbox data (UIDVALIDITY, counters, etc.) for status check … … 815 745 // Folder is empty but cache isn't 816 746 if (empty($mbox_data['EXISTS'])) { 817 if (! empty($index['seq']) || !empty($index['tree'])) {747 if (!$object->isEmpty()) { 818 748 $this->clear($mailbox); 819 749 $exists = false; … … 822 752 } 823 753 // Folder is not empty but cache is 824 else if ( empty($index['seq']) && empty($index['tree'])) {754 else if ($object->isEmpty()) { 825 755 unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); 826 756 return false; … … 829 759 // Validation flag 830 760 if (!$is_thread && empty($index['valid'])) { 831 unset($this->icache[$mailbox][ $is_thread ? 'thread' :'index']);761 unset($this->icache[$mailbox]['index']); 832 762 return false; 833 763 } … … 854 784 if ($is_thread) { 855 785 // check messages number... 856 if (!$this->skip_deleted && $mbox_data['EXISTS'] != @max(array_keys($index['depth']))) {786 if (!$this->skip_deleted && $mbox_data['EXISTS'] != $object->countMessages()) { 857 787 return false; 858 788 } … … 863 793 if (!empty($this->skip_deleted)) { 864 794 // compare counts if available 865 if ($mbox_data['COUNT_UNDELETED'] != null 866 && $mbox_data['COUNT_UNDELETED'] != count($index['uid'])) { 795 if (!empty($mbox_data['UNDELETED']) 796 && $mbox_data['UNDELETED']->count() != $object->count() 797 ) { 867 798 return false; 868 799 } 869 800 // compare UID sets 870 if ( $mbox_data['ALL_UNDELETED'] != null) {871 $uids_new = rcube_imap_generic::uncompressMessageSet($mbox_data['ALL_UNDELETED']);872 $uids_old = $ index['uid'];801 if (!empty($mbox_data['UNDELETED'])) { 802 $uids_new = $mbox_data['UNDELETED']->get(); 803 $uids_old = $object->get(); 873 804 874 805 if (count($uids_new) != count($uids_old)) { … … 885 816 // get all undeleted messages excluding cached UIDs 886 817 $ids = $this->imap->search_once($mailbox, 'ALL UNDELETED NOT UID '. 887 rcube_imap_generic::compressMessageSet($ index['uid']));888 889 if (! empty($ids)) {818 rcube_imap_generic::compressMessageSet($object->get())); 819 820 if (!$ids->isEmpty()) { 890 821 return false; 891 822 } … … 894 825 else { 895 826 // check messages number... 896 if ($mbox_data['EXISTS'] != max($index['seq'])) {827 if ($mbox_data['EXISTS'] != $object->count()) { 897 828 return false; 898 829 } 899 830 // ... and max UID 900 if ( max($index['uid']) != $this->imap->id2uid($mbox_data['EXISTS'], $mailbox, true)) {831 if ($object->max() != $this->imap->id2uid($mbox_data['EXISTS'], $mailbox, true)) { 901 832 return false; 902 833 } … … 1061 992 1062 993 $sort_field = $index['sort_field']; 1063 $sort_order = $index[' sort_order'];994 $sort_order = $index['object']->getParameters('ORDER'); 1064 995 $exists = true; 1065 996 … … 1070 1001 } 1071 1002 else { 1072 $data = array_combine($index['seq'], $index['uid']);1003 $data = $index['object']; 1073 1004 } 1074 1005 1075 1006 // update index and/or HIGHESTMODSEQ value 1076 $this->add_index_row($mailbox, $sort_field, $ sort_order, $data, $mbox_data, $exists);1007 $this->add_index_row($mailbox, $sort_field, $data, $mbox_data, $exists); 1077 1008 1078 1009 // update internal cache for get_index() 1079 $this->icache[$mailbox]['index'][' result'] = $data;1010 $this->icache[$mailbox]['index']['object'] = $data; 1080 1011 } 1081 1012 … … 1104 1035 1105 1036 /** 1106 * Creates 'depth' and 'children' arrays from stored thread 'tree' data.1107 */1108 private function build_thread_data($data, &$depth, &$children, $level = 0)1109 {1110 foreach ((array)$data as $key => $val) {1111 $children[$key] = !empty($val);1112 $depth[$key] = $level;1113 if (!empty($val))1114 $this->build_thread_data($val, $depth, $children, $level + 1);1115 }1116 }1117 1118 1119 /**1120 1037 * Saves message stored in internal cache 1121 1038 */ … … 1171 1088 private function get_index_data($mailbox, $sort_field, $sort_order, $mbox_data = array()) 1172 1089 { 1173 $data = array();1174 1175 1090 if (empty($mbox_data)) { 1176 1091 $mbox_data = $this->imap->mailbox_data($mailbox); 1177 1092 } 1178 1093 1179 // Prevent infinite loop.1180 // It happens when rcube_imap::message_index_direct() is called.1181 // There id2uid() is called which will again call get_index() and so on.1182 if (!$sort_field && !$this->skip_deleted)1183 $this->icache['pending_index_update'] = true;1184 1185 1094 if ($mbox_data['EXISTS']) { 1186 1095 // fetch sorted sequence numbers 1187 $data_seq = $this->imap->message_index_direct($mailbox, $sort_field, $sort_order); 1188 // fetch UIDs 1189 if (!empty($data_seq)) { 1190 // Seek in internal cache 1191 if (array_key_exists('index', (array)$this->icache[$mailbox]) 1192 && array_key_exists('result', (array)$this->icache[$mailbox]['index']) 1193 ) 1194 $data_uid = $this->icache[$mailbox]['index']['result']; 1195 else 1196 $data_uid = $this->imap->conn->fetchUIDs($mailbox, $data_seq); 1197 1198 // build index 1199 if (!empty($data_uid)) { 1200 foreach ($data_seq as $seq) 1201 if ($uid = $data_uid[$seq]) 1202 $data[$seq] = $uid; 1203 } 1204 } 1205 } 1206 1207 // Reset internal flags 1208 $this->icache['pending_index_update'] = false; 1209 1210 return $data; 1096 $index = $this->imap->message_index_direct($mailbox, $sort_field, $sort_order); 1097 } 1098 else { 1099 $index = new rcube_result_index($mailbox, '* SORT'); 1100 } 1101 1102 return $index; 1211 1103 } 1212 1104 }
Note: See TracChangeset
for help on using the changeset viewer.
