diff options
| author | alec <alec@208e9e7b-5314-0410-a742-e7e81cd9613c> | 2011-05-24 07:30:46 +0000 |
|---|---|---|
| committer | alec <alec@208e9e7b-5314-0410-a742-e7e81cd9613c> | 2011-05-24 07:30:46 +0000 |
| commit | 4386498aa7ae1d45dbdfd0ac659939dc0d163458 (patch) | |
| tree | 9c67f65c700924b578dfc9310c03e291dafc1847 /plugins | |
| parent | 2c0096833d314a51af6f237370e08d4d8edff0d4 (diff) | |
- Add memcache fallback, use rcube_cache objects
git-svn-id: https://svn.roundcube.net/trunk@4805 208e9e7b-5314-0410-a742-e7e81cd9613c
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/redundant_attachments/config.inc.php.dist | 13 | ||||
| -rw-r--r-- | plugins/redundant_attachments/redundant_attachments.php | 181 |
2 files changed, 135 insertions, 59 deletions
diff --git a/plugins/redundant_attachments/config.inc.php.dist b/plugins/redundant_attachments/config.inc.php.dist new file mode 100644 index 000000000..6c317ead1 --- /dev/null +++ b/plugins/redundant_attachments/config.inc.php.dist @@ -0,0 +1,13 @@ +<?php + +// By default this plugin stores attachments in filesystem +// and copies them into sql database. +// In environments with replicated database it is possible +// to use memcache as a fallback when write-master is unavailable. +$rcmail_config['redundant_attachments_memcache'] = false; + +// When memcache is used, attachment data expires after +// specied TTL time in seconds (max.2592000). Default is 12 hours. +$rcmail_config['redundant_attachments_memcache_ttl'] = 12 * 60 * 60; + +?> diff --git a/plugins/redundant_attachments/redundant_attachments.php b/plugins/redundant_attachments/redundant_attachments.php index 70976b43c..3c71dcb40 100644 --- a/plugins/redundant_attachments/redundant_attachments.php +++ b/plugins/redundant_attachments/redundant_attachments.php @@ -1,32 +1,84 @@ <?php /** * Redundant attachments - * + * * This plugin provides a redundant storage for temporary uploaded - * attachment files. They are stored in both the database backed + * attachment files. They are stored in both the database backend * as well as on the local file system. * + * It provides also memcache store as a fallback (see config file). + * * This plugin relies on the core filesystem_attachments plugin * and combines it with the functionality of the database_attachments plugin. * * @author Thomas Bruederli <roundcube@gmail.com> - * + * @author Aleksander Machniak <machniak@kolabsys.com> + * + * Copyright (C) 2011, The Roundcube Dev Team + * Copyright (C) 2011, Kolab Systems AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -require_once('plugins/filesystem_attachments/filesystem_attachments.php'); + +require_once(INSTALL_PATH . 'plugins/filesystem_attachments/filesystem_attachments.php'); class redundant_attachments extends filesystem_attachments { // A prefix for the cache key used in the session and in the key field of the cache table - private $cache_prefix = "ATTACH."; - + private $prefix = "ATTACH"; + + // rcube_cache instance for SQL DB + private $cache; + + // rcube_cache instance for memcache + private $mem_cache; + + private $loaded; + /** * Default constructor */ function init() { - parent::init(); - - $this->db = rcmail::get_instance()->get_dbh(); + parent::init(); + } + + /** + * Loads plugin configuration and initializes cache object(s) + */ + private function _load_drivers() + { + if ($this->loaded) { + return; + } + + $rcmail = rcmail::get_instance(); + + // load configuration + $this->load_config(); + + // Init SQL cache (disable cache data serialization) + $this->cache = $rcmail->get_cache($this->prefix, 'db', 0, false); + + // Init memcache (fallback) cache + if ($rcmail->config->get('redundant_attachments_memcache')) { + $ttl = 12 * 60 * 60; // 12 hours + $ttl = (int) $rcmail->config->get('redundant_attachments_memcache_ttl', $ttl); + $this->mem_cache = $rcmail->get_cache($this->prefix, 'memcache', $ttl, false); + } + + $this->loaded = true; } /** @@ -35,7 +87,7 @@ class redundant_attachments extends filesystem_attachments private function _key($args) { $uname = $args['path'] ? $args['path'] : $args['name']; - return $this->cache_prefix . $args['group'] . md5(mktime() . $uname . $_SESSION['user_id']); + return $args['group'] . md5(mktime() . $uname . $_SESSION['user_id']); } /** @@ -44,24 +96,23 @@ class redundant_attachments extends filesystem_attachments function upload($args) { $args = parent::upload($args); - - $key = $this->_key($args); + + $this->_load_drivers(); + + $key = $this->_key($args); $data = base64_encode(file_get_contents($args['path'])); - $status = $this->db->query( - "INSERT INTO ".get_table_name('cache')." - (created, user_id, cache_key, data) - VALUES (".$this->db->now().", ?, ?, ?)", - $_SESSION['user_id'], - $key, - $data); - + $status = $this->cache->write($key, $data); + + if (!$status && $this->mem_cache) { + $status = $this->mem_cache->write($key, $data); + } + if ($status) { $args['id'] = $key; $args['status'] = true; - unset($args['path']); } - + return $args; } @@ -72,19 +123,19 @@ class redundant_attachments extends filesystem_attachments { $args = parent::save($args); + $this->_load_drivers(); + if ($args['path']) $args['data'] = file_get_contents($args['path']); + $key = $this->_key($args); $data = base64_encode($args['data']); - $key = $this->_key($args); - $status = $this->db->query( - "INSERT INTO ".get_table_name('cache')." - (created, user_id, cache_key, data) - VALUES (".$this->db->now().", ?, ?, ?)", - $_SESSION['user_id'], - $key, - $data); + $status = $this->cache->write($key, $data); + + if (!$status && $this->mem_cache) { + $status = $this->mem_cache->write($key, $data); + } if ($status) { $args['id'] = $key; @@ -100,18 +151,21 @@ class redundant_attachments extends filesystem_attachments */ function remove($args) { - $args['status'] = false; - $status = $this->db->query( - "DELETE FROM ".get_table_name('cache')." - WHERE user_id=? - AND cache_key=?", - $_SESSION['user_id'], - $args['id']); + parent::remove($args); - if ($status) - $args['status'] = true; + $this->_load_drivers(); + + $status = $this->cache->remove($args['id']); - return parent::remove($args); + if (!$status && $this->mem_cache) { + $status = $this->cache->remove($args['id']); + } + + // we cannot trust the result of any of the methods above + // assume true, attachments will be removed on cleanup + $args['status'] = true; + + return $args; } /** @@ -132,38 +186,47 @@ class redundant_attachments extends filesystem_attachments { // attempt to get file from local file system $args = parent::get($args); + if ($args['path'] && ($args['status'] = file_exists($args['path']))) return $args; - + + $this->_load_drivers(); + // fetch from database if not found on FS - $sql_result = $this->db->query( - "SELECT cache_id, data - FROM ".get_table_name('cache')." - WHERE user_id=? - AND cache_key=?", - $_SESSION['user_id'], - $args['id']); + $data = $this->cache->read($args['id']); + + // fetch from memcache if not found on FS and DB + if (($data === false || $data === null) && $this->mem_cache) { + $data = $this->mem_cache->read($args['id']); + } - if ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $args['data'] = base64_decode($sql_arr['data']); + if ($data) { + $args['data'] = base64_decode($data); $args['status'] = true; } - + return $args; } - + /** * Delete all temp files associated with this user */ function cleanup($args) { - $prefix = $this->cache_prefix . $args['group']; - $this->db->query( - "DELETE FROM ".get_table_name('cache')." - WHERE user_id=? - AND cache_key like '{$prefix}%'", - $_SESSION['user_id']); - + $this->_load_drivers(); + + if ($this->cache) { + $this->cache->remove($args['group'], true); + } + + if ($this->mem_cache) { + $this->mem_cache->remove($args['group'], true); + } + parent::cleanup($args); + + $args['status'] = true; + + return $args; } } |
