Committer: ailyin
LJSUP-11496 (optimize get_daycounts for ONTD)U trunk/cgi-bin/LJ/DelayedEntry.pm U trunk/cgi-bin/LJ/Entry.pm U trunk/cgi-bin/LJ/User.pm U trunk/cgi-bin/ljprotocol.pl
Modified: trunk/cgi-bin/LJ/DelayedEntry.pm =================================================================== --- trunk/cgi-bin/LJ/DelayedEntry.pm 2012-03-11 14:35:54 UTC (rev 21342) +++ trunk/cgi-bin/LJ/DelayedEntry.pm 2012-03-11 15:03:24 UTC (rev 21343) @@ -1053,20 +1053,6 @@ return \@tags_array; } -sub __kill_dayct2_cache { - my ($u) = @_; - my $uid = LJ::want_userid($u) or return undef; - - my $memkey = [$uid, "dayct2:$uid:p"]; - LJ::MemCache::delete($memkey); - - $memkey = [$uid, "dayct2:$uid:a"]; - LJ::MemCache::delete($memkey); - - $memkey = [$uid, "dayct2:$uid:g"]; - LJ::MemCache::delete($memkey); -} - sub __statistics_absorber { my ($journal, $poster) = @_; Modified: trunk/cgi-bin/LJ/Entry.pm =================================================================== --- trunk/cgi-bin/LJ/Entry.pm 2012-03-11 14:35:54 UTC (rev 21342) +++ trunk/cgi-bin/LJ/Entry.pm 2012-03-11 15:03:24 UTC (rev 21343) @@ -2503,7 +2503,6 @@ my $dc = $u->log2_do(undef, "DELETE FROM log2 WHERE journalid=$jid AND jitemid=$jitemid $and"); LJ::MemCache::delete([$jid, "log2:$jid:$jitemid"]); LJ::MemCache::decr([$jid, "log2ct:$jid"]) if $dc > 0; - LJ::memcache_kill($jid, "dayct2"); if ( $jitemid == $u->get_sticky_entry_id() ){ $u->remove_sticky_entry_id(); Modified: trunk/cgi-bin/LJ/User.pm =================================================================== --- trunk/cgi-bin/LJ/User.pm 2012-03-11 14:35:54 UTC (rev 21342) +++ trunk/cgi-bin/LJ/User.pm 2012-03-11 15:03:24 UTC (rev 21343) @@ -6607,7 +6607,7 @@ my $u = shift; my $userid = LJ::want_userid($u); foreach my $key ("userid","bio","talk2ct","log2ct", - "log2lt","memkwid","dayct2","s1overr","s1uc","fgrp", + "log2lt","memkwid","s1overr","s1uc","fgrp", "friends","friendofs","tu","upicinf","upiccom", "upicurl", "intids", "memct", "lastcomm") { @@ -8184,41 +8184,41 @@ # non-zero count. examples: # [ [ 2003, 6, 5, 3 ], [ 2003, 6, 8, 4 ], ... ] # -sub get_daycounts -{ - my ($u, $remote) = @_; - my $uid = LJ::want_userid($u) or return undef; +sub get_daycounts { + my ( $u, $remote ) = @_; - my $memkind = 'p'; # public only, changed below - my $secwhere = "AND security='public'"; - my $viewall = 0; + # ['public'], ['all'], or [ 'gmask', $gmask ] + my $kind; if ($remote) { - # do they have the viewall priv? - my %getargs = eval { LJ::Request->args } || (); # eval for check web context - if (defined $getargs{'viewall'} and $getargs{'viewall'} eq '1' and LJ::check_priv($remote, 'canview', '*')) { + my $viewall = 0; + if ( LJ::is_web_context() && LJ::Request->get_param('viewall') && + LJ::check_priv( $remote, 'canview', '*' ) ) + { $viewall = 1; LJ::statushistory_add($u->{'userid'}, $remote->{'userid'}, "viewall", "calendar"); } - if ($remote->{'userid'} == $uid || $viewall) { - $secwhere = ""; # see everything - $memkind = 'a'; # all - } elsif ($remote->{'journaltype'} eq 'P') { - my $gmask = LJ::get_groupmask($u, $remote); - if ($gmask) { - $secwhere = "AND (security='public' OR (security='usemask' AND allowmask & $gmask))"; - $memkind = 'g' . $gmask; # friends case: allowmask == gmask == 1 + if ( LJ::u_equals( $u, $remote ) ) { + $kind = ['all']; + } else { + if ( my $gmask = LJ::get_groupmask($u, $remote) ) { + # friends case: allowmask == gmask == 1 + $kind = [ 'gmask', $gmask ]; + } else { + $kind = ['public']; } } + } else { + $kind = ['public']; } ## - ## the first element of array, that is stored in memcache, - ## is the time of the creation of the list. The memcache is + ## the first element of the array stored in memcache + ## is the time of the creation of the list. The memcache is ## invalid if there are new entries in journal since that time. ## - my $memkey = [$uid, "dayct2:$uid:$memkind"]; + my $memkey = [ $u->userid, join( ':', 'dayct3', $u->userid, @$kind ) ]; my $list = LJ::MemCache::get($memkey); if ($list) { my $list_create_time = shift @$list; @@ -8229,7 +8229,9 @@ ## get lock to prevent multiple apache processes to execute the sql below. ## one process runs, the other wait for results - my $release_lock = sub { $dbcr->selectrow_array("SELECT RELEASE_LOCK('$memkey')"); }; + my $release_lock = sub { + $dbcr->selectrow_array("SELECT RELEASE_LOCK('$memkey')"); + }; my $locked = $dbcr->selectrow_array("SELECT GET_LOCK('$memkey',10)"); return unless $locked; ## 10 seconds expired @@ -8243,22 +8245,128 @@ } } + if ( LJ::is_enabled( 'dayct_month', $u ) ) { + $release_lock->(); + my ( $min_year, $max_year ) = $dbcr->selectrow_array( + 'SELECT MIN(year), MAX(year) FROM log2 WHERE journalid=?', + undef, $u->userid ); + + my $days = []; + + foreach my $year ( $min_year .. $max_year ) { + foreach my $month ( 1 .. 12 ) { + my $month_daycounts = + get_month_daycounts( $u, $kind, $year, $month ); + push @$days, @$month_daycounts; + } + } + + LJ::MemCache::set( $memkey, [ time, @$days ] ); + return $days; + } + + my ( $selecttype, $gmask ) = @$kind; + my $secwhere; + if ( $selecttype eq 'all' ) { + $secwhere = ''; + } elsif ( $selecttype eq 'public' ) { + $secwhere = 'AND security="public"'; + } elsif ( $selecttype eq 'gmask' ) { + $secwhere = "AND ( security='public' OR " . + "(security='usemask' AND allowmask & $gmask) )"; + } + my $sth = $dbcr->prepare("SELECT year, month, day, COUNT(*) ". - "FROM log2 WHERE journalid=? $secwhere GROUP BY 1, 2, 3"); - $sth->execute($uid); - my @days; - while (my ($y, $m, $d, $c) = $sth->fetchrow_array) { + "FROM log2 WHERE journalid=? $secwhere " . + "GROUP BY year, month, day"); + $sth->execute( $u->userid ); + my $days = []; + while ( my ( $y, $m, $d, $c ) = $sth->fetchrow_array ) { # we force each number from string scalars (from DBI) to int scalars, # so they store smaller in memcache - push @days, [ int($y), int($m), int($d), int($c) ]; + push @$days, [ int($y), int($m), int($d), int($c) ]; } - LJ::MemCache::set($memkey, [time, @days]); + LJ::MemCache::set( $memkey, [time, @$days] ); $release_lock->(); - return \@days; + return $days; } +sub get_month_daycounts { + my ( $u, $kind, $year, $month ) = @_; + + my $memkind = join( ':', @$kind ); + + ## + ## the first element of the array stored in memcache + ## is the time of the creation of the list. The memcache is + ## invalid if there are new entries in journal since that time. + ## + my $memkey = [ $u->userid, + join( ':', 'dayct3', 'month', $year, $month, $u->userid, @$kind ) ]; + + my $list = LJ::MemCache::get($memkey); + if ($list) { + my $list_create_time = shift @$list; + + my $timeupdate = $u->timeupdate; + my $timeupdate_year = ( gmtime $timeupdate )[5] + 1900; + my $timeupdate_month = ( gmtime $timeupdate )[4] + 1; + + return $list if $timeupdate_year != $year || + $timeupdate_month != $month || + $u->timeupdate <= $list_create_time; + } + + my $dbcr = LJ::get_cluster_def_reader($u) or return; + + ## get lock to prevent multiple apache processes to execute the sql below. + ## one process runs, the other wait for results + my $release_lock = sub { + $dbcr->selectrow_array("SELECT RELEASE_LOCK('$memkey')"); + }; + my $locked = $dbcr->selectrow_array("SELECT GET_LOCK('$memkey',10)"); + return unless $locked; ## 10 seconds expired + + $list = LJ::MemCache::get($memkey); + if ($list) { + ## other process may have filled the data while we waited for the lock + my $list_create_time = shift @$list; + $release_lock->(); + return $list; + } + + my ( $selecttype, $gmask ) = @$kind; + my $secwhere; + if ( $selecttype eq 'all' ) { + $secwhere = ''; + } elsif ( $selecttype eq 'public' ) { + $secwhere = 'AND security="public"'; + } elsif ( $selecttype eq 'gmask' ) { + $secwhere = "AND ( security='public' OR " . + "(security='usemask' AND allowmask & $gmask) )"; + } + + my $sth = $dbcr->prepare("SELECT day, COUNT(*) ". + "FROM log2 WHERE journalid=? $secwhere AND " . + "year=? AND month=? " . + "GROUP BY day"); + $sth->execute( $u->userid, $year, $month ); + my $days = []; + while ( my ( $d, $c ) = $sth->fetchrow_array ) { + # we force each number from string scalars (from DBI) to int scalars, + # so they store smaller in memcache + push @$days, [ int($year), int($month), int($d), int($c) ]; + } + + my $exptime = 3600 + int( rand(3600) ); + LJ::MemCache::set( $memkey, [time, @$days], $exptime ); + + $release_lock->(); + return $days; +} + ## input: $u, $remote, $year, $month ## output: hashref with data for rendering calendar for given month, ## days: arrayref [ count of entries for each day] Modified: trunk/cgi-bin/ljprotocol.pl =================================================================== --- trunk/cgi-bin/ljprotocol.pl 2012-03-11 14:35:54 UTC (rev 21342) +++ trunk/cgi-bin/ljprotocol.pl 2012-03-11 15:03:24 UTC (rev 21343) @@ -2598,7 +2598,6 @@ } LJ::MemCache::incr([$ownerid, "log2ct:$ownerid"]); - LJ::memcache_kill($ownerid, "dayct2"); # set userprops. { @@ -3316,8 +3315,6 @@ } return fail($err,501,$dbcm->errstr) if $dbcm->err; - LJ::memcache_kill($ownerid, "dayct2"); - if (defined $oldevent->{'anum'}) { $res->{'anum'} = $oldevent->{'anum'}; $res->{'url'} = LJ::item_link($uowner, $itemid, $oldevent->{'anum'});