diff options
Diffstat (limited to 'engine/lib/database.php')
| -rw-r--r-- | engine/lib/database.php | 172 |
1 files changed, 96 insertions, 76 deletions
diff --git a/engine/lib/database.php b/engine/lib/database.php index f12b50079..a7949788d 100644 --- a/engine/lib/database.php +++ b/engine/lib/database.php @@ -12,15 +12,19 @@ /** * Query cache for all queries. * - * Each query and its results are stored in this array as: + * Each query and its results are stored in this cache as: * <code> - * $DB_QUERY_CACHE[$query] => array(result1, result2, ... resultN) + * $DB_QUERY_CACHE[query hash] => array(result1, result2, ... resultN) * </code> + * @see elgg_query_runner() for details on the hash. * - * @global array $DB_QUERY_CACHE + * @warning Elgg used to set this as an empty array to turn off the cache + * + * @global ElggLRUCache|null $DB_QUERY_CACHE + * @access private */ global $DB_QUERY_CACHE; -$DB_QUERY_CACHE = array(); +$DB_QUERY_CACHE = null; /** * Queries to be executed upon shutdown. @@ -38,6 +42,7 @@ $DB_QUERY_CACHE = array(); * </code> * * @global array $DB_DELAYED_QUERIES + * @access private */ global $DB_DELAYED_QUERIES; $DB_DELAYED_QUERIES = array(); @@ -48,7 +53,8 @@ $DB_DELAYED_QUERIES = array(); * Each database link created with establish_db_link($name) is stored in * $dblink as $dblink[$name] => resource. Use get_db_link($name) to retrieve it. * - * @global array $dblink + * @global resource[] $dblink + * @access private */ global $dblink; $dblink = array(); @@ -59,6 +65,7 @@ $dblink = array(); * Each call to the database increments this counter. * * @global integer $dbcalls + * @access private */ global $dbcalls; $dbcalls = 0; @@ -72,10 +79,12 @@ $dbcalls = 0; * resource. eg "read", "write", or "readwrite". * * @return void + * @throws DatabaseException + * @access private */ function establish_db_link($dblinkname = "readwrite") { // Get configuration, and globalise database link - global $CONFIG, $dblink, $DB_QUERY_CACHE, $dbcalls; + global $CONFIG, $dblink, $DB_QUERY_CACHE; if ($dblinkname != "readwrite" && isset($CONFIG->db[$dblinkname])) { if (is_array($CONFIG->db[$dblinkname])) { @@ -119,7 +128,8 @@ function establish_db_link($dblinkname = "readwrite") { // Set up cache if global not initialized and query cache not turned off if ((!$DB_QUERY_CACHE) && (!$db_cache_off)) { - $DB_QUERY_CACHE = new ElggStaticVariableCache('db_query_cache'); + // @todo if we keep this cache in 1.9, expose the size as a config parameter + $DB_QUERY_CACHE = new ElggLRUCache(200); } } @@ -130,9 +140,10 @@ function establish_db_link($dblinkname = "readwrite") { * links up separately; otherwise just create the one database link. * * @return void + * @access private */ function setup_db_connections() { - global $CONFIG, $dblink; + global $CONFIG; if (!empty($CONFIG->db->split)) { establish_db_link('read'); @@ -146,6 +157,7 @@ function setup_db_connections() { * Display profiling information about db at NOTICE debug level upon shutdown. * * @return void + * @access private */ function db_profiling_shutdown_hook() { global $dbcalls; @@ -158,6 +170,7 @@ function db_profiling_shutdown_hook() { * Execute any delayed queries upon shutdown. * * @return void + * @access private */ function db_delayedexecution_shutdown_hook() { global $DB_DELAYED_QUERIES; @@ -185,21 +198,6 @@ function db_delayedexecution_shutdown_hook() { } /** - * Registers shutdown functions for database profiling and delayed queries. - * - * @note Database connections are established upon first call to database. - * - * @return true - * @elgg_event_handler boot system - */ -function init_db() { - register_shutdown_function('db_delayedexecution_shutdown_hook'); - register_shutdown_function('db_profiling_shutdown_hook'); - - return true; -} - -/** * Returns (if required, also creates) a database link resource. * * Database link resources are stored in the {@link $dblink} global. These @@ -208,7 +206,8 @@ function init_db() { * * @param string $dblinktype The type of link we want: "read", "write" or "readwrite". * - * @return object Database link + * @return resource Database link + * @access private */ function get_db_link($dblinktype) { global $dblink; @@ -226,10 +225,11 @@ function get_db_link($dblinktype) { /** * Execute an EXPLAIN for $query. * - * @param str $query The query to explain + * @param string $query The query to explain * @param mixed $link The database link resource to user. * * @return mixed An object of the query's result, or FALSE + * @access private */ function explain_query($query, $link) { if ($result = execute_query("explain " . $query, $link)) { @@ -249,18 +249,23 @@ function explain_query($query, $link) { * {@link $dbcalls} is incremented and the query is saved into the {@link $DB_QUERY_CACHE}. * * @param string $query The query - * @param link $dblink The DB link + * @param resource $dblink The DB link * - * @return The result of mysql_query() + * @return resource result of mysql_query() * @throws DatabaseException + * @access private */ function execute_query($query, $dblink) { - global $CONFIG, $dbcalls; + global $dbcalls; if ($query == NULL) { throw new DatabaseException(elgg_echo('DatabaseException:InvalidQuery')); } + if (!is_resource($dblink)) { + throw new DatabaseException(elgg_echo('DatabaseException:InvalidDBLink')); + } + $dbcalls++; $result = mysql_query($query, $dblink); @@ -279,10 +284,11 @@ function execute_query($query, $dblink) { * the raw result from {@link mysql_query()}. * * @param string $query The query to execute - * @param resource $dblink The database link to use or the link type (read | write) + * @param resource|string $dblink The database link to use or the link type (read | write) * @param string $handler A callback function to pass the results array to * * @return true + * @access private */ function execute_delayed_query($query, $dblink, $handler = "") { global $DB_DELAYED_QUERIES; @@ -315,6 +321,7 @@ function execute_delayed_query($query, $dblink, $handler = "") { * @return true * @uses execute_delayed_query() * @uses get_db_link() + * @access private */ function execute_delayed_write_query($query, $handler = "") { return execute_delayed_query($query, 'write', $handler); @@ -329,6 +336,7 @@ function execute_delayed_write_query($query, $handler = "") { * @return true * @uses execute_delayed_query() * @uses get_db_link() + * @access private */ function execute_delayed_read_query($query, $handler = "") { return execute_delayed_query($query, 'read', $handler); @@ -348,6 +356,7 @@ function execute_delayed_read_query($query, $handler = "") { * * @return array An array of database result objects or callback function results. If the query * returned nothing, an empty array. + * @access private */ function get_data($query, $callback = "") { return elgg_query_runner($query, $callback, false); @@ -364,6 +373,7 @@ function get_data($query, $callback = "") { * @param string $callback A callback function * * @return mixed A single database result object or the result of the callback function. + * @access private */ function get_data_row($query, $callback = "") { return elgg_query_runner($query, $callback, true); @@ -382,23 +392,21 @@ function get_data_row($query, $callback = "") { * @return array An array of database result objects or callback function results. If the query * returned nothing, an empty array. * @since 1.8.0 + * @access private */ function elgg_query_runner($query, $callback = null, $single = false) { - global $CONFIG, $DB_QUERY_CACHE; + global $DB_QUERY_CACHE; - $query = elgg_format_query($query); - - // since we want to cache results of running the callback, we need to - // need to namespace the query with the callback, and single result request. - $hash = (string)$callback . (string)$single . $query; + // Since we want to cache results of running the callback, we need to + // need to namespace the query with the callback and single result request. + // https://github.com/elgg/elgg/issues/4049 + $hash = (string)$callback . (int)$single . $query; // Is cached? if ($DB_QUERY_CACHE) { - $cached_query = $DB_QUERY_CACHE[$hash]; - - if ($cached_query !== FALSE) { + if (isset($DB_QUERY_CACHE[$hash])) { elgg_log("DB query $query results returned from cache (hash: $hash)", 'NOTICE'); - return $cached_query; + return $DB_QUERY_CACHE[$hash]; } } @@ -409,7 +417,7 @@ function elgg_query_runner($query, $callback = null, $single = false) { // test for callback once instead of on each iteration. // @todo check profiling to see if this needs to be broken out into - // explicit cases instead of checking in the interation. + // explicit cases instead of checking in the iteration. $is_callable = is_callable($callback); while ($row = mysql_fetch_object($result)) { if ($is_callable) { @@ -447,21 +455,15 @@ function elgg_query_runner($query, $callback = null, $single = false) { * * @return int|false The database id of the inserted row if a AUTO_INCREMENT field is * defined, 0 if not, and false on failure. + * @access private */ function insert_data($query) { - global $CONFIG, $DB_QUERY_CACHE; - $query = elgg_format_query($query); elgg_log("DB query $query", 'NOTICE'); $dblink = get_db_link('write'); - // Invalidate query cache - if ($DB_QUERY_CACHE) { - $DB_QUERY_CACHE->clear(); - } - - elgg_log("Query cache invalidated", 'NOTICE'); + _elgg_invalidate_query_cache(); if (execute_query("$query", $dblink)) { return mysql_insert_id($dblink); @@ -471,27 +473,22 @@ function insert_data($query) { } /** - * Update a row in the database. + * Update the database. * * @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}. * * @param string $query The query to run. * - * @return Bool + * @return bool + * @access private */ function update_data($query) { - global $CONFIG, $DB_QUERY_CACHE; - $query = elgg_format_query($query); elgg_log("DB query $query", 'NOTICE'); $dblink = get_db_link('write'); - // Invalidate query cache - if ($DB_QUERY_CACHE) { - $DB_QUERY_CACHE->clear(); - elgg_log("Query cache invalidated", 'NOTICE'); - } + _elgg_invalidate_query_cache(); if (execute_query("$query", $dblink)) { return TRUE; @@ -501,27 +498,22 @@ function update_data($query) { } /** - * Remove a row from the database. + * Remove data from the database. * * @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}. * * @param string $query The SQL query to run * * @return int|false The number of affected rows or false on failure + * @access private */ function delete_data($query) { - global $CONFIG, $DB_QUERY_CACHE; - $query = elgg_format_query($query); elgg_log("DB query $query", 'NOTICE'); $dblink = get_db_link('write'); - // Invalidate query cache - if ($DB_QUERY_CACHE) { - $DB_QUERY_CACHE->clear(); - elgg_log("Query cache invalidated", 'NOTICE'); - } + _elgg_invalidate_query_cache(); if (execute_query("$query", $dblink)) { return mysql_affected_rows($dblink); @@ -530,6 +522,22 @@ function delete_data($query) { return FALSE; } +/** + * Invalidate the query cache + * + * @access private + */ +function _elgg_invalidate_query_cache() { + global $DB_QUERY_CACHE; + if ($DB_QUERY_CACHE instanceof ElggLRUCache) { + $DB_QUERY_CACHE->clear(); + elgg_log("Query cache invalidated", 'NOTICE'); + } elseif ($DB_QUERY_CACHE) { + // In case someone sets the cache to an array and primes it with data + $DB_QUERY_CACHE = array(); + elgg_log("Query cache invalidated", 'NOTICE'); + } +} /** * Return tables matching the database prefix {@link $CONFIG->dbprefix}% in the currently @@ -537,6 +545,7 @@ function delete_data($query) { * * @return array|false List of tables or false on failure * @static array $tables Tables found matching the database prefix + * @access private */ function get_db_tables() { global $CONFIG; @@ -579,6 +588,7 @@ function get_db_tables() { * @param string $table The name of the table to optimise * * @return bool + * @access private */ function optimize_table($table) { $table = sanitise_string($table); @@ -591,6 +601,7 @@ function optimize_table($table) { * @param resource $dblink The DB link * * @return string Database error message + * @access private */ function get_db_error($dblink) { return mysql_error($dblink); @@ -615,6 +626,7 @@ function get_db_error($dblink) { * * @return void * @throws DatabaseException + * @access private */ function run_sql_script($scriptlocation) { if ($script = file_get_contents($scriptlocation)) { @@ -633,7 +645,7 @@ function run_sql_script($scriptlocation) { $statement = str_replace("prefix_", $CONFIG->dbprefix, $statement); if (!empty($statement)) { try { - $result = update_data($statement); + update_data($statement); } catch (DatabaseException $e) { $errors[] = $e->getMessage(); } @@ -656,9 +668,10 @@ function run_sql_script($scriptlocation) { /** * Format a query string for logging - * + * * @param string $query Query string * @return string + * @access private */ function elgg_format_query($query) { // remove newlines and extra spaces so logs are easier to read @@ -710,9 +723,9 @@ function sanitize_string($string) { /** * Sanitises an integer for database use. * - * @param int $int Integer - * @param bool[optional] $signed Whether negative values should be allowed (true) - * @return int Sanitised integer + * @param int $int Value to be sanitized + * @param bool $signed Whether negative values should be allowed (true) + * @return int */ function sanitise_int($int, $signed = true) { $int = (int) $int; @@ -727,18 +740,25 @@ function sanitise_int($int, $signed = true) { } /** - * Sanitises an integer for database use. + * Sanitizes an integer for database use. * Wrapper function for alternate English spelling (@see sanitise_int) * - * @param int $int Integer - * @param bool[optional] $signed Whether negative values should be allowed (true) - * @return int Sanitised integer + * @param int $int Value to be sanitized + * @param bool $signed Whether negative values should be allowed (true) + * @return int */ function sanitize_int($int, $signed = true) { return sanitise_int($int, $signed); } /** - * @elgg_register_event boot system init_db + * Registers shutdown functions for database profiling and delayed queries. + * + * @access private */ -elgg_register_event_handler('boot', 'system', 'init_db', 0); +function init_db() { + register_shutdown_function('db_delayedexecution_shutdown_hook'); + register_shutdown_function('db_profiling_shutdown_hook'); +} + +elgg_register_event_handler('init', 'system', 'init_db'); |
