package org.dcache.services.info.gathers.poolmanager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Map; import diskCacheV111.pools.PoolCostInfo; import diskCacheV111.pools.PoolCostInfo.NamedPoolQueueInfo; import diskCacheV111.pools.PoolCostInfo.PoolQueueInfo; import diskCacheV111.pools.PoolCostInfo.PoolSpaceInfo; import diskCacheV111.vehicles.CostModulePoolInfoTable; import dmg.cells.nucleus.UOID; import org.dcache.services.info.base.FloatingPointStateValue; import org.dcache.services.info.base.IntegerStateValue; import org.dcache.services.info.base.StatePath; import org.dcache.services.info.base.StateUpdate; import org.dcache.services.info.base.StateUpdateManager; import org.dcache.services.info.base.StringStateValue; import org.dcache.services.info.gathers.CellMessageHandlerSkel; import org.dcache.services.info.gathers.MessageMetadataRepository; import org.dcache.services.info.stateInfo.SpaceInfo; /** * This class processing incoming CellMessages that contain CostModulePoolInfoTable * * @author Paul Millar <paul.millar@desy.de> */ public class PoolCostMsgHandler extends CellMessageHandlerSkel { private static final Logger LOGGER = LoggerFactory.getLogger(PoolCostMsgHandler.class); public PoolCostMsgHandler(StateUpdateManager sum, MessageMetadataRepository<UOID> msgMetaRepo) { super(sum, msgMetaRepo); } @Override public void process(Object msgPayload, long msgDeliveryPeriod) { long metricLifetime = (long) (msgDeliveryPeriod * 2.5); // Give metrics a lifetime of 2.5* message deliver period if (!(msgPayload instanceof CostModulePoolInfoTable)) { LOGGER.error("received non-CostModulePoolInfoTable object in message"); return; } CostModulePoolInfoTable poolInfoTbl = (CostModulePoolInfoTable) msgPayload; Collection<PoolCostInfo> poolInfos = poolInfoTbl.poolInfos(); if (poolInfos.size() > 0) { StateUpdate update = buildUpdate(poolInfos, metricLifetime); applyUpdates(update); } } /** * Build a StateUpdate for the supplied collection of pool information * @param poolInfos a collection of informaiton about the pools * @param metricLifetime the duration metrics should remain * @return a StateUpdate that updates the state */ private StateUpdate buildUpdate(Collection<PoolCostInfo> poolInfos, long metricLifetime) { StatePath poolsPath = new StatePath("pools"); StateUpdate update = new StateUpdate(); for (PoolCostInfo thisPoolInfo : poolInfos) { String poolName = thisPoolInfo.getPoolName(); StatePath pathToThisPool = poolsPath.newChild(poolName); StatePath pathToQueues = pathToThisPool.newChild("queues"); /* * Add all the standard queues */ addTapeQueueInfo(update, pathToQueues, "store", thisPoolInfo.getStoreQueue(), metricLifetime); addTapeQueueInfo(update, pathToQueues, "restore", thisPoolInfo.getRestoreQueue(), metricLifetime); addQueueInfo(update, pathToQueues, "p2p-queue", thisPoolInfo.getP2pQueue(), metricLifetime); addQueueInfo(update, pathToQueues, "p2p-clientqueue", thisPoolInfo.getP2pClientQueue(), metricLifetime); /* * Add the "extra" named queues */ addNamedQueues(update, pathToQueues, thisPoolInfo, metricLifetime); /* * Add information about our default queue's name, if we have one. */ String defaultQueue = thisPoolInfo.getDefaultQueueName(); update.appendUpdate(pathToQueues.newChild("default-queue"), new StringStateValue(defaultQueue, metricLifetime)); /** * Add information about this pool's space utilisation. */ addSpaceInfo(update, pathToThisPool.newChild("space"), thisPoolInfo.getSpaceInfo(), metricLifetime); } return update; } /** * Add information about a specific queue to a pool's portion of dCache state. * The state tree looks like: * * <pre> * [dCache] * | * +--[pools] * | | * | +--[<poolName>] * | | | * | | +--[queues] * | | | | * | | | +--[<queueName1>] * | | | | | * | | | | +--active: nnn * | | | | +--max-active: nnn * | | | | +--queued: nnn * | | | | * | | | +--[<queueName2>] * </pre> * * @param pathToQueues the StatePath pointing to queues (e.g., * "pools.mypool_1.queues") * @param queueName the name of the queue. */ private void addQueueInfo(StateUpdate stateUpdate, StatePath pathToQueues, String queueName, PoolQueueInfo info, long lifetime) { StatePath queuePath = pathToQueues.newChild(queueName); stateUpdate.appendUpdate(queuePath.newChild("active"), new IntegerStateValue(info.getActive(), lifetime)); stateUpdate.appendUpdate(queuePath.newChild("max-active"), new IntegerStateValue(info.getMaxActive(), lifetime)); stateUpdate.appendUpdate(queuePath.newChild("queued"), new IntegerStateValue(info.getQueued(), lifetime)); } /** * Add information about a specific tape queue to a pool's portion of dCache state. * The state tree looks like: * * <pre> * [dCache] * | * +--[pools] * | | * | +--[<poolName>] * | | | * | | +--[queues] * | | | | * | | | +--[<queueName1>] * | | | | | * | | | | +--active: nnn * | | | | +--queued: nnn * | | | | * | | | +--[<queueName2>] * </pre> * * The difference to regular queues is that tape queues to not have a public maximum * value for active tasks (specific providers may have one, but this is internal to * a provider). * * @param pathToQueues the StatePath pointing to queues (e.g., * "pools.mypool_1.queues") * @param queueName the name of the queue. */ private void addTapeQueueInfo(StateUpdate stateUpdate, StatePath pathToQueues, String queueName, PoolQueueInfo info, long lifetime) { StatePath queuePath = pathToQueues.newChild(queueName); stateUpdate.appendUpdate(queuePath.newChild("active"), new IntegerStateValue(info.getActive(), lifetime)); stateUpdate.appendUpdate(queuePath.newChild("queued"), new IntegerStateValue(info.getQueued(), lifetime)); } /** * Adds information from a pool's PoolSpaceInfo object. * We add this into the state in the following way: * * <pre> * [dCache] * | * +--[pools] * | | * | +--[<poolName>] * | | | * | | +--[space] * | | | | * | | | +--total: nnn * | | | +--free: nnn * | | | +--precious: nnn * | | | +--removable: nnn * | | | +--pinned: nnn * | | | +--used: nnn * | | | +--gap: nnn * | | | +--break-even: nnn * | | | +--LRU-seconds: nnn * </pre> * * @param stateUpdate the StateUpdate we will append * @param path the StatePath pointing to the space branch * @param info the space information to include. */ private void addSpaceInfo(StateUpdate stateUpdate, StatePath pathToSpace, PoolSpaceInfo info, long lifetime) { SpaceInfo si = new SpaceInfo(info); si.addMetrics(stateUpdate, pathToSpace, lifetime); stateUpdate.appendUpdate(pathToSpace.newChild("gap"), new IntegerStateValue(info.getGap(), lifetime)); stateUpdate.appendUpdate(pathToSpace.newChild("break-even"), new FloatingPointStateValue(info.getBreakEven(), lifetime)); stateUpdate.appendUpdate(pathToSpace.newChild("LRU-seconds"), new IntegerStateValue(info.getLRUSeconds(), lifetime)); } /** * Add information about all "named" queues. The available information is the * same as with regular queues, but there are arbirary number of these. The * information is presented underneath the named-queues branch of the queues * branch: * * <pre> * [dCache] * | * +--[pools] * | | * | +--[<poolName>] * | | | * | | +--[queues] * | | | | * | | | +--[named-queues] * | | | | | * | | | | +--[<namedQueue1>] * | | | | | | * | | | | | +--active: nnn * | | | | | +--max-active: nnn * </pre> * * @param update the StateUpdate we are appending to * @param pathToQueues the StatePath pointing to [queues] above * @param thisPoolInfo the information about this pool. */ private void addNamedQueues(StateUpdate update, StatePath pathToQueues, PoolCostInfo thisPoolInfo, long lifetime) { Map<String, NamedPoolQueueInfo> namedQueuesInfo = thisPoolInfo.getExtendedMoverHash(); if (namedQueuesInfo == null) { return; } StatePath pathToNamedQueues = pathToQueues.newChild("named-queues"); for (NamedPoolQueueInfo thisNamedQueueInfo : namedQueuesInfo.values()) { addQueueInfo(update, pathToNamedQueues, thisNamedQueueInfo.getName(), thisNamedQueueInfo, lifetime); } } }