Patch by mark. 

diffs (316 lines):

diff -r b7370be6d607 -r b2c0b0b8bf11 bin/upgrading/update-db-general.pl
--- a/bin/upgrading/update-db-general.pl        Thu Sep 03 17:21:35 2009 +0000
+++ b/bin/upgrading/update-db-general.pl        Thu Sep 03 21:58:25 2009 +0000
@@ -974,6 +974,7 @@ register_tabledrop("adopt");
 register_tabledrop("adopt");
 register_tabledrop("adoptlast");
 register_tabledrop("urimap");
+register_tabledrop("syndicated_hubbub");
 
 register_tablecreate("portal", <<'EOC');
 CREATE TABLE portal (
@@ -1388,18 +1389,22 @@ CREATE TABLE syndicated (
 )
 EOC
 
-register_tablecreate("syndicated_hubbub", <<'EOC');
-CREATE TABLE syndicated_hubbub (
+register_tablecreate("syndicated_hubbub2", <<'EOC');
+CREATE TABLE syndicated_hubbub2 (
+    id INT UNSIGNED NOT NULL,
     userid INT UNSIGNED NOT NULL,
-    huburl VARCHAR(255),
-    topicurl VARCHAR(255),
+    huburl VARCHAR(255) NOT NULL,
+    topicurl VARCHAR(255) NOT NULL,
+    verifytoken VARCHAR(64) NOT NULL,
+    lastseenat INT UNSIGNED NOT NULL,
     leasegoodto INT UNSIGNED,
-    verifytoken VARCHAR(64),
 
+    UNIQUE (userid, huburl, topicurl),
     UNIQUE (verifytoken),
-    UNIQUE (topicurl),
+    INDEX (topicurl),
     INDEX (leasegoodto),
-    PRIMARY KEY (userid)
+    INDEX (lastseenat),
+    PRIMARY KEY (id)
 )
 EOC
 
diff -r b7370be6d607 -r b2c0b0b8bf11 bin/worker/subscribe-hubbub
--- a/bin/worker/subscribe-hubbub       Thu Sep 03 17:21:35 2009 +0000
+++ b/bin/worker/subscribe-hubbub       Thu Sep 03 21:58:25 2009 +0000
@@ -55,8 +55,8 @@ sub work {
 
     # find tasks that need doing that are owned by users that are visible
     my $rows = $dbh->selectall_arrayref(
-        q{SELECT s.userid, s.huburl, s.topicurl, s.verifytoken, s.leasegoodto
-          FROM user u, syndicated_hubbub s
+        q{SELECT s.id, s.userid, s.huburl, s.topicurl, s.verifytoken, 
s.leasegoodto
+          FROM user u, syndicated_hubbub2 s
           WHERE u.userid = s.userid AND u.statusvis = 'V'
             AND (s.leasegoodto IS NULL OR s.leasegoodto < (UNIX_TIMESTAMP() + 
1800))
           LIMIT 500}
@@ -65,7 +65,7 @@ sub work {
 
     # iterate over tasks
     foreach my $row ( @$rows ) {
-        my ( $userid, $huburl, $topicurl, $verifytoken, $leasegoodto ) = @$row;
+        my ( $id, $userid, $huburl, $topicurl, $verifytoken, $leasegoodto ) = 
@$row;
         my $u = LJ::load_userid( $userid ) or next;
 
         print "[$$] Subscribing to " . $u->user . "(" . $u->id . ")\n";
@@ -85,12 +85,18 @@ sub work {
         # no matter what happens, bump the lease time artificially so
         # we won't retry every time this loop runs.  if the hub verifies
         # our subscription, the lease time will be set properly.
-        $dbh->do( 'UPDATE syndicated_hubbub SET leasegoodto = UNIX_TIMESTAMP() 
+ ?',
-                  undef, int( rand() * 3600 ) + 3600 );  # 1-2 hours random
+        $dbh->do( 'UPDATE syndicated_hubbub2 SET leasegoodto = 
UNIX_TIMESTAMP() + ? WHERE id = ?',
+                  undef, int( rand() * 3600 ) + 3600, $id );  # 1-2 hours 
random
 
         # be verbose
         print "             == " . $res->code . " " . $res->message . "\n";
     }
+
+    # now the other half of life: removing stale subscriptions.  we keep track 
of every
+    # time we see a feed reference a (userid, huburl, topicurl) combination.  
if one of those
+    # stops getting referenced for some period of time (24 hours?) then we 
should consider
+    # that subscription to be invalid.  (and in fact, we should unsubscribe.)
+    # FIXME: implement this ;)
 }
 
 
diff -r b7370be6d607 -r b2c0b0b8bf11 cgi-bin/LJ/SynSuck.pm
--- a/cgi-bin/LJ/SynSuck.pm     Thu Sep 03 17:21:35 2009 +0000
+++ b/cgi-bin/LJ/SynSuck.pm     Thu Sep 03 21:58:25 2009 +0000
@@ -158,9 +158,18 @@ sub process_content {
         return;
     }
 
-    # register feeds that can support hubbub
+    # register feeds that can support hubbub.
     if ( LJ::is_enabled( 'hubbub' ) && $feed->{self} && $feed->{hub} ) {
-        register_hubbub_feed( $userid, $feed->{self}, $feed->{hub} );
+        # this is a square operation.  register every "self" and the feed url 
along
+        # with the $synurl with every hub they say they talk to.  but for 
sanity,
+        # don't let them force us onto more than 10 subscriptions...
+        my $ct = 0;
+        foreach my $topic ( $synurl, @{ $feed->{self} } ) {
+            foreach my $hub ( @{ $feed->{hub} } ) {
+                last if $ct++ >= 10;
+                register_hubbub_feed( $userid, $topic, $hub );
+            }
+        }
     }
 
     # another sanity check
@@ -463,24 +472,29 @@ sub register_hubbub_feed {
     my $dbh = LJ::get_db_writer() or return;
     my $u = LJ::load_userid( $uid ) or return;
 
-    # if it exists, we need to know if we should be changing the record.  
i.e., if the
-    # feed changes its topic url, or hub, then we want to update this record 
so that the
-    # subscription system picks up on it.
+    # since we can have many records for a given feed, we want to see if we 
have an exact
+    # match for this particular combination.
     my $row = $dbh->selectrow_hashref(
-        q{SELECT huburl, topicurl, leasegoodto, verifytoken
-          FROM syndicated_hubbub WHERE userid = ?},
-        undef, $u->id
+        q{SELECT id, huburl, topicurl, leasegoodto, verifytoken
+          FROM syndicated_hubbub2 WHERE userid = ? AND huburl = ? AND topicurl 
= ?},
+        undef, $u->id, $huburl, $topicurl
     );
     return if $dbh->errstr;
 
-    # bail now if things look good
-    return if $row && $row->{huburl} eq $huburl && $row->{topicurl} eq 
$topicurl;
+    # if we do, then we want to update this row with a new lastseenat so our 
collector
+    # doesn't purge this subscription later
+    if ( $row && $row->{id} ) {
+        $dbh->do( 'UPDATE syndicated_hubbub2 SET lastseenat = UNIX_TIMESTAMP() 
WHERE id = ?',
+                  undef, $row->{id} );
+        return;
+    }
 
-    # not the same, or the row doesn't exist, so just replace, we don't need 
the old data
+    # this row (exactly) doesn't exist, so register it
+    my $id = LJ::alloc_global_counter( 'F' ) or return;
     $dbh->do(
-        q{REPLACE INTO syndicated_hubbub (userid, huburl, topicurl, 
leasegoodto, verifytoken)
-          VALUES (?, ?, ?, ?, ?)},
-        undef, $u->id, $huburl, $topicurl, undef, LJ::rand_chars( 64 )
+        q{INSERT IGNORE INTO syndicated_hubbub2 (id, userid, huburl, topicurl, 
leasegoodto, verifytoken, lastseenat)
+          VALUES (?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP())},
+        undef, $id, $u->id, $huburl, $topicurl, undef, LJ::rand_chars( 64 )
     );
 
     # no error checking for reasons above...
@@ -495,6 +509,10 @@ sub register_hubbub_feed {
 # post our subscriptions using HTTPS before we can do the "proper" way, though.
 sub process_hubbub_notification {
     my $bodyref = shift;
+
+    # needed for the future; get it early
+    my $sclient = LJ::theschwartz() or die;
+    my $dbr = LJ::get_db_reader() or die;
 
     # FIXME: this probably will explode horribly with aggregated content, so as
     # soon as that becomes supported somewhere, we need to fix this
@@ -510,34 +528,46 @@ sub process_hubbub_notification {
     }
 
     # worked, get self which should be the topic url
-    unless ( $feed->{self} ) {
-        warn "[$$] PubSubHubbub notification has no self link?\n";
+    unless ( $feed->{self} && ref $feed->{self} eq 'ARRAY' ) {
+        warn "[$$] PubSubHubbub notification has no self link(s)?\n";
         return;
     }
 
-    my $dbr = LJ::get_db_reader() or die;
-    my ( $uid ) = $dbr->selectrow_array(
-        'SELECT userid FROM syndicated_hubbub WHERE topicurl = ?',
-        undef, $feed->{self}
-    );
-    die if $dbr->err;
+    # now select everybody that uses this topic url.  note that this is 
actually kind of
+    # weird.  in theory we should only ever have one topicurl mapped to one 
feed, but if
+    # someone comes along and maps a bunch of topicurls to their feeds first, 
they can
+    # "break" hubbub subscriptions for popular feeds.  so we just make it so 
that we
+    # allow N feeds to have the same topic url and we schedule a refresh for 
all of them.
+    # a little more work for us and potentially more traffic, but it's better 
than the
+    # alternative...
+    my @uids;
+    foreach my $topic ( @{ $feed->{self} } ) {
+        my $uids = $dbr->selectcol_arrayref(
+            'SELECT userid FROM syndicated_hubbub2 WHERE topicurl = ?',
+            undef, $topic
+        );
+        die if $dbr->err;
 
-    # user must still be visible for us to care
-    my $u = LJ::load_userid( $uid ) or die;
-    return unless $u->is_visible;
+        push @uids, @{ $uids || [] };
+    }
 
-    # great! schedule a synsuck job :-)
-    my $sclient = LJ::theschwartz() or die;
-    $sclient->insert_jobs( TheSchwartz::Job->new(
-        funcname => 'DW::Worker::SynSuck',
-        arg      => { userid => $u->id },
-        uniqkey  => "synsuck:" . $u->id,
-        priority => 200, # arbitrary, high
-    ) );
+    # iterate over each user
+    foreach my $uid ( @uids ) {
+        # user must still be visible for us to care
+        my $u = LJ::load_userid( $uid ) or die;
+        next unless $u->is_visible;
 
-    # let devserver know
-    if ( $LJ::IS_DEV_SERVER ) {
-        warn "[$$] PubSubHubbub notification scheduled job for " . $u->user . 
"(" . $u->id . ").\n";
+        # great! schedule a synsuck job :-)
+        $sclient->insert_jobs( TheSchwartz::Job->new(
+            funcname => 'DW::Worker::SynSuck',
+            arg      => { userid => $u->id },
+            uniqkey  => "synsuck:" . $u->id,
+            priority => 200, # arbitrary, high, try to go fast
+        ) );
+
+        # let devserver know
+        warn "[$$] PubSubHubbub notification scheduled job for " . $u->user . 
"(" . $u->id . ").\n"
+            if $LJ::IS_DEV_SERVER;
     }
     return;
 }
diff -r b7370be6d607 -r b2c0b0b8bf11 cgi-bin/ljlib.pl
--- a/cgi-bin/ljlib.pl  Thu Sep 03 17:21:35 2009 +0000
+++ b/cgi-bin/ljlib.pl  Thu Sep 03 21:58:25 2009 +0000
@@ -2087,7 +2087,8 @@ sub get_secret
 # LJ-generic domains:
 #  $dom: 'S' == style, 'P' == userpic, 'A' == stock support answer
 #        'C' == captcha, 'E' == external user, 'O' == school
-#        'L' == poLL,  'M' == Messaging, 'H' == sHopping cart
+#        'L' == poLL,  'M' == Messaging, 'H' == sHopping cart,
+#        'F' == PubSubHubbub subscription id (F for Fred)
 #
 sub alloc_global_counter
 {
@@ -2097,7 +2098,7 @@ sub alloc_global_counter
 
     # $dom can come as a direct argument or as a string to be mapped via hook
     my $dom_unmod = $dom;
-    unless ($dom =~ /^[ESLPOAHCM]$/) {
+    unless ($dom =~ /^[ESLPOAHCMF]$/) {
         $dom = LJ::run_hook('map_global_counter_domain', $dom);
     }
     return LJ::errobj("InvalidParameters", params => { dom => $dom_unmod 
})->cond_throw
@@ -2137,6 +2138,8 @@ sub alloc_global_counter
         my $max_poll      = $dbh->selectrow_array("SELECT MAX(pollid) FROM 
poll");
         my $max_pollowner = $dbh->selectrow_array("SELECT MAX(pollid) FROM 
pollowner");
         $newmax = $max_poll > $max_pollowner ? $max_poll : $max_pollowner;
+    } elsif ( $dom eq 'F' ) {
+        $newmax = $dbh->selectrow_array( 'SELECT MAX(id) FROM 
syndicated_hubbub2' );
     } else {
         $newmax = LJ::run_hook('global_counter_init_value', $dom);
         die "No alloc_global_counter initalizer for domain '$dom'"
diff -r b7370be6d607 -r b2c0b0b8bf11 cgi-bin/parsefeed.pl
--- a/cgi-bin/parsefeed.pl      Thu Sep 03 17:21:35 2009 +0000
+++ b/cgi-bin/parsefeed.pl      Thu Sep 03 21:58:25 2009 +0000
@@ -280,10 +280,9 @@ sub StartTag {
                 return err( 'Feed not yet defined' )
                     unless $feed;
 
-                # we only take the first value, so if the user specifies
-                # multiple hubs (which is allowed) then we are going to just
-                # pick the first.  FIXME: subscribe to all?
-                $feed->{$_{rel}} ||= $_{href};
+                # allow these to be specified multiple times, the spec allows 
for multiple
+                # hubs.  the self link shouldn't allow multiples but it won't 
hurt if we let it.
+                push @{$feed->{$_{rel}} ||= []}, $_{href};
                 last TAGS;
             }
 
diff -r b7370be6d607 -r b2c0b0b8bf11 htdocs/misc/hubbub.bml
--- a/htdocs/misc/hubbub.bml    Thu Sep 03 17:21:35 2009 +0000
+++ b/htdocs/misc/hubbub.bml    Thu Sep 03 21:58:25 2009 +0000
@@ -71,23 +71,27 @@ _c?><?_code
 
     # validate the token matches something we know about
     my $dbh = LJ::get_db_writer() or return $fail->();
-    my ( $uid, $topicurldb )  = $dbh->selectrow_array(
-        'SELECT userid, topicurl FROM syndicated_hubbub WHERE verifytoken = ?',
+    my ( $id, $uid, $topicurldb )  = $dbh->selectrow_array(
+        'SELECT id, userid, topicurl FROM syndicated_hubbub2 WHERE verifytoken 
= ?',
         undef, $verifytoken
     );
     return $fail->( $dbh->errstr ) if $dbh->err;
 
     # must have a uid, and the topic url must match
-    return $err->( 'no matching row found [' . $verifytoken . ']' ) unless 
$uid;
-    return $err->( 'topic_url mismatch' ) unless $topicurl eq $topicurldb;
+    return $err->( 'no matching row found: ' . $verifytoken ) unless $uid;
+
+    # if the topic url doesn't match, then that's a terrible thing and we're 
not sure
+    # why, so log extra information
+    return $err->( 'topic_url mismatch: db=' . $topicurldb . ', hub=' . 
$topicurl )
+        unless $topicurl eq $topicurldb;
 
     # validate the user is still valid (didn't get suspended or anything)
     my $u = LJ::load_userid( $uid ) or return $fail->( 'failed to load user' );
     return $err->( 'user no longer visible' ) unless $u->is_visible;
     
     # okay, great; let's update our subscription record
-    $dbh->do( 'UPDATE syndicated_hubbub SET leasegoodto = UNIX_TIMESTAMP() + 
?',
-              undef, $leasetime );
+    $dbh->do( 'UPDATE syndicated_hubbub2 SET leasegoodto = UNIX_TIMESTAMP() + 
? WHERE id = ?',
+              undef, $leasetime, $id );
 
     # if we're a development server, warn some debugging so we know the hub 
hit us
     if ( $LJ::IS_DEV_SERVER ) {
_______________________________________________
dw-changelog mailing list
[email protected]
http://lists.dwscoalition.org/mailman/listinfo/dw-changelog

Reply via email to