add method to atomically change between shared and exclusive lock

This commit is contained in:
Robin Appelman 2015-05-29 14:34:21 +02:00
parent 43772e2a9a
commit a1372b2fb5
3 changed files with 82 additions and 0 deletions

View File

@ -98,6 +98,26 @@ class MemcacheLockingProvider implements ILockingProvider {
}
}
/**
* Change the type of an existing lock
*
* @param string $path
* @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE
* @throws \OCP\Lock\LockedException
*/
public function changeLock($path, $targetType) {
if ($targetType === self::LOCK_SHARED) {
if (!$this->memcache->cas($path, 'exclusive', 1)) {
throw new LockedException($path);
}
} else if ($targetType === self::LOCK_EXCLUSIVE) {
// we can only change a shared lock to an exclusive if there's only a single owner of the shared lock
if (!$this->memcache->cas($path, 1, 'exclusive')) {
throw new LockedException($path);
}
}
}
/**
* release all lock acquired by this instance
*/

View File

@ -45,6 +45,15 @@ interface ILockingProvider {
*/
public function releaseLock($path, $type);
/**
* Change the type of an existing lock
*
* @param string $path
* @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE
* @throws \OCP\Lock\LockedException
*/
public function changeLock($path, $targetType);
/**
* release all lock acquired by this instance
*/

View File

@ -158,4 +158,57 @@ abstract class LockingProvider extends TestCase {
$this->assertEquals('foo', $e->getPath());
}
}
public function testChangeLockToExclusive() {
$this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
$this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
$this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
$this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
}
public function testChangeLockToShared() {
$this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
$this->instance->changeLock('foo', ILockingProvider::LOCK_SHARED);
$this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
$this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testChangeLockToExclusiveDoubleShared() {
$this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
$this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
$this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testChangeLockToExclusiveNoShared() {
$this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testChangeLockToExclusiveFromExclusive() {
$this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
$this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testChangeLockToSharedNoExclusive() {
$this->instance->changeLock('foo', ILockingProvider::LOCK_SHARED);
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testChangeLockToSharedFromShared() {
$this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
$this->instance->changeLock('foo', ILockingProvider::LOCK_SHARED);
}
}