summaryrefslogtreecommitdiff
path: root/plugins/redundant_attachments
diff options
context:
space:
mode:
authoralec <alec@208e9e7b-5314-0410-a742-e7e81cd9613c>2011-05-24 07:30:46 +0000
committeralec <alec@208e9e7b-5314-0410-a742-e7e81cd9613c>2011-05-24 07:30:46 +0000
commit4386498aa7ae1d45dbdfd0ac659939dc0d163458 (patch)
tree9c67f65c700924b578dfc9310c03e291dafc1847 /plugins/redundant_attachments
parent2c0096833d314a51af6f237370e08d4d8edff0d4 (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/redundant_attachments')
-rw-r--r--plugins/redundant_attachments/config.inc.php.dist13
-rw-r--r--plugins/redundant_attachments/redundant_attachments.php181
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;
}
}