package org.apache.s4.comm.topology;
import java.io.File;
import java.io.FileOutputStream;
import java.net.InetAddress;
import java.nio.channels.FileLock;
import org.apache.s4.comm.topology.Cluster;
import org.apache.s4.comm.topology.ClusterNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.name.Named;
/**
* Implements the assignment interface {@link Assignment} using a file lock.
*
*/
public class AssignmentFromFile implements Assignment {
private static final Logger logger = LoggerFactory.getLogger(AssignmentFromFile.class);
final private Cluster cluster;
final private String lockDir;
@Inject
public AssignmentFromFile(Cluster cluster, @Named("cluster.lock_dir") String lockDir) {
this.cluster = cluster;
this.lockDir = lockDir;
}
/*
* (non-Javadoc)
*
* @see org.apache.s4.comm.topology.Assignment#assignClusterNode()
*/
@Override
public ClusterNode assignClusterNode() {
while (true) {
try {
for (ClusterNode node : cluster.getNodes()) {
boolean partitionAvailable = canTakeupProcess(node);
logger.info("Partition available: " + partitionAvailable);
if (partitionAvailable) {
boolean success = takeProcess(node);
logger.info("Acquire partition:" + ((success) ? "success." : "failure."));
if (success) {
return node;
}
}
}
Thread.sleep(5000);
} catch (Exception e) {
logger.error("Exception in assignPartition Method:", e);
}
}
}
private boolean takeProcess(ClusterNode node) {
File lockFile = null;
try {
// TODO:contruct from processConfig
String lockFileName = createLockFileName(node);
lockFile = new File(lockFileName);
if (!lockFile.exists()) {
FileOutputStream fos = new FileOutputStream(lockFile);
FileLock fl = fos.getChannel().tryLock();
if (fl != null) {
String message = "Partition acquired by PID:" + getPID() + " HOST:"
+ InetAddress.getLocalHost().getHostName();
fos.write(message.getBytes());
fos.close();
logger.info(message + " Lock File location: " + lockFile.getAbsolutePath());
return true;
}
}
} catch (Exception e) {
logger.error("Exception trying to take up partition:" + node.getPartition(), e);
} finally {
if (lockFile != null) {
lockFile.deleteOnExit();
}
}
return false;
}
private String createLockFileName(ClusterNode node) {
String lockFileName = "s4-" + node.getPartition() + ".lock";
if (lockDir != null && lockDir.trim().length() > 0) {
File file = new File(lockDir);
if (!file.exists()) {
file.mkdirs();
}
return lockDir + "/" + lockFileName;
} else {
return lockFileName;
}
}
private boolean canTakeupProcess(ClusterNode node) {
try {
InetAddress inetAddress = InetAddress.getByName(node.getMachineName());
logger.info("Host Name: " + InetAddress.getLocalHost().getCanonicalHostName());
if (!node.getMachineName().equals("localhost")) {
if (!InetAddress.getLocalHost().equals(inetAddress)) {
return false;
}
}
} catch (Exception e) {
logger.error("Invalid host:" + node.getMachineName());
return false;
}
String lockFileName = createLockFileName(node);
File lockFile = new File(lockFileName);
if (!lockFile.exists()) {
return true;
} else {
logger.info("Partition taken up by another process lockFile:" + lockFileName);
}
return false;
}
private long getPID() {
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
return Long.parseLong(processName.split("@")[0]);
}
}