From d96689620f856264f63cb7df7f483e0d4042b142 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 21 Feb 2016 19:09:04 +0100 Subject: [PATCH] Performance: Get event-to-mail relations once per events list, instead of doing SELECT for every event (including recurrences) --- plugins/calendar/calendar.php | 9 -------- .../calendar/drivers/kolab/kolab_calendar.php | 21 ++++++++++++------- plugins/libkolab/lib/kolab_storage_config.php | 14 ++++++++++--- .../drivers/kolab/tasklist_kolab_driver.php | 2 +- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 3e0c0adf..f4caa21b 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -1744,15 +1744,6 @@ class calendar extends rcube_plugin $event['attachments'][$k]['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']); } - // convert link URIs references into structs - if (array_key_exists('links', $event)) { - foreach ((array)$event['links'] as $i => $link) { - if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) { - $event['links'][$i] = $msgref; - } - } - } - // check for organizer in attendees list $organizer = null; foreach ((array)$event['attendees'] as $i => $attendee) { diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index a2ff6ee9..b06cbef2 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -298,13 +298,13 @@ class kolab_calendar extends kolab_storage_folder_api $events = array(); foreach ($this->storage->select($query) as $record) { - $event = $this->_to_driver_event($record, !$virtual); + $event = $this->_to_driver_event($record, !$virtual, false); // remember seen categories if ($event['categories']) { $cat = is_array($event['categories']) ? $event['categories'][0] : $event['categories']; $this->categories[$cat]++; - } + } // list events in requested time window if ($event['start'] <= $end && $event['end'] >= $start) { @@ -347,7 +347,7 @@ class kolab_calendar extends kolab_storage_folder_api // add top-level exceptions (aka loose single occurrences) else if (is_array($record['exceptions'])) { foreach ($record['exceptions'] as $ex) { - $component = $this->_to_driver_event($ex); + $component = $this->_to_driver_event($ex, false, false); if ($component['start'] <= $end && $component['end'] >= $start) { $events[] = $component; } @@ -381,6 +381,10 @@ class kolab_calendar extends kolab_storage_folder_api return true; }); + // Apply event-to-mail relations + $config = kolab_storage_config::get_instance(); + $config->apply_links($events, 'event'); + // avoid session race conditions that will loose temporary subscriptions $this->cal->rc->session->nowrite = true; @@ -622,7 +626,7 @@ class kolab_calendar extends kolab_storage_folder_api if (!$exception['_instance']) $exception['_instance'] = libcalendaring::recurrence_instance_identifier($exception); - $rec_event = $this->_to_driver_event($exception); + $rec_event = $this->_to_driver_event($exception, false, false); $rec_event['id'] = $event['uid'] . '-' . $exception['_instance']; $rec_event['isexception'] = 1; @@ -671,7 +675,7 @@ class kolab_calendar extends kolab_storage_folder_api // add to output if in range $rec_id = $event['uid'] . '-' . $instance_id; if (($next_event['start'] <= $end && $next_event['end'] >= $start) || ($event_id && $rec_id == $event_id)) { - $rec_event = $this->_to_driver_event($next_event); + $rec_event = $this->_to_driver_event($next_event, false, false); $rec_event['_instance'] = $instance_id; $rec_event['_count'] = $i + 1; @@ -703,10 +707,13 @@ class kolab_calendar extends kolab_storage_folder_api /** * Convert from Kolab_Format to internal representation */ - private function _to_driver_event($record, $noinst = false) + private function _to_driver_event($record, $noinst = false, $links = true) { $record['calendar'] = $this->id; - $record['links'] = $this->get_links($record['uid']); + + if ($links) { + $record['links'] = $this->get_links($record['uid']); + } if ($this->get_namespace() == 'other') { $record['className'] = 'fc-event-ns-other'; diff --git a/plugins/libkolab/lib/kolab_storage_config.php b/plugins/libkolab/lib/kolab_storage_config.php index 7da09bc6..7cd2c90d 100644 --- a/plugins/libkolab/lib/kolab_storage_config.php +++ b/plugins/libkolab/lib/kolab_storage_config.php @@ -608,10 +608,15 @@ class kolab_storage_config // get list of object UIDs and UIRs map foreach ($records as $i => $rec) { $uids[] = $rec['uid']; - $ids[self::build_member_url($rec['uid'])] = $i; + // there can be many objects with the same uid (recurring events) + $ids[self::build_member_url($rec['uid'])][] = $i; $records[$i]['links'] = array(); } + if (!empty($uids)) { + $uids = array_unique($uids); + } + // The whole story here is to not do SELECT for every object. // We'll build one SELECT for many (limit above) objects at once @@ -645,14 +650,17 @@ class kolab_storage_config $members = array(); foreach ((array) $relation['members'] as $member) { if (strpos($member, 'imap://') === 0) { - $members[$member] = kolab_storage_config::get_message_reference($link, $type) ?: array('uri' => $link); + $members[$member] = kolab_storage_config::get_message_reference($member, $type) ?: array('uri' => $member); } } + $members = array_values($members); // assign links to objects foreach ((array) $relation['members'] as $member) { if (($id = $ids[$member]) !== null) { - $records[$id]['links'] = array_unique(array_merge($records[$id]['links'], $members)); + foreach ($id as $i) { + $records[$i]['links'] = array_unique(array_merge($records[$i]['links'], $members)); + } } } } diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php index 0c5a65c6..9015fae2 100644 --- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php +++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php @@ -598,7 +598,7 @@ class tasklist_kolab_driver extends tasklist_driver } $config->apply_tags($results); - $config->apply_links($results); + $config->apply_links($results, 'task'); foreach (array_keys($results) as $idx) { $results[$idx] = $this->_to_rcube_task($results[$idx], $results[$idx]['list_id']);