Aaron Schulz has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/204219

Change subject: [WIP] Made wl_notificationtimestamp updates able to use queues
......................................................................

[WIP] Made wl_notificationtimestamp updates able to use queues

* This adds a wgActivityUpdatesUseJobQueue setting, which lets
  these updates work via the job queue, rather than direct DB
  master updates.

Bug: T91284
Change-Id: Ie60e20162fd833e64d81763a6aa1dc3faf2162f3
---
M includes/DefaultSettings.php
M includes/User.php
M includes/WatchedItem.php
A includes/jobqueue/jobs/ActivityUpdateJob.php
4 files changed, 143 insertions(+), 21 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/19/204219/1

diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index dc16ae3..a4ff50b 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -1588,6 +1588,15 @@
 $wgEnotifUseJobQ = false;
 
 /**
+ * Use the job queue for user activity updates like updating "last visited"
+ * fields for email notifications of page changes. This should only be enabled
+ * if the jobs have a dedicated runner to avoid update lag.
+ *
+ * @since 1.26
+ */
+$wgActivityUpdatesUseJobQueue = false;
+
+/**
  * Use real name instead of username in e-mail "from" field.
  */
 $wgEnotifUseRealName = false;
@@ -6416,6 +6425,7 @@
        'ThumbnailRender' => 'ThumbnailRenderJob',
        'recentChangesUpdate' => 'RecentChangesUpdateJob',
        'refreshLinksPrioritized' => 'RefreshLinksJob', // for cascading 
protection
+       'activityUpdateJob' => 'ActivityUpdateJob',
        'enqueue' => 'EnqueueJob', // local queue for multi-DC setups
        'null' => 'NullJob'
 );
diff --git a/includes/User.php b/includes/User.php
index f526fe0..59d0a99 100644
--- a/includes/User.php
+++ b/includes/User.php
@@ -3394,7 +3394,9 @@
                        $force = 'force';
                }
 
-               $this->getWatchedItem( $title )->resetNotificationTimestamp( 
$force, $oldid );
+               $this->getWatchedItem( $title )->resetNotificationTimestamp(
+                       $force, $oldid, WatchedItem::DEFERRED
+               );
        }
 
        /**
diff --git a/includes/WatchedItem.php b/includes/WatchedItem.php
index 524e701..882eb1b 100644
--- a/includes/WatchedItem.php
+++ b/includes/WatchedItem.php
@@ -27,20 +27,6 @@
  * @ingroup Watchlist
  */
 class WatchedItem {
-       /**
-        * Constant to specify that user rights 'editmywatchlist' and
-        * 'viewmywatchlist' should not be checked.
-        * @since 1.22
-        */
-       const IGNORE_USER_RIGHTS = 0;
-
-       /**
-        * Constant to specify that user rights 'editmywatchlist' and
-        * 'viewmywatchlist' should be checked.
-        * @since 1.22
-        */
-       const CHECK_USER_RIGHTS = 1;
-
        /** @var Title */
        public $mTitle;
 
@@ -58,6 +44,31 @@
 
        /** @var string */
        private $timestamp;
+
+       /**
+        * Constant to specify that user rights 'editmywatchlist' and
+        * 'viewmywatchlist' should not be checked.
+        * @since 1.22
+        */
+       const IGNORE_USER_RIGHTS = 0;
+
+       /**
+        * Constant to specify that user rights 'editmywatchlist' and
+        * 'viewmywatchlist' should be checked.
+        * @since 1.22
+        */
+       const CHECK_USER_RIGHTS = 1;
+
+       /**
+        * Do DB master updates right now
+        * @since 1.22
+        */
+       const IMMEDIATE = 0;
+       /**
+        * Do DB master updates via the job queue
+        * @since 1.22
+        */
+       const DEFERRED = 1;
 
        /**
         * Create a WatchedItem object with the given user and title
@@ -208,8 +219,13 @@
         * @param bool $force Whether to force the write query to be executed 
even if the
         *    page is not watched or the notification timestamp is already NULL.
         * @param int $oldid The revision id being viewed. If not given or 0, 
latest revision is assumed.
+        * @mode int $mode WatchedItem::DEFERRED/IMMEDIATE
         */
-       public function resetNotificationTimestamp( $force = '', $oldid = 0 ) {
+       public function resetNotificationTimestamp(
+               $force = '', $oldid = 0, $mode = self::IMMEDIATE
+       ) {
+               global $wgActivityUpdatesUseJobQueue;
+
                // Only loggedin user can have a watchlist
                if ( wfReadOnly() || $this->mUser->isAnon() || 
!$this->isAllowed( 'editmywatchlist' ) ) {
                        return;
@@ -258,11 +274,30 @@
                        }
                }
 
-               // If the page is watched by the user (or may be watched), 
update the timestamp on any
-               // any matching rows
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => 
$notificationTimestamp ),
-                       $this->dbCond(), __METHOD__ );
+               // If the page is watched by the user (or may be watched), 
update the timestamp
+               if ( $mode === self::DEFERRED && $wgActivityUpdatesUseJobQueue 
) {
+                       JobQueueGroup::singleton()->push(
+                               EnqueueJob::newFromLocalJobs( new 
JobSpecification(
+                                       'activityUpdateJob',
+                                       array(
+                                               'type'      => 
'updateWatchlistNotification',
+                                               'userid'    => 
$this->getUserId(),
+                                               'notifTime' => 
$notificationTimestamp,
+                                               'curTime'   => time()
+                                       ),
+                                       array( 'removeDuplicates' => true ),
+                                       $title
+                               ) )
+                       );
+               } else {
+                       $dbw = wfGetDB( DB_MASTER );
+                       $dbw->update( 'watchlist',
+                               array( 'wl_notificationtimestamp' => 
$notificationTimestamp ),
+                               $this->dbCond(),
+                               __METHOD__
+                       );
+               }
+
                $this->timestamp = null;
        }
 
diff --git a/includes/jobqueue/jobs/ActivityUpdateJob.php 
b/includes/jobqueue/jobs/ActivityUpdateJob.php
new file mode 100644
index 0000000..495bda9
--- /dev/null
+++ b/includes/jobqueue/jobs/ActivityUpdateJob.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Aaron Schulz
+ * @ingroup JobQueue
+ */
+
+/**
+ * Job for updating user activity like "last viewed" timestamps
+ *
+ * @ingroup JobQueue
+ * @since 1.26
+ */
+class ActivityUpdateJob extends Job {
+       function __construct( $title, $params ) {
+               parent::__construct( 'activityUpdateJob', $title, $params );
+
+               if ( !isset( $params['type'] ) ) {
+                       throw new InvalidArgumentException( "Missing 'type' 
parameter." );
+               }
+
+               $this->removeDuplicates = true;
+       }
+
+       public function run() {
+               if ( $this->params['type'] === 'updateWatchlistNotification' ) {
+                       $this->updateWatchlistNotification();
+               } else {
+                       throw new Exception( "Invalid 'type' parameter 
'{$this->params['type']}'." );
+               }
+
+               return true;
+       }
+
+       protected function updateWatchlistNotification() {
+               $casTimestamp = ( $this->params['notifTime'] !== null )
+                       ? $this->params['notifTime']
+                       : $this->params['curTime'];
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update( 'watchlist',
+                       array(
+                               'wl_notificationtimestamp' => 
$dbw->timestampOrNull( $this->params['notifTime'] )
+                       ),
+                       array(
+                               'wl_user' => $this->params['userid'],
+                               'wl_namespace' => $this->title->getNamespace(),
+                               'wl_title' => $this->title->getDBkey(),
+                               // Add a "check and set" style comparison to 
handle conflicts.
+                               // The inequality always avoids updates when 
the current value
+                               // is already NULL per ANSI SQL. This is 
desired since NULL means
+                               // that the user is "caught up" on edits 
already. When the field
+                               // is non-NULL, make sure not to set it back in 
time or set it to
+                               // NULL when newer revisions were in fact added 
to the page.
+                               'wl_notificationtimestamp < ' . 
$dbw->addQuotes( $dbw->timestamp( $casTimestamp ) )
+                       ),
+                       __METHOD__
+               );
+       }
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/204219
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie60e20162fd833e64d81763a6aa1dc3faf2162f3
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to