fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2011-05-17 04:02 am

[dw-free] http://bugs.dwscoalition.org/show_bug.cgi?id=3641

[commit: http://hg.dwscoalition.org/dw-free/rev/40cdb938430c]

http://bugs.dwscoalition.org/show_bug.cgi?id=3641

Better caching, and short-circuit when we hit something in the cache.

Patch by [personal profile] fu.

Files modified:
  • cgi-bin/LJ/Comment.pm
  • cgi-bin/LJ/S2.pm
  • htdocs/talkread.bml
  • t/subscription-nested.t
--------------------------------------------------------------------------------
diff -r 116559a9f5bb -r 40cdb938430c cgi-bin/LJ/Comment.pm
--- a/cgi-bin/LJ/Comment.pm	Tue May 17 10:20:10 2011 +0800
+++ b/cgi-bin/LJ/Comment.pm	Tue May 17 10:38:49 2011 +0800
@@ -1086,6 +1086,54 @@
     };
 }
 
+sub thread_has_subscription {
+    my ( $comment, $remote, $u ) = @_;
+
+    my @unknown_tracking_status;
+    my $watched = 0;
+
+    while ( $comment && $comment->valid && $comment->parenttalkid ) {
+        # check cache
+        $comment->{_watchedby} ||= {};
+        my $thread_watched = $comment->{_watchedby}->{$u->{userid}};
+
+        my $had_cached = defined $thread_watched;
+
+        unless ( $had_cached ) {
+            $thread_watched = $remote->has_subscription(
+                                event   => "JournalNewComment",
+                                journal => $u,
+                                arg2    => $comment->parenttalkid,
+                                require_active => 1,
+                                );
+        }
+
+        if ( $thread_watched ) {
+            $watched = 1;
+
+            # we had to go up a couple of levels before we could figure out
+            # whether we were watching or not
+            # so fix the status of intervening levels
+            foreach ( @unknown_tracking_status ) {
+                my $c = LJ::Comment->new( $u, dtalkid => $_ );
+                $c->{_watchedby}->{$u->{userid}} = $thread_watched;
+            }
+            @unknown_tracking_status = ();
+        }
+
+        # cache in this comment object if it's being watched by this user
+        $comment->{_watchedby}->{$u->{userid}} = $thread_watched;
+
+        # shortcircuit and stop going up the tree because:
+        last if $thread_watched;    # current comment is watched
+        last if $had_cached;        # we've been to this section of the ancestor tree already
+
+        push @unknown_tracking_status, $comment->dtalkid;
+        $comment = $comment->parent;
+    }
+
+    return $watched;
+}
 sub indent {
     return LJ::Talk::Post::indent(@_);
 }
diff -r 116559a9f5bb -r 40cdb938430c cgi-bin/LJ/S2.pm
--- a/cgi-bin/LJ/S2.pm	Tue May 17 10:20:10 2011 +0800
+++ b/cgi-bin/LJ/S2.pm	Tue May 17 10:38:49 2011 +0800
@@ -3271,24 +3271,7 @@
         # in other words, the user is not subscribed to this particular comment
 
         # see if any parents are being watched
-        my $watching_parent = 0;
-        while ($comment && $comment->valid && $comment->parenttalkid) {
-            # check cache
-            $comment->{_watchedby} ||= {};
-            my $thread_watched = $comment->{_watchedby}->{$u->{userid}};
-
-            # not cached
-            if (! defined $thread_watched) {
-                $thread_watched = $remote->has_subscription(journal => $u, event => "JournalNewComment", arg2 => $comment->parenttalkid);
-            }
-
-            $watching_parent = 1 if ($thread_watched);
-
-            # cache in this comment object if it's being watched by this user
-            $comment->{_watchedby}->{$u->{userid}} = $thread_watched;
-
-            $comment = $comment->parent;
-        }
+        my $watching_parent = $comment->thread_has_subscription( $remote, $u );
 
         my $etypeid = 'LJ::Event::JournalNewComment'->etypeid;
         my %subparams = (
diff -r 116559a9f5bb -r 40cdb938430c htdocs/talkread.bml
--- a/htdocs/talkread.bml	Tue May 17 10:20:10 2011 +0800
+++ b/htdocs/talkread.bml	Tue May 17 10:38:49 2011 +0800
@@ -535,28 +535,7 @@
                         $track_img = 'track_active';
                     } else {
                         # see if any parents are being watched
-                        while ($comment && $comment->valid && $comment->parenttalkid) {
-                            # check cache
-                            $comment->{_watchedby} ||= {};
-                            my $thread_watched = $comment->{_watchedby}->{$u->{userid}};
-
-                            # not cached
-                            if (! defined $thread_watched) {
-                                $thread_watched = $remote->has_subscription(
-                                                                            event   => "JournalNewComment",
-                                                                            journal => $u,
-                                                                            arg2    => $comment->parenttalkid,
-                                                                            require_active => 1,
-                                                                            );
-                            }
-
-                            $track_img = 'track_thread_active' if ($thread_watched);
-
-                            # cache in this comment object if it's being watched by this user
-                            $comment->{_watchedby}->{$u->{userid}} = $thread_watched;
-
-                            $comment = $comment->parent;
-                        }
+                        $track_img = 'track_thread_active' if $comment->thread_has_subscription( $remote, $u );
                     }
 
                     my $track_url = "$LJ::SITEROOT/manage/tracking/comments?journal=$u->{'user'}&talkid=$dtid";
diff -r 116559a9f5bb -r 40cdb938430c t/subscription-nested.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t/subscription-nested.t	Tue May 17 10:38:49 2011 +0800
@@ -0,0 +1,86 @@
+use strict;
+use Test::More;
+use lib "$ENV{LJHOME}/cgi-bin";
+require 'ljlib.pl';
+
+use LJ::Comment;
+use LJ::Talk;
+use LJ::Test qw( temp_user );
+
+sub check_thread_subscription {
+    my ( $entry, $u, $no_sub ) = @_;
+
+    subtest "checking thread subscription" => sub {
+        my $time = time();
+        my @comments = $entry->comment_list;
+
+        foreach my $comment ( @comments ) {
+            my $time = time();
+            my $has_sub = $comment->thread_has_subscription( $u, $entry->journal );
+
+            if ( $no_sub->{$comment->jtalkid} ) {
+                ok( ! $has_sub, $no_sub->{$comment->jtalkid} );
+            } else {
+                ok( $has_sub, "ancestor of " . $comment->jtalkid . " is tracked" );
+            }
+        }
+    }
+}
+
+note("shallow comment threads");
+{
+    my $u = temp_user();
+    my $e = $u->t_post_fake_entry;
+
+    my @comments;
+    my $c = $e->t_enter_comment;
+    push @comments, $c;
+
+    foreach ( 1...10 ) {
+        $c = $c->t_reply;
+        push @comments, $c;
+    }
+
+    $u->subscribe(  event   => "JournalNewComment",
+                    method  => "Email",
+                    journal => $u,
+                    arg2    => $comments[2]->jtalkid,
+                  );
+
+    check_thread_subscription( $e, $u, {
+        # not subscribed to #     because....
+        1                     =>  "above subscription point",
+        2                     =>  "above subscription point",
+        3                     =>  "subscribed starting from this comment (but not subscribed to ancestor)",
+    } );
+}
+
+note("deep comment thread");
+{
+    my $u = temp_user();
+    my $e = $u->t_post_fake_entry;
+
+    my @comments;
+    my $c = $e->t_enter_comment;
+    push @comments, $c;
+
+    foreach ( 1...500 ) {
+        $c = $c->t_reply;
+        push @comments, $c;
+    }
+
+    $u->subscribe(  event   => "JournalNewComment",
+                    method  => "Email",
+                    journal => $u,
+                    arg2    => $comments[2]->jtalkid,
+                  );
+
+    check_thread_subscription( $e, $u, {
+        # not subscribed to #     because....
+        1                     =>  "above subscription point",
+        2                     =>  "above subscription point",
+        3                     =>  "subscribed starting from this comment (but not subscribed to ancestor)",
+    } );
+}
+
+done_testing();
--------------------------------------------------------------------------------

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org