X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FStorage%2FNameTableStore.php;h=6c7919d2541c70604eb064d5490df43505299aca;hb=33afb7440a03df8d1878c94d2f3d3b9fdd1a848b;hp=52e8f5b99376efb30a32a806d3882516c1948cf3;hpb=84662b72f073f2df3aa8e8e209da0bc568b91716;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Storage/NameTableStore.php b/includes/Storage/NameTableStore.php index 52e8f5b993..6c7919d254 100644 --- a/includes/Storage/NameTableStore.php +++ b/includes/Storage/NameTableStore.php @@ -27,7 +27,6 @@ use Wikimedia\Assert\Assert; use Wikimedia\Rdbms\Database; use Wikimedia\Rdbms\IDatabase; use Wikimedia\Rdbms\ILoadBalancer; -use Wikimedia\Rdbms\LoadBalancer; /** * @author Addshore @@ -35,7 +34,7 @@ use Wikimedia\Rdbms\LoadBalancer; */ class NameTableStore { - /** @var LoadBalancer */ + /** @var ILoadBalancer */ private $loadBalancer; /** @var WANObjectCache */ @@ -159,11 +158,13 @@ class NameTableStore { if ( $searchResult === false ) { $id = $this->store( $name ); if ( $id === null ) { - // RACE: $name was already in the db, probably just inserted, so load from master - // Use DBO_TRX to avoid missing inserts due to other threads or REPEATABLE-READs - $table = $this->loadTable( - $this->getDBConnection( DB_MASTER, LoadBalancer::CONN_TRX_AUTOCOMMIT ) - ); + // RACE: $name was already in the db, probably just inserted, so load from master. + // Use DBO_TRX to avoid missing inserts due to other threads or REPEATABLE-READs. + // ...but not during unit tests, because we need the fake DB tables of the default + // connection. + $connFlags = defined( 'MW_PHPUNIT_TEST' ) ? 0 : ILoadBalancer::CONN_TRX_AUTOCOMMIT; + $table = $this->reloadMap( $connFlags ); + $searchResult = array_search( $name, $table, true ); if ( $searchResult === false ) { // Insert failed due to IGNORE flag, but DB_MASTER didn't give us the data @@ -172,14 +173,15 @@ class NameTableStore { $this->logger->error( $m ); throw new NameTableAccessException( $m ); } - $this->purgeWANCache( - function () { - $this->cache->reap( $this->getCacheKey(), INF ); - } - ); + } elseif ( isset( $table[$id] ) ) { + throw new NameTableAccessException( + "Expected unused ID from database insert for '$name' " + . " into '{$this->table}', but ID $id is already associated with" + . " the name '{$table[$id]}'! This may indicate database corruption!" ); } else { $table[$id] = $name; $searchResult = $id; + // As store returned an ID we know we inserted so delete from WAN cache $this->purgeWANCache( function () { @@ -193,6 +195,31 @@ class NameTableStore { return $searchResult; } + /** + * Reloads the name table from the master database, and purges the WAN cache entry. + * + * @note This should only be called in situations where the local cache has been detected + * to be out of sync with the database. There should be no reason to call this method + * from outside the NameTabelStore during normal operation. This method may however be + * useful in unit tests. + * + * @param int $connFlags ILoadBalancer::CONN_XXX flags. Optional. + * + * @return \string[] The freshly reloaded name map + */ + public function reloadMap( $connFlags = 0 ) { + $this->tableCache = $this->loadTable( + $this->getDBConnection( DB_MASTER, $connFlags ) + ); + $this->purgeWANCache( + function () { + $this->cache->reap( $this->getCacheKey(), INF ); + } + ); + + return $this->tableCache; + } + /** * Get the id of the given name. * If the name doesn't exist this will throw.