add method to atomically change between shared and exclusive lock
This commit is contained in:
parent
43772e2a9a
commit
a1372b2fb5
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue