Avoid locking aggregated SELECT in Category::refresh
authorAaron Schulz <aschulz@wikimedia.org>
Wed, 18 Apr 2018 23:09:55 +0000 (16:09 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Wed, 18 Apr 2018 23:10:04 +0000 (16:10 -0700)
LOCK IN SHARE MODE is not allowed with aggregation on postgres/oracle.
Split out the locking and aggregation into two separate queries.

Change-Id: I7f8d113fb678b368437dad84bdb93e81db314cd5

includes/Category.php

index 9241730..ac5cc42 100644 (file)
@@ -335,18 +335,28 @@ class Category {
 
                $dbw->startAtomic( __METHOD__ );
 
-               $cond1 = $dbw->conditional( [ 'page_namespace' => NS_CATEGORY ], 1, 'NULL' );
-               $cond2 = $dbw->conditional( [ 'page_namespace' => NS_FILE ], 1, 'NULL' );
-               $result = $dbw->selectRow(
+               // Lock all the `categorylinks` records and gaps for this category;
+               // this is a separate query due to postgres/oracle limitations
+               $dbw->selectRowCount(
                        [ 'categorylinks', 'page' ],
-                       [ 'pages' => 'COUNT(*)',
-                               'subcats' => "COUNT($cond1)",
-                               'files' => "COUNT($cond2)"
-                       ],
+                       '*',
                        [ 'cl_to' => $this->mName, 'page_id = cl_from' ],
                        __METHOD__,
                        [ 'LOCK IN SHARE MODE' ]
                );
+               // Get the aggregate `categorylinks` row counts for this category
+               $catCond = $dbw->conditional( [ 'page_namespace' => NS_CATEGORY ], 1, 'NULL' );
+               $fileCond = $dbw->conditional( [ 'page_namespace' => NS_FILE ], 1, 'NULL' );
+               $result = $dbw->selectRow(
+                       [ 'categorylinks', 'page' ],
+                       [
+                               'pages' => 'COUNT(*)',
+                               'subcats' => "COUNT($catCond)",
+                               'files' => "COUNT($fileCond)"
+                       ],
+                       [ 'cl_to' => $this->mName, 'page_id = cl_from' ],
+                       __METHOD__
+               );
 
                $shouldExist = $result->pages > 0 || $this->getTitle()->exists();