Named locks are session-level constructs and this transaction agnostic.
Also make lockIsFree() a bit more consistent when the thread has the
lock itself.
Change-Id: Ief51196161bbc50c798740f3c738fd0e39880508
}
public function lockIsFree( $lockName, $method ) {
- return true;
+ // RDBMs methods for checking named locks may or may not count this thread itself.
+ // In MySQL, IS_FREE_LOCK() returns 0 if the thread already has the lock. This is
+ // the behavior choosen by the interface for this method.
+ return !isset( $this->namedLocksHeld[$lockName] );
}
public function lock( $lockName, $method, $timeout = 5 ) {
* @since 1.20
*/
public function lockIsFree( $lockName, $method ) {
+ if ( !parent::lockIsFree( $lockName, $method ) ) {
+ return false; // already held
+ }
+
$encName = $this->addQuotes( $this->makeLockName( $lockName ) );
$result = $this->query( "SELECT IS_FREE_LOCK($encName) AS lockstatus", $method );
$row = $this->fetchObject( $result );
return $index;
}
}
+
+ protected function isTransactableQuery( $sql ) {
+ return parent::isTransactableQuery( $sql ) &&
+ !preg_match( '/^SELECT\s+(GET|RELEASE|IS_FREE)_LOCK\(/', $sql );
+ }
}
class_alias( DatabaseMysqlBase::class, 'DatabaseMysqlBase' );
return $this->conn ? pg_close( $this->conn ) : true;
}
+ protected function isTransactableQuery( $sql ) {
+ return parent::isTransactableQuery( $sql ) &&
+ !preg_match( '/^SELECT\s+pg_(try_|)advisory_\w+\(/', $sql );
+ }
+
public function doQuery( $sql ) {
$conn = $this->getBindingHandle();
}
public function lockIsFree( $lockName, $method ) {
+ if ( !parent::lockIsFree( $lockName, $method ) ) {
+ return false; // already held
+ }
// http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
$key = $this->addQuotes( $this->bigintFromLockName( $lockName ) );
$result = $this->query( "SELECT (CASE(pg_try_advisory_lock($key))
public function setSchemaVars( $vars );
/**
- * Check to see if a named lock is available (non-blocking)
+ * Check to see if a named lock is not locked by any thread (non-blocking)
*
* @param string $lockName Name of lock to poll
* @param string $method Name of method calling us
$this->assertFalse( (bool)$db->trxLevel(), "Transaction cleared." );
}
+ /**
+ * @covers Wikimedia\Rdbms\Database::getScopedLockAndFlush
+ * @covers Wikimedia\Rdbms\Database::lock
+ * @covers Wikimedia\Rdbms\Database::unlock
+ * @covers Wikimedia\Rdbms\Database::lockIsFree
+ */
public function testGetScopedLock() {
$db = $this->getMockDB( [ 'isOpen' ] );
$db->method( 'isOpen' )->willReturn( true );
+ $this->assertEquals( 0, $db->trxLevel() );
+ $this->assertEquals( true, $db->lockIsFree( 'x', __METHOD__ ) );
+ $this->assertEquals( true, $db->lock( 'x', __METHOD__ ) );
+ $this->assertEquals( false, $db->lockIsFree( 'x', __METHOD__ ) );
+ $this->assertEquals( true, $db->unlock( 'x', __METHOD__ ) );
+ $this->assertEquals( true, $db->lockIsFree( 'x', __METHOD__ ) );
+ $this->assertEquals( 0, $db->trxLevel() );
+
+ $db->setFlag( DBO_TRX );
+ $this->assertEquals( true, $db->lockIsFree( 'x', __METHOD__ ) );
+ $this->assertEquals( true, $db->lock( 'x', __METHOD__ ) );
+ $this->assertEquals( false, $db->lockIsFree( 'x', __METHOD__ ) );
+ $this->assertEquals( true, $db->unlock( 'x', __METHOD__ ) );
+ $this->assertEquals( true, $db->lockIsFree( 'x', __METHOD__ ) );
+ $db->clearFlag( DBO_TRX );
+
+ $this->assertEquals( 0, $db->trxLevel() );
+
$db->setFlag( DBO_TRX );
try {
$this->badLockingMethodImplicit( $db );