From 2172f4340c46f70042ce474e661b675d7483d3bd Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 12 Feb 2016 13:45:58 +0100 Subject: [PATCH] Performance: Consolidate metadata requests (#3989) This changes number of cache requests from 4 to 2 for each groupware folder. --- .../calendar/drivers/kolab/kolab_driver.php | 4 +- .../lib/rcube_kolab_contacts.php | 6 +- plugins/kolab_notes/kolab_notes.php | 6 +- plugins/libkolab/lib/kolab_storage.php | 84 ++++++++++++++----- plugins/libkolab/lib/kolab_storage_folder.php | 9 +- .../libkolab/lib/kolab_storage_folder_api.php | 55 +++++++++--- .../lib/kolab_storage_folder_user.php | 5 +- .../lib/kolab_storage_folder_virtual.php | 2 +- .../drivers/kolab/tasklist_kolab_driver.php | 4 +- 9 files changed, 119 insertions(+), 56 deletions(-) diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 8f47a457..24cdf6de 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -162,8 +162,8 @@ class kolab_driver extends calendar_driver // special handling for user or virtual folders if ($cal instanceof kolab_storage_folder_user) { $calendars[$cal->id] = array( - 'id' => $cal->id, - 'name' => kolab_storage::object_name($fullname), + 'id' => $cal->id, + 'name' => $fullname, 'listname' => $listname, 'editname' => $cal->get_foldername(), 'color' => $cal->get_color(), diff --git a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php index 7ed91cac..b53f8f5f 100644 --- a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php +++ b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php @@ -166,7 +166,6 @@ class rcube_kolab_contacts extends rcube_addressbook $this->action = rcube::get_instance()->action; } - /** * Getter for the address book name to be displayed * @@ -174,8 +173,7 @@ class rcube_kolab_contacts extends rcube_addressbook */ public function get_name() { - $folder = kolab_storage::object_name($this->imap_folder, $this->namespace); - return $folder; + return $this->storagefolder->get_name(); } /** @@ -186,7 +184,6 @@ class rcube_kolab_contacts extends rcube_addressbook return $this->storagefolder->get_foldername(); } - /** * Getter for the IMAP folder name * @@ -197,7 +194,6 @@ class rcube_kolab_contacts extends rcube_addressbook return $this->imap_folder; } - /** * Getter for the name of the namespace to which the IMAP folder belongs * diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php index bbac42dc..58741c65 100644 --- a/plugins/kolab_notes/kolab_notes.php +++ b/plugins/kolab_notes/kolab_notes.php @@ -239,7 +239,7 @@ class kolab_notes extends rcube_plugin else if ($folder->virtual) { $lists[$list_id] = array( 'id' => $list_id, - 'name' => kolab_storage::object_name($fullname), + 'name' => $fullname, 'listname' => $listname, 'virtual' => true, 'editable' => false, @@ -1045,7 +1045,7 @@ class kolab_notes extends rcube_plugin $newfolder = kolab_storage::folder_update($list); if ($newfolder === false) { - $save_error = $this->gettext(kolab_storage::$last_error); + $save_error = $this->gettext(kolab_storage::$last_error); } else { $success = true; @@ -1056,7 +1056,7 @@ class kolab_notes extends rcube_plugin // compose the new display name $delim = $this->rc->get_storage()->get_hierarchy_delimiter(); $path_imap = explode($delim, $newfolder); - $list['name'] = kolab_storage::object_name($newfolder); + $list['name'] = kolab_storage::object_name($newfolder); $list['editname'] = rcube_charset::convert(array_pop($path_imap), 'UTF7-IMAP'); $list['listname'] = str_repeat('   ', count($path_imap)) . '» ' . $list['editname']; } diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php index 9bafbe99..a3087e9b 100644 --- a/plugins/libkolab/lib/kolab_storage.php +++ b/plugins/libkolab/lib/kolab_storage.php @@ -25,7 +25,7 @@ class kolab_storage { - const CTYPE_KEY = '/shared/vendor/kolab/folder-type'; + const CTYPE_KEY = '/shared/vendor/kolab/folder-type'; const CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type'; const COLOR_KEY_SHARED = '/shared/vendor/kolab/color'; const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color'; @@ -551,6 +551,7 @@ class kolab_storage /** * Getter for human-readable name of Kolab object (folder) + * with kolab_custom_display_names support. * See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference * * @param string $folder IMAP folder name (UTF7-IMAP) @@ -560,13 +561,43 @@ class kolab_storage */ public static function object_name($folder, &$folder_ns=null) { - self::setup(); - // find custom display name in folder METADATA if ($name = self::custom_displayname($folder)) { return $name; } + return self::object_prettyname($folder, $folder_ns); + } + + /** + * Get custom display name (saved in metadata) for the given folder + */ + public static function custom_displayname($folder) + { + // find custom display name in folder METADATA + if (self::$config->get('kolab_custom_display_names', true) && self::setup()) { + $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED)); + if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) { + return $name; + } + } + + return false; + } + + /** + * Getter for human-readable name of Kolab object (folder) + * See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference + * + * @param string $folder IMAP folder name (UTF7-IMAP) + * @param string $folder_ns Will be set to namespace name of the folder + * + * @return string Name of the folder-object + */ + public static function object_prettyname($folder, &$folder_ns=null) + { + self::setup(); + $found = false; $namespace = self::$imap->get_namespace(); @@ -634,22 +665,6 @@ class kolab_storage return $folder; } - /** - * Get custom display name (saved in metadata) for the given folder - */ - public static function custom_displayname($folder) - { - // find custom display name in folder METADATA - if (self::$config->get('kolab_custom_display_names', true)) { - $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED)); - if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) { - return $name; - } - } - - return false; - } - /** * Helper method to generate a truncated folder name to display. * Note: $origname is a string returned by self::object_name() @@ -745,7 +760,7 @@ class kolab_storage } } - $names[$name] = self::object_name($name); + $names[$name] = $folder->get_name(); } // Build SELECT field of parent folder @@ -960,7 +975,7 @@ class kolab_storage foreach ($folders as $folder) { $folders[$folder->name] = $folder; $ns = $folder->get_namespace(); - $nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode » + $nsnames[$ns][$folder->name] = strtolower(html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode » } // $folders is a result of get_folders() we can assume folders were already sorted @@ -1017,7 +1032,7 @@ class kolab_storage $refs[$parent] = new kolab_storage_folder_user($parent, $parent_parent); } else { - $name = kolab_storage::object_name($parent, $folder->get_namespace()); + $name = kolab_storage::object_name($parent); $refs[$parent] = new kolab_storage_folder_virtual($parent, $name, $folder->get_namespace(), $parent_parent); } $parents[] = $refs[$parent]; @@ -1599,5 +1614,30 @@ class kolab_storage $db = rcmail::get_instance()->get_dbh(); $prefix = 'imap://' . urlencode($args['username']) . '@' . $args['host'] . '/%'; $db->query("DELETE FROM " . $db->table_name('kolab_folders', true) . " WHERE `resource` LIKE ?", $prefix); + + } + + /** + * Get folder METADATA for all supported keys + * Do this in one go for better caching performance + */ + public static function folder_metadata($folder) + { + if (self::setup()) { + $keys = array( + self::NAME_KEY_PRIVATE, + self::NAME_KEY_SHARED, + self::CTYPE_KEY, + self::CTYPE_KEY_PRIVATE, + self::COLOR_KEY_PRIVATE, + self::COLOR_KEY_SHARED, + self::UID_KEY_SHARED, + self::UID_KEY_CYRUS, + ); + + $metadata = self::$imap->get_metadata($folder, $keys); + + return $metadata[$folder]; + } } } diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 822c4d97..44fe6956 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -64,15 +64,16 @@ class kolab_storage_folder extends kolab_storage_folder_api */ public function set_folder($name, $type = null, $type_annotation = null) { + $this->name = $name; + if (empty($type_annotation)) { - $type_annotation = kolab_storage::folder_type($name); + $type_annotation = $this->get_type(); } $oldtype = $this->type; list($this->type, $suffix) = explode('.', $type_annotation); $this->default = $suffix == 'default'; $this->subtype = $this->default ? '' : $suffix; - $this->name = $name; $this->id = kolab_storage::folder_id($name); $this->valid = !empty($this->type) && $this->type != 'mail' && (!$type || $this->type == $type); @@ -155,7 +156,7 @@ class kolab_storage_folder extends kolab_storage_folder_api { // UID is defined in folder METADATA $metakeys = array(kolab_storage::UID_KEY_SHARED, kolab_storage::UID_KEY_CYRUS); - $metadata = $this->get_metadata($metakeys); + $metadata = $this->get_metadata(); if ($metadata !== null) { foreach ($metakeys as $key) { @@ -1168,6 +1169,4 @@ class kolab_storage_folder extends kolab_storage_folder_api return true; } - } - diff --git a/plugins/libkolab/lib/kolab_storage_folder_api.php b/plugins/libkolab/lib/kolab_storage_folder_api.php index 0b9091f2..32e839cf 100644 --- a/plugins/libkolab/lib/kolab_storage_folder_api.php +++ b/plugins/libkolab/lib/kolab_storage_folder_api.php @@ -57,7 +57,7 @@ abstract class kolab_storage_folder_api * @var array */ public $children = array(); - + /** * Name of the parent folder * @var string @@ -69,6 +69,7 @@ abstract class kolab_storage_folder_api protected $info; protected $idata; protected $namespace; + protected $metadata; /** @@ -135,10 +136,10 @@ abstract class kolab_storage_folder_api { if (!isset($this->namespace)) $this->namespace = $this->imap->folder_namespace($this->name); + return $this->namespace; } - /** * Get the display name value of this folder * @@ -146,9 +147,22 @@ abstract class kolab_storage_folder_api */ public function get_name() { - return kolab_storage::object_name($this->name, $this->get_namespace()); - } + $rcmail = rcube::get_instance(); + // find custom display name in folder METADATA + if ($rcmail->config->get('kolab_custom_display_names', true)) { + $metadata = $this->get_metadata(); + + if ($name = $metadata[kolab_storage::NAME_KEY_PRIVATE]) { + return $name; + } + if ($name = $metadata[kolab_storage::NAME_KEY_SHARED]) { + return $name; + } + } + + return kolab_storage::object_prettyname($this->name); + } /** * Getter for the top-end folder name (not the entire path) @@ -221,7 +235,7 @@ abstract class kolab_storage_folder_api public function get_color($default = null) { // color is defined in folder METADATA - $metadata = $this->get_metadata(array(kolab_storage::COLOR_KEY_PRIVATE, kolab_storage::COLOR_KEY_SHARED)); + $metadata = $this->get_metadata(); if (($color = $metadata[kolab_storage::COLOR_KEY_PRIVATE]) || ($color = $metadata[kolab_storage::COLOR_KEY_SHARED])) { return $color; } @@ -229,19 +243,20 @@ abstract class kolab_storage_folder_api return $default; } - /** * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION) + * supported by kolab_storage * - * @param array List of metadata keys to read * @return array Metadata entry-value hash array on success, NULL on error */ - public function get_metadata($keys) + public function get_metadata() { - $metadata = rcube::get_instance()->get_storage()->get_metadata($this->name, (array)$keys); - return $metadata[$this->name]; - } + if ($this->metadata === null) { + $this->metadata = kolab_storage::folder_metadata($this->name); + } + return $this->metadata; + } /** * Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION) @@ -251,10 +266,10 @@ abstract class kolab_storage_folder_api */ public function set_metadata($entries) { + $this->metadata = null; return $this->imap->set_metadata($this->name, $entries); } - /** * */ @@ -277,6 +292,21 @@ abstract class kolab_storage_folder_api return $this->idata; } + /** + * Returns (full) type of IMAP folder + * + * @return string Folder type + */ + public function get_type() + { + $metadata = $this->get_metadata(); + + if (!empty($metadata)) { + return kolab_storage::folder_select_metadata($metadata); + } + + return $this->type; + } /** * Get IMAP ACL information for this folder @@ -358,4 +388,3 @@ abstract class kolab_storage_folder_api return $this->name; } } - diff --git a/plugins/libkolab/lib/kolab_storage_folder_user.php b/plugins/libkolab/lib/kolab_storage_folder_user.php index 7c141c50..0ff0bcaa 100644 --- a/plugins/libkolab/lib/kolab_storage_folder_user.php +++ b/plugins/libkolab/lib/kolab_storage_folder_user.php @@ -72,7 +72,7 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual */ public function get_title() { - return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; '); + return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; '); } /** @@ -131,5 +131,4 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual return $success; } - -} \ No newline at end of file +} diff --git a/plugins/libkolab/lib/kolab_storage_folder_virtual.php b/plugins/libkolab/lib/kolab_storage_folder_virtual.php index e419ced9..bf3ba554 100644 --- a/plugins/libkolab/lib/kolab_storage_folder_virtual.php +++ b/plugins/libkolab/lib/kolab_storage_folder_virtual.php @@ -56,4 +56,4 @@ class kolab_storage_folder_virtual extends kolab_storage_folder_api { return $default; } -} \ No newline at end of file +} diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php index e930729a..885340ed 100644 --- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php +++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php @@ -214,7 +214,7 @@ class tasklist_kolab_driver extends tasklist_driver if ($folder instanceof kolab_storage_folder_user) { $lists[$list_id] = array( 'id' => $list_id, - 'name' => $folder->get_name(), + 'name' => $fullname, 'listname' => $listname, 'title' => $folder->get_title(), 'virtual' => true, @@ -228,7 +228,7 @@ class tasklist_kolab_driver extends tasklist_driver else if ($folder->virtual) { $lists[$list_id] = array( 'id' => $list_id, - 'name' => kolab_storage::object_name($fullname), + 'name' => $fullname, 'listname' => $listname, 'virtual' => true, 'editable' => false,