From a3644638aaf0418598196a870204e0b632a4c8ad Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Fri, 17 Apr 2015 06:28:40 -0400
Subject: [PATCH] Allow preference sections to define CSS class names
---
program/lib/Roundcube/rcube_cache_shared.php | 124 ++++++++++++++++++++++++++++++++--------
1 files changed, 98 insertions(+), 26 deletions(-)
diff --git a/program/lib/Roundcube/rcube_cache_shared.php b/program/lib/Roundcube/rcube_cache_shared.php
index c43d2ca..3f0f20e 100644
--- a/program/lib/Roundcube/rcube_cache_shared.php
+++ b/program/lib/Roundcube/rcube_cache_shared.php
@@ -27,7 +27,7 @@
* @author Thomas Bruederli <roundcube@gmail.com>
* @author Aleksander Machniak <alec@alec.pl>
*/
-class rcube_cache
+class rcube_cache_shared
{
/**
* Instance of database handler
@@ -44,6 +44,7 @@
private $cache = array();
private $cache_changes = array();
private $cache_sums = array();
+ private $max_packet = -1;
/**
@@ -72,7 +73,7 @@
else {
$this->type = 'db';
$this->db = $rcube->get_dbh();
- $this->table = $this->db->table_name('cache_shared');
+ $this->table = $this->db->table_name('cache_shared', true);
}
// convert ttl string to seconds
@@ -144,7 +145,7 @@
*/
function write($key, $data)
{
- return $this->write_record($key, $this->packed ? serialize($data) : $data);
+ return $this->write_record($key, $this->serialize($data));
}
@@ -193,12 +194,23 @@
{
if ($this->type == 'db' && $this->db && $this->ttl) {
$this->db->query(
- "DELETE FROM " . $this->table
- . " WHERE cache_key LIKE ?"
- . " AND " . $this->db->unixtimestamp('created') . " < ?",
- $this->prefix . '.%',
- time() - $this->ttl);
+ "DELETE FROM {$this->table}"
+ . " WHERE `cache_key` LIKE ?"
+ . " AND `expires` < " . $this->db->now(),
+ $this->prefix . '.%');
}
+ }
+
+
+ /**
+ * Remove expired records of all caches
+ */
+ static function gc()
+ {
+ $rcube = rcube::get_instance();
+ $db = $rcube->get_dbh();
+
+ $db->query("DELETE FROM " . $db->table_name('cache_shared', true) . " WHERE `expires` < " . $db->now());
}
@@ -216,7 +228,7 @@
if ($this->cache_changes[$key]) {
// Make sure we're not going to write unchanged data
// by comparing current md5 sum with the sum calculated on DB read
- $data = $this->packed ? serialize($data) : $data;
+ $data = $this->serialize($data);
if (!$this->cache_sums[$key] || $this->cache_sums[$key] != md5($data)) {
$this->write_record($key, $data);
@@ -252,7 +264,7 @@
if ($data) {
$md5sum = md5($data);
- $data = $this->packed ? unserialize($data) : $data;
+ $data = $this->unserialize($data);
if ($nostore) {
return $data;
@@ -267,18 +279,18 @@
}
else {
$sql_result = $this->db->limitquery(
- "SELECT data, cache_key".
- " FROM " . $this->table .
- " WHERE cache_key = ?".
+ "SELECT `data`, `cache_key`".
+ " FROM {$this->table}" .
+ " WHERE `cache_key` = ?".
// for better performance we allow more records for one key
// get the newer one
- " ORDER BY created DESC",
+ " ORDER BY `created` DESC",
0, 1, $this->prefix . '.' . $key);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
$md5sum = $sql_arr['data'] ? md5($sql_arr['data']) : null;
if ($sql_arr['data']) {
- $data = $this->packed ? unserialize($sql_arr['data']) : $sql_arr['data'];
+ $data = $this->unserialize($sql_arr['data']);
}
if ($nostore) {
@@ -301,13 +313,19 @@
* Writes single cache record into DB.
*
* @param string $key Cache key name
- * @param mxied $data Serialized cache data
+ * @param mixed $data Serialized cache data
*
* @param boolean True on success, False on failure
*/
private function write_record($key, $data)
{
if (!$this->db) {
+ return false;
+ }
+
+ // don't attempt to write too big data sets
+ if (strlen($data) > $this->max_packet_size()) {
+ trigger_error("rcube_cache: max_packet_size ($this->max_packet) exceeded for key $key. Tried to write " . strlen($data) . " bytes", E_USER_WARNING);
return false;
}
@@ -320,16 +338,18 @@
// Remove NULL rows (here we don't need to check if the record exist)
if ($data == 'N;') {
- $this->db->query("DELETE FROM " . $this->table . " WHERE cache_key = ?", $key);
+ $this->db->query("DELETE FROM {$this->table} WHERE `cache_key` = ?", $key);
return true;
}
// update existing cache record
if ($key_exists) {
$result = $this->db->query(
- "UPDATE " . $this->table .
- " SET created = " . $this->db->now() . ", data = ?" .
- " WHERE cache_key = ?",
+ "UPDATE {$this->table}" .
+ " SET `created` = " . $this->db->now() .
+ ", `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') .
+ ", `data` = ?".
+ " WHERE `cache_key` = ?",
$data, $key);
}
// add new cache record
@@ -337,9 +357,9 @@
// for better performance we allow more records for one key
// so, no need to check if record exist (see rcube_cache::read_record())
$result = $this->db->query(
- "INSERT INTO ".$this->table.
- " (created, cache_key, data)".
- " VALUES (".$this->db->now().", ?, ?)",
+ "INSERT INTO {$this->table}".
+ " (`created`, `expires`, `cache_key`, `data`)".
+ " VALUES (".$this->db->now().", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?)",
$key, $data);
}
@@ -388,15 +408,15 @@
// Remove all keys (in specified cache)
if ($key === null) {
- $where = " WHERE cache_key LIKE " . $this->db->quote($this->prefix.'.%');
+ $where = " WHERE `cache_key` LIKE " . $this->db->quote($this->prefix.'.%');
}
// Remove keys by name prefix
else if ($prefix_mode) {
- $where = " WHERE cache_key LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
+ $where = " WHERE `cache_key` LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
}
// Remove one key by name
else {
- $where = " WHERE cache_key = " . $this->db->quote($this->prefix.'.'.$key);
+ $where = " WHERE `cache_key` = " . $this->db->quote($this->prefix.'.'.$key);
}
$this->db->query("DELETE FROM " . $this->table . $where);
@@ -541,4 +561,56 @@
// This way each cache will have its own index
return $this->prefix . 'INDEX';
}
+
+ /**
+ * Serializes data for storing
+ */
+ private function serialize($data)
+ {
+ if ($this->type == 'db') {
+ return $this->db->encode($data, $this->packed);
+ }
+
+ return $this->packed ? serialize($data) : $data;
+ }
+
+ /**
+ * Unserializes serialized data
+ */
+ private function unserialize($data)
+ {
+ if ($this->type == 'db') {
+ return $this->db->decode($data, $this->packed);
+ }
+
+ return $this->packed ? @unserialize($data) : $data;
+ }
+
+ /**
+ * Determine the maximum size for cache data to be written
+ */
+ private function max_packet_size()
+ {
+ if ($this->max_packet < 0) {
+ $this->max_packet = 2097152; // default/max is 2 MB
+
+ if ($this->type == 'db') {
+ if ($value = $this->db->get_variable('max_allowed_packet', $this->max_packet)) {
+ $this->max_packet = $value;
+ }
+ $this->max_packet -= 2000;
+ }
+ else if ($this->type == 'memcache') {
+ $stats = $this->db->getStats();
+ $remaining = $stats['limit_maxbytes'] - $stats['bytes'];
+ $this->max_packet = min($remaining / 5, $this->max_packet);
+ }
+ else if ($this->type == 'apc' && function_exists('apc_sma_info')) {
+ $stats = apc_sma_info();
+ $this->max_packet = min($stats['avail_mem'] / 5, $this->max_packet);
+ }
+ }
+
+ return $this->max_packet;
+ }
}
--
Gitblit v1.9.1