code.onehippo.org is currently readonly. We are migrating to code.bloomreach.com, please continue working there on Monday 14/12. See: https://docs.bloomreach.com/display/engineering/GitLab

Commit ac0b839d authored by Ard Schrijvers's avatar Ard Schrijvers

REPO-1811 Implement autocloseable LockResource and integration tests

parent 8ddbbc21
......@@ -27,6 +27,7 @@ import java.util.concurrent.ScheduledExecutorService;
import org.onehippo.cms7.services.lock.Lock;
import org.onehippo.cms7.services.lock.LockException;
import org.onehippo.cms7.services.lock.LockManagerException;
import org.onehippo.cms7.services.lock.LockResource;
import org.slf4j.Logger;
import static java.util.concurrent.TimeUnit.SECONDS;
......@@ -70,14 +71,14 @@ public abstract class AbstractLockManager implements InternalLockManager {
}
@Override
public synchronized void lock(final String key) throws LockException {
public synchronized LockResource lock(final String key) throws LockException {
checkLive();
validateKey(key);
final MutableLock lock = localLocks.get(key);
if (lock == null) {
getLogger().debug("Create lock '{}' for thread '{}'", key, Thread.currentThread().getName());
localLocks.put(key, createLock(key, Thread.currentThread().getName()));
return;
return new LockResourceImpl(key);
}
final Thread lockThread = lock.getThread().get();
if (lockThread == null || !lockThread.isAlive()) {
......@@ -85,17 +86,29 @@ public abstract class AbstractLockManager implements InternalLockManager {
"now gets the lock", lock.getLockThread(), key, Thread.currentThread().getName());
unlock(key);
localLocks.put(key, createLock(key, Thread.currentThread().getName()));
return;
return new LockResourceImpl(key);
}
if (lockThread == Thread.currentThread()) {
getLogger().debug("Thread '{}' already contains lock '{}', increase hold count", Thread.currentThread().getName(), key);
lock.increment();
return;
return new LockResourceImpl(key);
}
throw new LockException(String.format("This thread '%s' cannot lock '%s' : already locked by thread '%s'",
Thread.currentThread().getName(), key, lockThread.getName()));
}
private class LockResourceImpl implements LockResource {
private String key;
LockResourceImpl(final String key) {
this.key = key;
}
@Override
public void close() {
unlock(key);
}
}
@Override
public synchronized void unlock(final String key) {
checkLive();
......
......@@ -36,6 +36,7 @@ import org.onehippo.cms7.services.lock.Lock;
import org.onehippo.cms7.services.lock.LockException;
import org.onehippo.cms7.services.lock.LockManager;
import org.onehippo.cms7.services.lock.LockManagerException;
import org.onehippo.cms7.services.lock.LockResource;
import org.onehippo.repository.journal.JournalConnectionHelperAccessor;
import org.onehippo.repository.lock.db.DbLockManager;
import org.onehippo.repository.lock.memory.MemoryLockManager;
......@@ -88,6 +89,58 @@ public class LockManagerBasicTest extends AbstractLockManagerTest {
// now we should be able to lock again
lockManager.lock(key);
dbRowAssertion(key, "RUNNING");
lockManager.unlock(key);
}
@Test
public void lock_try_with_resource_construct() throws Exception {
String key = "123";
try (LockResource lock = lockManager.lock(key)) {
dbRowAssertion(key, "RUNNING");
}
assertDbRowDoesExist(key);
dbRowAssertion(key, "FREE");
}
@Test
public void lock_nested_try_with_resource_construct() throws Exception {
String key = "123";
try (LockResource lock = lockManager.lock(key)) {
try (LockResource lock2 = lockManager.lock(key)) {
dbRowAssertion(key, "RUNNING");
}
dbRowAssertion(key, "RUNNING");
}
assertDbRowDoesExist(key);
dbRowAssertion(key, "FREE");
}
@Test
public void lock_nested_try_on_unavailable_lock() throws Exception {
String key = "123";
final LockRunnable runnable = new LockRunnable(key, true);
final Thread lockThread = new Thread(runnable);
lockThread.start();
// give lockThread time to lock
Thread.sleep(100);
try (LockResource lock = lockManager.lock(key)) {
fail("should not be able to lock");
} catch (LockException e) {
// expected
}
assertDbRowDoesExist(key);
dbRowAssertion(key, "RUNNING");
runnable.keepAlive = false;
// after the thread is finished, the lock manager should have no locks any more
lockThread.join();
if (runnable.e != null) {
fail(runnable.e.toString());
}
}
private void assertDbRowDoesExist(final String key) throws SQLException {
......@@ -195,8 +248,7 @@ public class LockManagerBasicTest extends AbstractLockManagerTest {
@Override
public void run() {
try {
lockManager.lock(key);
try (LockResource lock = lockManager.lock(key)){
while (keepAlive) {
Thread.sleep(25);
}
......@@ -278,6 +330,7 @@ public class LockManagerBasicTest extends AbstractLockManagerTest {
lockManager.lock(key);
assertEquals(key, lockManager.getLocks().iterator().next().getLockKey());
assertEquals(Thread.currentThread().getName(), lockManager.getLocks().iterator().next().getLockThread());
lockManager.unlock(key);
}
......@@ -295,7 +348,10 @@ public class LockManagerBasicTest extends AbstractLockManagerTest {
dbRowAssertion("c", "RUNNING");
dbRowAssertion("d", "RUNNING");
lockManager.clear();
try (Log4jInterceptor interceptor = Log4jInterceptor.onWarn().trap(MemoryLockManager.class, DbLockManager.class).build()) {
lockManager.clear();
assertTrue(interceptor.messages().anyMatch(m -> m.contains("Lock 'a' owned by 'default' was never")));
}
dbRowAssertion("a", "FREE");
dbRowAssertion("b", "FREE");
......@@ -340,6 +396,8 @@ public class LockManagerBasicTest extends AbstractLockManagerTest {
assertEquals(4, locks.size());
}
lockManager.unlock("a");
lockManager.unlock("b");
}
@Test
......@@ -356,6 +414,9 @@ public class LockManagerBasicTest extends AbstractLockManagerTest {
assertTrue(lockManager.isLocked("c"));
assertTrue(lockManager.isLocked("d"));
}
lockManager.unlock("a");
lockManager.unlock("b");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment