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.php | 143 +++++++++++++++++++++++++++++++++++------------
1 files changed, 105 insertions(+), 38 deletions(-)
diff --git a/program/lib/Roundcube/rcube_cache.php b/program/lib/Roundcube/rcube_cache.php
index 3e1ce4f..303abda 100644
--- a/program/lib/Roundcube/rcube_cache.php
+++ b/program/lib/Roundcube/rcube_cache.php
@@ -2,8 +2,6 @@
/*
+-----------------------------------------------------------------------+
- | program/include/rcube_cache.php |
- | |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2011, The Roundcube Dev Team |
| Copyright (C) 2011, Kolab Systems AG |
@@ -14,7 +12,6 @@
| |
| PURPOSE: |
| Caching engine |
- | |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
@@ -41,12 +38,14 @@
private $type;
private $userid;
private $prefix;
+ private $table;
private $ttl;
private $packed;
private $index;
private $cache = array();
private $cache_changes = array();
private $cache_sums = array();
+ private $max_packet = -1;
/**
@@ -74,8 +73,9 @@
$this->db = function_exists('apc_exists'); // APC 3.1.4 required
}
else {
- $this->type = 'db';
- $this->db = $rcube->get_dbh();
+ $this->type = 'db';
+ $this->db = $rcube->get_dbh();
+ $this->table = $this->db->table_name('cache', true);
}
// convert ttl string to seconds
@@ -148,7 +148,7 @@
*/
function write($key, $data)
{
- return $this->write_record($key, $this->packed ? serialize($data) : $data);
+ return $this->write_record($key, $this->serialize($data));
}
@@ -195,16 +195,27 @@
*/
function expunge()
{
- if ($this->type == 'db' && $this->db) {
+ if ($this->type == 'db' && $this->db && $this->ttl) {
$this->db->query(
- "DELETE FROM ".$this->db->table_name('cache').
- " WHERE user_id = ?".
- " AND cache_key LIKE ?".
- " AND " . $this->db->unixtimestamp('created')." < ?",
+ "DELETE FROM {$this->table}".
+ " WHERE `user_id` = ?".
+ " AND `cache_key` LIKE ?".
+ " AND `expires` < " . $this->db->now(),
$this->userid,
- $this->prefix.'.%',
- time() - $this->ttl);
+ $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', true) . " WHERE `expires` < " . $db->now());
}
@@ -222,7 +233,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);
@@ -258,7 +269,7 @@
if ($data) {
$md5sum = md5($data);
- $data = $this->packed ? unserialize($data) : $data;
+ $data = $this->unserialize($data);
if ($nostore) {
return $data;
@@ -273,20 +284,19 @@
}
else {
$sql_result = $this->db->limitquery(
- "SELECT data, cache_key".
- " FROM ".$this->db->table_name('cache').
- " WHERE user_id = ?".
- " AND cache_key = ?".
+ "SELECT `data`, `cache_key`".
+ " FROM {$this->table}".
+ " WHERE `user_id` = ? AND `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->userid, $this->prefix.'.'.$key);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
$key = substr($sql_arr['cache_key'], strlen($this->prefix)+1);
$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) {
@@ -309,13 +319,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;
}
@@ -329,9 +345,8 @@
// Remove NULL rows (here we don't need to check if the record exist)
if ($data == 'N;') {
$this->db->query(
- "DELETE FROM ".$this->db->table_name('cache').
- " WHERE user_id = ?".
- " AND cache_key = ?",
+ "DELETE FROM {$this->table}".
+ " WHERE `user_id` = ? AND `cache_key` = ?",
$this->userid, $key);
return true;
@@ -340,10 +355,12 @@
// update existing cache record
if ($key_exists) {
$result = $this->db->query(
- "UPDATE ".$this->db->table_name('cache').
- " SET created = ". $this->db->now().", data = ?".
- " WHERE user_id = ?".
- " AND cache_key = ?",
+ "UPDATE {$this->table}".
+ " SET `created` = " . $this->db->now().
+ ", `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL').
+ ", `data` = ?".
+ " WHERE `user_id` = ?".
+ " AND `cache_key` = ?",
$data, $this->userid, $key);
}
// add new cache record
@@ -351,9 +368,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->db->table_name('cache').
- " (created, user_id, cache_key, data)".
- " VALUES (".$this->db->now().", ?, ?, ?)",
+ "INSERT INTO {$this->table}".
+ " (`created`, `expires`, `user_id`, `cache_key`, `data`)".
+ " VALUES (" . $this->db->now() . ", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?, ?)",
$this->userid, $key, $data);
}
@@ -367,7 +384,6 @@
* @param string $key Cache key name or pattern
* @param boolean $prefix_mode Enable it to clear all keys starting
* with prefix specified in $key
- *
*/
private function remove_record($key=null, $prefix_mode=false)
{
@@ -403,20 +419,19 @@
// Remove all keys (in specified cache)
if ($key === null) {
- $where = " AND cache_key LIKE " . $this->db->quote($this->prefix.'.%');
+ $where = " AND `cache_key` LIKE " . $this->db->quote($this->prefix.'.%');
}
// Remove keys by name prefix
else if ($prefix_mode) {
- $where = " AND cache_key LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
+ $where = " AND `cache_key` LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
}
// Remove one key by name
else {
- $where = " AND cache_key = " . $this->db->quote($this->prefix.'.'.$key);
+ $where = " AND `cache_key` = " . $this->db->quote($this->prefix.'.'.$key);
}
$this->db->query(
- "DELETE FROM ".$this->db->table_name('cache').
- " WHERE user_id = ?" . $where,
+ "DELETE FROM {$this->table} WHERE `user_id` = ?" . $where,
$this->userid);
}
@@ -556,4 +571,56 @@
// This way each cache will have its own index
return sprintf('%d:%s%s', $this->userid, $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