295 lines
9.9 KiB
Perl
295 lines
9.9 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# DW::User::DVersion::Migrate8To9 - Handling dversion 8 to 9 migration
|
|
#
|
|
# Authors:
|
|
# Andrea Nall <anall@andreanall.com>
|
|
#
|
|
# Copyright (c) 2010 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::User::DVersion::Migrate8To9;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
require 'ljlib.pl';
|
|
use LJ::User;
|
|
use Time::HiRes qw( usleep );
|
|
|
|
sub do_upgrade {
|
|
my $readonly_bit;
|
|
|
|
foreach ( keys %LJ::CAP ) {
|
|
if ( $LJ::CAP{$_}->{'_name'} eq "_moveinprogress"
|
|
&& $LJ::CAP{$_}->{'readonly'} == 1 )
|
|
{
|
|
$readonly_bit = $_;
|
|
last;
|
|
}
|
|
}
|
|
unless ( defined $readonly_bit ) {
|
|
die
|
|
"Won't move user without %LJ::CAP capability class named '_moveinprogress' with readonly => 1\n";
|
|
}
|
|
|
|
my $logpropid = LJ::get_prop( log => 'picture_keyword' )->{id};
|
|
my $talkpropid = LJ::get_prop( talk => 'picture_keyword' )->{id};
|
|
|
|
my $logpropid_map = LJ::get_prop( log => 'picture_mapid' )->{id};
|
|
my $talkpropid_map = LJ::get_prop( talk => 'picture_mapid' )->{id};
|
|
|
|
my $BLOCK_INSERT = 25;
|
|
|
|
my ($u) = @_;
|
|
|
|
return 0 if $u->readonly;
|
|
|
|
return 1 if $u->dversion >= 9;
|
|
|
|
# we really cannot have the user doing things during this process
|
|
$u->modify_caps( [$readonly_bit], [] );
|
|
|
|
# wait a quarter of a second, give any request the user might be doing a chance to stop
|
|
# as the user changing things could lead to slight data loss re. userpic selection
|
|
# on entries and comments
|
|
usleep(250000);
|
|
|
|
# do this in an eval so, in case something dies, we don't leave the user locked
|
|
my $rv = 0;
|
|
|
|
eval {
|
|
# Unfortunately, we need to iterate over all clusters to get a list
|
|
# of used keywords so we can give proper ids to everything,
|
|
# even removed keywords
|
|
my %keywords;
|
|
my %to_update;
|
|
if ( $u->is_individual ) {
|
|
foreach my $cluster_id (@LJ::CLUSTERS) {
|
|
my $dbcm_o = LJ::get_cluster_master($cluster_id);
|
|
|
|
my $entries = $dbcm_o->selectall_arrayref(
|
|
q{
|
|
SELECT log2.journalid AS journalid,
|
|
log2.jitemid AS jitemid,
|
|
logprop2.value AS value
|
|
FROM logprop2
|
|
INNER JOIN log2
|
|
ON ( logprop2.journalid = log2.journalid
|
|
AND logprop2.jitemid = log2.jitemid )
|
|
WHERE posterid = ?
|
|
AND propid=?
|
|
}, undef, $u->id, $logpropid
|
|
);
|
|
die $dbcm_o->errstr if $dbcm_o->err;
|
|
my $comments = $dbcm_o->selectall_arrayref(
|
|
q{
|
|
SELECT talkprop2.journalid AS journalid,
|
|
talkprop2.jtalkid AS jtalkid,
|
|
talkprop2.value AS value
|
|
FROM talkprop2
|
|
INNER JOIN talk2
|
|
ON ( talkprop2.journalid = talk2.journalid
|
|
AND talkprop2.jtalkid = talk2.jtalkid )
|
|
WHERE posterid = ?
|
|
AND tpropid=?
|
|
}, undef, $u->id, $talkpropid
|
|
);
|
|
die $dbcm_o->errstr if $dbcm_o->err;
|
|
|
|
$to_update{$cluster_id} = {
|
|
entries => $entries,
|
|
comments => $comments,
|
|
};
|
|
$keywords{ $_->[2] }->{count}++ foreach ( @$entries, @$comments );
|
|
}
|
|
}
|
|
|
|
my $origmap = $u->selectall_hashref(
|
|
q{
|
|
SELECT kwid, picid FROM userpicmap2 WHERE userid=?
|
|
}, "kwid", undef, $u->id
|
|
);
|
|
die $u->errstr if $u->err;
|
|
|
|
my $picmap = $u->selectall_hashref(
|
|
q{
|
|
SELECT picid, state FROM userpic2 WHERE userid=?
|
|
}, "picid", undef, $u->id
|
|
);
|
|
die $u->errstr if $u->err;
|
|
|
|
my %outrows;
|
|
|
|
my %kwid_map;
|
|
|
|
foreach my $k ( keys %keywords ) {
|
|
if ( $k =~ m/^pic#(\d+)$/ ) {
|
|
my $picid = $1;
|
|
next if !exists $picmap->{$picid} || $picmap->{$picid}->{state} eq 'X';
|
|
$keywords{$k}->{kwid} = undef;
|
|
$keywords{$k}->{picid} = $picid;
|
|
$outrows{$picid}->{0}++;
|
|
}
|
|
else {
|
|
my $kwid = $u->get_keyword_id( $k, 1 );
|
|
$kwid_map{$kwid} = $k;
|
|
my $picid = $origmap->{$kwid}->{picid};
|
|
$keywords{$k}->{kwid} = $kwid;
|
|
$keywords{$k}->{picid} = $picid;
|
|
$outrows{ $picid || 0 }->{$kwid}++;
|
|
}
|
|
}
|
|
|
|
foreach my $r ( values %$origmap ) {
|
|
$outrows{ $r->{picid} }->{ $r->{kwid} }++ if $r->{picid} && $r->{kwid};
|
|
}
|
|
|
|
{
|
|
my ( @bind, @vals );
|
|
|
|
# flush rows to destination table
|
|
my $flush = sub {
|
|
return unless @bind;
|
|
|
|
# insert data
|
|
my $bind = join( ",", @bind );
|
|
$u->do( "REPLACE INTO userpicmap3 (userid,mapid,kwid,picid) VALUES $bind",
|
|
undef, @vals );
|
|
die $u->errstr if $u->err;
|
|
|
|
# reset values
|
|
@bind = ();
|
|
@vals = ();
|
|
};
|
|
|
|
foreach my $picid ( sort { $a <=> $b } keys %outrows ) {
|
|
foreach my $kwid ( sort { $a <=> $b } keys %{ $outrows{$picid} } ) {
|
|
next if $kwid == 0 && $picid == 0;
|
|
push @bind, "(?,?,?,?)";
|
|
my $mapid = LJ::alloc_user_counter( $u, 'Y' );
|
|
my $keyword = $kwid == 0 ? "pic#$picid" : $kwid_map{$kwid};
|
|
|
|
# if $keyword is undef, this isn't used on any entries, so we don't care about the mapid
|
|
# however, if $kwid is undef, this is a pic#xxx keyword, and had to have existed on an entry
|
|
$keywords{$keyword}->{mapid} = $mapid if defined $keyword;
|
|
push @vals, ( $u->id, $mapid, $kwid || undef, $picid || undef );
|
|
$flush->() if @bind > $BLOCK_INSERT;
|
|
}
|
|
}
|
|
$flush->();
|
|
}
|
|
|
|
if ( $u->is_individual ) {
|
|
foreach my $cluster_id (@LJ::CLUSTERS) {
|
|
next unless $to_update{$cluster_id};
|
|
my $data = $to_update{$cluster_id};
|
|
|
|
my $dbcm_o = LJ::get_cluster_master($cluster_id);
|
|
|
|
{
|
|
my ( @bind, @vals );
|
|
|
|
# flush rows to destination table
|
|
my $flush = sub {
|
|
return unless @bind;
|
|
|
|
# insert data
|
|
my $bind = join( ",", @bind );
|
|
$dbcm_o->do(
|
|
"REPLACE INTO logprop2 (journalid,jitemid,propid,value) VALUES $bind",
|
|
undef, @vals );
|
|
die $u->errstr if $u->err;
|
|
|
|
# reset values
|
|
@bind = ();
|
|
@vals = ();
|
|
};
|
|
|
|
foreach my $entry ( @{ $data->{entries} } ) {
|
|
next unless $keywords{ $entry->[2] }->{mapid};
|
|
push @bind, "(?,?,?,?)";
|
|
push @vals,
|
|
(
|
|
$entry->[0], $entry->[1], $logpropid_map,
|
|
$keywords{ $entry->[2] }->{mapid}
|
|
);
|
|
$flush->() if @bind > $BLOCK_INSERT;
|
|
}
|
|
$flush->();
|
|
|
|
foreach my $entry ( @{ $data->{entries} } ) {
|
|
LJ::MemCache::delete(
|
|
[ $entry->[0], "logprop:" . $entry->[0] . ":" . $entry->[1] ] );
|
|
}
|
|
}
|
|
{
|
|
my ( @bind, @vals );
|
|
|
|
# flush rows to destination table
|
|
my $flush = sub {
|
|
return unless @bind;
|
|
|
|
# insert data
|
|
my $bind = join( ",", @bind );
|
|
$dbcm_o->do(
|
|
"REPLACE INTO talkprop2 (journalid,jtalkid,tpropid,value) VALUES $bind",
|
|
undef, @vals
|
|
);
|
|
die $u->errstr if $u->err;
|
|
|
|
# reset values
|
|
@bind = ();
|
|
@vals = ();
|
|
};
|
|
|
|
foreach my $comment ( @{ $data->{comments} } ) {
|
|
next unless $keywords{ $comment->[2] }->{mapid};
|
|
push @bind, "(?,?,?,?)";
|
|
push @vals,
|
|
(
|
|
$comment->[0], $comment->[1], $talkpropid_map,
|
|
$keywords{ $comment->[2] }->{mapid}
|
|
);
|
|
$flush->() if @bind > $BLOCK_INSERT;
|
|
}
|
|
$flush->();
|
|
|
|
foreach my $comment ( @{ $data->{comments} } ) {
|
|
LJ::MemCache::delete(
|
|
[ $comment->[0], "talkprop:" . $comment->[0] . ":" . $comment->[1] ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$rv = 1;
|
|
};
|
|
|
|
my $err = $@;
|
|
|
|
# okay, we're done, the user can do things again
|
|
$u->modify_caps( [], [$readonly_bit] );
|
|
|
|
die $err if $err;
|
|
|
|
return $rv;
|
|
}
|
|
|
|
sub upgrade_to_dversion_9 {
|
|
|
|
# If user has been purged, go ahead and update version
|
|
# Otherwise move their data
|
|
my $ok = $_[0]->is_expunged ? 1 : do_upgrade(@_);
|
|
|
|
$_[0]->update_self( { 'dversion' => 9 } ) if $ok;
|
|
|
|
LJ::Userpic->delete_cache( $_[0] );
|
|
|
|
return $ok;
|
|
}
|
|
|
|
*LJ::User::upgrade_to_dversion_9 = \&upgrade_to_dversion_9;
|