diff --git a/boot.php b/boot.php index aa5574e3c7..85270e5305 100644 --- a/boot.php +++ b/boot.php @@ -127,6 +127,10 @@ define ( 'CACHE_MONTH', 0 ); define ( 'CACHE_WEEK', 1 ); define ( 'CACHE_DAY', 2 ); define ( 'CACHE_HOUR', 3 ); +define ( 'CACHE_HALF_HOUR', 4 ); +define ( 'CACHE_QUARTER_HOUR', 5 ); +define ( 'CACHE_FIVE_MINUTES', 6 ); +define ( 'CACHE_MINUTE', 7 ); /* @}*/ /** diff --git a/doc/htconfig.md b/doc/htconfig.md index fa26236673..6021682757 100644 --- a/doc/htconfig.md +++ b/doc/htconfig.md @@ -40,6 +40,9 @@ line to your .htconfig.php: * max_batch_queue - Default value is 1000. * max_processes_backend - Maximum number of concurrent database processes for background tasks. Default value is 5. * max_processes_frontend - Maximum number of concurrent database processes for foreground tasks. Default value is 20. +* memcache (Boolean) - Use memcache. To use memcache the PECL extension "memcache" has to be installed and activated. +* memcache_host - Hostname of the memcache daemon. Default is '127.0.0.1'. +* memcache_port- Portnumberof the memcache daemon. Default is 11211. * no_oembed (Boolean) - Don't use OEmbed to fetch more information about a link. * no_oembed_rich_content (Boolean) - Don't show the rich content (e.g. embedded PDF). * no_smilies (Boolean) - Don't show smilies. diff --git a/include/cache.php b/include/cache.php index d0b0dfafda..45938dddf8 100644 --- a/include/cache.php +++ b/include/cache.php @@ -1,72 +1,195 @@ connect($memcache_host, $memcache_port)) { + return false; + } + + return $memcache; + } + + /** + * @brief Return the duration for a given cache level + * + * @param integer $level Cache level + * + * @return integer The cache duration in seconds + */ + private function duration($level) { + switch($level) { + case CACHE_MONTH; + $seconds = 2592000; + break; + case CACHE_WEEK; + $seconds = 604800; + break; + case CACHE_DAY; + $seconds = 86400; + break; + case CACHE_HOUR; + $seconds = 3600; + break; + case CACHE_HALF_HOUR; + $seconds = 1800; + break; + case CACHE_QUARTER_HOUR; + $seconds = 900; + break; + case CACHE_FIVE_MINUTES; + $seconds = 300; + break; + case CACHE_MINUTE; + $seconds = 60; + break; + } + return $seconds; + } + + /** + * @brief Fetch cached data according to the key + * + * @param string $key The key to the cached data + * + * @return mixed Cached $value or "null" if not found + */ + public static function get($key) { + + $memcache = self::memcache(); + if (is_object($memcache)) { + // We fetch with the hostname as key to avoid problems with other applications + $value = $memcache->get(get_app()->get_hostname().":".$key); + if (!is_bool($value)) { + return unserialize($value); + } return null; } - public static function set($key,$value, $duration = CACHE_MONTH) { + // Frequently clear cache + self::clear($duration); - q("REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')", - dbesc($key), - dbesc($value), - intval($duration), - dbesc(datetime_convert())); + $r = q("SELECT `v` FROM `cache` WHERE `k`='%s' LIMIT 1", + dbesc($key) + ); + if (count($r)) { + return $r[0]['v']; } - -/* - * - * Leaving this legacy code temporaily to see how REPLACE fares - * as opposed to non-atomic checks when faced with fast moving key duplication. - * As a MySQL extension it isn't portable, but we're not yet very portable. - */ - -/* - * $r = q("SELECT * FROM `cache` WHERE `k`='%s' limit 1", - * dbesc($key) - * ); - * if(count($r)) { - * q("UPDATE `cache` SET `v` = '%s', `updated = '%s' WHERE `k` = '%s'", - * dbesc($value), - * dbesc(datetime_convert()), - * dbesc($key)); - * } - * else { - * q("INSERT INTO `cache` (`k`,`v`,`updated`) VALUES ('%s','%s','%s')", - * dbesc($key), - * dbesc($value), - * dbesc(datetime_convert())); - * } - * } - */ - - - public static function clear(){ - q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", - dbesc(datetime_convert('UTC','UTC',"now - 30 days")), intval(CACHE_MONTH)); - - q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", - dbesc(datetime_convert('UTC','UTC',"now - 7 days")), intval(CACHE_WEEK)); - - q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", - dbesc(datetime_convert('UTC','UTC',"now - 1 days")), intval(CACHE_DAY)); - - q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", - dbesc(datetime_convert('UTC','UTC',"now - 1 hours")), intval(CACHE_HOUR)); - } - + return null; } + /** + * @brief Put data in the cache according to the key + * + * @param string $key The key to the cached data + * @param mixed $valie The value that is about to be stored + * @param integer $duration The cache lifespan + */ + public static function set($key, $value, $duration = CACHE_MONTH) { + + // Do we have an installed memcache? Use it instead. + $memcache = self::memcache(); + if (is_object($memcache)) { + // We store with the hostname as key to avoid problems with other applications + $memcache->set(get_app()->get_hostname().":".$key, serialize($value), MEMCACHE_COMPRESSED, self::duration($duration)); + return; + } + + /// @todo store the cache data in the same way like the config data + q("REPLACE INTO `cache` (`k`,`v`,`expire_mode`,`updated`) VALUES ('%s','%s',%d,'%s')", + dbesc($key), + dbesc($value), + intval($duration), + dbesc(datetime_convert())); + } + + /** + * @brief Remove outdated data from the cache + * + * @param integer $maxlevel The maximum cache level that is to be cleared + */ + public static function clear($max_level = CACHE_MONTH) { + + // Clear long lasting cache entries only once a day + if (get_config("system", "cache_cleared_day") < time() - self::duration(CACHE_DAY)) { + if ($max_level == CACHE_MONTH) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 30 days")), intval(CACHE_MONTH)); + } + + if ($max_level <= CACHE_WEEK) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 7 days")), intval(CACHE_WEEK)); + } + + if ($max_level <= CACHE_DAY) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 1 days")), intval(CACHE_DAY)); + } + set_config("system", "cache_cleared_day", time()); + } + + if (($max_level <= CACHE_HOUR) AND (get_config("system", "cache_cleared_hour")) < time() - self::duration(CACHE_HOUR)) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 1 hours")), intval(CACHE_HOUR)); + + set_config("system", "cache_cleared_hour", time()); + } + + if (($max_level <= CACHE_HALF_HOUR) AND (get_config("system", "cache_cleared_half_hour")) < time() - self::duration(CACHE_HALF_HOUR)) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 30 minutes")), intval(CACHE_HALF_HOUR)); + + set_config("system", "cache_cleared_half_hour", time()); + } + + if (($max_level <= CACHE_QUARTER_HOUR) AND (get_config("system", "cache_cleared_hour")) < time() - self::duration(CACHE_QUARTER_HOUR)) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 15 minutes")), intval(CACHE_QUARTER_HOUR)); + + set_config("system", "cache_cleared_quarter_hour", time()); + } + + if (($max_level <= CACHE_FIVE_MINUTES) AND (get_config("system", "cache_cleared_five_minute")) < time() - self::duration(CACHE_FIVE_MINUTES)) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 5 minutes")), intval(CACHE_FIVE_MINUTES)); + + set_config("system", "cache_cleared_five_minute", time()); + } + + if (($max_level <= CACHE_MINUTE) AND (get_config("system", "cache_cleared_minute")) < time() - self::duration(CACHE_MINUTE)) { + q("DELETE FROM `cache` WHERE `updated` < '%s' AND `expire_mode` = %d", + dbesc(datetime_convert('UTC','UTC',"now - 1 minutes")), intval(CACHE_MINUTE)); + + set_config("system", "cache_cleared_minute", time()); + } + } +} diff --git a/include/dbstructure.php b/include/dbstructure.php index b0f90ae245..3d14615327 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -443,6 +443,7 @@ function db_definition($charset) { "indexes" => array( "PRIMARY" => array("k".db_index_suffix($charset)), "updated" => array("updated"), + "expire_mode_updated" => array("expire_mode", "updated"), ) ); $database["challenge"] = array( diff --git a/include/identity.php b/include/identity.php index b3dbea8fc6..a30d81cf3a 100644 --- a/include/identity.php +++ b/include/identity.php @@ -149,17 +149,23 @@ function get_profiledata_by_nick($nickname, $uid = 0, $profile = 0) { if($profile) { $profile_int = intval($profile); - $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* FROM `profile` - INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` - WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d AND `contact`.`self` = 1 LIMIT 1", + $r = q("SELECT `contact`.`id` AS `contact_id`, `profile`.`uid` AS `profile_uid`, `profile`.*, + `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* + FROM `profile` + INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self` + INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` + WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d LIMIT 1", dbesc($nickname), intval($profile_int) ); } if((!$r) && (!count($r))) { - $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* FROM `profile` - INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` - WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` = 1 AND `contact`.`self` = 1 LIMIT 1", + $r = q("SELECT `contact`.`id` AS `contact_id`, `profile`.`uid` AS `profile_uid`, `profile`.*, + `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* + FROM `profile` + INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self` + INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` + WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` LIMIT 1", dbesc($nickname) ); } diff --git a/include/items.php b/include/items.php index 27c198d894..98927e6585 100644 --- a/include/items.php +++ b/include/items.php @@ -770,7 +770,6 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa logger('item_store: ' . print_r($arr,true), LOGGER_DATA); - q("COMMIT;"); q("START TRANSACTION;"); $r = dbq("INSERT INTO `item` (`" @@ -887,13 +886,16 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa create_tags_from_item($current_post); create_files_from_item($current_post); - q("COMMIT"); - // Only check for notifications on start posts if ($arr['parent-uri'] === $arr['uri']) { add_thread($current_post); + q("COMMIT"); + + add_shadow_thread($current_post); } else { update_thread($parent_id); + q("COMMIT"); + add_shadow_entry($arr); } diff --git a/include/ostatus.php b/include/ostatus.php index 5dcc7d5a7e..83bc493e39 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -813,7 +813,8 @@ class ostatus { WHERE `term`.`uid` = %d AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`url` = '%s'))", intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url)); -/* +/* 2016-10-23: The old query will be kept until we are sure that the query above is a good and fast replacement + $parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN (SELECT `parent` FROM `item` WHERE `id` IN (SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))", @@ -1981,8 +1982,9 @@ class ostatus { intval($owner["uid"]), intval($owner["id"]), intval($authorid), dbesc($check_date), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN)); -/* - // We keep this old query until we are sure that the new one works better + +/* 2016-10-23: The old query will be kept until we are sure that the query above is a good and fast replacement + $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` STRAIGHT_JOIN `thread` ON `thread`.`iid` = `item`.`parent` LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid` diff --git a/include/session.php b/include/session.php index 8f9d64606c..c69a402317 100644 --- a/include/session.php +++ b/include/session.php @@ -1,43 +1,62 @@ get(get_app()->get_hostname().":session:".$id); + if (!is_bool($data)) { + return $data; + } + logger("no data for session $id", LOGGER_TRACE); + return ''; + } + + $r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id)); + + if (dbm::is_result($r)) { $session_exists = true; return $r[0]['data']; } else { logger("no data for session $id", LOGGER_TRACE); } - return ''; -}} -if(! function_exists('ref_session_write')) { -function ref_session_write ($id,$data) { + return ''; +} + +function ref_session_write($id, $data) { global $session_exists, $session_expire; - if(! $id || ! $data) { + if (!$id || !$data) { return false; } $expire = time() + $session_expire; $default_expire = time() + 300; - if($session_exists) { + $memcache = cache::memcache(); + if (is_object($memcache)) { + $memcache->set(get_app()->get_hostname().":session:".$id, $data, MEMCACHE_COMPRESSED, $expire); + return true; + } + + if ($session_exists) { $r = q("UPDATE `session` SET `data` = '%s' WHERE `data` != '%s' AND `sid` = '%s'", @@ -53,24 +72,30 @@ function ref_session_write ($id,$data) { dbesc($id), dbesc($default_expire), dbesc($data)); return true; -}} +} -if(! function_exists('ref_session_close')) { function ref_session_close() { return true; -}} +} + +function ref_session_destroy($id) { + $memcache = cache::memcache(); + + if (is_object($memcache)) { + $memcache->delete(get_app()->get_hostname().":session:".$id); + return true; + } -if(! function_exists('ref_session_destroy')) { -function ref_session_destroy ($id) { q("DELETE FROM `session` WHERE `sid` = '%s'", dbesc($id)); - return true; -}} -if(! function_exists('ref_session_gc')) { + return true; +} + function ref_session_gc($expire) { q("DELETE FROM `session` WHERE `expire` < %d", dbesc(time())); + return true; -}} +} $gc_probability = 50; @@ -78,7 +103,8 @@ ini_set('session.gc_probability', $gc_probability); ini_set('session.use_only_cookies', 1); ini_set('session.cookie_httponly', 1); -if (!get_config('system', 'disable_database_session')) +if (!get_config('system', 'disable_database_session')) { session_set_save_handler('ref_session_open', 'ref_session_close', 'ref_session_read', 'ref_session_write', 'ref_session_destroy', 'ref_session_gc'); +} diff --git a/include/socgraph.php b/include/socgraph.php index a41861d6ea..e1b5cdbf9a 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -1075,8 +1075,14 @@ function all_friends($uid,$cid,$start = 0, $limit = 80) { function suggestion_query($uid, $start = 0, $limit = 80) { - if(! $uid) + if (!$uid) { return array(); + } + + $list = Cache::get("suggestion_query:".$uid.":".$start.":".$limit); + if (!is_null($list)) { + return $list; + } $network = array(NETWORK_DFRN); @@ -1087,9 +1093,10 @@ function suggestion_query($uid, $start = 0, $limit = 80) { $network[] = NETWORK_OSTATUS; $sql_network = implode("', '", $network); - //$sql_network = "'".$sql_network."', ''"; $sql_network = "'".$sql_network."'"; + /// @todo This query is really slow + // By now we cache the data for five minutes $r = q("SELECT count(glink.gcid) as `total`, gcontact.* from gcontact INNER JOIN `glink` ON `glink`.`gcid` = `gcontact`.`id` where uid = %d and not gcontact.nurl in ( select nurl from contact where uid = %d ) @@ -1108,8 +1115,10 @@ function suggestion_query($uid, $start = 0, $limit = 80) { intval($limit) ); - if(count($r) && count($r) >= ($limit -1)) + if(count($r) && count($r) >= ($limit -1)) { + Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $r, CACHE_FIVE_MINUTES); return $r; + } $r2 = q("SELECT gcontact.* FROM gcontact INNER JOIN `glink` ON `glink`.`gcid` = `gcontact`.`id` @@ -1138,6 +1147,7 @@ function suggestion_query($uid, $start = 0, $limit = 80) { while (sizeof($list) > ($limit)) array_pop($list); + Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $list, CACHE_FIVE_MINUTES); return $list; } diff --git a/include/threads.php b/include/threads.php index 2e02e7ada3..a487d6e01f 100644 --- a/include/threads.php +++ b/include/threads.php @@ -18,42 +18,61 @@ function add_thread($itemid, $onlyshadow = false) { .implode("', '", array_values($item)) ."')"); - logger("add_thread: Add thread for item ".$itemid." - ".print_r($result, true), LOGGER_DEBUG); + logger("Add thread for item ".$itemid." - ".print_r($result, true), LOGGER_DEBUG); + } +} + +function add_shadow_thread($itemid) { + $items = q("SELECT `uid`, `wall`, `private`, `moderated`, `visible`, `contact-id`, `deleted`, `network` + FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid)); + + if (!dbm::is_result($items)) { + return; } + $item = $items[0]; + // is it already a copy? - if (($itemid == 0) OR ($item['uid'] == 0)) + if (($itemid == 0) OR ($item['uid'] == 0)) { return; + } // Is it a visible public post? - if (!$item["visible"] OR $item["deleted"] OR $item["moderated"] OR $item["private"]) + if (!$item["visible"] OR $item["deleted"] OR $item["moderated"] OR $item["private"]) { return; + } // is it an entry from a connector? Only add an entry for natively connected networks - if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""))) + if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""))) { return; + } // Only do these checks if the post isn't a wall post if (!$item["wall"]) { // Check, if hide-friends is activated - then don't do a shadow entry $r = q("SELECT `hide-friends` FROM `profile` WHERE `is-default` AND `uid` = %d AND NOT `hide-friends`", $item['uid']); - if (!count($r)) + + if (!dbm::is_result($r)) { return; + } + // Check if the contact is hidden or blocked $r = q("SELECT `id` FROM `contact` WHERE NOT `hidden` AND NOT `blocked` AND `id` = %d", $item['contact-id']); - if (!count($r)) + + if (!dbm::is_result($r)) { return; + } } // Only add a shadow, if the profile isn't hidden $r = q("SELECT `uid` FROM `user` where `uid` = %d AND NOT `hidewall`", $item['uid']); - if (!count($r)) + if (!dbm::is_result($r)) { return; + } - $item = q("SELECT * FROM `item` WHERE `id` = %d", - intval($itemid)); + $item = q("SELECT * FROM `item` WHERE `id` = %d", intval($itemid)); if (count($item) AND ($item[0]["allow_cid"] == '') AND ($item[0]["allow_gid"] == '') AND ($item[0]["deny_cid"] == '') AND ($item[0]["deny_gid"] == '')) { @@ -61,7 +80,7 @@ function add_thread($itemid, $onlyshadow = false) { $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = 0 LIMIT 1", dbesc($item['uri'])); - if (!$r) { + if (!dbm::is_result($r)) { // Preparing public shadow (removing user specific data) require_once("include/items.php"); require_once("include/Contact.php"); @@ -72,7 +91,7 @@ function add_thread($itemid, $onlyshadow = false) { $item[0]['contact-id'] = get_contact($item[0]['author-link'], 0); $public_shadow = item_store($item[0], false, false, true); - logger("add_thread: Stored public shadow for post ".$itemid." under id ".$public_shadow, LOGGER_DEBUG); + logger("Stored public shadow for thread ".$itemid." under id ".$public_shadow, LOGGER_DEBUG); } } } @@ -193,8 +212,10 @@ function update_threads() { logger("update_threads: fetched messages: ".count($messages)); - while ($message = $db->qfetch()) + while ($message = $db->qfetch()) { add_thread($message["id"]); + add_shadow_thread($message["id"]); + } $db->qclose(); } @@ -227,7 +248,7 @@ function update_shadow_copy() { logger("fetched messages: ".count($messages)); while ($message = $db->qfetch()) - add_thread($message["iid"], true); + add_shadow_thread($message["iid"]); $db->qclose(); } diff --git a/mod/item.php b/mod/item.php index 94ff6b93d4..a56dde3c19 100644 --- a/mod/item.php +++ b/mod/item.php @@ -788,7 +788,6 @@ function item_post(&$a) { } else $post_id = 0; - q("COMMIT;"); q("START TRANSACTION;"); $r = q("INSERT INTO `item` (`guid`, `extid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`, @@ -990,12 +989,14 @@ function item_post(&$a) { create_tags_from_item($post_id); create_files_from_item($post_id); - q("COMMIT"); - - if ($post_id == $parent) + if ($post_id == $parent) { add_thread($post_id); - else { + q("COMMIT"); + + add_shadow_thread($post_id); + } else { update_thread($parent, true); + q("COMMIT"); // Insert an item entry for UID=0 for global entries // We have to remove or change some data before that, diff --git a/mod/photos.php b/mod/photos.php index 19d3d1c6c4..34e5eb4ba3 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -53,12 +53,18 @@ function photos_init(&$a) { $sql_extra = permissions_sql($a->data['user']['uid']); - $albums = qu("SELECT count(distinct `resource-id`) AS `total`, `album` FROM `photo` USE INDEX (`uid_album_created`) WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' - $sql_extra GROUP BY `album` ORDER BY `created` DESC", - intval($a->data['user']['uid']), - dbesc('Contact Photos'), - dbesc( t('Contact Photos')) - ); + $albums = Cache::get("photos-albums:".$a->data['user']['uid']); + if (is_null($albums)) { + /// @todo This query needs to be renewed. It is really slow + // At this time we just store the data in the cache + $albums = qu("SELECT count(distinct `resource-id`) AS `total`, `album` FROM `photo` USE INDEX (`uid_album_created`) WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' + $sql_extra GROUP BY `album` ORDER BY `created` DESC", + intval($a->data['user']['uid']), + dbesc('Contact Photos'), + dbesc( t('Contact Photos')) + ); + Cache::set("photos-albums:".$a->data['user']['uid'], $albums, CACHE_FIVE_MINUTES); + } $albums_visible = ((intval($a->data['user']['hidewall']) && (! local_user()) && (! remote_user())) ? false : true); diff --git a/mod/profile.php b/mod/profile.php index a8a6ad3885..279f863523 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -282,16 +282,20 @@ function profile_content(&$a, $update = 0) { $pager_sql = sprintf(" LIMIT %d, %d ",intval($a->pager['start']), intval($a->pager['itemspage'])); $r = q("SELECT `thread`.`iid` AS `item_id`, `thread`.`network` AS `item_network` - FROM `thread` FORCE INDEX (`uid_created`) INNER JOIN `item` ON `item`.`id` = `thread`.`iid` - $sql_post_table INNER JOIN `contact` ON `contact`.`id` = `thread`.`contact-id` - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - WHERE `thread`.`uid` = %d AND `thread`.`visible` = 1 AND `thread`.`deleted` = 0 - and `thread`.`moderated` = 0 - AND `thread`.`wall` = 1 - $sql_extra $sql_extra2 - ORDER BY `thread`.`created` DESC $pager_sql ", - intval($a->profile['profile_uid']) - + FROM `thread` + STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` + $sql_post_table + STRAIGHT_JOIN `contact` ON `contact`.`id` = `thread`.`contact-id` + AND NOT `contact`.`blocked` AND NOT `contact`.`pending` + WHERE `thread`.`uid` = %d AND `thread`.`visible` + AND `thread`.`contact-id` = %d + AND NOT `thread`.`deleted` + AND NOT `thread`.`moderated` + AND `thread`.`wall` + $sql_extra $sql_extra2 + ORDER BY `thread`.`created` DESC $pager_sql", + intval($a->profile['profile_uid']), + intval($a->profile['contact_id']) ); }