Buddylist is unbelievably taxing in a situation where buddylist_get_buddies() is called in a large social network. Simply put, eventually buddylist_get_buddies() effectively loads all the users in the entire extended network a single user. We have a site where a single call to buddylist_get_buddies() generates over 20,000 queries!! The user had about 600 buddies, and the result was crippling.
Here's a rundown of what happens:
- A single user is loaded via user_load().
- Buddylist's hook_user calls buddylist_get_buddies() to set the return to $user->buddies
- In buddylist_get_buddies(), every user that is a buddy of the original user is loaded.
- Buddylist's hook_user calls buddylist_get_buddies() to set the return to the buddy's $user->buddies
- Cycle continues until every user that is a buddy of any user is loaded.
So this is a minor fix that gives a drastic improvement in performance. This convenience of having $user->buddies simply isn't feasible. Especially considering buddylist already provides handy functions like buddylist_get_buddylist() that make the need for these users to be there all the time unnecessary.
Comment | File | Size | Author |
---|---|---|---|
buddylist_remove_user_load.patch | 928 bytes | quicksketch |
Comments
Comment #1
joshk CreditAttribution: joshk commentedI see the issue here, and this clearly has to get solved for this module to scale.
However, tearing it out will likely break a lot of sites that depend on it for simple functionality, so this change would likely need to be acoompanieid by a branch and some documentation.
I'd like to be able to make this change. Perhaps as part of a new branch to begin working towards a better/stronger/faster drupal 6 version?
Comment #2
quicksketchA new branch sounds optimal for this change, a clear API breakage. We definitely should also start a changelog, and begin following these changes between 1.x and 2.x.
Comment #3
dldege CreditAttribution: dldege commentedHi Gang,
Sorry I've dropped of the buddylist planet for quite awhile - I've seen this issue before and I removed that code from my own local copy. What about making this a variable_get() driven behavior that way it can be disabled yet preserve the API?
I'm mostly commening because I see mention of doing a Drupal 6 version - has something changed with buddylist 2 - I was sort of under the impression this version of the module was going to fade away. If plans are being made to do a new version of this code for 6 I'd be interested and I'd suggest a complete rewrite. This code base is a mess and could be way better and simpler.
Cheers!
Comment #4
joshk CreditAttribution: joshk commentedFollowing up better late than never, I actually don't see this. There's no user_load in buddylist_get_buddies(), which would be the cause of such recursion:
I'll keep an eye on this as we work towards 6.0 though. Please update me if I'm wrong here.
Comment #5
quicksketchOh... looks like I've misdirected my hostility. buddylist_get_buddylist() is the function that contains a user_load(), not buddylist_get_buddies(). Hmm, I'm not sure there's a problem here after all.
On our particular site, our User #1 was automatically friending all new users (similar to a mySpace scenario). What we were seeing was the individual queries caused by the buddy-groups option (which does an individual SQL query per user in the list during buddylist_get_buddies()).
Well, I don't think this is the problem I thought it was. Simultaneously, I still feel it's wasted queries to call buddylist_get_buddies on every user_load(). The function is easy enough I can call it manually whenever needed. So I'd still vouch for including this patch, even though it's not the nightmare that I thought it was.
Comment #6
apotek CreditAttribution: apotek commentedThis is definitely an issue. On our site, there was no way to keep it live without doing this:
function buddylist_user($type, &$edit, &$thisuser, $category = NULL) {
....
else if ($type == 'load') {
/** @logomod, LOGOT-349: Kill the module invoke all hook_user load cycle for the buddylist module so a user's buddies aren't loaded every time the user is loaded.
$thisuser->buddies = buddylist_get_buddies($thisuser->uid);
*/
}
...
The things is that for every buddy of user A, each buddy triggers the hook _user with $type 'load', which means that for each and every buddy of user A, all the buddies of user A's buddies also get loaded. There's a non-linear collapse of scalability here.
Huge +1 from me.