JanZerebecki has uploaded a new change for review.

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

Change subject: EntityUsageTable: Wrap batches in transactions
......................................................................

EntityUsageTable: Wrap batches in transactions

Also reduces the default batch size to 100.
As per jcrespo's comment https://phabricator.wikimedia.org/T107319#1570912

Bug: T107319
Change-Id: I992f0a8bd6494ebc225e80e4cdae830583612478
---
M client/includes/Usage/Sql/EntityUsageTable.php
M client/includes/Usage/Sql/SqlUsageTracker.php
M client/includes/store/sql/ConsistentReadConnectionManager.php
M 
client/tests/phpunit/includes/store/sql/ConsistentReadConnectionManagerTest.php
4 files changed, 45 insertions(+), 13 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase 
refs/changes/43/233743/1

diff --git a/client/includes/Usage/Sql/EntityUsageTable.php 
b/client/includes/Usage/Sql/EntityUsageTable.php
index f68b864..89e1a1a 100644
--- a/client/includes/Usage/Sql/EntityUsageTable.php
+++ b/client/includes/Usage/Sql/EntityUsageTable.php
@@ -4,6 +4,7 @@
 
 use ArrayIterator;
 use DatabaseBase;
+use Exception;
 use InvalidArgumentException;
 use Iterator;
 use Wikibase\Client\Usage\EntityUsage;
@@ -131,6 +132,7 @@
         * @param string $touched timestamp
         */
        private function touchUsageBatch( array $rowIds, $touched ) {
+               $this->connection->begin( __METHOD__ );
                $this->connection->update(
                        $this->tableName,
                        array(
@@ -141,6 +143,7 @@
                        ),
                        __METHOD__
                );
+               $this->connection->commit( __METHOD__ );
        }
 
        /**
@@ -195,8 +198,12 @@
                $c = 0;
 
                foreach ( $batches as $rows ) {
+                       $this->connection->begin( __METHOD__ );
+
                        $this->connection->insert( $this->tableName, $rows, 
__METHOD__, array( 'IGNORE' ) );
                        $c += $this->connection->affectedRows();
+
+                       $this->connection->commit( __METHOD__ );
                }
 
                return $c;
@@ -344,6 +351,7 @@
                $batches = array_chunk( $idStrings, $this->batchSize );
 
                foreach ( $batches as $batch ) {
+                       $this->connection->begin( __METHOD__ );
                        $this->connection->delete(
                                $this->tableName,
                                array(
@@ -351,6 +359,7 @@
                                ),
                                __METHOD__
                        );
+                       $this->connection->commit( __METHOD__ );
                }
        }
 
diff --git a/client/includes/Usage/Sql/SqlUsageTracker.php 
b/client/includes/Usage/Sql/SqlUsageTracker.php
index 34356dc..fd35634 100644
--- a/client/includes/Usage/Sql/SqlUsageTracker.php
+++ b/client/includes/Usage/Sql/SqlUsageTracker.php
@@ -37,7 +37,7 @@
        /**
         * @var int
         */
-       private $batchSize = 1000;
+       private $batchSize = 100;
 
        /**
         * @param EntityIdParser $idParser
@@ -129,7 +129,9 @@
                        return;
                }
 
-               $db = $this->connectionManager->beginAtomicSection( __METHOD__ 
);
+               // NOTE: while logically we'd like the below to be atomic, we 
don't wrap it in a
+               // transaction to prevent long lock retention during big 
updates.
+               $db = $this->connectionManager->getWriteConnection();
 
                try {
                        $usageTable = $this->newUsageTable( $db );
@@ -145,9 +147,9 @@
                        $usageTable->touchUsages( $pageId, $keep, $touched );
                        $usageTable->addUsages( $pageId, $added, $touched );
 
-                       $this->connectionManager->commitAtomicSection( $db, 
__METHOD__ );
+                       $this->connectionManager->releaseConnection( $db );
                } catch ( Exception $ex ) {
-                       $this->connectionManager->rollbackAtomicSection( $db, 
__METHOD__ );
+                       $this->connectionManager->releaseConnection( $db );
 
                        if ( $ex instanceof DBError ) {
                                throw new UsageTrackerException( 
$ex->getMessage(), $ex->getCode(), $ex );
@@ -168,16 +170,18 @@
         * @throws UsageTrackerException
         */
        public function pruneStaleUsages( $pageId, $lastUpdatedBefore ) {
-               $db = $this->connectionManager->beginAtomicSection( __METHOD__ 
);
+               // NOTE: while logically we'd like the below to be atomic, we 
don't wrap it in a
+               // transaction to prevent long lock retention during big 
updates.
+               $db = $this->connectionManager->getWriteConnection();
 
                try {
                        $usageTable = $this->newUsageTable( $db );
                        $pruned = $usageTable->pruneStaleUsages( $pageId, 
$lastUpdatedBefore );
 
-                       $this->connectionManager->commitAtomicSection( $db, 
__METHOD__ );
+                       $this->connectionManager->releaseConnection( $db );
                        return $pruned;
                } catch ( Exception $ex ) {
-                       $this->connectionManager->rollbackAtomicSection( $db, 
__METHOD__ );
+                       $this->connectionManager->releaseConnection( $db );
 
                        if ( $ex instanceof DBError ) {
                                throw new UsageTrackerException( 
$ex->getMessage(), $ex->getCode(), $ex );
@@ -200,15 +204,17 @@
                        return;
                }
 
-               $db = $this->connectionManager->beginAtomicSection( __METHOD__ 
);
+               // NOTE: while logically we'd like the below to be atomic, we 
don't wrap it in a
+               // transaction to prevent long lock retention during big 
updates.
+               $db = $this->connectionManager->getWriteConnection();
 
                try {
                        $usageTable = $this->newUsageTable( $db );
                        $usageTable->removeEntities( $entityIds );
 
-                       $this->connectionManager->commitAtomicSection( $db, 
__METHOD__ );
+                       $this->connectionManager->releaseConnection( $db );
                } catch ( Exception $ex ) {
-                       $this->connectionManager->rollbackAtomicSection( $db, 
__METHOD__ );
+                       $this->connectionManager->releaseConnection( $db );
 
                        if ( $ex instanceof DBError ) {
                                throw new UsageTrackerException( 
$ex->getMessage(), $ex->getCode(), $ex );
diff --git a/client/includes/store/sql/ConsistentReadConnectionManager.php 
b/client/includes/store/sql/ConsistentReadConnectionManager.php
index 9e48c45..503a3b0 100644
--- a/client/includes/store/sql/ConsistentReadConnectionManager.php
+++ b/client/includes/store/sql/ConsistentReadConnectionManager.php
@@ -70,7 +70,8 @@
        }
 
        /**
-        * Returns a database connection for reading.
+        * Returns a database connection for reading. The connection should 
later be released by
+        * calling releaseConnection().
         *
         * @note: If forceMaster() or beginAtomicSection() were previously 
called on this
         * ConsistentReadConnectionManager instance, this method will return a 
connection to the master database,
@@ -84,11 +85,12 @@
        }
 
        /**
-        * Returns a connection to the master DB, for updating.
+        * Returns a connection to the master DB, for updating. The connection 
should later be released
+        * by calling releaseConnection().
         *
         * @return DatabaseBase
         */
-       private function getWriteConnection() {
+       public function getWriteConnection() {
                return $this->loadBalancer->getConnection( DB_MASTER, array(), 
$this->dbName );
        }
 
diff --git 
a/client/tests/phpunit/includes/store/sql/ConsistentReadConnectionManagerTest.php
 
b/client/tests/phpunit/includes/store/sql/ConsistentReadConnectionManagerTest.php
index 6190ac9..cfaeb9c 100644
--- 
a/client/tests/phpunit/includes/store/sql/ConsistentReadConnectionManagerTest.php
+++ 
b/client/tests/phpunit/includes/store/sql/ConsistentReadConnectionManagerTest.php
@@ -43,6 +43,21 @@
                $this->assertSame( $connection, $actual );
        }
 
+       public function testGetWriteConnection() {
+               $connection = $this->getConnectionMock();
+               $lb = $this->getLoadBalancerMock();
+
+               $lb->expects( $this->once() )
+                       ->method( 'getConnection' )
+                       ->with( DB_MASTER )
+                       ->will( $this->returnValue( $connection ) );
+
+               $manager = new ConsistentReadConnectionManager( $lb );
+               $actual = $manager->getWriteConnection();
+
+               $this->assertSame( $connection, $actual );
+       }
+
        public function testForceMaster() {
                $connection = $this->getConnectionMock();
                $lb = $this->getLoadBalancerMock();

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I992f0a8bd6494ebc225e80e4cdae830583612478
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: wmf/1.26wmf20
Gerrit-Owner: JanZerebecki <jan.wikime...@zerebecki.de>
Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to