Skip to content
Snippets Groups Projects
Commit a1372b2f authored by Robin Appelman's avatar Robin Appelman
Browse files

add method to atomically change between shared and exclusive lock

parent 43772e2a
No related branches found
No related tags found
No related merge requests found
...@@ -98,6 +98,26 @@ class MemcacheLockingProvider implements ILockingProvider { ...@@ -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 * release all lock acquired by this instance
*/ */
......
...@@ -45,6 +45,15 @@ interface ILockingProvider { ...@@ -45,6 +45,15 @@ interface ILockingProvider {
*/ */
public function releaseLock($path, $type); 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 * release all lock acquired by this instance
*/ */
......
...@@ -158,4 +158,57 @@ abstract class LockingProvider extends TestCase { ...@@ -158,4 +158,57 @@ abstract class LockingProvider extends TestCase {
$this->assertEquals('foo', $e->getPath()); $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);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment