Improved performance of kolab cache by bypassing Roundcube messages cache (Request #1740)

This commit is contained in:
Aleksander Machniak 2013-10-07 09:56:06 +02:00
parent c97615aeef
commit 16d9509a5d
2 changed files with 74 additions and 18 deletions

View file

@ -100,12 +100,15 @@ class kolab_storage_cache
$this->_sync_lock(); $this->_sync_lock();
// synchronize IMAP mailbox cache // synchronize IMAP mailbox cache
$this->bypass(true);
$this->imap->folder_sync($this->folder->name); $this->imap->folder_sync($this->folder->name);
// compare IMAP index with object cache index // compare IMAP index with object cache index
$imap_index = $this->imap->index($this->folder->name); $imap_index = $this->imap->index($this->folder->name);
$this->index = $imap_index->get(); $this->index = $imap_index->get();
$this->bypass(false);
// determine objects to fetch or to invalidate // determine objects to fetch or to invalidate
if ($this->ready) { if ($this->ready) {
// read cache index // read cache index
@ -523,8 +526,14 @@ class kolab_storage_cache
if (!$type) if (!$type)
$type = $this->folder->type; $type = $this->folder->type;
$this->bypass(true);
$results = array(); $results = array();
foreach ((array)$this->imap->fetch_headers($this->folder->name, $index, false) as $msguid => $headers) { $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']); $object_type = kolab_format::mime2object_type($headers->others['x-kolab-type']);
// check object type header and abort on mismatch // check object type header and abort on mismatch
@ -782,4 +791,34 @@ class kolab_storage_cache
return $this->uid2msg[$uid]; return $this->uid2msg[$uid];
} }
/**
* Bypass Roundcube messages cache.
* Roundcube cache duplicates information already stored in kolab_cache.
*
* @param bool $disable True disables, False enables messages cache
*/
public function bypass($disable = false)
{
// if kolab cache is disabled do nothing
if (!$this->enabled) {
return;
}
if ($this->messages_cache === null) {
$rcmail = rcube::get_instance();
$this->messages_cache = (bool) $rcmail->config->get('messages_cache');
}
if ($this->messages_cache) {
// we'll disable messages cache, but keep index cache
// default mode is both (MODE_INDEX | MODE_MESSAGE)
$mode = rcube_imap_cache::MODE_INDEX;
if (!$disable) {
$mode |= rcube_imap_cache::MODE_MESSAGE;
}
$this->imap->set_messages_caching(true, $mode);
}
}
} }

View file

@ -340,7 +340,6 @@ class kolab_storage_folder
return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name); return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name);
} }
/** /**
* Get number of objects stored in this folder * Get number of objects stored in this folder
* *
@ -502,6 +501,7 @@ class kolab_storage_folder
* @param string The IMAP message UID to fetch * @param string The IMAP message UID to fetch
* @param string The object type expected (use wildcard '*' to accept all types) * @param string The object type expected (use wildcard '*' to accept all types)
* @param string The folder name where the message is stored * @param string The folder name where the message is stored
*
* @return mixed Hash array representing the Kolab object, a kolab_format instance or false if not found * @return mixed Hash array representing the Kolab object, a kolab_format instance or false if not found
*/ */
public function read_object($msguid, $type = null, $folder = null) public function read_object($msguid, $type = null, $folder = null)
@ -511,31 +511,31 @@ class kolab_storage_folder
$this->imap->set_folder($folder); $this->imap->set_folder($folder);
$headers = $this->imap->get_message_headers($msguid); $this->cache->bypass(true);
$message = null; $message = new rcube_message($msguid);
$this->cache->bypass(false);
// Message doesn't exist? // Message doesn't exist?
if (empty($headers)) { if (empty($message->headers)) {
return false; return false;
} }
// extract the X-Kolab-Type header from the XML attachment part if missing // extract the X-Kolab-Type header from the XML attachment part if missing
if (empty($headers->others['x-kolab-type'])) { if (empty($message->headers->others['x-kolab-type'])) {
$message = new rcube_message($msguid);
foreach ((array)$message->attachments as $part) { foreach ((array)$message->attachments as $part) {
if (strpos($part->mimetype, kolab_format::KTYPE_PREFIX) === 0) { if (strpos($part->mimetype, kolab_format::KTYPE_PREFIX) === 0) {
$headers->others['x-kolab-type'] = $part->mimetype; $message->headers->others['x-kolab-type'] = $part->mimetype;
break; break;
} }
} }
} }
// fix buggy messages stating the X-Kolab-Type header twice // fix buggy messages stating the X-Kolab-Type header twice
else if (is_array($headers->others['x-kolab-type'])) { else if (is_array($message->headers->others['x-kolab-type'])) {
$headers->others['x-kolab-type'] = reset($headers->others['x-kolab-type']); $message->headers->others['x-kolab-type'] = reset($message->headers->others['x-kolab-type']);
} }
// no object type header found: abort // no object type header found: abort
if (empty($headers->others['x-kolab-type'])) { if (empty($message->headers->others['x-kolab-type'])) {
rcube::raise_error(array( rcube::raise_error(array(
'code' => 600, 'code' => 600,
'type' => 'php', 'type' => 'php',
@ -546,14 +546,13 @@ class kolab_storage_folder
return false; return false;
} }
$object_type = kolab_format::mime2object_type($headers->others['x-kolab-type']); $object_type = kolab_format::mime2object_type($message->headers->others['x-kolab-type']);
$content_type = kolab_format::KTYPE_PREFIX . $object_type; $content_type = kolab_format::KTYPE_PREFIX . $object_type;
// check object type header and abort on mismatch // check object type header and abort on mismatch
if ($type != '*' && $object_type != $type) if ($type != '*' && $object_type != $type)
return false; return false;
if (!$message) $message = new rcube_message($msguid);
$attachments = array(); $attachments = array();
// get XML part // get XML part
@ -595,7 +594,7 @@ class kolab_storage_folder
} }
// check kolab format version // check kolab format version
$format_version = $headers->others['x-kolab-mime-version']; $format_version = $message->headers->others['x-kolab-mime-version'];
if (empty($format_version)) { if (empty($format_version)) {
list($xmltype, $subtype) = explode('.', $object_type); list($xmltype, $subtype) = explode('.', $object_type);
$xmlhead = substr($xml, 0, 512); $xmlhead = substr($xml, 0, 512);
@ -749,7 +748,9 @@ class kolab_storage_folder
// delete old message // delete old message
if ($result && !empty($object['_msguid']) && !empty($object['_mailbox'])) { if ($result && !empty($object['_msguid']) && !empty($object['_mailbox'])) {
$this->cache->bypass(true);
$this->imap->delete_message($object['_msguid'], $object['_mailbox']); $this->imap->delete_message($object['_msguid'], $object['_mailbox']);
$this->cache->bypass(false);
$this->cache->set($object['_msguid'], false, $object['_mailbox']); $this->cache->set($object['_msguid'], false, $object['_mailbox']);
} }
@ -844,6 +845,8 @@ class kolab_storage_folder
$msguid = is_array($object) ? $object['_msguid'] : $this->cache->uid2msguid($object); $msguid = is_array($object) ? $object['_msguid'] : $this->cache->uid2msguid($object);
$success = false; $success = false;
$this->cache->bypass(true);
if ($msguid && $expunge) { if ($msguid && $expunge) {
$success = $this->imap->delete_message($msguid, $this->name); $success = $this->imap->delete_message($msguid, $this->name);
} }
@ -851,6 +854,8 @@ class kolab_storage_folder
$success = $this->imap->set_flag($msguid, 'DELETED', $this->name); $success = $this->imap->set_flag($msguid, 'DELETED', $this->name);
} }
$this->cache->bypass(false);
if ($success) { if ($success) {
$this->cache->set($msguid, false); $this->cache->set($msguid, false);
} }
@ -865,7 +870,11 @@ class kolab_storage_folder
public function delete_all() public function delete_all()
{ {
$this->cache->purge(); $this->cache->purge();
return $this->imap->clear_folder($this->name); $this->cache->bypass(true);
$result = $this->imap->clear_folder($this->name);
$this->cache->bypass(false);
return $result;
} }
@ -878,7 +887,11 @@ class kolab_storage_folder
public function undelete($uid) public function undelete($uid)
{ {
if ($msguid = $this->cache->uid2msguid($uid, true)) { if ($msguid = $this->cache->uid2msguid($uid, true)) {
if ($this->imap->set_flag($msguid, 'UNDELETED', $this->name)) { $this->cache->bypass(true);
$result = $this->imap->set_flag($msguid, 'UNDELETED', $this->name);
$this->cache->bypass(false);
if ($result) {
return $msguid; return $msguid;
} }
} }
@ -897,7 +910,11 @@ class kolab_storage_folder
public function move($uid, $target_folder) public function move($uid, $target_folder)
{ {
if ($msguid = $this->cache->uid2msguid($uid)) { if ($msguid = $this->cache->uid2msguid($uid)) {
if ($this->imap->move_message($msguid, $target_folder, $this->name)) { $this->cache->bypass(true);
$result = $this->imap->move_message($msguid, $target_folder, $this->name);
$this->cache->bypass(false);
if ($result) {
$this->cache->move($msguid, $uid, $target_folder); $this->cache->move($msguid, $uid, $target_folder);
return true; return true;
} }