/*
* Copyright (c) 2008-2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.coordinator.client.service;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* DistributedPersistentLockTest unit test
*/
public class DistributedPersistentLockTest extends CoordinatorTestBase {
private static final Logger _logger = LoggerFactory.getLogger(DistributedPersistentLockTest.class);
private final int NUMRUNS = 5;
private final int NUMCLIENTS = 10;
/**
* Simulates a client acquiring and releasing persistent locks.
* Also simulates failure to release persistent locks when attempted by incorrect owner.
* Repeated NUMCLIENTS times.
*
* @throws Exception
*/
@Test
public void acquireAndReleaseDistributedPersistentLock() throws Exception {
_logger.info("*** acquireAndReleaseDistributedPersistentLock start");
List<DistributedPersistentLock> locks = new ArrayList<DistributedPersistentLock>();
for (int i = 0; i < NUMRUNS; i++) {
String lockName = String.format("%s-%s", "lock", i);
CoordinatorClient testClient = connectClient();
try {
locks.add(testClient.getPersistentLock(lockName));
} catch (Exception e) {
_logger.info(": Problem when instantiating lock {}", lockName, e);
Assert.assertNull(e);
}
_logger.info(": Initialized lock: {}", lockName);
String clientName = "Tester" + i;
String failClientName = "xyz";
String ownerName = null;
boolean bLockActionResult;
try {
_logger.info(": {} trying to acquire lock: {}", clientName, lockName);
bLockActionResult = locks.get(i).acquireLock(clientName);
_logger.info(": Lock acquire result: {}", bLockActionResult);
ownerName = locks.get(i).getLockOwner();
_logger.info(": Lock held by: {}", ownerName);
Assert.assertTrue(ownerName.equals(clientName));
_logger.info(": Verified lock: {} is held by: {}", lockName, clientName);
} catch (Exception e) {
Assert.assertNull(e);
}
try {
ownerName = locks.get(i).getLockOwner();
_logger.info("Curr owner: {}", ownerName);
_logger.info("Check if {} is owner: {}", failClientName, failClientName.equals(ownerName));
_logger.info(": {} trying to release lock: {}", failClientName, lockName);
bLockActionResult = locks.get(i).releaseLock(failClientName);
_logger.info(": Lock release result: {}", bLockActionResult);
} catch (Exception e) {
Assert.assertNotNull(e);
_logger.info(": {} Failed to release lock: {}", failClientName, lockName);
}
ownerName = locks.get(i).getLockOwner();
Assert.assertNotNull(ownerName);
_logger.info(": {} is owner of lock: {}", ownerName, lockName);
try {
_logger.info(": Releasing lock: {}", lockName);
locks.get(i).releaseLock(clientName);
_logger.info(": Released lock: {}", lockName);
} catch (Exception e) {
Assert.assertNull(e);
}
_logger.info(": Verify lock: {} is free", lockName);
ownerName = locks.get(i).getLockOwner();
_logger.info(": {} is owner of lock: {}", ownerName, lockName);
Assert.assertNull(ownerName);
_logger.info(": Reacquire lock: {}", lockName);
try {
_logger.info(": {} trying to acquire lock: {}", clientName, lockName);
bLockActionResult = locks.get(i).acquireLock(clientName);
_logger.info(": Lock acquire result: {}", bLockActionResult);
ownerName = locks.get(i).getLockOwner();
_logger.info(": Lock held by: {}", ownerName);
Assert.assertTrue(ownerName.equals(clientName));
_logger.info(": Verified lock: {} is held by: {}", lockName, clientName);
} catch (Exception e) {
Assert.assertNull(e);
}
}
_logger.info("*** acquireAndReleaseDistributedPersistentLock end");
}
/**
* Simulates a client acquiring persistent locks.
* Also simulates failure to acquire persistent locks when attempted on granted locks.
* Repeated NUMCLIENTS times.
*
* @throws Exception
*/
@Test
public void acquireDistributedPersistentLock() throws Exception {
_logger.info("*** acquireDistributedPersistentLock start");
List<DistributedPersistentLock> locks = new ArrayList<DistributedPersistentLock>();
for (int i = 0; i < NUMRUNS; i++) {
String lockName = String.format("%s-%s", "lock", i);
DistributedPersistentLock lock = null;
try {
locks.add(connectClient().getPersistentLock(lockName));
} catch (Exception e) {
_logger.info(": Problem when instantiating lock: {}", lockName, e);
Assert.assertNull(e);
}
_logger.info(": Initialized lock: {}", lockName);
try {
String clientName = "Tester" + i;
_logger.info(": {} trying to acquire lock: {}", clientName, lockName);
boolean bLockActionResult = locks.get(i).acquireLock(clientName);
_logger.info(": Lock acquire result: {}", bLockActionResult);
String ownerName = locks.get(i).getLockOwner();
_logger.info(": Lock held by: {}", ownerName);
Assert.assertTrue(ownerName.equals(clientName));
_logger.info(": Verified lock: {} is held by: {}", lockName, ownerName);
String failClientName = "xyz";
_logger.info(": {} trying to acquire lock: {}", failClientName, lockName);
bLockActionResult = locks.get(i).acquireLock(failClientName);
_logger.info(": Lock acquire result: {}", bLockActionResult);
ownerName = locks.get(i).getLockOwner();
_logger.info(": Lock held by: {}", ownerName);
Assert.assertFalse(ownerName.equals(failClientName));
_logger.info(": Lock held by: {}, could not be granted to: {}", ownerName, failClientName);
} catch (Exception e) {
_logger.warn("Problem acquiring lock: {}", lockName, e);
Assert.assertNull(e);
}
}
_logger.info("*** acquireDistributedPersistentLock end");
}
/**
* Simulates a client releasing persistent locks.
* If run standalone, this has nothing to do and is like a NO-OP.
* When run as part of the DistributedPersistentLockTest test suite, it release locks
* created by acquireDistributedPersistentLock
* Repeated NUMCLIENTS times.
*
* @throws Exception
*/
@Test
public void releaseDistributedPersistentLock() throws Exception {
_logger.info("*** releaseDistributedPersistentLock start");
List<DistributedPersistentLock> locks = new ArrayList<DistributedPersistentLock>();
for (int i = 0; i < NUMRUNS; i++) {
String lockName = String.format("%s-%s", "lock", i);
try {
locks.add(connectClient().getPersistentLock(lockName));
} catch (Exception e) {
_logger.info(": Problem when instantiating lock {}", lockName, e);
Assert.assertNull(e);
}
_logger.info(": Initialized lock: {}", lockName);
try {
_logger.info(": Try releasing lock without checking: {}", lockName);
locks.get(i).releaseLock("abc");
String lockOwner = locks.get(i).getLockOwner();
if (lockOwner != null) {
boolean bLockActionResult = locks.get(i).releaseLock(lockOwner);
_logger.info(": Released lock: {}; result: {}", lockName, bLockActionResult);
} else {
_logger.warn(": Lock: {} not found. Nothing to release.", lockName);
}
} catch (Exception e) {
_logger.warn("Problem releasing lock: {}", lockName, e);
Assert.assertNull(e);
}
}
_logger.info("*** releaseDistributedPersistentLock end");
}
/**
* Simulates multiple clients accessing persistent lock API simultaneously.
*
* @throws Exception
*/
@Test
public void miscDistributedPersistentLock() throws Exception {
_logger.info("*** miscDistributedPersistentLock start");
ExecutorService clients = Executors.newFixedThreadPool(NUMCLIENTS);
for (int i = 0; i < NUMCLIENTS; i++) {
clients.submit(new Runnable() {
@Override
public void run() {
String lockName = "TestLock";
String clientName = Thread.currentThread().getName();
String currOwnerName = null;
DistributedPersistentLock lock = null;
try {
lock = connectClient().getPersistentLock(lockName);
} catch (Exception e) {
_logger.info(": {} miscDistributedPersistentLock could not get coordinator client", e);
Assert.assertNull(e);
}
_logger.info(": ### Client {}, Initialized lock {} ###", clientName, lockName);
while (true) {
try {
_logger.info(": {} ------ client: starts loop ------", clientName);
_logger.info(": {} client trying to acquire lock", clientName);
Thread.sleep(50);
boolean bLockActionResult = lock.acquireLock(clientName);
currOwnerName = lock.getLockOwner();
_logger.info(": {} is current owner", currOwnerName);
Thread.sleep(50);
if (bLockActionResult) {
_logger.info(": {} request succeeded. doing work", currOwnerName);
Thread.sleep(50);
_logger.info(": {} work done. releasing lock", currOwnerName);
bLockActionResult = lock.releaseLock(clientName);
_logger.info(": lock release status: {}; {} released lock", bLockActionResult, clientName);
Thread.sleep(100);
} else {
_logger.info(": {} request failed. retrying.", clientName);
Thread.sleep(50);
}
} catch (InterruptedException e) {
// Ignore this.
} catch (Exception e) {
_logger.info(": {} transient error ...", clientName, e);
}
}
}
});
}
clients.awaitTermination(20, TimeUnit.SECONDS);
_logger.info("*** miscDistributedPersistentLock end");
}
}