Committer: vsukhanov
LJSUP-6730: add some AI to friends counter handling.U trunk/cgi-bin/LJ/User.pm U trunk/cgi-bin/ljprotocol.pl
Modified: trunk/cgi-bin/LJ/User.pm =================================================================== --- trunk/cgi-bin/LJ/User.pm 2010-09-06 10:15:50 UTC (rev 17292) +++ trunk/cgi-bin/LJ/User.pm 2010-09-06 11:28:56 UTC (rev 17293) @@ -3208,6 +3208,14 @@ return $u->{journaltype} eq "I"; } +## Can we add this account to someone's friendsOf list +sub can_be_counted_as_friendof { + my $u = shift; + return 0 unless $u->statusvis =~ /^[VML]$/o; + return 0 unless $u->journaltype =~ /^[PI]$/o; + return 1; +} + ## We trust OpenID users if they are either from trusted OpenID provider or ## have e-mail validated. During e-mail validation, they answer CAPTCHA test. ## Trusted OpenID users are like registered user, untrusted are like anonymous @@ -4413,11 +4421,11 @@ } ## Returns exact friendsOf count. Whitout limit. +## Use it with care. sub precise_friendsof_count { my $u = shift; - ## TODO: add caching here - my $ckey = [ $u->userid, "friendof:precise_cnt:" . $u->userid ]; + my $ckey = [ $u->userid, "friendof:person_cnt:" . $u->userid ]; my $cached = LJ::MemCache::get($ckey); return $cached if defined $cached; @@ -4431,21 +4439,75 @@ foreach my $fuid (@uid_batch){ my $fu = $us->{$fuid}; next unless $fu; - my $status = $u->statusvis; - next unless $u->statusvis =~ /^[VML]$/o; - next unless $u->journaltype =~ /^[PI]$/o; + next unless $fu->can_be_counted_as_friendof; ## Friend!!! $res++; } } - + + ## actual data LJ::MemCache::set($ckey => $res); + LJ::MemCache::set([ $u->userid, "friendof:person_cnt:added:" . $u->userid ], time()); ## and it's age + return $res; } +## Class method +sub increase_friendsof_counter { + my $class = shift; + my $uid = shift; + $class->_incr_decr_friendsof_counter($uid, 'incr'); +} +sub decrease_friendsof_counter { + my $class = shift; + my $uid = shift; + $class->_incr_decr_friendsof_counter($uid, 'decr'); +} +sub _incr_decr_friendsof_counter { + my $class = shift; + my $uid = shift; + my $action = shift; + ## it takes a lot of time (>5 seconds) to calculate 'friendof:person_cnt:X' counter. + ## So update it with a bit of intellect. + my $precise_friendsof_counter = [ $uid, "friendof:person_cnt:$uid" ]; + my $precise_frof_cnt_added = [ $uid, "friendof:person_cnt:added:$uid" ]; + my $vals = LJ::MemCache::get_multi($precise_friendsof_counter, $precise_frof_cnt_added); + + my $counter = $vals->{"friendof:person_cnt:$uid"}; + my $added = $vals->{"friendof:person_cnt:added:$uid"}; + + if ($counter and $added){ + if ($added < time - 24*3600){ + ## flush data to avoid long-life accumulation of errors + LJ::MemCache::delete($precise_friendsof_counter); + + } else { + ## just increment counter. + ## + ## Much better to use CAS operation here. But original perl Cache::Memcached client + ## does not provide appropriate functionality. + ## we use two memcache keys instead: + ## - one as lifetime mark ('friendof:person_cnt:added:$fid') + ## - other as counter value ('friendof:person_cnt:$fid') + ## + my $u = LJ::load_userid($uid); + if ($u->can_be_counted_as_friendof){ + ## update memcached value + if ($action eq 'incr'){ + LJ::MemCache::incr($precise_friendsof_counter); + } elsif ($action eq 'decr'){ + LJ::MemCache::decr($precise_friendsof_counter); + } + } + + } + } + +} + sub fb_push { my $u = shift; eval { @@ -5605,7 +5667,6 @@ return $count; } - package LJ; use Carp; @@ -7927,6 +7988,7 @@ if (!$dbh->err && $cnt == 1) { LJ::run_hooks('befriended', $friender, LJ::load_userid($add_id)) + LJ::User->increase_friendsof_counter($fid); } } @@ -7937,7 +7999,6 @@ # delete friend-of memcache keys for anyone who was added foreach my $fid (@add_ids) { LJ::MemCache::delete([ $userid, "frgmask:$userid:$fid" ]); - LJ::MemCache::delete([ $fid, "friendof:precise_cnt:$fid" ]); LJ::memcache_kill($fid, 'friendofs'); LJ::memcache_kill($fid, 'friendofs2'); @@ -7993,6 +8054,7 @@ if (!$dbh->err && $cnt > 0) { LJ::run_hooks('defriended', $u, LJ::load_userid($del_id)); + LJ::User->decrease_friendsof_counter($del_id); } } @@ -8004,7 +8066,6 @@ # delete friend-of memcache keys for anyone who was removed foreach my $fid (@del_ids) { LJ::MemCache::delete([ $userid, "frgmask:$userid:$fid" ]); - LJ::MemCache::delete([ $fid, "friendof:precise_cnt:$fid" ]); LJ::memcache_kill($fid, 'friendofs'); LJ::memcache_kill($fid, 'friendofs2'); Modified: trunk/cgi-bin/ljprotocol.pl =================================================================== --- trunk/cgi-bin/ljprotocol.pl 2010-09-06 10:15:50 UTC (rev 17292) +++ trunk/cgi-bin/ljprotocol.pl 2010-09-06 11:28:56 UTC (rev 17293) @@ -2864,6 +2864,7 @@ if ($cnt == 1) { LJ::run_hooks('befriended', LJ::load_userid($userid), LJ::load_userid($friendid)); + LJ::User->increase_friendsof_counter($friendid); } my $memkey = [$userid,"frgmask:$userid:$friendid"];