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 );
/* @}*/
/**
* 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.
<?php
+/**
+ * @file include/cache.php
+ *
+ * @brief Class for storing data for a short time
+ */
+
+use \Friendica\Core\Config;
+use \Friendica\Core\PConfig;
+
+class Cache {
/**
- * cache api
+ * @brief Check for memcache and open a connection if configured
+ *
+ * @return object|boolean The memcache object - or "false" if not successful
*/
+ public static function memcache() {
+ if (!function_exists('memcache_connect')) {
+ return false;
+ }
+
+ if (!Config::get('system', 'memcache')) {
+ return false;
+ }
+
+ $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
+ $memcache_port = Config::get('system', 'memcache_port', 11211);
- class Cache {
- public static function get($key) {
+ $memcache = new Memcache;
- $r = q("SELECT `v` FROM `cache` WHERE `k`='%s' limit 1",
- dbesc($key)
- );
+ if (!$memcache->connect($memcache_host, $memcache_port)) {
+ return false;
+ }
- if (count($r))
- return $r[0]['v'];
+ 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'];
}
+ return null;
+ }
-/*
- *
- * 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.
- */
+ /**
+ * @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;
+ }
-/*
- * $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()));
- * }
- * }
- */
+ /// @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());
+ }
- public static function clear(){
+ 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 - 30 days")), intval(CACHE_MONTH));
+ 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 - 7 days")), intval(CACHE_WEEK));
+ 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 - 1 days")), intval(CACHE_DAY));
+ 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 - 1 hours")), intval(CACHE_HOUR));
+ 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());
+ }
+ }
+}
"indexes" => array(
"PRIMARY" => array("k".db_index_suffix($charset)),
"updated" => array("updated"),
+ "expire_mode_updated" => array("expire_mode", "updated"),
)
);
$database["challenge"] = array(
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)
);
}
logger('item_store: ' . print_r($arr,true), LOGGER_DATA);
- q("COMMIT;");
q("START TRANSACTION;");
$r = dbq("INSERT INTO `item` (`"
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);
}
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'))",
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`
<?php
-
// Session management functions. These provide database storage of PHP
// session info.
+require_once('include/cache.php');
+
$session_exists = 0;
$session_expire = 180000;
-if(! function_exists('ref_session_open')) {
-function ref_session_open ($s,$n) {
+function ref_session_open($s, $n) {
return true;
-}}
+}
-if(! function_exists('ref_session_read')) {
-function ref_session_read ($id) {
+function ref_session_read($id) {
global $session_exists;
- if(x($id))
- $r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id));
- if(count($r)) {
+ if (!x($id)) {
+ return '';
+ }
+
+ $memcache = cache::memcache();
+ if (is_object($memcache)) {
+ $data = $memcache->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) {
+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'",
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')) {
function ref_session_gc($expire) {
q("DELETE FROM `session` WHERE `expire` < %d", dbesc(time()));
+
return true;
-}}
+}
$gc_probability = 50;
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');
+}
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);
$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 )
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`
while (sizeof($list) > ($limit))
array_pop($list);
+ Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $list, CACHE_FIVE_MINUTES);
return $list;
}
.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"] == '')) {
$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");
$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);
}
}
}
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();
}
logger("fetched messages: ".count($messages));
while ($message = $db->qfetch())
- add_thread($message["iid"], true);
+ add_shadow_thread($message["iid"]);
$db->qclose();
}
} else
$post_id = 0;
- q("COMMIT;");
q("START TRANSACTION;");
$r = q("INSERT INTO `item` (`guid`, `extid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`,
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,
$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);
$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'])
);
}