SqlBagOStuff: Fix modtoken comparison

String offsets in MariaDB are 1-based, except in "Oracle compatible"
mode. SUBSTR(modtoken,0,13) was always the empty string and so the
modtoken comparison was always true. I was able to reproduce a failure
to reach consistency using ring replication.

Add regression test.

Bug: T315271
Change-Id: I74e54e8aba44505dd04426c12d91a9ea0de17f22
This commit is contained in:
Tim Starling 2022-08-17 13:24:41 +10:00
parent 00a5a4d57a
commit 3cabe8bf8a
3 changed files with 20 additions and 3 deletions

View file

@ -1190,7 +1190,8 @@ class SqlBagOStuff extends MediumSpecificBagOStuff {
$expressionsByColumn['modtoken'] = $db->addQuotes( $mt );
foreach ( $expressionsByColumn as $column => $updateExpression ) {
$rhs = $db->conditional(
$db->addQuotes( substr( $mt, 0, 13 ) ) . ' >= SUBSTR(modtoken,0,13)',
$db->addQuotes( substr( $mt, 0, 13 ) ) . ' >= ' .
$db->buildSubString( 'modtoken', 1, 13 ),
$updateExpression,
$column
);

View file

@ -11,9 +11,9 @@ use Wikimedia\TestingAccessWrapper;
*/
abstract class BagOStuffTestBase extends MediaWikiIntegrationTestCase {
/** @var BagOStuff */
private $cache;
protected $cache;
private const TEST_TIME = 1563892142;
protected const TEST_TIME = 1563892142;
protected function setUp(): void {
parent::setUp();

View file

@ -15,4 +15,20 @@ class SqlBagOStuffMultiPrimaryIntegrationTest extends BagOStuffTestBase {
'reportDupes' => false
] );
}
public function testModtoken() {
$now = self::TEST_TIME;
$this->cache->setMockTime( $now );
$this->cache->set( 'test', 'a' );
$this->assertSame( 'a', $this->cache->get( 'test' ) );
$now--;
// Modtoken comparison makes this a no-op
$this->cache->set( 'test', 'b' );
$this->assertSame( 'a', $this->cache->get( 'test' ) );
$now += 2;
$this->cache->set( 'test', 'c' );
$this->assertSame( 'c', $this->cache->get( 'test' ) );
}
}