/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.metering.vplex; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Class to hold data collected from a VPlex perpetual performance data file */ public class VPlexPerpetualCSVFileData { // Constants public static final String ZERO = "0"; public static final String NO_DATA = "no data"; public static final String TIME_UTC = "Time (UTC)"; public static final String TIME = "Time"; public static final String DIRECTOR_BUSY = "director.busy"; public static final String DIRECTOR_FE_OPS = "director.fe-ops"; public static final String FE_PORT_READ = "fe-prt.read"; public static final String FE_PORT_WRITE = "fe-prt.write"; public static final String FE_PORT_OPS = "fe-prt.ops"; public static final String HEADER_KEY_DIRECTOR_BUSY = "director.busy (%)"; public static final String HEADER_KEY_DIRECTOR_FE_OPS = "director.fe-ops (counts/s)"; public static final String HEADER_KEY_TIME_UTC = "Time (UTC)"; private static final Pattern FILENAME_PATTERN = Pattern.compile(".*?/([\\w\\-_]+)_PERPETUAL_vplex_sys_perf_mon.log"); // Total number of lines in the file private final int totalLines; // Name of the director to which this file applies private String directorName; // Name of the file private String name; // Headers private List<String> headers; // Structure to hold the data. Each entry in the list is a data line that has a map of key-values representing the data points private List<Map<String, String>> data; // Mapping of Time Values to their numeric index in the 'data' list private Map<String, Integer> timeToDataIndex; public VPlexPerpetualCSVFileData(String name, int totalLines) { this.name = name; this.totalLines = totalLines; Matcher matcher = FILENAME_PATTERN.matcher(this.name); if (matcher.matches()) { this.directorName = matcher.group(1); } } /** * Total lines that are in the file * * @return int */ public int getTotalLines() { return totalLines; } /** * Returns the name of the director to which this file applies * * @return String name */ public String getDirectorName() { return directorName; } /** * Return the name and path of the file * * @return String name */ public String getName() { return name; } /** * The values returned represent values that describe what the metrics are (Kb/sec, IOs/sec, etc.) * * @return List of String values presenting the headers */ public List<String> getHeaders() { return Collections.unmodifiableList(headers); } /** * Save the headers for this data set * * @param headers [IN] - metric names */ public void addHeaders(String[] headers) { if (this.headers == null) { this.headers = new ArrayList<>(); } this.headers.clear(); Collections.addAll(this.headers, headers); } /** * Reset object's data collections */ public void close() { if (data != null) { data.clear(); data = null; } if (headers != null) { headers.clear(); headers = null; } if (timeToDataIndex != null) { timeToDataIndex.clear(); timeToDataIndex = null; } } /** * Add the data values. This would represent a single line in the perpetual data file. * * @param values [IN] - Data values */ public void addDataLine(String[] values) { assert (headers != null && !headers.isEmpty() && headers.size() == values.length); // Create data if it doesn't exist if (data == null) { data = new ArrayList<>(totalLines); timeToDataIndex = new HashMap<>(); } // Iterate through the passed in values. The number of values should match the number // of header entries, which specify what the value represents (time, Kb/sec, etc.) Map<String, String> dataMap = new HashMap<>(); int numHeaders = headers.size(); int currentDataIndex = data.size(); for (int index = 0; index < numHeaders; index++) { String header = headers.get(index); String value = values[index]; // For possibly very common values, use a static String reference if (value.equals(ZERO)) { value = ZERO; } else if (value.equals(NO_DATA)) { value = NO_DATA; } dataMap.put(header, value); if (header.equals(TIME_UTC)) { timeToDataIndex.put(value, currentDataIndex); } } // Add the mapping to the data line structure data.add(dataMap); } /** * Return the data line values * * @return List of Map of String (metric name) to String (metric value) */ public List<Map<String, String>> getDataLines() { return Collections.unmodifiableList(data); } /** * For a given 'timeUTC' value, find its index in the data lines. * * @param timeUTC [IN] - Time UTC value to look up * @return An index into the 'data' List if 'timeUTC' exists, otherwise 0. */ public Integer getDataIndexForTime(Long timeUTC) { Integer result = timeToDataIndex.get(timeUTC.toString()); return (result != null) ? result : 0; } @Override public String toString() { return String.format("VPlexPerpetualCSVFileData{name='%s', totalLines=%d}", name, totalLines); } }