Merge pull request #2887 from annando/1611-api-performance

API calls should be much faster than before
This commit is contained in:
Tobias Diekershoff 2016-11-05 08:25:09 +01:00 committed by GitHub
commit ba1cd57087
2 changed files with 185 additions and 161 deletions

View file

@ -428,9 +428,20 @@ function contacts_not_grouped($uid,$start = 0,$count = 0) {
return $r;
}
function get_contact($url, $uid = 0) {
/**
* @brief Fetch the contact id for a given url and user
*
* @param string $url Contact URL
* @param integer $uid The user id for the contact
* @param boolean $no_update Don't update the contact
*
* @return integer Contact ID
*/
function get_contact($url, $uid = 0, $no_update = false) {
require_once("include/Scrape.php");
logger("Get contact data for url ".$url." and user ".$uid." - ".App::callstack(), LOGGER_DEBUG);;
$data = array();
$contactid = 0;
@ -460,8 +471,9 @@ function get_contact($url, $uid = 0) {
$update_photo = ($contact[0]['avatar-date'] < datetime_convert('','','now -7 days'));
//$update_photo = ($contact[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
if (!$update_photo)
if (!$update_photo OR $no_update) {
return($contactid);
}
} elseif ($uid != 0)
return 0;

View file

@ -280,6 +280,45 @@
$duration = (float)(microtime(true)-$stamp);
logger("API call duration: ".round($duration, 2)."\t".$a->query_string, LOGGER_DEBUG);
if (get_config("system", "profiler")) {
logger(sprintf("Database: %s/%s, Network: %s, Rendering: %s, Session: %s, I/O: %s, Other: %s, Total: %s",
round($a->performance["database"] - $a->performance["database_write"], 3),
round($a->performance["database_write"], 3),
round($a->performance["network"], 2),
round($a->performance["rendering"], 2),
round($a->performance["parser"], 2),
round($a->performance["file"], 2),
round($duration - $a->performance["database"]
- $a->performance["network"] - $a->performance["rendering"]
- $a->performance["parser"] - $a->performance["file"], 2),
round($duration, 2)),
LOGGER_DEBUG);
if (get_config("rendertime", "callstack")) {
$o = "Database Read:\n";
foreach ($a->callstack["database"] AS $func => $time) {
$time = round($time, 3);
if ($time > 0)
$o .= $func.": ".$time."\n";
}
$o .= "\nDatabase Write:\n";
foreach ($a->callstack["database_write"] AS $func => $time) {
$time = round($time, 3);
if ($time > 0)
$o .= $func.": ".$time."\n";
}
$o .= "\nNetwork:\n";
foreach ($a->callstack["network"] AS $func => $time) {
$time = round($time, 3);
if ($time > 0)
$o .= $func.": ".$time."\n";
}
logger($o, LOGGER_DEBUG);
}
}
if ($r===false) {
// api function returned false withour throw an
// exception. This should not happend, throw a 500
@ -391,7 +430,7 @@
* Contact url or False if contact id is unknown
*/
function api_unique_id_to_url($id){
$r = q("SELECT `url` FROM `gcontact` WHERE `id`=%d LIMIT 1",
$r = q("SELECT `url` FROM `contact` WHERE `uid` = 0 AND `id` = %d LIMIT 1",
intval($id));
if ($r)
return ($r[0]["url"]);
@ -423,7 +462,7 @@
if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
}
// Searching for unique contact id
// Searching for contact id with uid = 0
if(!is_null($contact_id) AND (intval($contact_id) != 0)){
$user = dbesc(api_unique_id_to_url($contact_id));
@ -496,14 +535,16 @@
// Selecting the id by priority, friendica first
api_best_nickname($uinfo);
// if the contact wasn't found, fetch it from the unique contacts
// if the contact wasn't found, fetch it from the contacts with uid = 0
if (count($uinfo)==0) {
$r = array();
if ($url != "")
$r = q("SELECT * FROM `gcontact` WHERE `nurl`='%s' LIMIT 1", dbesc(normalise_link($url)));
$r = q("SELECT * FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' LIMIT 1", dbesc(normalise_link($url)));
if ($r) {
$network_name = network_to_name($r[0]['network'], $r[0]['url']);
// If no nick where given, extract it from the address
if (($r[0]['nick'] == "") OR ($r[0]['name'] == $r[0]['nick']))
$r[0]['nick'] = api_get_nick($r[0]["url"]);
@ -513,8 +554,10 @@
'id_str' => (string) $r[0]["id"],
'name' => $r[0]["name"],
'screen_name' => (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']),
'location' => $r[0]["location"],
'location' => ($r[0]["location"] != "") ? $r[0]["location"] : $network_name,
'description' => $r[0]["about"],
'profile_image_url' => $r[0]["micro"],
'profile_image_url_https' => $r[0]["micro"],
'url' => $r[0]["url"],
'protected' => false,
'followers_count' => 0,
@ -531,16 +574,13 @@
'contributors_enabled' => false,
'is_translator' => false,
'is_translation_enabled' => false,
'profile_image_url' => $r[0]["photo"],
'profile_image_url_https' => $r[0]["photo"],
'following' => false,
'follow_request_sent' => false,
'notifications' => false,
'statusnet_blocking' => false,
'notifications' => false,
'statusnet_profile_url' => $r[0]["url"],
'uid' => 0,
'cid' => get_contact($r[0]["url"], api_user()),
'cid' => get_contact($r[0]["url"], api_user(), true),
'self' => 0,
'network' => $r[0]["network"],
);
@ -563,22 +603,24 @@
intval(api_user())
);
//AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
// Counting is deactivated by now, due to performance issues
// count public wall messages
$r = q("SELECT COUNT(*) as `count` FROM `item` WHERE `uid` = %d AND `wall`",
intval($uinfo[0]['uid'])
);
$countitms = $r[0]['count'];
//$r = q("SELECT COUNT(*) as `count` FROM `item` WHERE `uid` = %d AND `wall`",
// intval($uinfo[0]['uid'])
//);
//$countitms = $r[0]['count'];
$countitms = 0;
} else {
// Counting is deactivated by now, due to performance issues
//$r = q("SELECT count(*) as `count` FROM `item`
// WHERE `contact-id` = %d",
// intval($uinfo[0]['id'])
//);
//$countitms = $r[0]['count'];
$countitms = 0;
}
else {
//AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
$r = q("SELECT count(*) as `count` FROM `item`
WHERE `contact-id` = %d",
intval($uinfo[0]['id'])
);
$countitms = $r[0]['count'];
}
/*
// Counting is deactivated by now, due to performance issues
// count friends
$r = q("SELECT count(*) as `count` FROM `contact`
WHERE `uid` = %d AND `rel` IN ( %d, %d )
@ -609,6 +651,10 @@
$countfollowers = 0;
$starred = 0;
}
*/
$countfriends = 0;
$countfollowers = 0;
$starred = 0;
// Add a nick if it isn't present there
if (($uinfo[0]['nick'] == "") OR ($uinfo[0]['name'] == $uinfo[0]['nick'])) {
@ -617,12 +663,11 @@
$network_name = network_to_name($uinfo[0]['network'], $uinfo[0]['url']);
$gcontact_id = get_gcontact_id(array("url" => $uinfo[0]['url'], "network" => $uinfo[0]['network'],
"photo" => $uinfo[0]['micro'], "name" => $uinfo[0]['name']));
$pcontact_id = get_contact($uinfo[0]['url'], 0, true);
$ret = Array(
'id' => intval($gcontact_id),
'id_str' => (string) intval($gcontact_id),
'id' => intval($pcontact_id),
'id_str' => (string) intval($pcontact_id),
'name' => (($uinfo[0]['name']) ? $uinfo[0]['name'] : $uinfo[0]['nick']),
'screen_name' => (($uinfo[0]['nick']) ? $uinfo[0]['nick'] : $uinfo[0]['name']),
'location' => ($usr) ? $usr[0]['default-location'] : $network_name,
@ -633,13 +678,20 @@
'protected' => false,
'followers_count' => intval($countfollowers),
'friends_count' => intval($countfriends),
'listed_count' => 0,
'created_at' => api_date($uinfo[0]['created']),
'favourites_count' => intval($starred),
'utc_offset' => "0",
'time_zone' => 'UTC',
'statuses_count' => intval($countitms),
'following' => (($uinfo[0]['rel'] == CONTACT_IS_FOLLOWER) OR ($uinfo[0]['rel'] == CONTACT_IS_FRIEND)),
'geo_enabled' => false,
'verified' => true,
'statuses_count' => intval($countitms),
'lang' => '',
'contributors_enabled' => false,
'is_translator' => false,
'is_translation_enabled' => false,
'following' => (($uinfo[0]['rel'] == CONTACT_IS_FOLLOWER) OR ($uinfo[0]['rel'] == CONTACT_IS_FRIEND)),
'follow_request_sent' => false,
'statusnet_blocking' => false,
'notifications' => false,
//'statusnet_profile_url' => App::get_baseurl()."/contacts/".$uinfo[0]['cid'],
@ -663,21 +715,15 @@
*/
function api_item_get_user(&$a, $item) {
// Make sure that there is an entry in the global contacts for author and owner
get_gcontact_id(array("url" => $item['author-link'], "network" => $item['network'],
"photo" => $item['author-avatar'], "name" => $item['author-name']));
$status_user = api_get_user($a, $item["author-link"]);
get_gcontact_id(array("url" => $item['owner-link'], "network" => $item['network'],
"photo" => $item['owner-avatar'], "name" => $item['owner-name']));
$status_user = api_get_user($a,$item["author-link"]);
$status_user["protected"] = (($item["allow_cid"] != "") OR
($item["allow_gid"] != "") OR
($item["deny_cid"] != "") OR
($item["deny_gid"] != "") OR
$item["private"]);
$owner_user = api_get_user($a,$item["owner-link"]);
$owner_user = api_get_user($a, $item["owner-link"]);
return (array($status_user, $owner_user));
}
@ -1106,12 +1152,11 @@
$privacy_sql = "";
// get last public wall message
$lastwall = q("SELECT `item`.*, `i`.`contact-id` as `reply_uid`, `i`.`author-link` AS `item-author`
FROM `item`, `item` as `i`
$lastwall = q("SELECT `item`.*
FROM `item`
WHERE `item`.`contact-id` = %d AND `item`.`uid` = %d
AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s')))
AND `i`.`id` = `item`.`parent`
AND `item`.`type`!='activity' $privacy_sql
AND `item`.`type` != 'activity' $privacy_sql
ORDER BY `item`.`id` DESC
LIMIT 1",
intval($user_info['cid']),
@ -1125,37 +1170,7 @@
if (count($lastwall)>0){
$lastwall = $lastwall[0];
$in_reply_to_status_id = NULL;
$in_reply_to_user_id = NULL;
$in_reply_to_status_id_str = NULL;
$in_reply_to_user_id_str = NULL;
$in_reply_to_screen_name = NULL;
if (intval($lastwall['parent']) != intval($lastwall['id'])) {
$in_reply_to_status_id= intval($lastwall['parent']);
$in_reply_to_status_id_str = (string) intval($lastwall['parent']);
$r = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s'", dbesc(normalise_link($lastwall['item-author'])));
if ($r) {
if ($r[0]['nick'] == "")
$r[0]['nick'] = api_get_nick($r[0]["url"]);
$in_reply_to_screen_name = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
$in_reply_to_user_id = intval($r[0]['id']);
$in_reply_to_user_id_str = (string) intval($r[0]['id']);
}
}
// There seems to be situation, where both fields are identical:
// https://github.com/friendica/friendica/issues/1010
// This is a bugfix for that.
if (intval($in_reply_to_status_id) == intval($lastwall['id'])) {
logger('api_status_show: this message should never appear: id: '.$lastwall['id'].' similar to reply-to: '.$in_reply_to_status_id, LOGGER_DEBUG);
$in_reply_to_status_id = NULL;
$in_reply_to_user_id = NULL;
$in_reply_to_status_id_str = NULL;
$in_reply_to_user_id_str = NULL;
$in_reply_to_screen_name = NULL;
}
$in_reply_to = api_in_reply_to($lastwall);
$converted = api_convert_item($lastwall);
@ -1171,11 +1186,11 @@
'text' => $converted["text"],
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'truncated' => false,
'in_reply_to_status_id' => $in_reply_to_status_id,
'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
'user' => $user_info,
$geo => NULL,
'coordinates' => "",
@ -1252,29 +1267,7 @@
if (count($lastwall)>0){
$lastwall = $lastwall[0];
$in_reply_to_status_id = NULL;
$in_reply_to_user_id = NULL;
$in_reply_to_status_id_str = NULL;
$in_reply_to_user_id_str = NULL;
$in_reply_to_screen_name = NULL;
if ($lastwall['parent']!=$lastwall['id']) {
$reply = q("SELECT `item`.`id`, `item`.`contact-id` as `reply_uid`, `contact`.`nick` as `reply_author`, `item`.`author-link` AS `item-author`
FROM `item`,`contact` WHERE `contact`.`id`=`item`.`contact-id` AND `item`.`id` = %d", intval($lastwall['parent']));
if (count($reply)>0) {
$in_reply_to_status_id = intval($lastwall['parent']);
$in_reply_to_status_id_str = (string) intval($lastwall['parent']);
$r = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s'", dbesc(normalise_link($reply[0]['item-author'])));
if ($r) {
if ($r[0]['nick'] == "")
$r[0]['nick'] = api_get_nick($r[0]["url"]);
$in_reply_to_screen_name = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
$in_reply_to_user_id = intval($r[0]['id']);
$in_reply_to_user_id_str = (string) intval($r[0]['id']);
}
}
}
$in_reply_to = api_in_reply_to($lastwall);
$converted = api_convert_item($lastwall);
@ -1287,14 +1280,14 @@
'text' => $converted["text"],
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'id' => intval($lastwall['contact-id']),
'id_str' => (string) $lastwall['contact-id'],
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
$geo => NULL,
'favorited' => $lastwall['starred'] ? true : false,
'statusnet_html' => $converted["html"],
@ -1333,9 +1326,9 @@
$userlist = array();
if (isset($_GET["q"])) {
$r = q("SELECT id FROM `gcontact` WHERE `name`='%s'", dbesc($_GET["q"]));
$r = q("SELECT id FROM `contact` WHERE `uid` = 0 AND `name` = '%s'", dbesc($_GET["q"]));
if (!count($r))
$r = q("SELECT `id` FROM `gcontact` WHERE `nick`='%s'", dbesc($_GET["q"]));
$r = q("SELECT `id` FROM `contact` WHERE `uid` = 0 AND `nick` = '%s'", dbesc($_GET["q"]));
if (count($r)) {
$k = 0;
@ -1381,7 +1374,6 @@
$user_info = api_get_user($a);
// get last newtork messages
// params
$count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
@ -2371,7 +2363,7 @@
//builtin_activity_puller($i, $activities);
// get user data and add it to the array of the activity
$user = api_get_user($a, $i['author-link']);
$user = api_get_user($a, $i['author-link']);
switch($i['verb']) {
case ACTIVITY_LIKE:
$activities['like'][] = $user;
@ -2485,43 +2477,7 @@
if ($filter_user AND ($status_user["id"] != $user_info["id"]))
continue;
if ($item['thr-parent'] != $item['uri']) {
$r = q("SELECT id FROM item WHERE uid=%d AND uri='%s' LIMIT 1",
intval(api_user()),
dbesc($item['thr-parent']));
if ($r)
$in_reply_to_status_id = intval($r[0]['id']);
else
$in_reply_to_status_id = intval($item['parent']);
$in_reply_to_status_id_str = (string) intval($item['parent']);
$in_reply_to_screen_name = NULL;
$in_reply_to_user_id = NULL;
$in_reply_to_user_id_str = NULL;
$r = q("SELECT `author-link` FROM item WHERE uid=%d AND id=%d LIMIT 1",
intval(api_user()),
intval($in_reply_to_status_id));
if ($r) {
$r = q("SELECT * FROM `gcontact` WHERE `url` = '%s'", dbesc(normalise_link($r[0]['author-link'])));
if ($r) {
if ($r[0]['nick'] == "")
$r[0]['nick'] = api_get_nick($r[0]["url"]);
$in_reply_to_screen_name = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
$in_reply_to_user_id = intval($r[0]['id']);
$in_reply_to_user_id_str = (string) intval($r[0]['id']);
}
}
} else {
$in_reply_to_screen_name = NULL;
$in_reply_to_user_id = NULL;
$in_reply_to_status_id = NULL;
$in_reply_to_user_id_str = NULL;
$in_reply_to_status_id_str = NULL;
}
$in_reply_to = api_in_reply_to($item);
$converted = api_convert_item($item);
@ -2534,14 +2490,14 @@
'text' => $converted["text"],
'truncated' => False,
'created_at'=> api_date($item['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'source' => (($item['app']) ? $item['app'] : 'web'),
'id' => intval($item['id']),
'id_str' => (string) intval($item['id']),
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
$geo => NULL,
'favorited' => $item['starred'] ? true : false,
'user' => $status_user ,
@ -2794,7 +2750,9 @@
$stringify_ids = (x($_REQUEST,'stringify_ids')?$_REQUEST['stringify_ids']:false);
$r = q("SELECT `gcontact`.`id` FROM `contact`, `gcontact` WHERE `contact`.`nurl` = `gcontact`.`nurl` AND `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` $sql_extra",
$r = q("SELECT `pcontact`.`id` FROM `contact`
INNER JOIN `contact` AS `pcontact` ON `contact`.`nurl` = `pcontact`.`nurl` AND `pcontact`.`uid` = 0
WHERE `contact`.`uid` = %s AND NOT `contact`.`self`",
intval(api_user())
);
@ -2889,7 +2847,7 @@
* @brief delete a direct_message from mail table through api
*
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string
* @return string
*/
function api_direct_messages_destroy($type){
$a = get_app();
@ -3266,10 +3224,10 @@
}
$attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
// Skip if there is no shared message in there
// we already checked this in diaspora::is_reshare()
// but better one more than one less...
if ($body == $attributes)
// Skip if there is no shared message in there
// we already checked this in diaspora::is_reshare()
// but better one more than one less...
if ($body == $attributes)
return false;
@ -3348,7 +3306,7 @@
$nick = "";
$r = q("SELECT `nick` FROM `gcontact` WHERE `nurl` = '%s'",
$r = q("SELECT `nick` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s'",
dbesc(normalise_link($profile)));
if ($r)
$nick = $r[0]["nick"];
@ -3407,6 +3365,60 @@
return(false);
}
function api_in_reply_to($item) {
$in_reply_to = array();
$in_reply_to['status_id'] = NULL;
$in_reply_to['user_id'] = NULL;
$in_reply_to['status_id_str'] = NULL;
$in_reply_to['user_id_str'] = NULL;
$in_reply_to['screen_name'] = NULL;
if (($item['thr-parent'] != $item['uri']) AND (intval($item['parent']) != intval($item['id']))) {
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
intval($item['uid']),
dbesc($item['thr-parent']));
if (dbm::is_result($r)) {
$in_reply_to['status_id'] = intval($r[0]['id']);
} else {
$in_reply_to['status_id'] = intval($item['parent']);
}
$in_reply_to['status_id_str'] = (string) intval($in_reply_to['status_id']);
$r = q("SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM item
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id`
WHERE `item`.`id` = %d LIMIT 1",
intval($in_reply_to['status_id'])
);
if (dbm::is_result($r)) {
if ($r[0]['nick'] == "") {
$r[0]['nick'] = api_get_nick($r[0]["url"]);
}
$in_reply_to['screen_name'] = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
$in_reply_to['user_id'] = intval($r[0]['id']);
$in_reply_to['user_id_str'] = (string) intval($r[0]['id']);
}
// There seems to be situation, where both fields are identical:
// https://github.com/friendica/friendica/issues/1010
// This is a bugfix for that.
if (intval($in_reply_to['status_id']) == intval($item['id'])) {
logger('this message should never appear: id: '.$item['id'].' similar to reply-to: '.$in_reply_to['status_id'], LOGGER_DEBUG);
$in_reply_to['status_id'] = NULL;
$in_reply_to['user_id'] = NULL;
$in_reply_to['status_id_str'] = NULL;
$in_reply_to['user_id_str'] = NULL;
$in_reply_to['screen_name'] = NULL;
}
}
return $in_reply_to;
}
function api_clean_plain_items($Text) {
$include_entities = strtolower(x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:"false");
@ -3893,7 +3905,7 @@
$user_info = api_get_user($a);
$searchstring = (x($_REQUEST,'searchstring') ? $_REQUEST['searchstring'] : "");
$uid = $user_info['uid'];
// error if no searchstring specified
if ($searchstring == "") {
$answer = array('result' => 'error', 'message' => 'searchstring not specified');