package com.neverwinterdp.registry.lock;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.neverwinterdp.registry.ErrorCode;
import com.neverwinterdp.registry.Node;
import com.neverwinterdp.registry.NodeCreateMode;
import com.neverwinterdp.registry.Registry;
import com.neverwinterdp.registry.RegistryConfig;
import com.neverwinterdp.registry.RegistryException;
import com.neverwinterdp.registry.zk.RegistryImpl;
import com.neverwinterdp.util.FileUtil;
import com.neverwinterdp.zk.tool.server.EmbededZKServer;
public class LockUnitTest {
static {
System.setProperty("log4j.configuration", "file:src/test/resources/test-log4j.properties") ;
}
final static String LOCK_DIR = "/locks" ;
private EmbededZKServer zkServerLauncher ;
private AtomicLong lockOrder ;
@Before
public void setup() throws Exception {
FileUtil.removeIfExist("./build/data", false);
lockOrder = new AtomicLong() ;
zkServerLauncher = new EmbededZKServer("./build/data/zookeeper") ;
zkServerLauncher.start();
}
@After
public void teardown() throws Exception {
zkServerLauncher.shutdown();
}
private Registry newRegistry() {
return new RegistryImpl(RegistryConfig.getDefault()) ;
}
@Test
public void testConcurrentLock() throws Exception {
String DATA = "lock directory";
Registry registry = newRegistry().connect();
Node lockDir = registry.create(LOCK_DIR, DATA.getBytes(), NodeCreateMode.PERSISTENT) ;
registry.disconnect();
Worker[] worker = new Worker[50];
ExecutorService executorPool = Executors.newFixedThreadPool(worker.length);
for(int i = 0; i < worker.length; i++) {
worker[i] = new Worker("worker-" + (i + 1)) ;
executorPool.execute(worker[i]);
if(i % 10 == 0) Thread.sleep(new Random().nextInt(50));
}
executorPool.shutdown();
executorPool.awaitTermination(15 * 60 * 1000, TimeUnit.MILLISECONDS);
for(int i = 0; i < worker.length; i++) {
Assert.assertTrue(worker[i].complete);
}
}
public class Worker implements Runnable {
String name ;
LockId lockId ;
boolean complete = false;
public Worker(String name) {
this.name = name ;
}
public void run() {
try {
Random random = new Random() ;
Thread.sleep(random.nextInt(100));
Registry registry = newRegistry().connect();
Node lockDir = registry.get(LOCK_DIR) ;
Lock lock = lockDir.getLock("write") ;
lockId = lock.lock(60 * 1000) ; //wait max 15s for lock
System.out.println("\nWorker " + name + " acquires the lock: " + lockId);
long execTime = random.nextInt(1000) ;
Thread.sleep(execTime);
System.out.println(" Process in " + execTime);
Assert.assertEquals(lockOrder.getAndIncrement(), lockId.getSequence()) ;
lock.unlock();
System.out.println("Worker " + name + " releases the lock: " + lockId);
complete = true ;
registry.disconnect();
} catch(RegistryException e) {
if(e.getErrorCode() == ErrorCode.Timeout) {
complete = true ;
System.err.println(e.getMessage()) ;
} else {
e.printStackTrace();
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
}