diff --git a/common.php b/common.php index 9b904ccaa..de3f7a09e 100644 --- a/common.php +++ b/common.php @@ -48,61 +48,10 @@ define('TOR_TYPE_SILVER', 2); define('GUEST_UID', -1); define('BOT_UID', -746); -// DBS -class DBS -{ - var $cfg = array(); // $srv_name => $srv_cfg - var $srv = array(); // $srv_name => $db_obj - var $alias = array(); // $srv_alias => $srv_name - - var $log_file = 'sql_queries'; - var $log_counter = 0; - var $num_queries = 0; - var $sql_inittime = 0; - var $sql_timetotal = 0; - - function DBS ($cfg) - { - $this->cfg = $cfg['db']; - $this->alias = $cfg['db_alias']; - - foreach ($this->cfg as $srv_name => $srv_cfg) - { - $this->srv[$srv_name] = null; - } - } - - // получение/инициализация класса для сервера $srv_name - function get_db_obj ($srv_name_or_alias = 'db1') - { - $srv_name = $this->get_srv_name($srv_name_or_alias); - - if (!is_object($this->srv[$srv_name])) - { - $this->srv[$srv_name] = new sql_db($this->cfg[$srv_name]); - $this->srv[$srv_name]->db_server = $srv_name; - } - return $this->srv[$srv_name]; - } - - // определение имени сервера - function get_srv_name ($name) - { - if (isset($this->alias[$name])) - { - $srv_name = $this->alias[$name]; - } - else if (isset($this->cfg[$name])) - { - $srv_name = $name; - } - else - { - $srv_name = 'db1'; - } - return $srv_name; - } -} +/** + * Database + */ +require(CORE_DIR . 'dbs.php'); $DBS = new DBS($bb_cfg); @@ -112,12 +61,13 @@ function DB ($db_alias = 'db1') return $DBS->get_db_obj($db_alias); } -// Cache +/** + * Cache + */ define('PEER_HASH_PREFIX', 'peer_'); define('PEERS_LIST_PREFIX', 'peers_list_'); - -define('PEER_HASH_EXPIRE', round($bb_cfg['announce_interval'] * (0.85*$tr_cfg['expire_factor']))); // sec -define('PEERS_LIST_EXPIRE', round($bb_cfg['announce_interval'] * 0.7)); // sec +define('PEER_HASH_EXPIRE', round($bb_cfg['announce_interval'] * (0.85 * $tr_cfg['expire_factor']))); // sec +define('PEERS_LIST_EXPIRE', round($bb_cfg['announce_interval'] * 0.7)); // sec if (!function_exists('sqlite_escape_string')) { @@ -127,120 +77,7 @@ if (!function_exists('sqlite_escape_string')) } } -class CACHES -{ - var $cfg = array(); // конфиг - var $obj = array(); // кеш-объекты - var $ref = array(); // ссылки на $obj (имя_кеша => кеш_объект) - - function CACHES ($cfg) - { - $this->cfg = $cfg['cache']; - $this->obj['__stub'] = new cache_common(); - } - - function get_cache_obj ($cache_name) - { - if (!isset($this->ref[$cache_name])) - { - if (!$engine_cfg =& $this->cfg['engines'][$cache_name]) - { - $this->ref[$cache_name] =& $this->obj['__stub']; - } - else - { - $cache_type =& $engine_cfg[0]; - $cache_cfg =& $engine_cfg[1]; - - switch ($cache_type) - { - case 'memcache': - if (!isset($this->obj[$cache_name])) - { - $this->obj[$cache_name] = new cache_memcache($this->cfg['memcache'], $this->cfg['prefix']); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - - case 'sqlite': - if (!isset($this->obj[$cache_name])) - { - $cache_cfg['pconnect'] = $this->cfg['pconnect']; - $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db'); - - $this->obj[$cache_name] = new cache_sqlite($cache_cfg, $this->cfg['prefix']); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - - case 'db_sqlite': - if (!isset($this->obj[$cache_name])) - { - $cache_cfg['pconnect'] = $this->cfg['pconnect']; - $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db'); - $cache_cfg['table_name'] = $cache_name; - $cache_cfg['table_schema'] = $this->get_table_schema($cache_cfg); - - $this->obj[$cache_name] = new sqlite_common($cache_cfg); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - - case 'redis': - if (!isset($this->obj[$cache_name])) - { - $this->obj[$cache_name] = new cache_redis($this->cfg['redis'], $this->cfg['prefix']); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - - case 'apc': - if (!isset($this->obj[$cache_name])) - { - $this->obj[$cache_name] = new cache_apc($this->cfg['prefix']); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - - case 'xcache': - if (!isset($this->obj[$cache_name])) - { - $this->obj[$cache_name] = new cache_xcache($this->cfg['prefix']); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - - default: //filecache - if (!isset($this->obj[$cache_name])) - { - $this->obj[$cache_name] = new cache_file($this->cfg['db_dir'] . $cache_name .'/', $this->cfg['prefix']); - } - $this->ref[$cache_name] =& $this->obj[$cache_name]; - break; - } - } - } - - return $this->ref[$cache_name]; - } - - function get_db_path ($name, $cfg, $ext) - { - if (!empty($cfg['shard_type']) && $cfg['shard_type'] != 'none') - { - return $this->cfg['db_dir'] . $name .'_*'. $ext; - } - else - { - return $this->cfg['db_dir'] . $name . $ext; - } - } - - function get_table_schema ($cfg) - { - return "CREATE TABLE {$cfg['table_name']} ( {$cfg['columns']} )"; - } -} +require(CORE_DIR . 'caches.php'); $CACHES = new CACHES($bb_cfg); @@ -250,1488 +87,31 @@ function CACHE ($cache_name) return $CACHES->get_cache_obj($cache_name); } -class cache_common -{ - var $used = false; - /** - * Returns value of variable - */ - function get ($name, $get_miss_key_callback = '', $ttl = 604800) - { - if ($get_miss_key_callback) return $get_miss_key_callback($name); - return is_array($name) ? array() : false; - } - /** - * Store value of variable - */ - function set ($name, $value, $ttl = 604800) - { - return false; - } - /** - * Remove variable - */ - function rm ($name = '') - { - return false; - } - - var $num_queries = 0; - var $sql_starttime = 0; - var $sql_inittime = 0; - var $sql_timetotal = 0; - var $cur_query_time = 0; - - var $dbg = array(); - var $dbg_id = 0; - var $dbg_enabled = false; - var $cur_query = null; - - function debug ($mode, $cur_query = null) - { - if (!$this->dbg_enabled) return; - - $id =& $this->dbg_id; - $dbg =& $this->dbg[$id]; - - if ($mode == 'start') - { - $this->sql_starttime = utime(); - - $dbg['sql'] = isset($cur_query) ? short_query($cur_query) : short_query($this->cur_query); - $dbg['src'] = $this->debug_find_source(); - $dbg['file'] = $this->debug_find_source('file'); - $dbg['line'] = $this->debug_find_source('line'); - $dbg['time'] = ''; - } - else if ($mode == 'stop') - { - $this->cur_query_time = utime() - $this->sql_starttime; - $this->sql_timetotal += $this->cur_query_time; - $dbg['time'] = $this->cur_query_time; - $id++; - } - } - - function debug_find_source ($mode = '') - { - foreach (debug_backtrace() as $trace) - { - if ($trace['file'] !== __FILE__) - { - switch ($mode) - { - case 'file': return $trace['file']; - case 'line': return $trace['line']; - default: return hide_bb_path($trace['file']) .'('. $trace['line'] .')'; - } - } - } - return 'src not found'; - } -} - -class cache_memcache extends cache_common -{ - var $used = true; - var $engine = 'Memcache'; - var $cfg = null; - var $prefix = null; - var $memcache = null; - var $connected = false; - - function cache_memcache ($cfg, $prefix = null) - { - if (!$this->is_installed()) - { - die('Error: Memcached extension not installed'); - } - - $this->cfg = $cfg; - $this->prefix = $prefix; - $this->memcache = new Memcache; - $this->dbg_enabled = sql_dbg_enabled(); - } - - function connect () - { - $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; - - $this->cur_query = $connect_type .' '. $this->cfg['host'] .':'. $this->cfg['port']; - $this->debug('start'); - - if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) - { - $this->connected = true; - } - - if (DBG_LOG) dbg_log(' ', 'CACHE-connect'. ($this->connected ? '' : '-FAIL')); - - if (!$this->connected && $this->cfg['con_required']) - { - die('Could not connect to memcached server'); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - function get ($name, $get_miss_key_callback = '', $ttl = 0) - { - if (!$this->connected) $this->connect(); - - $this->cur_query = "cache->get('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->memcache->get($this->prefix . $name) : false; - } - - function set ($name, $value, $ttl = 0) - { - if (!$this->connected) $this->connect(); - - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->memcache->set($this->prefix . $name, $value, false, $ttl) : false; - } - - function rm ($name = '') - { - if (!$this->connected) $this->connect(); - - if ($name) - { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->memcache->delete($this->prefix . $name, 0) : false; - } - else - { - return ($this->connected) ? $this->memcache->flush() : false; - } - } - - function is_installed () - { - return class_exists('Memcache'); - } -} - -class cache_sqlite extends cache_common -{ - var $used = true; - var $db = null; - var $prefix = null; - var $cfg = array( - 'db_file_path' => '/path/to/cache.db.sqlite', - 'table_name' => 'cache', - 'table_schema' => 'CREATE TABLE cache ( - cache_name VARCHAR(255), - cache_expire_time INT, - cache_value TEXT, - PRIMARY KEY (cache_name) - )', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'CACHE', - ); - - function cache_sqlite ($cfg, $prefix = null) - { - $this->cfg = array_merge($this->cfg, $cfg); - $this->db = new sqlite_common($this->cfg); - $this->prefix = $prefix; - } - - function get ($name, $get_miss_key_callback = '', $ttl = 604800) - { - if (empty($name)) - { - return is_array($name) ? array() : false; - } - $this->db->shard($name); - $cached_items = array(); - $this->prefix_len = strlen($this->prefix); - $this->prefix_sql = sqlite_escape_string($this->prefix); - - $name_ary = $name_sql = (array) $name; - array_deep($name_sql, 'sqlite_escape_string'); - - // get available items - $rowset = $this->db->fetch_rowset(" - SELECT cache_name, cache_value - FROM ". $this->cfg['table_name'] ." - WHERE cache_name IN('$this->prefix_sql". join("','$this->prefix_sql", $name_sql) ."') AND cache_expire_time > ". TIMENOW ." - LIMIT ". count($name) ." - "); - - $this->db->debug('start', 'unserialize()'); - foreach ($rowset as $row) - { - $cached_items[substr($row['cache_name'], $this->prefix_len)] = unserialize($row['cache_value']); - } - $this->db->debug('stop'); - - // get miss items - if ($get_miss_key_callback AND $miss_key = array_diff($name_ary, array_keys($cached_items))) - { - foreach ($get_miss_key_callback($miss_key) as $k => $v) - { - $this->set($this->prefix . $k, $v, $ttl); - $cached_items[$k] = $v; - } - } - // return - if (is_array($this->prefix . $name)) - { - return $cached_items; - } - else - { - return isset($cached_items[$name]) ? $cached_items[$name] : false; - } - } - - function set ($name, $value, $ttl = 604800) - { - $this->db->shard($this->prefix . $name); - $name_sql = sqlite_escape_string($this->prefix . $name); - $expire = TIMENOW + $ttl; - $value_sql = sqlite_escape_string(serialize($value)); - - $result = $this->db->query("REPLACE INTO ". $this->cfg['table_name'] ." (cache_name, cache_expire_time, cache_value) VALUES ('$name_sql', $expire, '$value_sql')"); - return (bool) $result; - } - - function rm ($name = '') - { - if ($name) - { - $this->db->shard($this->prefix . $name); - $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($this->prefix . $name) ."'"); - } - else - { - $result = $this->db->query("DELETE FROM ". $this->cfg['table_name']); - } - return (bool) $result; - } - - function gc ($expire_time = TIMENOW) - { - $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time"); - return ($result) ? $this->db->changes() : 0; - } -} - -class sqlite_common extends cache_common -{ - var $cfg = array( - 'db_file_path' => 'sqlite.db', - 'table_name' => 'table_name', - 'table_schema' => 'CREATE TABLE table_name (...)', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'SQLite', - 'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга) - 'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления) - ); - var $engine = 'SQLite'; - var $dbh = null; - var $connected = false; - var $shard_val = false; - - var $table_create_attempts = 0; - - function sqlite_common ($cfg) - { - $this->cfg = array_merge($this->cfg, $cfg); - $this->dbg_enabled = sql_dbg_enabled(); - } - - function connect () - { - $this->cur_query = ($this->dbg_enabled) ? 'connect to: '. $this->cfg['db_file_path'] : 'connect'; - $this->debug('start'); - - if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) - { - $this->connected = true; - } - - if (DBG_LOG) dbg_log(' ', $this->cfg['log_name'] .'-connect'. ($this->connected ? '' : '-FAIL')); - - if (!$this->connected && $this->cfg['con_required']) - { - trigger_error('SQLite not connected', E_USER_ERROR); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - function create_table () - { - $this->table_create_attempts++; - return $this->dbh->query($this->cfg['table_schema']); - } - - function shard ($name) - { - $type = $this->cfg['shard_type']; - - if ($type == 'none') return; - if (is_array($name)) trigger_error('cannot shard: $name is array', E_USER_ERROR); - - // define shard_val - if ($type == 'string') - { - $shard_val = substr($name, 0, $this->cfg['shard_val']); - } - else - { - $shard_val = $name % $this->cfg['shard_val']; - } - // все запросы должны быть к одному и тому же шарду - if ($this->shard_val !== false) - { - if ($shard_val != $this->shard_val) - { - trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR); - } - else - { - return; - } - } - $this->shard_val = $shard_val; - $this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']); - } - - function query ($query) - { - if (!$this->connected) $this->connect(); - - $this->cur_query = $query; - $this->debug('start'); - - if (!$result = @$this->dbh->query($query)) - { - $rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})"); - $rowscount = 0; - while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) - { - $rowscount++; - } - if (!$this->table_create_attempts && !$rowscount) - { - if ($this->create_table()) - { - $result = $this->dbh->query($query); - } - } - if (!$result) - { - $this->trigger_error($this->get_error_msg()); - } - } - - $this->debug('stop'); - $this->cur_query = null; - - $this->num_queries++; - - return $result; - } - - function fetch_row ($query) - { - $result = $this->query($query); - return is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false; - } - - function fetch_rowset ($query) - { - $result = $this->query($query); - $rowset = array(); - while ($row = $result->fetchArray(SQLITE3_ASSOC)) - { - $rowset[] = $row; - } - return $rowset; - } - - function changes () - { - return is_resource($this->dbh) ? $this->dbh->changes() : 0; - } - - function escape ($str) - { - return sqlite_escape_string($str); - } - - function get_error_msg () - { - return 'SQLite error #'. ($err_code = $this->dbh->lastErrorCode()) .': '. $this->dbh->lastErrorMsg(); - } - - function rm ($name = '') - { - if ($name) - { - $this->db->shard($this->prefix . $name); - $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($this->prefix . $name) ."'"); - } - else - { - $result = $this->db->query("DELETE FROM ". $this->cfg['table_name']); - } - return (bool) $result; - } - - function gc ($expire_time = TIMENOW) - { - $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time"); - return ($result) ? sqlite_changes($this->db->dbh) : 0; - } - - function trigger_error ($msg = 'DB Error') - { - if (error_reporting()) trigger_error($msg, E_USER_ERROR); - } -} - -class cache_redis extends cache_common -{ - var $used = true; - var $engine = 'Redis'; - var $cfg = null; - var $redis = null; - var $prefix = null; - var $connected = false; - - function cache_redis ($cfg, $prefix = null) - { - if (!$this->is_installed()) - { - die('Error: Redis extension not installed'); - } - - $this->cfg = $cfg; - $this->prefix = $prefix; - $this->redis = new Redis(); - $this->dbg_enabled = sql_dbg_enabled(); - } - - function connect () - { - $this->cur_query = 'connect '. $this->cfg['host'] .':'. $this->cfg['port']; - $this->debug('start'); - - if (@$this->redis->connect($this->cfg['host'], $this->cfg['port'])) - { - $this->connected = true; - } - - if (!$this->connected && $this->cfg['con_required']) - { - die('Could not connect to redis server'); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - function get ($name, $get_miss_key_callback = '', $ttl = 0) - { - if (!$this->connected) $this->connect(); - - $this->cur_query = "cache->get('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? unserialize($this->redis->get($this->prefix . $name)) : false; - } - - function set ($name, $value, $ttl = 0) - { - if (!$this->connected) $this->connect(); - - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - - if ($this->redis->set($this->prefix . $name, serialize($value))) - { - if ($ttl > 0) - { - $this->redis->expire($this->prefix . $name, $ttl); - } - - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return true; - } - else - { - return false; - } - } - - function rm ($name = '') - { - if (!$this->connected) $this->connect(); - - if ($name) - { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->redis->del($this->prefix . $name) : false; - } - else - { - return ($this->connected) ? $this->redis->flushdb() : false; - } - } - - function is_installed () - { - return class_exists('Redis'); - } -} - -class cache_apc extends cache_common -{ - var $used = true; - var $engine = 'APC'; - var $prefix = null; - - function cache_apc ($prefix = null) - { - if (!$this->is_installed()) - { - die('Error: APC extension not installed'); - } - $this->dbg_enabled = sql_dbg_enabled(); - $this->prefix = $prefix; - } - - function get ($name, $get_miss_key_callback = '', $ttl = 0) - { - $this->cur_query = "cache->get('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return apc_fetch($this->prefix . $name); - } - - function set ($name, $value, $ttl = 0) - { - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return apc_store($this->prefix . $name, $value, $ttl); - } - - function rm ($name = '') - { - if ($name) - { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return apc_delete($this->prefix . $name); - } - else - { - return apc_clear_cache(); - } - } - - function is_installed () - { - return function_exists('apc_fetch'); - } -} - -class cache_xcache extends cache_common -{ - var $used = true; - var $engine = 'XCache'; - var $prefix = null; - - function cache_xcache ($prefix = null) - { - if (!$this->is_installed()) - { - die('Error: XCache extension not installed'); - } - $this->dbg_enabled = sql_dbg_enabled(); - $this->prefix = $prefix; - } - - function get ($name, $get_miss_key_callback = '', $ttl = 0) - { - $this->cur_query = "cache->get('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return xcache_get($this->prefix . $name); - } - - function set ($name, $value, $ttl = 0) - { - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return xcache_set($this->prefix . $name, $value, $ttl); - } - - function rm ($name = '') - { - if ($name) - { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return xcache_unset($this->prefix . $name); - } - else - { - xcache_clear_cache(XC_TYPE_PHP, 0); - xcache_clear_cache(XC_TYPE_VAR, 0); - return; - } - } - - function is_installed () - { - return function_exists('xcache_get'); - } -} - -class cache_file extends cache_common -{ - var $used = true; - var $engine = 'Filecache'; - var $dir = null; - var $prefix = null; - - function cache_file ($dir, $prefix = null) - { - $this->dir = $dir; - $this->prefix = $prefix; - $this->dbg_enabled = sql_dbg_enabled(); - } - - function get ($name, $get_miss_key_callback = '', $ttl = 0) - { - $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; - - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - - if (file_exists($filename)) - { - require($filename); - } - - $this->debug('stop'); - $this->cur_query = null; - - return (!empty($filecache['value'])) ? $filecache['value'] : false; - } - - function set ($name, $value, $ttl = 86400) - { - if (!function_exists('var_export')) - { - return false; - } - - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - - $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; - $expire = TIMENOW + $ttl; - $cache_data = array( - 'expire' => $expire, - 'value' => $value, - ); - - $filecache = "'; - - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool) file_write($filecache, $filename, false, true, true); - } - - function rm ($name = '') - { - $clear = false; - if ($name) - { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - - $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; - if (file_exists($filename)) - { - $clear = (bool) unlink($filename); - } - - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - } - else - { - if (is_dir($this->dir)) - { - if ($dh = opendir($this->dir)) - { - while (($file = readdir($dh)) !== false) - { - if ($file != "." && $file != "..") - { - $filename = $this->dir . $file; - - unlink($filename); - $clear = true; - } - } - closedir($dh); - } - } - } - return $clear; - } - - function gc ($expire_time = TIMENOW) - { - $clear = false; - - if (is_dir($this->dir)) - { - if ($dh = opendir($this->dir)) - { - while (($file = readdir($dh)) !== false) - { - if ($file != "." && $file != "..") - { - $filename = $this->dir . $file; - - require($filename); - - if(!empty($filecache['expire']) && ($filecache['expire'] < $expire_time)) - { - unlink($filename); - $clear = true; - } - } - } - closedir($dh); - } - } - - return $clear; - } -} +// Main cache class +require(INC_DIR . 'cache/common.php'); + +// Common cache classes +require(INC_DIR . 'cache/memcache.php'); +require(INC_DIR . 'cache/sqlite.php'); +require(INC_DIR . 'cache/sqlite_common.php'); +require(INC_DIR . 'cache/redis.php'); +require(INC_DIR . 'cache/apc.php'); +require(INC_DIR . 'cache/xcache.php'); +require(INC_DIR . 'cache/file.php'); /** * Datastore */ -class datastore_common -{ - /** - * Директория с builder-скриптами (внутри INC_DIR) - */ - var $ds_dir = 'datastore/'; - /** - * Готовая к употреблению data - * array('title' => data) - */ - var $data = array(); - /** - * Список элементов, которые будут извлечены из хранилища при первом же запросе get() - * до этого момента они ставятся в очередь $queued_items для дальнейшего извлечения _fetch()'ем - * всех элементов одним запросом - * array('title1', 'title2'...) - */ - var $queued_items = array(); - - /** - * 'title' => 'builder script name' inside "includes/datastore" dir - */ - var $known_items = array( - 'cat_forums' => 'build_cat_forums.php', - 'jumpbox' => 'build_cat_forums.php', - 'viewtopic_forum_select' => 'build_cat_forums.php', - 'latest_news' => 'build_cat_forums.php', - 'network_news' => 'build_cat_forums.php', - 'ads' => 'build_cat_forums.php', - 'moderators' => 'build_moderators.php', - 'stats' => 'build_stats.php', - 'ranks' => 'build_ranks.php', - 'attach_extensions' => 'build_attach_extensions.php', - 'smile_replacements' => 'build_smilies.php', - ); - - /** - * Constructor - */ - function datastore_common () {} - - /** - * @param array(item1_title, item2_title...) or single item's title - */ - function enqueue ($items) - { - foreach ((array) $items as $item) - { - // игнор уже поставленного в очередь либо уже извлеченного - if (!in_array($item, $this->queued_items) && !isset($this->data[$item])) - { - $this->queued_items[] = $item; - } - } - } - - function &get ($title) - { - if (!isset($this->data[$title])) - { - $this->enqueue($title); - $this->_fetch(); - } - return $this->data[$title]; - } - - function store ($item_name, $item_data) {} - - function rm ($items) - { - foreach ((array) $items as $item) - { - unset($this->data[$item]); - } - } - - function update ($items) - { - if ($items == 'all') - { - $items = array_keys(array_unique($this->known_items)); - } - foreach ((array) $items as $item) - { - $this->_build_item($item); - } - } - - function _fetch () - { - $this->_fetch_from_store(); - - foreach ($this->queued_items as $title) - { - if (!isset($this->data[$title]) || $this->data[$title] === false) - { - $this->_build_item($title); - } - } - - $this->queued_items = array(); - } - - function _fetch_from_store () {} - - function _build_item ($title) - { - if (!empty($this->known_items[$title])) - { - require(INC_DIR . $this->ds_dir . $this->known_items[$title]); - } - else - { - trigger_error("Unknown datastore item: $title", E_USER_ERROR); - } - } - - var $num_queries = 0; - var $sql_starttime = 0; - var $sql_inittime = 0; - var $sql_timetotal = 0; - var $cur_query_time = 0; - - var $dbg = array(); - var $dbg_id = 0; - var $dbg_enabled = false; - var $cur_query = null; - - function debug ($mode, $cur_query = null) - { - if (!$this->dbg_enabled) return; - - $id =& $this->dbg_id; - $dbg =& $this->dbg[$id]; - - if ($mode == 'start') - { - $this->sql_starttime = utime(); - - $dbg['sql'] = isset($cur_query) ? short_query($cur_query) : short_query($this->cur_query); - $dbg['src'] = $this->debug_find_source(); - $dbg['file'] = $this->debug_find_source('file'); - $dbg['line'] = $this->debug_find_source('line'); - $dbg['time'] = ''; - } - else if ($mode == 'stop') - { - $this->cur_query_time = utime() - $this->sql_starttime; - $this->sql_timetotal += $this->cur_query_time; - $dbg['time'] = $this->cur_query_time; - $id++; - } - } - - function debug_find_source ($mode = '') - { - foreach (debug_backtrace() as $trace) - { - if ($trace['file'] !== __FILE__) - { - switch ($mode) - { - case 'file': return $trace['file']; - case 'line': return $trace['line']; - default: return hide_bb_path($trace['file']) .'('. $trace['line'] .')'; - } - } - } - return 'src not found'; - } -} - -class datastore_memcache extends datastore_common -{ - var $cfg = null; - var $memcache = null; - var $connected = false; - var $engine = 'Memcache'; - var $prefix = null; - - function datastore_memcache ($cfg, $prefix = null) - { - if (!$this->is_installed()) - { - die('Error: Memcached extension not installed'); - } - - $this->cfg = $cfg; - $this->prefix = $prefix; - $this->memcache = new Memcache; - $this->dbg_enabled = sql_dbg_enabled(); - } - - function connect () - { - $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; - - $this->cur_query = $connect_type .' '. $this->cfg['host'] .':'. $this->cfg['port']; - $this->debug('start'); - - if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) - { - $this->connected = true; - } - - if (DBG_LOG) dbg_log(' ', 'CACHE-connect'. ($this->connected ? '' : '-FAIL')); - - if (!$this->connected && $this->cfg['con_required']) - { - die('Could not connect to memcached server'); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - function store ($title, $var) - { - if (!$this->connected) $this->connect(); - $this->data[$title] = $var; - - $this->cur_query = "cache->set('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool) $this->memcache->set($this->prefix . $title, $var); - } - - function clean () - { - if (!$this->connected) $this->connect(); - foreach ($this->known_items as $title => $script_name) - { - $this->cur_query = "cache->rm('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->memcache->delete($this->prefix . $title, 0); - } - } - - function _fetch_from_store () - { - if (!$items = $this->queued_items) - { - $src = $this->_debug_find_caller('enqueue'); - trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); - } - - if (!$this->connected) $this->connect(); - foreach ($items as $item) - { - $this->cur_query = "cache->get('$item')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->data[$item] = $this->memcache->get($this->prefix . $item); - } - } - - function is_installed () - { - return class_exists('Memcache'); - } -} - -class datastore_sqlite extends datastore_common -{ - var $engine = 'SQLite'; - var $db = null; - var $prefix = null; - var $cfg = array( - 'db_file_path' => '/path/to/datastore.db.sqlite', - 'table_name' => 'datastore', - 'table_schema' => 'CREATE TABLE datastore ( - ds_title VARCHAR(255), - ds_data TEXT, - PRIMARY KEY (ds_title) - )', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'DATASTORE', - ); - - function datastore_sqlite ($cfg, $prefix = null) - { - $this->cfg = array_merge($this->cfg, $cfg); - $this->db = new sqlite_common($this->cfg); - $this->prefix = $prefix; - } - - function store ($item_name, $item_data) - { - $this->data[$item_name] = $item_data; - - $ds_title = sqlite_escape_string($this->prefix . $item_name); - $ds_data = sqlite_escape_string(serialize($item_data)); - - $result = $this->db->query("REPLACE INTO ". $this->cfg['table_name'] ." (ds_title, ds_data) VALUES ('$ds_title', '$ds_data')"); - - return (bool) $result; - } - - function clean () - { - $this->db->query("DELETE FROM ". $this->cfg['table_name']); - } - - function _fetch_from_store () - { - if (!$items = $this->queued_items) return; - - $prefix_len = strlen($this->prefix); - $prefix_sql = sqlite_escape_string($this->prefix); - - array_deep($items, 'sqlite_escape_string'); - $items_list = $prefix_sql . join("','$prefix_sql", $items); - - $rowset = $this->db->fetch_rowset("SELECT ds_title, ds_data FROM ". $this->cfg['table_name'] ." WHERE ds_title IN ('$items_list')"); - - $this->db->debug('start', "unserialize()"); - foreach ($rowset as $row) - { - $this->data[substr($row['ds_title'], $prefix_len)] = unserialize($row['ds_data']); - } - $this->db->debug('stop'); - } -} - -class datastore_redis extends datastore_common -{ - var $cfg = null; - var $redis = null; - var $prefix = null; - var $connected = false; - var $engine = 'Redis'; - - function datastore_redis ($cfg, $prefix = null) - { - if (!$this->is_installed()) - { - die('Error: Redis extension not installed'); - } - - $this->cfg = $cfg; - $this->redis = new Redis(); - $this->dbg_enabled = sql_dbg_enabled(); - $this->prefix = $prefix; - } - - function connect () - { - $this->cur_query = 'connect '. $this->cfg['host'] .':'. $this->cfg['port']; - $this->debug('start'); - - if (@$this->redis->connect($this->cfg['host'],$this->cfg['port'])) - { - $this->connected = true; - } - - if (!$this->connected && $this->cfg['con_required']) - { - die('Could not connect to redis server'); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - function store ($title, $var) - { - if (!$this->connected) $this->connect(); - $this->data[$title] = $var; - - $this->cur_query = "cache->set('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool) $this->redis->set($this->prefix . $title, serialize($var)); - } - - function clean () - { - if (!$this->connected) $this->connect(); - foreach ($this->known_items as $title => $script_name) - { - $this->cur_query = "cache->rm('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->redis->del($this->prefix . $title); - } - } - - function _fetch_from_store () - { - if (!$items = $this->queued_items) - { - $src = $this->_debug_find_caller('enqueue'); - trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); - } - - if (!$this->connected) $this->connect(); - foreach ($items as $item) - { - $this->cur_query = "cache->get('$item')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->data[$item] = unserialize($this->redis->get($this->prefix . $item)); - } - } - - function is_installed () - { - return class_exists('Redis'); - } -} - -class datastore_xcache extends datastore_common -{ - var $prefix = null; - var $engine = 'XCache'; - - function datastore_xcache ($prefix = null) - { - if (!$this->is_installed()) - { - die('Error: XCache extension not installed'); - } - - $this->dbg_enabled = sql_dbg_enabled(); - $this->prefix = $prefix; - } - - function store ($title, $var) - { - $this->data[$title] = $var; - - $this->cur_query = "cache->set('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool) xcache_set($this->prefix . $title, $var); - } - - function clean () - { - foreach ($this->known_items as $title => $script_name) - { - $this->cur_query = "cache->rm('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - xcache_unset($this->prefix . $title); - } - } - - function _fetch_from_store () - { - if (!$items = $this->queued_items) - { - $src = $this->_debug_find_caller('enqueue'); - trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); - } - - foreach ($items as $item) - { - $this->cur_query = "cache->set('$item')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->data[$item] = xcache_get($this->prefix . $item); - } - } - - function is_installed () - { - return function_exists('xcache_get'); - } -} - -class datastore_apc extends datastore_common -{ - var $engine = 'APC'; - var $prefix = null; - - function datastore_apc ($prefix = null) - { - if (!$this->is_installed()) - { - die('Error: APC extension not installed'); - } - $this->dbg_enabled = sql_dbg_enabled(); - $this->prefix = $prefix; - } - - function store ($title, $var) - { - $this->data[$title] = $var; - - $this->cur_query = "cache->set('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool) apc_store($this->prefix . $title, $var); - } - - function clean () - { - foreach ($this->known_items as $title => $script_name) - { - $this->cur_query = "cache->rm('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - apc_delete($this->prefix . $title); - } - } - - function _fetch_from_store () - { - if (!$items = $this->queued_items) - { - $src = $this->_debug_find_caller('enqueue'); - trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); - } - - foreach ($items as $item) - { - $this->cur_query = "cache->get('$item')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->data[$item] = apc_fetch($this->prefix . $item); - } - } - - function is_installed () - { - return function_exists('apc_fetch'); - } -} - -class datastore_file extends datastore_common -{ - var $dir = null; - var $prefix = null; - var $engine = 'Filecache'; - - function datastore_file ($dir, $prefix = null) - { - $this->prefix = $prefix; - $this->dir = $dir; - $this->dbg_enabled = sql_dbg_enabled(); - } - - function store ($title, $var) - { - $this->cur_query = "cache->set('$title')"; - $this->debug('start'); - - $this->data[$title] = $var; - - $filename = $this->dir . clean_filename($this->prefix . $title) . '.php'; - - $filecache = "'; - - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool) file_write($filecache, $filename, false, true, true); - } - - function clean () - { - $dir = $this->dir; - - if (is_dir($dir)) - { - if ($dh = opendir($dir)) - { - while (($file = readdir($dh)) !== false) - { - if ($file != "." && $file != "..") - { - $filename = $dir . $file; - - unlink($filename); - } - } - closedir($dh); - } - } - } - - function _fetch_from_store () - { - if (!$items = $this->queued_items) - { - $src = $this->_debug_find_caller('enqueue'); - trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); - } - - foreach($items as $item) - { - $filename = $this->dir . $this->prefix . $item . '.php'; - - $this->cur_query = "cache->get('$item')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - if(file_exists($filename)) - { - require($filename); - - $this->data[$item] = $filecache; - } - } - } -} +// Main datastore class +require(INC_DIR . 'datastore/common.php'); + +// Common datastore classes +require(INC_DIR . 'datastore/memcache.php'); +require(INC_DIR . 'datastore/sqlite.php'); +require(INC_DIR . 'datastore/redis.php'); +require(INC_DIR . 'datastore/xcache.php'); +require(INC_DIR . 'datastore/apc.php'); +require(INC_DIR . 'datastore/file.php'); // Initialize Datastore switch ($bb_cfg['datastore_type']) diff --git a/library/config.php b/library/config.php index 5b9883fd7..7bb896f88 100644 --- a/library/config.php +++ b/library/config.php @@ -262,6 +262,7 @@ define('ATTACH_DIR', BB_PATH .'/library/attach_mod/' ); define('CFG_DIR', BB_PATH .'/library/config/' ); define('INC_DIR', BB_PATH .'/library/includes/' ); define('CLASS_DIR', BB_PATH .'/library/includes/classes/'); +define('CORE_DIR', BB_PATH .'/library/includes/core/' ); define('UCP_DIR', BB_PATH .'/library/includes/ucp/' ); define('LANG_ROOT_DIR', BB_PATH .'/library/language/' ); define('IMAGES_DIR', BB_PATH .'/styles/images/' ); diff --git a/library/includes/cache/apc.php b/library/includes/cache/apc.php new file mode 100644 index 000000000..472d79edb --- /dev/null +++ b/library/includes/cache/apc.php @@ -0,0 +1,65 @@ +is_installed()) + { + die('Error: APC extension not installed'); + } + $this->dbg_enabled = sql_dbg_enabled(); + $this->prefix = $prefix; + } + + function get ($name, $get_miss_key_callback = '', $ttl = 0) + { + $this->cur_query = "cache->get('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return apc_fetch($this->prefix . $name); + } + + function set ($name, $value, $ttl = 0) + { + $this->cur_query = "cache->set('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return apc_store($this->prefix . $name, $value, $ttl); + } + + function rm ($name = '') + { + if ($name) + { + $this->cur_query = "cache->rm('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return apc_delete($this->prefix . $name); + } + else + { + return apc_clear_cache(); + } + } + + function is_installed () + { + return function_exists('apc_fetch'); + } +} \ No newline at end of file diff --git a/library/includes/cache/common.php b/library/includes/cache/common.php new file mode 100644 index 000000000..79a0ff525 --- /dev/null +++ b/library/includes/cache/common.php @@ -0,0 +1,84 @@ +dbg_enabled) return; + + $id =& $this->dbg_id; + $dbg =& $this->dbg[$id]; + + if ($mode == 'start') + { + $this->sql_starttime = utime(); + + $dbg['sql'] = isset($cur_query) ? short_query($cur_query) : short_query($this->cur_query); + $dbg['src'] = $this->debug_find_source(); + $dbg['file'] = $this->debug_find_source('file'); + $dbg['line'] = $this->debug_find_source('line'); + $dbg['time'] = ''; + } + else if ($mode == 'stop') + { + $this->cur_query_time = utime() - $this->sql_starttime; + $this->sql_timetotal += $this->cur_query_time; + $dbg['time'] = $this->cur_query_time; + $id++; + } + } + + function debug_find_source ($mode = '') + { + foreach (debug_backtrace() as $trace) + { + if ($trace['file'] !== __FILE__) + { + switch ($mode) + { + case 'file': return $trace['file']; + case 'line': return $trace['line']; + default: return hide_bb_path($trace['file']) .'('. $trace['line'] .')'; + } + } + } + return 'src not found'; + } +} \ No newline at end of file diff --git a/library/includes/cache/file.php b/library/includes/cache/file.php new file mode 100644 index 000000000..8538d22c6 --- /dev/null +++ b/library/includes/cache/file.php @@ -0,0 +1,136 @@ +dir = $dir; + $this->prefix = $prefix; + $this->dbg_enabled = sql_dbg_enabled(); + } + + function get ($name, $get_miss_key_callback = '', $ttl = 0) + { + $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; + + $this->cur_query = "cache->set('$name')"; + $this->debug('start'); + + if (file_exists($filename)) + { + require($filename); + } + + $this->debug('stop'); + $this->cur_query = null; + + return (!empty($filecache['value'])) ? $filecache['value'] : false; + } + + function set ($name, $value, $ttl = 86400) + { + if (!function_exists('var_export')) + { + return false; + } + + $this->cur_query = "cache->set('$name')"; + $this->debug('start'); + + $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; + $expire = TIMENOW + $ttl; + $cache_data = array( + 'expire' => $expire, + 'value' => $value, + ); + + $filecache = "'; + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return (bool) file_write($filecache, $filename, false, true, true); + } + + function rm ($name = '') + { + $clear = false; + if ($name) + { + $this->cur_query = "cache->rm('$name')"; + $this->debug('start'); + + $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; + if (file_exists($filename)) + { + $clear = (bool) unlink($filename); + } + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + } + else + { + if (is_dir($this->dir)) + { + if ($dh = opendir($this->dir)) + { + while (($file = readdir($dh)) !== false) + { + if ($file != "." && $file != "..") + { + $filename = $this->dir . $file; + + unlink($filename); + $clear = true; + } + } + closedir($dh); + } + } + } + return $clear; + } + + function gc ($expire_time = TIMENOW) + { + $clear = false; + + if (is_dir($this->dir)) + { + if ($dh = opendir($this->dir)) + { + while (($file = readdir($dh)) !== false) + { + if ($file != "." && $file != "..") + { + $filename = $this->dir . $file; + + require($filename); + + if(!empty($filecache['expire']) && ($filecache['expire'] < $expire_time)) + { + unlink($filename); + $clear = true; + } + } + } + closedir($dh); + } + } + + return $clear; + } +} \ No newline at end of file diff --git a/library/includes/cache/memcache.php b/library/includes/cache/memcache.php new file mode 100644 index 000000000..0c76fecf6 --- /dev/null +++ b/library/includes/cache/memcache.php @@ -0,0 +1,100 @@ +is_installed()) + { + die('Error: Memcached extension not installed'); + } + + $this->cfg = $cfg; + $this->prefix = $prefix; + $this->memcache = new Memcache; + $this->dbg_enabled = sql_dbg_enabled(); + } + + function connect () + { + $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; + + $this->cur_query = $connect_type .' '. $this->cfg['host'] .':'. $this->cfg['port']; + $this->debug('start'); + + if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) + { + $this->connected = true; + } + + if (DBG_LOG) dbg_log(' ', 'CACHE-connect'. ($this->connected ? '' : '-FAIL')); + + if (!$this->connected && $this->cfg['con_required']) + { + die('Could not connect to memcached server'); + } + + $this->debug('stop'); + $this->cur_query = null; + } + + function get ($name, $get_miss_key_callback = '', $ttl = 0) + { + if (!$this->connected) $this->connect(); + + $this->cur_query = "cache->get('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return ($this->connected) ? $this->memcache->get($this->prefix . $name) : false; + } + + function set ($name, $value, $ttl = 0) + { + if (!$this->connected) $this->connect(); + + $this->cur_query = "cache->set('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return ($this->connected) ? $this->memcache->set($this->prefix . $name, $value, false, $ttl) : false; + } + + function rm ($name = '') + { + if (!$this->connected) $this->connect(); + + if ($name) + { + $this->cur_query = "cache->rm('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return ($this->connected) ? $this->memcache->delete($this->prefix . $name, 0) : false; + } + else + { + return ($this->connected) ? $this->memcache->flush() : false; + } + } + + function is_installed () + { + return class_exists('Memcache'); + } +} \ No newline at end of file diff --git a/library/includes/cache/redis.php b/library/includes/cache/redis.php new file mode 100644 index 000000000..431dade3a --- /dev/null +++ b/library/includes/cache/redis.php @@ -0,0 +1,109 @@ +is_installed()) + { + die('Error: Redis extension not installed'); + } + + $this->cfg = $cfg; + $this->prefix = $prefix; + $this->redis = new Redis(); + $this->dbg_enabled = sql_dbg_enabled(); + } + + function connect () + { + $this->cur_query = 'connect '. $this->cfg['host'] .':'. $this->cfg['port']; + $this->debug('start'); + + if (@$this->redis->connect($this->cfg['host'], $this->cfg['port'])) + { + $this->connected = true; + } + + if (!$this->connected && $this->cfg['con_required']) + { + die('Could not connect to redis server'); + } + + $this->debug('stop'); + $this->cur_query = null; + } + + function get ($name, $get_miss_key_callback = '', $ttl = 0) + { + if (!$this->connected) $this->connect(); + + $this->cur_query = "cache->get('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return ($this->connected) ? unserialize($this->redis->get($this->prefix . $name)) : false; + } + + function set ($name, $value, $ttl = 0) + { + if (!$this->connected) $this->connect(); + + $this->cur_query = "cache->set('$name')"; + $this->debug('start'); + + if ($this->redis->set($this->prefix . $name, serialize($value))) + { + if ($ttl > 0) + { + $this->redis->expire($this->prefix . $name, $ttl); + } + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return true; + } + else + { + return false; + } + } + + function rm ($name = '') + { + if (!$this->connected) $this->connect(); + + if ($name) + { + $this->cur_query = "cache->rm('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return ($this->connected) ? $this->redis->del($this->prefix . $name) : false; + } + else + { + return ($this->connected) ? $this->redis->flushdb() : false; + } + } + + function is_installed () + { + return class_exists('Redis'); + } +} \ No newline at end of file diff --git a/library/includes/cache/sqlite.php b/library/includes/cache/sqlite.php new file mode 100644 index 000000000..31ce41a95 --- /dev/null +++ b/library/includes/cache/sqlite.php @@ -0,0 +1,110 @@ + '/path/to/cache.db.sqlite', + 'table_name' => 'cache', + 'table_schema' => 'CREATE TABLE cache ( + cache_name VARCHAR(255), + cache_expire_time INT, + cache_value TEXT, + PRIMARY KEY (cache_name) + )', + 'pconnect' => true, + 'con_required' => true, + 'log_name' => 'CACHE', + ); + + function cache_sqlite ($cfg, $prefix = null) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->db = new sqlite_common($this->cfg); + $this->prefix = $prefix; + } + + function get ($name, $get_miss_key_callback = '', $ttl = 604800) + { + if (empty($name)) + { + return is_array($name) ? array() : false; + } + $this->db->shard($name); + $cached_items = array(); + $this->prefix_len = strlen($this->prefix); + $this->prefix_sql = sqlite_escape_string($this->prefix); + + $name_ary = $name_sql = (array) $name; + array_deep($name_sql, 'sqlite_escape_string'); + + // get available items + $rowset = $this->db->fetch_rowset(" + SELECT cache_name, cache_value + FROM ". $this->cfg['table_name'] ." + WHERE cache_name IN('$this->prefix_sql". join("','$this->prefix_sql", $name_sql) ."') AND cache_expire_time > ". TIMENOW ." + LIMIT ". count($name) ." + "); + + $this->db->debug('start', 'unserialize()'); + foreach ($rowset as $row) + { + $cached_items[substr($row['cache_name'], $this->prefix_len)] = unserialize($row['cache_value']); + } + $this->db->debug('stop'); + + // get miss items + if ($get_miss_key_callback AND $miss_key = array_diff($name_ary, array_keys($cached_items))) + { + foreach ($get_miss_key_callback($miss_key) as $k => $v) + { + $this->set($this->prefix . $k, $v, $ttl); + $cached_items[$k] = $v; + } + } + // return + if (is_array($this->prefix . $name)) + { + return $cached_items; + } + else + { + return isset($cached_items[$name]) ? $cached_items[$name] : false; + } + } + + function set ($name, $value, $ttl = 604800) + { + $this->db->shard($this->prefix . $name); + $name_sql = sqlite_escape_string($this->prefix . $name); + $expire = TIMENOW + $ttl; + $value_sql = sqlite_escape_string(serialize($value)); + + $result = $this->db->query("REPLACE INTO ". $this->cfg['table_name'] ." (cache_name, cache_expire_time, cache_value) VALUES ('$name_sql', $expire, '$value_sql')"); + return (bool) $result; + } + + function rm ($name = '') + { + if ($name) + { + $this->db->shard($this->prefix . $name); + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($this->prefix . $name) ."'"); + } + else + { + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name']); + } + return (bool) $result; + } + + function gc ($expire_time = TIMENOW) + { + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time"); + return ($result) ? $this->db->changes() : 0; + } +} \ No newline at end of file diff --git a/library/includes/cache/sqlite_common.php b/library/includes/cache/sqlite_common.php new file mode 100644 index 000000000..ba7f5ad8b --- /dev/null +++ b/library/includes/cache/sqlite_common.php @@ -0,0 +1,181 @@ + 'sqlite.db', + 'table_name' => 'table_name', + 'table_schema' => 'CREATE TABLE table_name (...)', + 'pconnect' => true, + 'con_required' => true, + 'log_name' => 'SQLite', + 'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга) + 'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления) + ); + var $engine = 'SQLite'; + var $dbh = null; + var $connected = false; + var $shard_val = false; + + var $table_create_attempts = 0; + + function sqlite_common ($cfg) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->dbg_enabled = sql_dbg_enabled(); + } + + function connect () + { + $this->cur_query = ($this->dbg_enabled) ? 'connect to: '. $this->cfg['db_file_path'] : 'connect'; + $this->debug('start'); + + if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) + { + $this->connected = true; + } + + if (DBG_LOG) dbg_log(' ', $this->cfg['log_name'] .'-connect'. ($this->connected ? '' : '-FAIL')); + + if (!$this->connected && $this->cfg['con_required']) + { + trigger_error('SQLite not connected', E_USER_ERROR); + } + + $this->debug('stop'); + $this->cur_query = null; + } + + function create_table () + { + $this->table_create_attempts++; + return $this->dbh->query($this->cfg['table_schema']); + } + + function shard ($name) + { + $type = $this->cfg['shard_type']; + + if ($type == 'none') return; + if (is_array($name)) trigger_error('cannot shard: $name is array', E_USER_ERROR); + + // define shard_val + if ($type == 'string') + { + $shard_val = substr($name, 0, $this->cfg['shard_val']); + } + else + { + $shard_val = $name % $this->cfg['shard_val']; + } + // все запросы должны быть к одному и тому же шарду + if ($this->shard_val !== false) + { + if ($shard_val != $this->shard_val) + { + trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR); + } + else + { + return; + } + } + $this->shard_val = $shard_val; + $this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']); + } + + function query ($query) + { + if (!$this->connected) $this->connect(); + + $this->cur_query = $query; + $this->debug('start'); + + if (!$result = @$this->dbh->query($query)) + { + $rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})"); + $rowscount = 0; + while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) + { + $rowscount++; + } + if (!$this->table_create_attempts && !$rowscount) + { + if ($this->create_table()) + { + $result = $this->dbh->query($query); + } + } + if (!$result) + { + $this->trigger_error($this->get_error_msg()); + } + } + + $this->debug('stop'); + $this->cur_query = null; + + $this->num_queries++; + + return $result; + } + + function fetch_row ($query) + { + $result = $this->query($query); + return is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false; + } + + function fetch_rowset ($query) + { + $result = $this->query($query); + $rowset = array(); + while ($row = $result->fetchArray(SQLITE3_ASSOC)) + { + $rowset[] = $row; + } + return $rowset; + } + + function changes () + { + return is_resource($this->dbh) ? $this->dbh->changes() : 0; + } + + function escape ($str) + { + return sqlite_escape_string($str); + } + + function get_error_msg () + { + return 'SQLite error #'. ($err_code = $this->dbh->lastErrorCode()) .': '. $this->dbh->lastErrorMsg(); + } + + function rm ($name = '') + { + if ($name) + { + $this->db->shard($this->prefix . $name); + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($this->prefix . $name) ."'"); + } + else + { + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name']); + } + return (bool) $result; + } + + function gc ($expire_time = TIMENOW) + { + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time"); + return ($result) ? sqlite_changes($this->db->dbh) : 0; + } + + function trigger_error ($msg = 'DB Error') + { + if (error_reporting()) trigger_error($msg, E_USER_ERROR); + } +} \ No newline at end of file diff --git a/library/includes/cache/xcache.php b/library/includes/cache/xcache.php new file mode 100644 index 000000000..b1e391f72 --- /dev/null +++ b/library/includes/cache/xcache.php @@ -0,0 +1,67 @@ +is_installed()) + { + die('Error: XCache extension not installed'); + } + $this->dbg_enabled = sql_dbg_enabled(); + $this->prefix = $prefix; + } + + function get ($name, $get_miss_key_callback = '', $ttl = 0) + { + $this->cur_query = "cache->get('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return xcache_get($this->prefix . $name); + } + + function set ($name, $value, $ttl = 0) + { + $this->cur_query = "cache->set('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return xcache_set($this->prefix . $name, $value, $ttl); + } + + function rm ($name = '') + { + if ($name) + { + $this->cur_query = "cache->rm('$name')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return xcache_unset($this->prefix . $name); + } + else + { + xcache_clear_cache(XC_TYPE_PHP, 0); + xcache_clear_cache(XC_TYPE_VAR, 0); + return; + } + } + + function is_installed () + { + return function_exists('xcache_get'); + } +} \ No newline at end of file diff --git a/library/includes/core/caches.php b/library/includes/core/caches.php new file mode 100644 index 000000000..ac10299ce --- /dev/null +++ b/library/includes/core/caches.php @@ -0,0 +1,118 @@ + кеш_объект) + + function CACHES ($cfg) + { + $this->cfg = $cfg['cache']; + $this->obj['__stub'] = new cache_common(); + } + + function get_cache_obj ($cache_name) + { + if (!isset($this->ref[$cache_name])) + { + if (!$engine_cfg =& $this->cfg['engines'][$cache_name]) + { + $this->ref[$cache_name] =& $this->obj['__stub']; + } + else + { + $cache_type =& $engine_cfg[0]; + $cache_cfg =& $engine_cfg[1]; + + switch ($cache_type) + { + case 'memcache': + if (!isset($this->obj[$cache_name])) + { + $this->obj[$cache_name] = new cache_memcache($this->cfg['memcache'], $this->cfg['prefix']); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'sqlite': + if (!isset($this->obj[$cache_name])) + { + $cache_cfg['pconnect'] = $this->cfg['pconnect']; + $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db'); + + $this->obj[$cache_name] = new cache_sqlite($cache_cfg, $this->cfg['prefix']); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'db_sqlite': + if (!isset($this->obj[$cache_name])) + { + $cache_cfg['pconnect'] = $this->cfg['pconnect']; + $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db'); + $cache_cfg['table_name'] = $cache_name; + $cache_cfg['table_schema'] = $this->get_table_schema($cache_cfg); + + $this->obj[$cache_name] = new sqlite_common($cache_cfg); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'redis': + if (!isset($this->obj[$cache_name])) + { + $this->obj[$cache_name] = new cache_redis($this->cfg['redis'], $this->cfg['prefix']); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'apc': + if (!isset($this->obj[$cache_name])) + { + $this->obj[$cache_name] = new cache_apc($this->cfg['prefix']); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'xcache': + if (!isset($this->obj[$cache_name])) + { + $this->obj[$cache_name] = new cache_xcache($this->cfg['prefix']); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + default: //filecache + if (!isset($this->obj[$cache_name])) + { + $this->obj[$cache_name] = new cache_file($this->cfg['db_dir'] . $cache_name .'/', $this->cfg['prefix']); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + } + } + } + + return $this->ref[$cache_name]; + } + + function get_db_path ($name, $cfg, $ext) + { + if (!empty($cfg['shard_type']) && $cfg['shard_type'] != 'none') + { + return $this->cfg['db_dir'] . $name .'_*'. $ext; + } + else + { + return $this->cfg['db_dir'] . $name . $ext; + } + } + + function get_table_schema ($cfg) + { + return "CREATE TABLE {$cfg['table_name']} ( {$cfg['columns']} )"; + } +} \ No newline at end of file diff --git a/library/includes/core/dbs.php b/library/includes/core/dbs.php new file mode 100644 index 000000000..a3e9ef913 --- /dev/null +++ b/library/includes/core/dbs.php @@ -0,0 +1,58 @@ + $srv_cfg + var $srv = array(); // $srv_name => $db_obj + var $alias = array(); // $srv_alias => $srv_name + + var $log_file = 'sql_queries'; + var $log_counter = 0; + var $num_queries = 0; + var $sql_inittime = 0; + var $sql_timetotal = 0; + + function DBS ($cfg) + { + $this->cfg = $cfg['db']; + $this->alias = $cfg['db_alias']; + + foreach ($this->cfg as $srv_name => $srv_cfg) + { + $this->srv[$srv_name] = null; + } + } + + // получение/инициализация класса для сервера $srv_name + function get_db_obj ($srv_name_or_alias = 'db1') + { + $srv_name = $this->get_srv_name($srv_name_or_alias); + + if (!is_object($this->srv[$srv_name])) + { + $this->srv[$srv_name] = new sql_db($this->cfg[$srv_name]); + $this->srv[$srv_name]->db_server = $srv_name; + } + return $this->srv[$srv_name]; + } + + // определение имени сервера + function get_srv_name ($name) + { + if (isset($this->alias[$name])) + { + $srv_name = $this->alias[$name]; + } + else if (isset($this->cfg[$name])) + { + $srv_name = $name; + } + else + { + $srv_name = 'db1'; + } + return $srv_name; + } +} \ No newline at end of file diff --git a/library/includes/datastore/apc.php b/library/includes/datastore/apc.php new file mode 100644 index 000000000..03a52c1f2 --- /dev/null +++ b/library/includes/datastore/apc.php @@ -0,0 +1,71 @@ +is_installed()) + { + die('Error: APC extension not installed'); + } + $this->dbg_enabled = sql_dbg_enabled(); + $this->prefix = $prefix; + } + + function store ($title, $var) + { + $this->data[$title] = $var; + + $this->cur_query = "cache->set('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return (bool) apc_store($this->prefix . $title, $var); + } + + function clean () + { + foreach ($this->known_items as $title => $script_name) + { + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + apc_delete($this->prefix . $title); + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) + { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + foreach ($items as $item) + { + $this->cur_query = "cache->get('$item')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + $this->data[$item] = apc_fetch($this->prefix . $item); + } + } + + function is_installed () + { + return function_exists('apc_fetch'); + } +} \ No newline at end of file diff --git a/library/includes/datastore/common.php b/library/includes/datastore/common.php new file mode 100644 index 000000000..8b7232582 --- /dev/null +++ b/library/includes/datastore/common.php @@ -0,0 +1,175 @@ + data) + */ + var $data = array(); + /** + * Список элементов, которые будут извлечены из хранилища при первом же запросе get() + * до этого момента они ставятся в очередь $queued_items для дальнейшего извлечения _fetch()'ем + * всех элементов одним запросом + * array('title1', 'title2'...) + */ + var $queued_items = array(); + + /** + * 'title' => 'builder script name' inside "includes/datastore" dir + */ + var $known_items = array( + 'cat_forums' => 'build_cat_forums.php', + 'jumpbox' => 'build_cat_forums.php', + 'viewtopic_forum_select' => 'build_cat_forums.php', + 'latest_news' => 'build_cat_forums.php', + 'network_news' => 'build_cat_forums.php', + 'ads' => 'build_cat_forums.php', + 'moderators' => 'build_moderators.php', + 'stats' => 'build_stats.php', + 'ranks' => 'build_ranks.php', + 'attach_extensions' => 'build_attach_extensions.php', + 'smile_replacements' => 'build_smilies.php', + ); + + /** + * Constructor + */ + function datastore_common () {} + + /** + * @param array(item1_title, item2_title...) or single item's title + */ + function enqueue ($items) + { + foreach ((array) $items as $item) + { + // игнор уже поставленного в очередь либо уже извлеченного + if (!in_array($item, $this->queued_items) && !isset($this->data[$item])) + { + $this->queued_items[] = $item; + } + } + } + + function &get ($title) + { + if (!isset($this->data[$title])) + { + $this->enqueue($title); + $this->_fetch(); + } + return $this->data[$title]; + } + + function store ($item_name, $item_data) {} + + function rm ($items) + { + foreach ((array) $items as $item) + { + unset($this->data[$item]); + } + } + + function update ($items) + { + if ($items == 'all') + { + $items = array_keys(array_unique($this->known_items)); + } + foreach ((array) $items as $item) + { + $this->_build_item($item); + } + } + + function _fetch () + { + $this->_fetch_from_store(); + + foreach ($this->queued_items as $title) + { + if (!isset($this->data[$title]) || $this->data[$title] === false) + { + $this->_build_item($title); + } + } + + $this->queued_items = array(); + } + + function _fetch_from_store () {} + + function _build_item ($title) + { + if (!empty($this->known_items[$title])) + { + require(INC_DIR . $this->ds_dir . $this->known_items[$title]); + } + else + { + trigger_error("Unknown datastore item: $title", E_USER_ERROR); + } + } + + var $num_queries = 0; + var $sql_starttime = 0; + var $sql_inittime = 0; + var $sql_timetotal = 0; + var $cur_query_time = 0; + + var $dbg = array(); + var $dbg_id = 0; + var $dbg_enabled = false; + var $cur_query = null; + + function debug ($mode, $cur_query = null) + { + if (!$this->dbg_enabled) return; + + $id =& $this->dbg_id; + $dbg =& $this->dbg[$id]; + + if ($mode == 'start') + { + $this->sql_starttime = utime(); + + $dbg['sql'] = isset($cur_query) ? short_query($cur_query) : short_query($this->cur_query); + $dbg['src'] = $this->debug_find_source(); + $dbg['file'] = $this->debug_find_source('file'); + $dbg['line'] = $this->debug_find_source('line'); + $dbg['time'] = ''; + } + else if ($mode == 'stop') + { + $this->cur_query_time = utime() - $this->sql_starttime; + $this->sql_timetotal += $this->cur_query_time; + $dbg['time'] = $this->cur_query_time; + $id++; + } + } + + function debug_find_source ($mode = '') + { + foreach (debug_backtrace() as $trace) + { + if ($trace['file'] !== __FILE__) + { + switch ($mode) + { + case 'file': return $trace['file']; + case 'line': return $trace['line']; + default: return hide_bb_path($trace['file']) .'('. $trace['line'] .')'; + } + } + } + return 'src not found'; + } +} \ No newline at end of file diff --git a/library/includes/datastore/file.php b/library/includes/datastore/file.php new file mode 100644 index 000000000..8eeddb7d5 --- /dev/null +++ b/library/includes/datastore/file.php @@ -0,0 +1,87 @@ +prefix = $prefix; + $this->dir = $dir; + $this->dbg_enabled = sql_dbg_enabled(); + } + + function store ($title, $var) + { + $this->cur_query = "cache->set('$title')"; + $this->debug('start'); + + $this->data[$title] = $var; + + $filename = $this->dir . clean_filename($this->prefix . $title) . '.php'; + + $filecache = "'; + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return (bool) file_write($filecache, $filename, false, true, true); + } + + function clean () + { + $dir = $this->dir; + + if (is_dir($dir)) + { + if ($dh = opendir($dir)) + { + while (($file = readdir($dh)) !== false) + { + if ($file != "." && $file != "..") + { + $filename = $dir . $file; + + unlink($filename); + } + } + closedir($dh); + } + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) + { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + foreach($items as $item) + { + $filename = $this->dir . $this->prefix . $item . '.php'; + + $this->cur_query = "cache->get('$item')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + if(file_exists($filename)) + { + require($filename); + + $this->data[$item] = $filecache; + } + } + } +} \ No newline at end of file diff --git a/library/includes/datastore/memcache.php b/library/includes/datastore/memcache.php new file mode 100644 index 000000000..96fdf9242 --- /dev/null +++ b/library/includes/datastore/memcache.php @@ -0,0 +1,103 @@ +is_installed()) + { + die('Error: Memcached extension not installed'); + } + + $this->cfg = $cfg; + $this->prefix = $prefix; + $this->memcache = new Memcache; + $this->dbg_enabled = sql_dbg_enabled(); + } + + function connect () + { + $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; + + $this->cur_query = $connect_type .' '. $this->cfg['host'] .':'. $this->cfg['port']; + $this->debug('start'); + + if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) + { + $this->connected = true; + } + + if (DBG_LOG) dbg_log(' ', 'CACHE-connect'. ($this->connected ? '' : '-FAIL')); + + if (!$this->connected && $this->cfg['con_required']) + { + die('Could not connect to memcached server'); + } + + $this->debug('stop'); + $this->cur_query = null; + } + + function store ($title, $var) + { + if (!$this->connected) $this->connect(); + $this->data[$title] = $var; + + $this->cur_query = "cache->set('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return (bool) $this->memcache->set($this->prefix . $title, $var); + } + + function clean () + { + if (!$this->connected) $this->connect(); + foreach ($this->known_items as $title => $script_name) + { + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + $this->memcache->delete($this->prefix . $title, 0); + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) + { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + if (!$this->connected) $this->connect(); + foreach ($items as $item) + { + $this->cur_query = "cache->get('$item')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + $this->data[$item] = $this->memcache->get($this->prefix . $item); + } + } + + function is_installed () + { + return class_exists('Memcache'); + } +} \ No newline at end of file diff --git a/library/includes/datastore/redis.php b/library/includes/datastore/redis.php new file mode 100644 index 000000000..10b71019d --- /dev/null +++ b/library/includes/datastore/redis.php @@ -0,0 +1,99 @@ +is_installed()) + { + die('Error: Redis extension not installed'); + } + + $this->cfg = $cfg; + $this->redis = new Redis(); + $this->dbg_enabled = sql_dbg_enabled(); + $this->prefix = $prefix; + } + + function connect () + { + $this->cur_query = 'connect '. $this->cfg['host'] .':'. $this->cfg['port']; + $this->debug('start'); + + if (@$this->redis->connect($this->cfg['host'],$this->cfg['port'])) + { + $this->connected = true; + } + + if (!$this->connected && $this->cfg['con_required']) + { + die('Could not connect to redis server'); + } + + $this->debug('stop'); + $this->cur_query = null; + } + + function store ($title, $var) + { + if (!$this->connected) $this->connect(); + $this->data[$title] = $var; + + $this->cur_query = "cache->set('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return (bool) $this->redis->set($this->prefix . $title, serialize($var)); + } + + function clean () + { + if (!$this->connected) $this->connect(); + foreach ($this->known_items as $title => $script_name) + { + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + $this->redis->del($this->prefix . $title); + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) + { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + if (!$this->connected) $this->connect(); + foreach ($items as $item) + { + $this->cur_query = "cache->get('$item')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + $this->data[$item] = unserialize($this->redis->get($this->prefix . $item)); + } + } + + function is_installed () + { + return class_exists('Redis'); + } +} \ No newline at end of file diff --git a/library/includes/datastore/sqlite.php b/library/includes/datastore/sqlite.php new file mode 100644 index 000000000..26a4ccff8 --- /dev/null +++ b/library/includes/datastore/sqlite.php @@ -0,0 +1,66 @@ + '/path/to/datastore.db.sqlite', + 'table_name' => 'datastore', + 'table_schema' => 'CREATE TABLE datastore ( + ds_title VARCHAR(255), + ds_data TEXT, + PRIMARY KEY (ds_title) + )', + 'pconnect' => true, + 'con_required' => true, + 'log_name' => 'DATASTORE', + ); + + function datastore_sqlite ($cfg, $prefix = null) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->db = new sqlite_common($this->cfg); + $this->prefix = $prefix; + } + + function store ($item_name, $item_data) + { + $this->data[$item_name] = $item_data; + + $ds_title = sqlite_escape_string($this->prefix . $item_name); + $ds_data = sqlite_escape_string(serialize($item_data)); + + $result = $this->db->query("REPLACE INTO ". $this->cfg['table_name'] ." (ds_title, ds_data) VALUES ('$ds_title', '$ds_data')"); + + return (bool) $result; + } + + function clean () + { + $this->db->query("DELETE FROM ". $this->cfg['table_name']); + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) return; + + $prefix_len = strlen($this->prefix); + $prefix_sql = sqlite_escape_string($this->prefix); + + array_deep($items, 'sqlite_escape_string'); + $items_list = $prefix_sql . join("','$prefix_sql", $items); + + $rowset = $this->db->fetch_rowset("SELECT ds_title, ds_data FROM ". $this->cfg['table_name'] ." WHERE ds_title IN ('$items_list')"); + + $this->db->debug('start', "unserialize()"); + foreach ($rowset as $row) + { + $this->data[substr($row['ds_title'], $prefix_len)] = unserialize($row['ds_data']); + } + $this->db->debug('stop'); + } +} \ No newline at end of file diff --git a/library/includes/datastore/xcache.php b/library/includes/datastore/xcache.php new file mode 100644 index 000000000..2bd5f3fb8 --- /dev/null +++ b/library/includes/datastore/xcache.php @@ -0,0 +1,72 @@ +is_installed()) + { + die('Error: XCache extension not installed'); + } + + $this->dbg_enabled = sql_dbg_enabled(); + $this->prefix = $prefix; + } + + function store ($title, $var) + { + $this->data[$title] = $var; + + $this->cur_query = "cache->set('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return (bool) xcache_set($this->prefix . $title, $var); + } + + function clean () + { + foreach ($this->known_items as $title => $script_name) + { + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + xcache_unset($this->prefix . $title); + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) + { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + foreach ($items as $item) + { + $this->cur_query = "cache->set('$item')"; + $this->debug('start'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + $this->data[$item] = xcache_get($this->prefix . $item); + } + } + + function is_installed () + { + return function_exists('xcache_get'); + } +} \ No newline at end of file diff --git a/library/includes/init_bb.php b/library/includes/init_bb.php index 3994af630..bc72a297f 100644 --- a/library/includes/init_bb.php +++ b/library/includes/init_bb.php @@ -429,7 +429,7 @@ function make_url ($path = '') require(INC_DIR .'functions.php'); require(INC_DIR .'sessions.php'); require(INC_DIR .'template.php'); -require(INC_DIR .'core/mysql.php'); +require(CORE_DIR .'mysql.php'); define('SQL_LAYER', 'mysql');