diff options
47 files changed, 226 insertions, 111 deletions
diff --git a/Bugzilla/Attachment.pm b/Bugzilla/Attachment.pm index bb0f83aba..2b2159346 100644 --- a/Bugzilla/Attachment.pm +++ b/Bugzilla/Attachment.pm @@ -921,6 +921,9 @@ sub update { $dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?', undef, ($timestamp, $self->bug_id)); $self->{modification_time} = $timestamp; + # because we updated the attachments table after SUPER::update(), we + # need to ensure the cache is flushed. + Bugzilla->memcached->clear({ table => 'attachments', id => $self->id }); } return $changes; @@ -945,11 +948,21 @@ sub remove_from_db { my $dbh = Bugzilla->dbh; $dbh->bz_start_transaction(); - $dbh->do('DELETE FROM flags WHERE attach_id = ?', undef, $self->id); + my $flag_ids = $dbh->selectcol_arrayref( + 'SELECT id FROM flags WHERE attach_id = ?', undef, $self->id); + $dbh->do('DELETE FROM flags WHERE ' . $dbh->sql_in('id', $flag_ids)) + if @$flag_ids; $dbh->do('DELETE FROM attach_data WHERE id = ?', undef, $self->id); $dbh->do('UPDATE attachments SET mimetype = ?, ispatch = ?, isobsolete = ? WHERE attach_id = ?', undef, ('text/plain', 0, 1, $self->id)); $dbh->bz_commit_transaction(); + + # As we don't call SUPER->remove_from_db we need to manually clear + # memcached here. + Bugzilla->memcached->clear({ table => 'attachments', id => $self->id }); + foreach my $flag_id (@$flag_ids) { + Bugzilla->memcached->clear({ table => 'flags', id => $flag_id }); + } } ############################### diff --git a/Bugzilla/Auth/Verify.pm b/Bugzilla/Auth/Verify.pm index a8cd0af2c..3578631f1 100644 --- a/Bugzilla/Auth/Verify.pm +++ b/Bugzilla/Auth/Verify.pm @@ -97,6 +97,7 @@ sub create_or_update_user { if ($extern_id && $username_user_id && !$extern_user_id) { $dbh->do('UPDATE profiles SET extern_id = ? WHERE userid = ?', undef, $extern_id, $username_user_id); + Bugzilla->memcached->clear({ table => 'profiles', id => $username_user_id }); } # Finally, at this point, one of these will give us a valid user id. @@ -109,23 +110,26 @@ sub create_or_update_user { 'Bugzilla::Auth::Verify::create_or_update_user'}) unless $user_id; - my $user = new Bugzilla::User($user_id); + my $user = new Bugzilla::User({ id => $user_id, cache => 1 }); # Now that we have a valid User, we need to see if any data has to be # updated. + my $user_updated = 0; if ($username && lc($user->login) ne lc($username)) { validate_email_syntax($username) || return { failure => AUTH_ERROR, error => 'auth_invalid_email', details => {addr => $username} }; $user->set_login($username); + $user_updated = 1; } if ($real_name && $user->name ne $real_name) { # $real_name is more than likely tainted, but we only use it # in a placeholder and we never use it after this. trick_taint($real_name); $user->set_name($real_name); + $user_updated = 1; } - $user->update(); + $user->update() if $user_updated; return { user => $user }; } diff --git a/Bugzilla/Auth/Verify/DB.pm b/Bugzilla/Auth/Verify/DB.pm index 2fcfd4017..783e7490a 100644 --- a/Bugzilla/Auth/Verify/DB.pm +++ b/Bugzilla/Auth/Verify/DB.pm @@ -103,6 +103,7 @@ sub change_password { my $cryptpassword = bz_crypt($password); $dbh->do("UPDATE profiles SET cryptpassword = ? WHERE userid = ?", undef, $cryptpassword, $user->id); + Bugzilla->memcached->clear({ table => 'profiles', id => $user->id }); } 1; diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index b6861b509..a99dfaf85 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -76,6 +76,8 @@ use constant LIST_ORDER => ID_FIELD; # Bugs have their own auditing table, bugs_activity. use constant AUDIT_CREATES => 0; use constant AUDIT_UPDATES => 0; +# This will be enabled later +use constant USE_MEMCACHED => 0; # This is a sub because it needs to call other subroutines. sub DB_COLUMNS { diff --git a/Bugzilla/Classification.pm b/Bugzilla/Classification.pm index 88ec4eb3b..5d75a6dc6 100644 --- a/Bugzilla/Classification.pm +++ b/Bugzilla/Classification.pm @@ -56,6 +56,7 @@ use constant VALIDATORS => { ############################### #### Constructors ##### ############################### + sub remove_from_db { my $self = shift; my $dbh = Bugzilla->dbh; @@ -63,9 +64,18 @@ sub remove_from_db { ThrowUserError("classification_not_deletable") if ($self->id == 1); $dbh->bz_start_transaction(); + # Reclassify products to the default classification, if needed. - $dbh->do("UPDATE products SET classification_id = 1 - WHERE classification_id = ?", undef, $self->id); + my $product_ids = $dbh->selectcol_arrayref( + 'SELECT id FROM products WHERE classification_id = ?', undef, $self->id); + + if (@$product_ids) { + $dbh->do('UPDATE products SET classification_id = 1 WHERE ' + . $dbh->sql_in('id', $product_ids)); + foreach my $id (@$product_ids) { + Bugzilla->memcached->clear({ table => 'products', id => $id }); + } + } $self->SUPER::remove_from_db(); diff --git a/Bugzilla/Comment/TagWeights.pm b/Bugzilla/Comment/TagWeights.pm index 5835efbc4..f1a220a47 100644 --- a/Bugzilla/Comment/TagWeights.pm +++ b/Bugzilla/Comment/TagWeights.pm @@ -35,6 +35,9 @@ use constant NAME_FIELD => 'tag'; use constant LIST_ORDER => 'weight DESC'; use constant VALIDATORS => { }; +# There's no gain to caching these objects +use constant USE_MEMCACHED => 0; + sub tag { return $_[0]->{'tag'} } sub weight { return $_[0]->{'weight'} } diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 5cd246b8e..97d03dc42 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -1078,6 +1078,8 @@ sub create { # Restore the original obsolete state of the custom field. $dbh->do('UPDATE fielddefs SET obsolete = 0 WHERE id = ?', undef, $field->id) unless $is_obsolete; + + Bugzilla->memcached->clear({ table => 'fielddefs', id => $field->id }); } }; diff --git a/Bugzilla/Flag.pm b/Bugzilla/Flag.pm index 089ac6c9f..6ef7be81e 100644 --- a/Bugzilla/Flag.pm +++ b/Bugzilla/Flag.pm @@ -480,6 +480,7 @@ sub update { $dbh->do('UPDATE flags SET modification_date = ? WHERE id = ?', undef, ($timestamp, $self->id)); $self->{'modification_date'} = format_time($timestamp, '%Y.%m.%d %T'); + Bugzilla->memcached->clear({ table => 'flags', id => $self->id }); } return $changes; } @@ -626,6 +627,7 @@ sub force_retarget { if ($is_retargetted) { $dbh->do('UPDATE flags SET type_id = ? WHERE id = ?', undef, ($flag->type_id, $flag->id)); + Bugzilla->memcached->clear({ table => 'flags', id => $flag->id }); } else { # Track deleted attachment flags. diff --git a/Bugzilla/FlagType.pm b/Bugzilla/FlagType.pm index 910e2d425..3325c8c5c 100644 --- a/Bugzilla/FlagType.pm +++ b/Bugzilla/FlagType.pm @@ -200,8 +200,16 @@ sub update { # Silently remove requestees from flags which are no longer # specifically requestable. if (!$self->is_requesteeble) { - $dbh->do('UPDATE flags SET requestee_id = NULL WHERE type_id = ?', - undef, $self->id); + my $ids = $dbh->selectcol_arrayref( + 'SELECT id FROM flags WHERE type_id = ? AND requestee_id IS NOT NULL', + undef, $self->id); + + if (@$ids) { + $dbh->do('UPDATE flags SET requestee_id = NULL WHERE ' . $dbh->sql_in('id', $ids)); + foreach my $id (@$ids) { + Bugzilla->memcached->clear({ table => 'flags', id => $id }); + } + } } Bugzilla::Hook::process('flagtype_end_of_update', diff --git a/Bugzilla/Install/Requirements.pm b/Bugzilla/Install/Requirements.pm index cea5a4a34..384df221e 100644 --- a/Bugzilla/Install/Requirements.pm +++ b/Bugzilla/Install/Requirements.pm @@ -375,6 +375,12 @@ sub OPTIONAL_MODULES { # memcached { + package => 'URI-Escape', + module => 'URI::Escape', + version => 0, + feature => ['memcached'], + }, + { package => 'Cache-Memcached', module => 'Cache::Memcached', version => '0', diff --git a/Bugzilla/Memcached.pm b/Bugzilla/Memcached.pm index b1b10311b..4bfca2b65 100644 --- a/Bugzilla/Memcached.pm +++ b/Bugzilla/Memcached.pm @@ -14,6 +14,12 @@ use warnings; use Bugzilla::Error; use Bugzilla::Util qw(trick_taint); use Scalar::Util qw(blessed); +use URI::Escape; +use Encode; +use Sys::Syslog qw(:DEFAULT); + +# memcached keys have a maximum length of 250 bytes +use constant MAX_KEY_LENGTH => 250; sub _new { my $invocant = shift; @@ -26,10 +32,11 @@ sub _new { && Bugzilla->params->{memcached_servers}) { require Cache::Memcached; + $self->{namespace} = Bugzilla->params->{memcached_namespace} || ''; $self->{memcached} = Cache::Memcached->new({ servers => [ split(/[, ]+/, Bugzilla->params->{memcached_servers}) ], - namespace => Bugzilla->params->{memcached_namespace} || '', + namespace => $self->{namespace}, }); } return bless($self, $class); @@ -129,6 +136,11 @@ sub clear_all { if (!$memcached->incr("prefix", 1)) { $memcached->add("prefix", time()); } + + # BMO - log that we've wiped the cache + openlog('apache', 'cons,pid', 'local4'); + syslog('notice', encode_utf8('[memcached] cache cleared')); + closelog(); } # in order to clear all our keys, we add a prefix to all our keys. when we @@ -155,6 +167,14 @@ sub _prefix { return $request_cache->{memcached_prefix}; } +sub _encode_key { + my ($self, $key) = @_; + $key = $self->_prefix . ':' . uri_escape_utf8($key); + return length($self->{namespace} . $key) > MAX_KEY_LENGTH + ? undef + : $key; +} + sub _set { my ($self, $key, $value) = @_; if (blessed($value)) { @@ -162,13 +182,17 @@ sub _set { ThrowCodeError('param_invalid', { function => "Bugzilla::Memcached::set", param => "value" }); } - return $self->{memcached}->set($self->_prefix . ':' . $key, $value); + $key = $self->_encode_key($key) + or return; + return $self->{memcached}->set($key, $value); } sub _get { my ($self, $key) = @_; - my $value = $self->{memcached}->get($self->_prefix . ':' . $key); + $key = $self->_encode_key($key) + or return; + my $value = $self->{memcached}->get($key); return unless defined $value; # detaint returned values @@ -187,7 +211,9 @@ sub _get { sub _delete { my ($self, $key) = @_; - return $self->{memcached}->delete($self->_prefix . ':' . $key); + $key = $self->_encode_key($key) + or return; + return $self->{memcached}->delete($key); } 1; diff --git a/Bugzilla/Milestone.pm b/Bugzilla/Milestone.pm index 92bc2192a..a5f3ed383 100644 --- a/Bugzilla/Milestone.pm +++ b/Bugzilla/Milestone.pm @@ -121,6 +121,7 @@ sub update { $dbh->do('UPDATE products SET defaultmilestone = ? WHERE id = ? AND defaultmilestone = ?', undef, ($self->name, $self->product_id, $changes->{value}->[0])); + Bugzilla->memcached->clear({ table => 'produles', id => $self->product_id }); } return $changes; } diff --git a/Bugzilla/Object.pm b/Bugzilla/Object.pm index 43d2c07ac..936465b3f 100644 --- a/Bugzilla/Object.pm +++ b/Bugzilla/Object.pm @@ -48,9 +48,8 @@ use constant AUDIT_UPDATES => 1; use constant AUDIT_REMOVES => 1; # When USE_MEMCACHED is true, the class is suitable for serialisation to -# Memcached. This will be flipped to true by default once the majority of -# Bugzilla Object have been tested with Memcached. -use constant USE_MEMCACHED => 0; +# Memcached. See documentation in Bugzilla::Memcached for more information. +use constant USE_MEMCACHED => 1; # This allows the JSON-RPC interface to return Bugzilla::Object instances # as though they were hashes. In the future, this may be modified to return @@ -188,7 +187,20 @@ sub new_from_list { # their own implementation of match which is not compatible # with this one. However, match() still needs to have the right $invocant # in order to do $class->DB_TABLE and so on. - return match($invocant, { $id_field => \@detainted_ids }); + my $list = match($invocant, { $id_field => \@detainted_ids }); + + # BMO: Populate the object cache with bug objects, which helps + # inline-history when viewing bugs with dependencies. + if ($class eq 'Bugzilla::Bug') { + foreach my $object (@$list) { + $class->_object_cache_set( + { id => $object->id, cache => 1 }, + $object + ); + } + } + + return $list; } sub new_from_hash { diff --git a/Bugzilla/Search/Recent.pm b/Bugzilla/Search/Recent.pm index 125850e85..b9f6428d7 100644 --- a/Bugzilla/Search/Recent.pm +++ b/Bugzilla/Search/Recent.pm @@ -53,6 +53,9 @@ use constant VALIDATORS => { use constant UPDATE_COLUMNS => qw(bug_list list_order); +# There's no gain to caching these objects +use constant USE_MEMCACHED => 0; + ################### # DB Manipulation # ################### diff --git a/Bugzilla/Search/Saved.pm b/Bugzilla/Search/Saved.pm index 99194112a..536cf39a4 100644 --- a/Bugzilla/Search/Saved.pm +++ b/Bugzilla/Search/Saved.pm @@ -199,6 +199,7 @@ sub rename_field_value { } $dbh->do("UPDATE $table SET query = ? WHERE $id_field = ?", undef, $query, $id); + Bugzilla->memcached->clear({ table => $table, id => $id }); } $dbh->bz_commit_transaction(); diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 1c6e68078..0429a25e3 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -305,6 +305,7 @@ sub update_last_seen_date { # pending changes $dbh->do("UPDATE profiles SET last_seen_date = ? WHERE userid = ?", undef, $date, $self->id); + Bugzilla->memcached->clear({ table => 'profiles', id => $self->id }); } } diff --git a/buglist.cgi b/buglist.cgi index f9cda72ec..57b906949 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -435,6 +435,7 @@ if ($cmdtype eq "dorem") { $dbh->do('DELETE FROM namedquery_group_map WHERE namedquery_id = ?', undef, $query_id); + Bugzilla->memcached->clear({ table => 'namedqueries', id => $query_id }); } # Now reset the cached queries diff --git a/contrib/merge-users.pl b/contrib/merge-users.pl index 99fe3fef0..de2fe9ec5 100755 --- a/contrib/merge-users.pl +++ b/contrib/merge-users.pl @@ -244,4 +244,9 @@ Bugzilla::Hook::process('merge_users_after', { old_id => $old_id, new_id => $new # Commit the transaction $dbh->bz_commit_transaction(); +# It's complex to determine which items now need to be flushed from memcached. +# As user merge is expected to be a rare event, we just flush the entire cache +# when users are merged. +Bugzilla->memcached->clear_all(); + print "Done.\n"; diff --git a/contrib/reorg-tools/bmo-plan.txt b/contrib/reorg-tools/bmo-plan.txt deleted file mode 100755 index 838ff0ab9..000000000 --- a/contrib/reorg-tools/bmo-plan.txt +++ /dev/null @@ -1,82 +0,0 @@ -==BMO Reorg Plan== - -Do the following things, mostly in order (but see "Timing" at the end): - -1) Create new classifications using GUI: - Graveyard (Description: "Old, retired products", sort key: <last>) - -2) Rename classifications using GUI: - Client Support to Other - -3) Move products between classification using GUI: - Grendel from Client Software to Graveyard - CCK from Unclassified to Graveyard - Derivatives from Unclassified to Graveyard - MozillaClassic from Unclassified to Graveyard - UI: "reclassify" link from the top-level classification list - -4) Create new products using GUI: - Core Graveyard in Graveyard - (desc: "Old, retired Core components", closed for entry, no charts) - MailNews Core in Components - (desc: "Mail and news components common to Thunderbird and SeaMonkey", - open for bug entry, create charts) - -5) Rename products using GUI, and fix queries using fixqueries.pl: -mysql> update series_categories set name="SeaMonkey (2)" where id=32; - Mozilla Application Suite to SeaMonkey - Sumo to support.mozilla.com - -5.5) Rename versions and milestones in Toolkit to match Firefox before step 6 - -6) Sync milestones, versions and groups between products using -syncmsandversions.pl: - Core -> Core Graveyard (new) - Core -> MailNews Core (new) - Firefox -> Toolkit - Core -> SeaMonkey - mozilla.org -> Websites (only 1) - -6.5) Sync flag inclusions using syncflags.pl: - Core -> Core Graveyard (new) - Core -> MailNews Core (new) - Core -> SeaMonkey - mozilla.org -> Websites (only 1) - -6.7) Allow Firefox flags temporarily in Toolkit: - 250 | blocking-firefox3 | blocking1.9 - 387 - 419 | blocking-firefox3.1 | blocking1.9.1 - 416 - 63 | blocking0.8 | blocking1.6 - 69 - 76 | blocking0.9 | blocking1.7 - 83 - 36 | review | review - 4 - 356 | wanted-firefox3 | wanted1.9 - 357 - 418 | wanted-firefox3.1 | wanted1.9.1 - 417 - -7) Move components using movecomponent.pl. - Any instruction beginning "moved from". - Can't fix the queries for this - oh well - <Very long list> - -8) Rename components using GUI, and fix queries using fixqueries.pl. - Any instruction beginning "renamed from" or "MailNews: prefix removed". - <Long list> - -9) Create new components using GUI. - Any instruction beginning "new". - <Long list> - -10) Move open bugs using GUI: - XP Miscellany to Core/General - -11) Merge components by moving bugs using GUI: - Any instruction beginning "merge in". - Merge all bugs, including closed. Delete empty component when done. - <long list of merges> - -12) Close Core Graveyard (and Grendel if necessary) to new bugs - -13) Rename Toolkit versions and milestones back (from 5.5) - -14) Execute flag mapping SQL using Reed's mapping to update bugs in Toolkit - -15) Disable above-listed flags in point 6.7 in Toolkit again diff --git a/contrib/reorg-tools/convert_date_time_date.pl b/contrib/reorg-tools/convert_date_time_date.pl index aa3b58ca1..a2e9bfffc 100755 --- a/contrib/reorg-tools/convert_date_time_date.pl +++ b/contrib/reorg-tools/convert_date_time_date.pl @@ -55,4 +55,8 @@ Bugzilla->dbh->bz_alter_column('bugs', $column, { TYPE => 'DATE' }); Bugzilla->dbh->do("UPDATE fielddefs SET type = ? WHERE name = ?", undef, FIELD_TYPE_DATE, $column); +# It's complex to determine which items now need to be flushed from memcached. +# As this is expected to be a rare event, we just flush the entire cache. +Bugzilla->memcached->clear_all(); + print "\ndone.\n"; diff --git a/contrib/reorg-tools/fix_all_open_status_queries.pl b/contrib/reorg-tools/fix_all_open_status_queries.pl index b51ac21c2..7c8d8be68 100755 --- a/contrib/reorg-tools/fix_all_open_status_queries.pl +++ b/contrib/reorg-tools/fix_all_open_status_queries.pl @@ -137,4 +137,8 @@ print "Adding new status '$new_status'.\n\n"; do_namedqueries($new_status); do_series($new_status); +# It's complex to determine which items now need to be flushed from memcached. +# As this is expected to be a rare event, we just flush the entire cache. +Bugzilla->memcached->clear_all(); + exit(0); diff --git a/contrib/reorg-tools/fixgroupqueries.pl b/contrib/reorg-tools/fixgroupqueries.pl index 1c75edb97..0bd64cd40 100755 --- a/contrib/reorg-tools/fixgroupqueries.pl +++ b/contrib/reorg-tools/fixgroupqueries.pl @@ -116,4 +116,8 @@ print "Changing all instances of '$old' to '$new'.\n\n"; #do_namedqueries($old, $new); do_series($old, $new); +# It's complex to determine which items now need to be flushed from memcached. +# As this is expected to be a rare event, we just flush the entire cache. +Bugzilla->memcached->clear_all(); + exit(0); diff --git a/contrib/reorg-tools/fixqueries.pl b/contrib/reorg-tools/fixqueries.pl index 4b862fd72..221213058 100755 --- a/contrib/reorg-tools/fixqueries.pl +++ b/contrib/reorg-tools/fixqueries.pl @@ -128,5 +128,9 @@ do_namedqueries($field, $old, $new); do_series($field, $old, $new); do_series_categories($old, $new); +# It's complex to determine which items now need to be flushed from memcached. +# As this is expected to be a rare event, we just flush the entire cache. +Bugzilla->memcached->clear_all(); + exit(0); diff --git a/contrib/reorg-tools/migrate_crash_signatures.pl b/contrib/reorg-tools/migrate_crash_signatures.pl index b12446280..4323c1d01 100755 --- a/contrib/reorg-tools/migrate_crash_signatures.pl +++ b/contrib/reorg-tools/migrate_crash_signatures.pl @@ -123,4 +123,10 @@ foreach my $bug (@$bugs) { print "done.\n"; } -$dbh->bz_commit_transaction() if $UPDATE_DB; +if ($UPDATE_DB) { + $dbh->bz_commit_transaction(); + + # It's complex to determine which items now need to be flushed from memcached. + # As this is expected to be a rare event, we just flush the entire cache. + Bugzilla->memcached->clear_all(); +} diff --git a/contrib/reorg-tools/migrate_orange_bugs.pl b/contrib/reorg-tools/migrate_orange_bugs.pl index ae68b227c..4902464a3 100755 --- a/contrib/reorg-tools/migrate_orange_bugs.pl +++ b/contrib/reorg-tools/migrate_orange_bugs.pl @@ -145,6 +145,10 @@ foreach my $bug (@$bugs) { $dbh->bz_commit_transaction() if $doit; if ($doit) { + # It's complex to determine which items now need to be flushed from memcached. + # As this is expected to be a rare event, we just flush the entire cache. + Bugzilla->memcached->clear_all(); + print colored(['green'], "DATABASE WAS UPDATED\n"); } else { diff --git a/contrib/reorg-tools/move_flag_types.pl b/contrib/reorg-tools/move_flag_types.pl index a75b7f497..7b7fe2081 100755 --- a/contrib/reorg-tools/move_flag_types.pl +++ b/contrib/reorg-tools/move_flag_types.pl @@ -162,6 +162,10 @@ if (@$flags) { $flag_update_sth->execute($params{'newid'}, $flag_id); } } + + # It's complex to determine which items now need to be flushed from memcached. + # As this is expected to be a rare event, we just flush the entire cache. + Bugzilla->memcached->clear_all(); } else { print "No flags to move\n"; diff --git a/contrib/reorg-tools/movebugs.pl b/contrib/reorg-tools/movebugs.pl index adc02a1e0..b9acc2443 100755 --- a/contrib/reorg-tools/movebugs.pl +++ b/contrib/reorg-tools/movebugs.pl @@ -173,3 +173,7 @@ Bugzilla::Hook::process('reorg_move_bugs', { bug_ids => $ra_ids } ); $dbh->bz_commit_transaction(); +foreach my $bug_id (@$ra_ids) { + Bugzilla->memcached->clear({ table => 'bugs', id => $bug_id }); +} + diff --git a/contrib/reorg-tools/movecomponent.pl b/contrib/reorg-tools/movecomponent.pl index 702dbc6f0..162942627 100755 --- a/contrib/reorg-tools/movecomponent.pl +++ b/contrib/reorg-tools/movecomponent.pl @@ -193,4 +193,13 @@ $dbh->do("INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, ($userid, $fieldid, $oldproduct, $newproduct, $compid)); Bugzilla::Hook::process('reorg_move_bugs', { bug_ids => $ra_ids } ) if $doit; -$dbh->bz_commit_transaction() if $doit; + +if ($doit) { + $dbh->bz_commit_transaction(); + + # It's complex to determine which items now need to be flushed from memcached. + # As this is expected to be a rare event, we just flush the entire cache. + Bugzilla->memcached->clear_all(); +} + + diff --git a/contrib/reorg-tools/reset_default_user.pl b/contrib/reorg-tools/reset_default_user.pl index 42a7998de..173d03849 100755 --- a/contrib/reorg-tools/reset_default_user.pl +++ b/contrib/reorg-tools/reset_default_user.pl @@ -136,6 +136,8 @@ foreach my $bug (@$bugs) { $dbh->do("UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?", undef, $timestamp, $timestamp, $bug_id); + Bugzilla->memcached->clear({ table => 'bugs', id => $bug_id }); + print "done.\n"; } } diff --git a/editclassifications.cgi b/editclassifications.cgi index db9dd7f0a..817c53af7 100755 --- a/editclassifications.cgi +++ b/editclassifications.cgi @@ -198,9 +198,10 @@ if ($action eq 'update') { if ($action eq 'reclassify') { my $classification = Bugzilla::Classification->check($class_name); - + my $sth = $dbh->prepare("UPDATE products SET classification_id = ? WHERE name = ?"); + my @names; if (defined $cgi->param('add_products')) { check_token_data($token, 'reclassify_classifications'); @@ -208,6 +209,7 @@ if ($action eq 'reclassify') { foreach my $prod ($cgi->param("prodlist")) { trick_taint($prod); $sth->execute($classification->id, $prod); + push @names, $prod; } } delete_token($token); @@ -216,7 +218,8 @@ if ($action eq 'reclassify') { if (defined $cgi->param('myprodlist')) { foreach my $prod ($cgi->param("myprodlist")) { trick_taint($prod); - $sth->execute(1,$prod); + $sth->execute(1, $prod); + push @names, $prod; } } delete_token($token); @@ -226,6 +229,10 @@ if ($action eq 'reclassify') { $vars->{'classification'} = $classification; $vars->{'token'} = issue_session_token('reclassify_classifications'); + foreach my $name (@names) { + Bugzilla->memcached->clear({ table => 'products', name => $name }); + } + LoadTemplate($action); } diff --git a/editusers.cgi b/editusers.cgi index a6a93c41e..b92ace507 100755 --- a/editusers.cgi +++ b/editusers.cgi @@ -646,6 +646,11 @@ if ($action eq 'search') { $dbh->bz_commit_transaction(); delete_token($token); + # It's complex to determine which items now need to be flushed from + # memcached. As user deletion is expected to be a rare event, we just + # flush the entire cache when a user is deleted. + Bugzilla->memcached->clear_all(); + $vars->{'message'} = 'account_deleted'; $vars->{'otheruser'}{'login'} = $otherUser->login; $vars->{'restrictablegroups'} = $user->bless_groups(); diff --git a/extensions/ContributorEngagement/Extension.pm b/extensions/ContributorEngagement/Extension.pm index 0e86eb4ca..aa8804034 100644 --- a/extensions/ContributorEngagement/Extension.pm +++ b/extensions/ContributorEngagement/Extension.pm @@ -39,6 +39,7 @@ sub install_update_db { _populate_first_reviewed_ids(); } } + sub _populate_first_reviewed_ids { my $dbh = Bugzilla->dbh; @@ -96,6 +97,7 @@ sub flag_end_of_update { Bugzilla->dbh->do("UPDATE profiles SET first_patch_reviewed_id = ? WHERE userid = ?", undef, $attachment->id, $attachment->attacher->id); + Bugzilla->memcached->clear({ table => 'profiles', id => $$attachment->attacher->id }); last; } } diff --git a/extensions/EditComments/Extension.pm b/extensions/EditComments/Extension.pm index 7396c6f28..a3769544f 100644 --- a/extensions/EditComments/Extension.pm +++ b/extensions/EditComments/Extension.pm @@ -226,6 +226,7 @@ sub bug_end_of_update { $dbh->do("UPDATE longdescs SET thetext = ?, edit_count = edit_count + 1 WHERE comment_id = ?", undef, $new_comment, $comment_id); + Bugzilla->memcached->clear({ table => 'longdescs', id => $comment_id }); # Log old comment to the longdescs activity table $timestamp ||= $dbh->selectrow_array("SELECT NOW()"); diff --git a/extensions/FlagDefaultRequestee/Extension.pm b/extensions/FlagDefaultRequestee/Extension.pm index 9c15f741a..0ab599cd3 100644 --- a/extensions/FlagDefaultRequestee/Extension.pm +++ b/extensions/FlagDefaultRequestee/Extension.pm @@ -121,6 +121,7 @@ sub _set_default_requestee { $dbh->do("UPDATE flagtypes SET default_requestee = ? WHERE id = ?", undef, $requestee_id, $type->id); + Bugzilla->memcached->clear({ table => 'flagtypes', id => $type->id }); } ################## diff --git a/extensions/Push/lib/BacklogMessage.pm b/extensions/Push/lib/BacklogMessage.pm index 8f5263038..cd40ebefb 100644 --- a/extensions/Push/lib/BacklogMessage.pm +++ b/extensions/Push/lib/BacklogMessage.pm @@ -15,6 +15,7 @@ use base 'Bugzilla::Object'; use constant AUDIT_CREATES => 0; use constant AUDIT_UPDATES => 0; use constant AUDIT_REMOVES => 0; +use constant USE_MEMCACHED => 0; use Bugzilla; use Bugzilla::Error; diff --git a/extensions/Push/lib/Backoff.pm b/extensions/Push/lib/Backoff.pm index 05ee0a775..55552e5e1 100644 --- a/extensions/Push/lib/Backoff.pm +++ b/extensions/Push/lib/Backoff.pm @@ -15,6 +15,7 @@ use base 'Bugzilla::Object'; use constant AUDIT_CREATES => 0; use constant AUDIT_UPDATES => 0; use constant AUDIT_REMOVES => 0; +use constant USE_MEMCACHED => 0; use Bugzilla; use Bugzilla::Util; diff --git a/extensions/Push/lib/LogEntry.pm b/extensions/Push/lib/LogEntry.pm index 303c19da4..848df0480 100644 --- a/extensions/Push/lib/LogEntry.pm +++ b/extensions/Push/lib/LogEntry.pm @@ -15,6 +15,7 @@ use base 'Bugzilla::Object'; use constant AUDIT_CREATES => 0; use constant AUDIT_UPDATES => 0; use constant AUDIT_REMOVES => 0; +use constant USE_MEMCACHED => 0; use Bugzilla; use Bugzilla::Error; diff --git a/extensions/Push/lib/Message.pm b/extensions/Push/lib/Message.pm index ebe32d0ea..6d2ed2531 100644 --- a/extensions/Push/lib/Message.pm +++ b/extensions/Push/lib/Message.pm @@ -15,6 +15,7 @@ use base 'Bugzilla::Object'; use constant AUDIT_CREATES => 0; use constant AUDIT_UPDATES => 0; use constant AUDIT_REMOVES => 0; +use constant USE_MEMCACHED => 0; use Bugzilla; use Bugzilla::Error; diff --git a/extensions/Review/Extension.pm b/extensions/Review/Extension.pm index c92d17d8b..b495c9ecd 100644 --- a/extensions/Review/Extension.pm +++ b/extensions/Review/Extension.pm @@ -273,6 +273,7 @@ sub _adjust_request_count { undef, $requestee_id ); + Bugzilla->memcached->clear({ table => 'profiles', id => $requestee_id }); } sub _new_reviewers_from_input { diff --git a/extensions/Review/lib/Util.pm b/extensions/Review/lib/Util.pm index 7304f9ba6..83589e2d0 100644 --- a/extensions/Review/lib/Util.pm +++ b/extensions/Review/lib/Util.pm @@ -58,6 +58,7 @@ sub _update_profile { $data->{needinfo} || 0, $data->{id} ); + Bugzilla->memcached->clear({ table => 'profiles', id => $data->{id} }); } 1; diff --git a/extensions/TagNewUsers/Extension.pm b/extensions/TagNewUsers/Extension.pm index 599504225..7f12445fb 100644 --- a/extensions/TagNewUsers/Extension.pm +++ b/extensions/TagNewUsers/Extension.pm @@ -168,6 +168,7 @@ sub _update_comment_count { 'UPDATE profiles SET comment_count=? WHERE userid=?', undef, $count, $id ); + Bugzilla->memcached->clear({ table => 'profiles', id => $id }); $self->{comment_count} = $count; } @@ -179,6 +180,7 @@ sub _first_patch_bug_id { 'UPDATE profiles SET first_patch_bug_id=? WHERE userid=?', undef, $bug_id, $self->id ); + Bugzilla->memcached->clear({ table => 'profiles', id => $self->id }); $self->{first_patch_bug_id} = $bug_id; } diff --git a/extensions/UserProfile/Extension.pm b/extensions/UserProfile/Extension.pm index 673c0c2a1..efd83591d 100644 --- a/extensions/UserProfile/Extension.pm +++ b/extensions/UserProfile/Extension.pm @@ -45,6 +45,7 @@ sub _user_set_last_activity_ts { "UPDATE profiles SET last_activity_ts = ? WHERE userid = ?", undef, $value, $self->id); + Bugzilla->memcached->clear({ table => 'profiles', id => $self->id }); } sub _user_clear_last_statistics_ts { @@ -56,6 +57,7 @@ sub _user_clear_last_statistics_ts { "UPDATE profiles SET last_statistics_ts = NULL WHERE userid = ?", undef, $self->id); + Bugzilla->memcached->clear({ table => 'profiles', id => $self->id }); } # diff --git a/extensions/UserProfile/bin/update.pl b/extensions/UserProfile/bin/update.pl index 457585f8d..2a4997aee 100755 --- a/extensions/UserProfile/bin/update.pl +++ b/extensions/UserProfile/bin/update.pl @@ -50,6 +50,7 @@ if (@$user_ids) { last_user_activity($user_id), $user_id ); + Bugzilla->memcached->clear({ table => 'profiles', id => $user_id }); } $dbh->do( "DELETE FROM profiles_statistics_recalc WHERE " . $dbh->sql_in('user_id', $user_ids) diff --git a/extensions/UserProfile/lib/Util.pm b/extensions/UserProfile/lib/Util.pm index b5550bdc1..71d0e6501 100644 --- a/extensions/UserProfile/lib/Util.pm +++ b/extensions/UserProfile/lib/Util.pm @@ -171,6 +171,9 @@ EOF $dbh->do( "UPDATE profiles SET last_statistics_ts=NULL WHERE " . $dbh->sql_in('userid', $user_ids) ); + foreach my $id (@$user_ids) { + Bugzilla->memcached->clear({ table => 'profiles', id => $id }); + } return scalar(@$user_ids); } @@ -209,6 +212,7 @@ sub _set_last_statistics_ts { undef, $timestamp, $user_id, ); + Bugzilla->memcached->clear({ table => 'profiles', id => $user_id }); } sub _update_statistics { @@ -32,6 +32,7 @@ use Bugzilla; use Bugzilla::Bug; use Bugzilla::Constants; use Bugzilla::Search; +use Bugzilla::Search::Saved; use Bugzilla::User; use Bugzilla::Util; use Bugzilla::Error; @@ -54,9 +55,11 @@ if ($cgi->param('nukedefaultquery')) { if ($userid) { my $token = $cgi->param('token'); check_hash_token($token, ['nukedefaultquery']); - $dbh->do("DELETE FROM namedqueries" . - " WHERE userid = ? AND name = ?", - undef, ($userid, DEFAULT_QUERY_NAME)); + my $named_queries = Bugzilla::Search::Saved->match( + { userid => $userid, name => DEFAULT_QUERY_NAME }); + if (@$named_queries) { + $named_queries->[0]->remove_from_db(); + } } $buffer = ""; } diff --git a/sanitycheck.cgi b/sanitycheck.cgi index 36751d821..f718312f4 100755 --- a/sanitycheck.cgi +++ b/sanitycheck.cgi @@ -91,6 +91,7 @@ else { } } my $vars = {}; +my $clear_memcached = 0; print $cgi->header() unless Bugzilla->usage_mode == USAGE_MODE_CMDLINE; @@ -167,6 +168,7 @@ if ($cgi->param('createmissinggroupcontrolmapentries')) { } Status('group_control_map_entries_repaired', {counter => $counter}); + $clear_memcached = 1 if $counter; } ########################################################################### @@ -193,6 +195,7 @@ if ($cgi->param('repair_creation_date')) { $sth_UpdateDate->execute($date, $bugid); } Status('bug_creation_date_fixed', {bug_count => scalar(@$bug_ids)}); + $clear_memcached = 1 if @$bug_ids; } ########################################################################### @@ -209,6 +212,7 @@ if ($cgi->param('repair_everconfirmed')) { $dbh->do("UPDATE bugs SET everconfirmed = 1 WHERE bug_status IN ($confirmed_open_states)"); Status('everconfirmed_end'); + $clear_memcached = 1; } ########################################################################### @@ -224,11 +228,12 @@ if ($cgi->param('repair_bugs_fulltext')) { ON bugs_fulltext.bug_id = bugs.bug_id WHERE bugs_fulltext.bug_id IS NULL'); - foreach my $bugid (@$bug_ids) { - Bugzilla::Bug->new($bugid)->_sync_fulltext( new_bug => 1 ); - } + foreach my $bugid (@$bug_ids) { + Bugzilla::Bug->new($bugid)->_sync_fulltext( new_bug => 1 ); + } - Status('bugs_fulltext_fixed', {bug_count => scalar(@$bug_ids)}); + Status('bugs_fulltext_fixed', {bug_count => scalar(@$bug_ids)}); + $clear_memcached = 1 if @$bug_ids; } ########################################################################### @@ -264,7 +269,10 @@ if ($cgi->param('rescanallBugMail')) { Bugzilla::BugMail::Send($bugid, $vars); } - Status('send_bugmail_end') if scalar(@$list); + if (@$list) { + Status('send_bugmail_end'); + Bugzilla->memcached->clear_all(); + } unless (Bugzilla->usage_mode == USAGE_MODE_CMDLINE) { $template->process('global/footer.html.tmpl', $vars) @@ -298,6 +306,7 @@ if ($cgi->param('remove_invalid_bug_references')) { if (scalar(@$bug_ids)) { $dbh->do("DELETE FROM $table WHERE $field IN (" . join(',', @$bug_ids) . ")"); + $clear_memcached = 1; } } @@ -328,6 +337,7 @@ if ($cgi->param('remove_invalid_attach_references')) { $dbh->bz_commit_transaction(); Status('attachment_reference_deletion_end'); + $clear_memcached = 1 if @$attach_ids; } ########################################################################### @@ -354,12 +364,17 @@ if ($cgi->param('remove_old_whine_targets')) { $dbh->do("DELETE FROM whine_schedules WHERE mailto_type = $type AND mailto IN (" . join(',', @$old_ids) . ")"); + $clear_memcached = 1; } } $dbh->bz_commit_transaction(); Status('whines_obsolete_target_deletion_end'); } +# If any repairs were attempted or made, we need to clear memcached to ensure +# state is consistent. +Bugzilla->memcached->clear_all() if $clear_memcached; + ########################################################################### # Repair hook ########################################################################### @@ -735,6 +750,7 @@ if (scalar(@invalid_flags)) { # Silently delete these flags, with no notification to requesters/setters. $dbh->do('DELETE FROM flags WHERE id IN (' . join(',', @flag_ids) .')'); Status('flag_deletion_end'); + Bugzilla->memcached->clear_all(); } else { foreach my $flag (@$invalid_flags) { diff --git a/userprefs.cgi b/userprefs.cgi index b0969b93d..4ba0fd906 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -511,12 +511,13 @@ sub SaveSavedSearches { } $user->flush_queries_cache; - + # Update profiles.mybugslink. my $showmybugslink = defined($cgi->param("showmybugslink")) ? 1 : 0; $dbh->do("UPDATE profiles SET mybugslink = ? WHERE userid = ?", - undef, ($showmybugslink, $user->id)); + undef, ($showmybugslink, $user->id)); $user->{'showmybugslink'} = $showmybugslink; + Bugzilla->memcached->clear({ table => 'profiles', id => $user->id }); } |