fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2010-10-03 02:39 pm

[dw-free] New dversion for userpics to make renaming userpics faster

[commit: http://hg.dwscoalition.org/dw-free/rev/7b8044812951]

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

Better, faster userpic renames, done by updating at most three rows in
userpicmap3. We'll be slowly rolling out the ability to rename again post
codepush.

Patch by [personal profile] exor674.

Files modified:
  • bin/worker/userpic-rename
  • cgi-bin/DW/Worker/UserpicRenameWorker.pm
  • cgi-bin/LJ/Userpic.pm
  • htdocs/editicons.bml
--------------------------------------------------------------------------------
diff -r 2ee31e71f90c -r 7b8044812951 bin/worker/userpic-rename
--- a/bin/worker/userpic-rename	Sun Oct 03 21:26:08 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#!/usr/bin/perl
-#
-# bin/worker/userpic-rename
-#
-# TheSchwartz worker for renaming userpics
-#
-# Authors:
-#      Allen Petersen <allen@suberic.net>
-#
-# Copyright (c) 2009 by Dreamwidth Studios, LLC.
-#
-# This program is free software; you may redistribute it and/or modify it under
-# the same terms as Perl itself. For a copy of the license, please reference
-# 'perldoc perlartistic' or 'perldoc perlgpl'.
-
-use strict;
-use warnings;
-
-use lib "$ENV{LJHOME}/cgi-bin";
-use LJ::Worker::TheSchwartz;
-use DW::Worker::UserpicRenameWorker;
-
-foreach my $capability (DW::Worker::UserpicRenameWorker->schwartz_capabilities) {
-    schwartz_decl( $capability );
-}
-
-schwartz_work(); # Never returns.
diff -r 2ee31e71f90c -r 7b8044812951 cgi-bin/DW/Worker/UserpicRenameWorker.pm
--- a/cgi-bin/DW/Worker/UserpicRenameWorker.pm	Sun Oct 03 21:26:08 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-#!/usr/bin/perl
-#
-# DW::Worker::UserpicRenameWorker
-#
-# TheSchwartz worker module for renaming userpics.  Called with
-# LJ::theschwartz()->insert('DW::Worker::UserpicRenameWorker', {
-# 'uid' => $u->userid, 'keywordmap' => Storable::nfreeze(\%keywordmap);
-#
-# Authors:
-#      Allen Petersen <allen@suberic.net>
-#
-# Copyright (c) 2009 by Dreamwidth Studios, LLC.
-#
-# This program is free software; you may redistribute it and/or modify it under
-# the same terms as Perl itself. For a copy of the license, please reference
-# 'perldoc perlartistic' or 'perldoc perlgpl'.
-
-package DW::Worker::UserpicRenameWorker;
-
-use strict;
-use warnings;
-use base 'TheSchwartz::Worker';
-
-sub schwartz_capabilities { return ('DW::Worker::UserpicRenameWorker'); }
-
-sub keep_exit_status_for { 86400 } # 24 hours
-
-my $logpropid;
-my $talkpropid;
-
-sub work {
-    my ($class, $job) = @_;
-
-    my $arg = $job->arg;
-
-    my ($uid, $keywordmapstring) = map { delete $arg->{$_} } qw( uid keywordmap );
-
-    return $job->permanent_failure("Unknown keys: " . join(", ", keys %$arg))
-        if keys %$arg;
-    return $job->permanent_failure("Missing argument")
-        unless defined $uid && defined $keywordmapstring;
-
-    my $keywordmap = eval { Storable::thaw($keywordmapstring) } or return $job->failed("Failed to load keywordmap from arg '$keywordmapstring':  " . $@);
-
-    # get the user from the uid
-    my $u = LJ::want_user($uid) or return $job->failed("Unable to load user with uid $uid");
-
-    # only get the propids once; they're not going to change
-    unless ($logpropid && $talkpropid) {
-        $logpropid = LJ::get_prop( log => 'picture_keyword' )->{id};
-        $talkpropid = LJ::get_prop( talk => 'picture_keyword' )->{id};
-    }
-
-    # only update 1000 rows at a time.
-    my $LIMIT = 1000;
-
-    # now we go through each cluster and update the logprop2 and talkprop2
-    # tables with the new values.
-    foreach my $cluster_id (@LJ::CLUSTERS) {
-        my $dbcm = LJ::get_cluster_master($cluster_id);
-        
-        foreach my $kw (keys %$keywordmap) {
-            # find entries for clearing cache
-            my $matches = $dbcm->selectall_arrayref(q{
-                SELECT log2.journalid AS journalid, 
-                       log2.jitemid AS jitemid 
-                FROM logprop2 
-                INNER JOIN log2 
-                    ON ( logprop2.journalid = log2.journalid 
-                        AND logprop2.jitemid = log2.jitemid ) 
-                WHERE posterid = ? 
-                    AND propid=?
-                    AND value = ?
-                }, undef, $u->id, $logpropid, $kw);
-
-            # update entries
-            my $updateresults = $LIMIT;
-            while ($updateresults == $LIMIT) {
-                $updateresults = $dbcm->do( q{
-                    UPDATE logprop2 
-                    SET value = ? 
-                    WHERE propid=? 
-                        AND value = ? 
-                        AND EXISTS ( 
-                            SELECT posterid 
-                            FROM log2 
-                            WHERE log2.journalid = logprop2.journalid 
-                                AND log2.jitemid = logprop2.jitemid 
-                                AND log2.posterid = ? )
-                    LIMIT ?
-                    }, undef, $keywordmap->{$kw}, $logpropid, $kw, $u->id, $LIMIT);
-                return $job->permanent_failure($dbcm->errstr) if $dbcm->err;
-            }
-
-            # clear cache
-            foreach my $match (@$matches) {
-                LJ::MemCache::delete([ $match->[0], "logprop:" . $match->[0]. ":" . $match->[1] ]);
-            }
-            
-            # update comments
-            # find comments for clearing cache
-            $matches = $dbcm->selectall_arrayref( q{
-                SELECT talkprop2.journalid AS journalid, 
-                       talkprop2.jtalkid AS jtalkid 
-                FROM talkprop2 
-                INNER JOIN talk2 
-                    ON ( talkprop2.journalid = talk2.journalid 
-                        AND talkprop2.jtalkid = talk2.jtalkid ) 
-                WHERE posterid = ? 
-                    AND tpropid=? 
-                    AND value = ? 
-                }, undef, $u->id, $talkpropid, $kw);
-            
-            # update coments
-            $updateresults = $LIMIT;
-            while ($updateresults == $LIMIT) {
-                $updateresults = $dbcm->do( q{
-                    UPDATE talkprop2 
-                    SET value = ? 
-                    WHERE tpropid=? 
-                        AND value = ? 
-                        AND EXISTS ( 
-                            SELECT posterid 
-                            FROM talk2 
-                            WHERE talk2.journalid = talkprop2.journalid 
-                                AND talk2.jtalkid = talkprop2.jtalkid 
-                                AND talk2.posterid = ? ) 
-                    LIMIT ? 
-                    }, undef, $keywordmap->{$kw}, $talkpropid, $kw, $u->id, $LIMIT);
-                return $job->permanent_failure($dbcm->errstr) if $dbcm->err;
-            }
-
-            # clear cache
-            foreach my $match (@$matches) {
-                LJ::MemCache::delete([ $match->[0], "talkprop:" . $match->[0]. ":" . $match->[1] ]);
-            }
-        }
-    }
-
-    $job->completed;
-}
-
-1;
diff -r 2ee31e71f90c -r 7b8044812951 cgi-bin/LJ/Userpic.pm
--- a/cgi-bin/LJ/Userpic.pm	Sun Oct 03 21:26:08 2010 +0800
+++ b/cgi-bin/LJ/Userpic.pm	Sun Oct 03 22:39:08 2010 +0800
@@ -1142,19 +1142,13 @@ sub set_keywords {
 # all new keywords must not currently be in use; you can't rename a keyword
 # to a keyword currently mapped to another (or the same) userpic.  this will
 # result in an error and no changes made to these keywords.
-#
-# the setting of new keywords is done by Userpic->set_keywords; the remapping
-# of existing pics is done asynchonously via TheSchwartz using the
-# DW::Worker::UserpicRenameWorker.
 sub set_and_rename_keywords {
     my ( $self, $new_keyword_string, $orig_keyword_string ) = @_;
 
-    my $sclient = LJ::theschwartz();
-    
-    # error out if TheSchwartz isn't available.
+    my $u = $self->owner;
     LJ::errobj("Userpic::RenameKeywords",
-               origkw    => $orig_keyword_string,
-               newkw     => $new_keyword_string)->throw unless $sclient;
+                origkw    => $orig_keyword_string,
+                newkw     => $new_keyword_string)->throw unless LJ::is_enabled( "icon_renames" ) || $u->userpic_have_mapid;
 
     my @keywords = split(',', $new_keyword_string);
     my @orig_keywords = split(',', $orig_keyword_string);
@@ -1190,28 +1184,45 @@ sub set_and_rename_keywords {
     if (keys(%keywordmap)) {
 
         #make sure that none of the target keywords already exist.
-        my $u = $self->owner;
         foreach my $kw ( values %keywordmap ) {
             if ( $u && $u->get_picid_from_keyword( $kw, -1 ) != -1 ) {
                 LJ::errobj( "Userpic::RenameKeywordExisting",
                             keyword => $kw )->throw;
             }
         }
-        
-        # set the keywords for this userpic to the new set of keywords
-        $self->set_keywords(@keywords);
-        
-        # send to TheSchwartz to do the actual renaming
-        my $job = TheSchwartz::Job->new_from_array(
-            'DW::Worker::UserpicRenameWorker', { 
-                'uid' => $u->userid, 
-                'keywordmap' => Storable::nfreeze(\%keywordmap) } );
-        
-        unless ($job && $sclient->insert($job)) {
-            LJ::errobj("Userpic::RenameKeywords",
-                       origkw    => $orig_keyword_string,
-                       newkw     => $new_keyword_string)->throw;
+
+        while (my ($origkw, $newkw) = each( %keywordmap )) {
+
+            # need to check if the kwid already has a mapid
+            my $mapid = $u->get_mapid_from_keyword( $newkw );
+
+            # if it does, we have to remap it
+            if ( $mapid ) {
+                my $oldid = $u->get_mapid_from_keyword( $origkw );
+
+                # redirect the old mapid to the new mapid
+                $u->do( "UPDATE userpicmap3 SET kwid = NULL, picid = NULL, redirect_mapid = ? WHERE mapid = ? AND userid = ?",
+                        undef, $mapid, $oldid, $u->id );
+                die $u->errstr if $u->err;
+
+                # change any redirects pointing to the old mapid to the new mapid
+                $u->do( "UPDATE userpicmap3 SET redirect_mapid = ? WHERE redirect_mapid = ? AND userid = ?",
+                        undef, $mapid, $oldid, $u->id );
+                die $u->errstr if $u->err;
+
+                # and set the new mapid to point to the picture
+                $u->do( "UPDATE userpicmap3 SET picid = ? WHERE mapid = ? AND userid = ?",
+                        undef, $self->picid, $mapid, $u->id );
+                die $u->errstr if $u->err;
+
+            } else {
+                $u->do( "UPDATE userpicmap3 SET kwid = ? WHERE kwid = ? AND userid = ?",
+                        undef, $u->get_keyword_id( $newkw ), $u->get_keyword_id( $origkw ), $u->id );
+                die $u->errstr if $u->err;
+            }
         }
+        LJ::Userpic->delete_cache($u);
+        $u->clear_userpic_kw_map;
     }
 
     return 1;
diff -r 2ee31e71f90c -r 7b8044812951 htdocs/editicons.bml
--- a/htdocs/editicons.bml	Sun Oct 03 21:26:08 2010 +0800
+++ b/htdocs/editicons.bml	Sun Oct 03 22:39:08 2010 +0800
@@ -90,6 +90,8 @@ use strict;
     my $factory_redirect;
     my $no_errors = 1;
     my $success_count = 0;
+
+    my $display_rename = LJ::is_enabled( "icon_renames" ) ? 1 : 0 ;
 
     ### save/update mode
     if (LJ::did_post()) {
@@ -508,7 +510,6 @@ use strict;
         $body .= "</div>";
 
         $body .= "<div id='list_userpics' style='width: 98%; float: left;'>";
-        my $display_rename = LJ::theschwartz() ? 1 : 0;
 
         if ( $keyword_sort ) {
             @userpics = LJ::Userpic->sort( \@userpics );
@@ -537,7 +538,7 @@ use strict;
             if ($display_rename) {
                 $body .= "<div id='rename_div_$pid' class='userpic_rename pkg'>\n";
                 $body .= "<script type='text/javascript'>document.getElementById('rename_div_$pid').style.display = 'none';</script>\n";
-                if ( LJ::is_enabled( "icon_renames" ) ) {
+                if ( $u->userpic_have_mapid ) {
                     $body .= LJ::html_check({ 'type' => 'checkbox', 'name' => "rename_keyword_$pid", 'class' => "checkbox",
                                               'id' => "rename_keyword_$pid", 'value' => 1,
                                               'disabled' => $LJ::DISABLE_MEDIA_UPLOADS });
@@ -625,18 +626,19 @@ sub update_userpics
     my $u = shift;
     my @userpics = @$userpicsref;
     my $err = shift;
-    
-    
+
+    my $display_rename = LJ::is_enabled( "icon_renames" ) ? 1 : 0 ;
+
     # form being posted isn't multipart, since we were able to read from %POST
     unless (LJ::check_form_auth()) {
         return $err->($ML{'error.invalidform'});
     }
-    
+
     my @delete; # userpic objects to delete
     my @inactive_picids;
     my %picid_of_kwid;
     my %used_keywords;
-    
+
     # we need to count keywords based on what the user provided, in order
     # to find duplicates. $up->keywords doesn't work, because re-using a
     # keyword will remove it from the other userpic without our knowing
@@ -668,8 +670,8 @@ sub update_userpics
         if ($POST{"kw_$picid"} ne $POST{"kw_orig_$picid"}) {
             my $kws = $POST{"kw_$picid"};
 
-            if ($POST{"rename_keyword_$picid"}) {
-                if ( LJ::is_enabled( "icon_renames" ) ) {
+            if ( $POST{"rename_keyword_$picid"} ) {
+                if ( $display_rename && $u->userpic_have_mapid ) {
                     eval {
                        $up->set_and_rename_keywords($kws, $POST{"kw_orig_$picid"});
                     } or push @errors, $@->as_html;
--------------------------------------------------------------------------------