package diskCacheV111.services.web;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import diskCacheV111.poolManager.PoolManagerCellInfo;
import diskCacheV111.pools.PoolCellInfo;
import diskCacheV111.util.CacheException;
import dmg.cells.nucleus.CellAddressCore;
import dmg.cells.nucleus.CellPath;
import dmg.cells.nucleus.NoRouteToCellException;
import org.dcache.cells.AbstractCell;
import org.dcache.cells.CellStub;
import org.dcache.util.Option;
import org.dcache.util.Args;
public class PoolInfoObserverV3 extends AbstractCell
{
private static final Logger _log =
LoggerFactory.getLogger(PoolInfoObserverV3.class);
private static final String THREAD_NAME = "pool-info-observer";
private static final String POOL_MANAGER = "PoolManager";
private static final String TOPOLOGY_NAME = "PoolManager";
private static final String TOPOLOGY_CONTEXT_KEY = "poolgroup-map.ser";
@Option(
name = "refresh-time",
unit = "seconds",
defaultValue = "60"
)
protected long _interval;
private Thread _refreshThread;
private CellStub _poolManager;
private CellStub _pool;
public PoolInfoObserverV3(String name, String args)
{
super(name, PoolInfoObserverV3.class.getName(), new Args(args));
}
@Override
protected void starting() throws Exception
{
super.starting();
_poolManager = new CellStub(this, new CellPath(POOL_MANAGER), 30000);
_pool = new CellStub(this, null, 60000);
_refreshThread = new Thread(THREAD_NAME) {
@Override
public void run() {
try {
while (!Thread.interrupted()) {
try {
refresh();
} catch (CacheException | NoRouteToCellException e) {
_log.error("Failed to update topology map: " + e.getMessage());
} catch (RuntimeException e) {
_log.error("Failed to update topology map: " + e);
}
Thread.sleep(_interval * 1000);
}
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
}
};
}
@Override
protected void started()
{
_refreshThread.start();
}
public void messageArrived(NoRouteToCellException e)
{
_log.warn(e.getMessage());
}
private void refresh()
throws CacheException, InterruptedException, NoRouteToCellException
{
CellInfoContainer container = collectPoolGroups();
PoolCellQueryContainer topology = collectPoolInfo(container);
getNucleus().setDomainContext(TOPOLOGY_CONTEXT_KEY, topology);
}
private CellInfoContainer collectPoolGroups()
throws CacheException, InterruptedException, NoRouteToCellException
{
CellInfoContainer container = new CellInfoContainer();
Object[] poolGroups =
_poolManager.sendAndWait("psux ls pgroup", Object[].class);
for (Object o: poolGroups) {
if (o == null) {
continue;
}
String name = o.toString();
Object[] props =
_poolManager.sendAndWait("psux ls pgroup " + name, Object[].class);
if ((props.length < 3) ||
(! (props[0] instanceof String)) ||
(! (props[1] instanceof Object []))) {
_log.error("Unexpected reply from PoolManager: {}", props);
continue;
}
for (Object p: (Object[]) props[1]) {
container.addPool(TOPOLOGY_NAME, name, p.toString());
}
}
return container;
}
private PoolCellQueryContainer
collectPoolInfo(final CellInfoContainer container)
throws CacheException, InterruptedException, NoRouteToCellException
{
PoolManagerCellInfo poolManagerInfo =
_poolManager.sendAndWait("xgetcellinfo", PoolManagerCellInfo.class);
Set<CellAddressCore> pools = poolManagerInfo.getPoolCells();
final PoolCellQueryContainer result = new PoolCellQueryContainer();
final CountDownLatch latch = new CountDownLatch(pools.size());
for (final CellAddressCore pool: pools) {
final long start = System.currentTimeMillis();
Futures.addCallback(_pool.send(new CellPath(pool), "xgetcellinfo", PoolCellInfo.class),
new FutureCallback<PoolCellInfo>()
{
@Override
public void onSuccess(PoolCellInfo info)
{
long now = System.currentTimeMillis();
long ping = now - start;
result.put(info.getCellName(),
new PoolCellQueryInfo(info, ping, now));
container.addInfo(info.getCellName(), info);
latch.countDown();
}
@Override
public void onFailure(Throwable t)
{
_log.warn("Failed to query {}: {}", pool, t.getMessage());
latch.countDown();
}
});
}
latch.await();
Map<String,Map<String,Map<String,Object>>> allClasses =
container.createExternalTopologyMap();
for (Map<String,Map<String,Object>> groupMap: allClasses.values()) {
for (Map<String,Object> tableMap: groupMap.values()) {
for (String poolName: tableMap.keySet()) {
tableMap.put(poolName, result.getInfoByName(poolName));
}
}
}
result.setTopology(allClasses);
return result;
}
public String ac_show_topology(Args args)
{
Object o = getNucleus().getDomainContext(TOPOLOGY_CONTEXT_KEY);
return (o == null) ? "" : o.toString();
}
@Override
public void stopped()
{
if (_refreshThread != null) {
_refreshThread.interrupt();
}
}
@Override
public void getInfo(PrintWriter pw)
{
pw.println("Update interval: " + _interval + " [sec]");
}
}