package org.dcache.services.info.stateInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.dcache.services.info.base.IntegerStateValue;
import org.dcache.services.info.base.StateExhibitor;
import org.dcache.services.info.base.StatePath;
import org.dcache.services.info.stateInfo.LinkInfo.UNIT_TYPE;
/**
* Scan through the known list of links and build up an associated collection
* of LinkInfo objects.
*/
public class LinkInfoVisitor extends SkeletonListVisitor
{
private static final Logger LOGGER = LoggerFactory.getLogger(LinkInfoVisitor.class);
private static final StatePath LINK_PATH = StatePath.parsePath("links");
private static final String LINK_POOLS_PATH_ELEMENT = "pools";
private static final String LINK_POOLGROUPS_PATH_ELEMENT = "poolgroups";
private static final String LINK_UNITGROUPS_PATH_ELEMENT = "unitgroups";
private static final String LINK_UNITS_PATH_ELEMENT = "units";
private static final String LINK_SPACE_PATH_ELEMENT = "space";
/*
* The names of the branches for different collections of units.
*/
private static final String LINK_STORE_PATH_ELEMENT = "store";
private static final String LINK_NET_PATH_ELEMENT = "net";
private static final String LINK_PROTO_PATH_ELEMENT = "protocol";
private static final String LINK_DCACHE_PATH_ELEMENT = "dcache";
private static final String LINK_PREFS_PATH_ELEMENT = "prefs";
/*
* The names under which metrics for different link operations are
* stored.
*/
private static final String LINK_READ_METRIC_PATH_ELEMENT = "read";
private static final String LINK_WRITE_METRIC_PATH_ELEMENT = "write";
private static final String LINK_CACHE_METRIC_PATH_ELEMENT = "cache";
private static final String LINK_P2P_METRIC_PATH_ELEMENT = "p2p";
/**
* A simple Map that allows us to convert a string into the corresponding
* LinkInfo.UNIT_TYPE enum.
*/
public static final Map<String, LinkInfo.UNIT_TYPE> UNIT_TYPE_NAMES =
Collections.unmodifiableMap(new HashMap<String, LinkInfo.UNIT_TYPE>() {
private static final long serialVersionUID =
4631442886053020941L;
{
put(LINK_STORE_PATH_ELEMENT, UNIT_TYPE.STORE);
put(LINK_NET_PATH_ELEMENT, UNIT_TYPE.NETWORK);
put(LINK_DCACHE_PATH_ELEMENT, UNIT_TYPE.DCACHE);
put(LINK_PROTO_PATH_ELEMENT, UNIT_TYPE.PROTOCOL);
}
});
/**
* A simple Map that allows us to convert a String into the corresponding
* LinkInfo.OPERATION enum.
*/
public static final Map<String, LinkInfo.OPERATION> OPERATION_NAMES =
Collections.unmodifiableMap(new HashMap<String, LinkInfo.OPERATION>() {
private static final long serialVersionUID =
8199146124808181726L;
{
put(LINK_READ_METRIC_PATH_ELEMENT, LinkInfo.OPERATION.READ);
put(LINK_WRITE_METRIC_PATH_ELEMENT,
LinkInfo.OPERATION.WRITE);
put(LINK_CACHE_METRIC_PATH_ELEMENT,
LinkInfo.OPERATION.CACHE);
put(LINK_P2P_METRIC_PATH_ELEMENT, LinkInfo.OPERATION.P2P);
}
});
/**
* Obtain information about the current links in dCache
*
* @return a Mapping between a link's ID and the corresponding LinkInfo.
*/
public static Map<String, LinkInfo> getDetails(StateExhibitor exhibitor)
{
LOGGER.trace("Gathering link information.");
LinkInfoVisitor visitor = new LinkInfoVisitor();
exhibitor.visitState(visitor);
return visitor.getInfo();
}
/** The mapping between link names and corresponding LinkInfo object */
private final Map<String, LinkInfo> _links = new HashMap<>();
private LinkInfo _thisLink;
private StatePath _thisLinkPoolsPath;
private StatePath _thisLinkPoolgroupPath;
private StatePath _thisLinkUnitgroupsPath;
private StatePath _thisLinkUnitsPath;
private StatePath _thisLinkSpacePath;
private StatePath _thisLinkOperationPrefPath;
private StatePath _thisLinkPath;
public LinkInfoVisitor()
{
super(LINK_PATH);
}
@Override
protected void newListItem(String listItemName)
{
super.newListItem(listItemName);
_thisLink = new LinkInfo(listItemName);
_links.put(listItemName, _thisLink);
/**
* Build up the various StatePaths where we expect data to appear for
* this link.
*/
_thisLinkPath = LINK_PATH.newChild(listItemName);
_thisLinkPoolsPath = _thisLinkPath.newChild(LINK_POOLS_PATH_ELEMENT);
_thisLinkPoolgroupPath =
_thisLinkPath.newChild(LINK_POOLGROUPS_PATH_ELEMENT);
_thisLinkUnitgroupsPath =
_thisLinkPath.newChild(LINK_UNITGROUPS_PATH_ELEMENT);
_thisLinkUnitsPath = _thisLinkPath.newChild(LINK_UNITS_PATH_ELEMENT);
_thisLinkSpacePath = _thisLinkPath.newChild(LINK_SPACE_PATH_ELEMENT);
_thisLinkOperationPrefPath =
_thisLinkPath.newChild(LINK_PREFS_PATH_ELEMENT);
}
@Override
public void visitCompositePreDescend(StatePath path,
Map<String, String> metadata)
{
super.visitCompositePreDescend(path, metadata);
/** Only process items within subtree starting link.<link id> */
if (!isInListItem()) {
return;
}
String listItem = path.getLastElement();
/**
* Skip if we're looking at link.<link id>.units or link.<link
* id>.units.<UNIT_TYPE>
*/
if (_thisLinkUnitsPath.equals(path) ||
(_thisLinkUnitsPath.isParentOf(path) && UNIT_TYPE_NAMES.containsKey(listItem))) {
return;
}
/*
* Skip link.<link id>.space and any child element of this path
*/
if (_thisLinkSpacePath.equals(path) || _thisLinkSpacePath.isParentOf(path)) {
return;
}
StatePath parentPath = path.parentPath();
String parentLastElement = parentPath.getLastElement();
/**
* If we're looking at the parent element of any lists, ignore this
* item
*/
if (_thisLinkPath.equals(path) ||
_thisLinkOperationPrefPath.equals(path) ||
_thisLinkUnitsPath.equals(path) ||
_thisLinkPoolsPath.equals(path) ||
_thisLinkPoolgroupPath.equals(path) ||
_thisLinkUnitgroupsPath.equals(path)) {
return;
}
/** If we're looking at link.<link id>.units.<UNIT_TYPE>.<listItem> */
if (_thisLinkUnitsPath.isParentOf(parentPath) &&
UNIT_TYPE_NAMES.containsKey(parentLastElement)) {
LOGGER.trace("Adding pool {}", listItem);
_thisLink.addUnit(UNIT_TYPE_NAMES.get(parentLastElement), listItem);
return;
}
/** If we're looking at link.<link id>.pools.<listItem> */
if (_thisLinkPoolsPath.isParentOf(path)) {
LOGGER.trace("Adding pool {}", listItem);
_thisLink.addPool(listItem);
return;
}
/** If we're looking at link.<link id>.poolgroups.<listItem> */
if (_thisLinkPoolgroupPath.isParentOf(path)) {
LOGGER.trace("Adding poolgroup {}", listItem);
_thisLink.addPoolgroup(listItem);
return;
}
/** If we're looking at link.<link id>.unitgroups.<listItem> */
if (_thisLinkUnitgroupsPath.isParentOf(path)) {
LOGGER.trace("Adding unitgroup {}", listItem);
_thisLink.addUnitgroup(listItem);
return;
}
LOGGER.warn("Unexpected element at {}", path);
}
/**
* Called when an integer metric is encountered.
*/
@Override
public void visitInteger(StatePath path, IntegerStateValue value)
{
if (!isInListItem()) {
return;
}
if (!_thisLinkOperationPrefPath.isParentOf(path)) {
return;
}
String metricName = path.getLastElement();
if (OPERATION_NAMES.containsKey(metricName)) {
_thisLink.setOperationPref(OPERATION_NAMES.get(metricName),
value.getValue());
}
}
/**
* Provide the mapping between a link's name and corresponding LinkInfo
* object.
*
* @return
*/
public Map<String, LinkInfo> getInfo()
{
return _links;
}
public String debugInfo()
{
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, LinkInfo> entry : _links.entrySet()) {
LinkInfo info = entry.getValue();
sb.append(info.debugInfo());
sb.append("\n");
}
return sb.toString();
}
}