package com.ibm.nmon.parser.gc;
import java.util.Map;
import java.util.TimeZone;
import org.slf4j.Logger;
import com.ibm.nmon.data.BasicDataSet;
import com.ibm.nmon.data.DataRecord;
import com.ibm.nmon.data.DataType;
import com.ibm.nmon.data.SubDataType;
import com.ibm.nmon.parser.util.XMLParserHelper;
/**
* Data holder for an in-progress GC parse session. Also contains various utility functions for
* setting values on the current DataRecord and logging errors.
*/
public final class GCParserContext {
private final Logger logger;
private final BasicDataSet data;
private DataRecord currentRecord;
private final TimeZone timeZone;
private int lineNumber;
private Map<String, String> attributes;
private boolean isGencon;
// verbose GC does not log a count of compactions
private int compactionCount;
GCParserContext(BasicDataSet data, Logger logger, TimeZone timeZone) {
this.data = data;
this.logger = logger;
this.timeZone = timeZone;
reset();
}
public void reset() {
currentRecord = null;
attributes = null;
lineNumber = 0;
isGencon = false;
compactionCount = 0;
}
public int getLineNumber() {
return lineNumber;
}
void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
public BasicDataSet getData() {
return data;
}
public TimeZone getTimeZone() {
return timeZone;
}
public DataRecord getCurrentRecord() {
return currentRecord;
}
public void setCurrentRecord(DataRecord currentRecord) {
this.currentRecord = currentRecord;
}
public void saveRecord() {
data.addRecord(currentRecord);
}
public void setGencon(boolean isGencon) {
this.isGencon = isGencon;
}
public boolean isGencon() {
return isGencon;
}
public int incrementCompactionCount() {
return ++compactionCount;
}
public void resetCompactionCount() {
compactionCount = 0;
}
public void setValue(String typeId, String field, String attribute) {
String value = attributes.get(attribute);
if (value == null) {
logMissingAttribute(attribute);
return;
}
currentRecord.setValue(getDataType(typeId), field, parseDouble(attribute));
}
public void setValue(String typeId, String field, double value) {
currentRecord.setValue(getDataType(typeId), field, value);
}
public void setValueDiv1000(String typeId, String field, String name) {
String value = attributes.get(name);
if (value == null) {
logMissingAttribute(name);
return;
}
currentRecord.setValue(getDataType(typeId), field, parseDouble(name) / 1000);
}
public void parseAttributes(String unparsedAttributes) {
this.attributes = XMLParserHelper.parseAttributes(unparsedAttributes);
}
public String getAttribute(String name) {
return attributes.get(name);
}
public double parseDouble(String name) {
String value = attributes.get(name);
if (value == null) {
logMissingAttribute(name);
return Double.NaN;
}
double toReturn;
try {
toReturn = Double.parseDouble(value);
}
catch (NumberFormatException nfe) {
logger.warn("attribute '{}' with value '{}', defined at line {}, is not a number", new Object[] { name,
value, getLineNumber(), });
toReturn = Double.NaN;
}
return toReturn;
}
public void logMissingAttribute(String attribute) {
logger.warn("no attribute named {} defined at line {}", attribute, getLineNumber());
}
public void logUnrecognizedElement(String elementName) {
logger.warn("unrecogized element '{}' at line {}", elementName, getLineNumber());
}
public void logInvalidValue(String attribute, String value) {
logger.warn("attribute '{}' with value '{}', defined at line {}, is not a valid value", new Object[] {
attribute, value, getLineNumber() });
}
public DataType getDataType(String typeId) {
String jvmName = data.getMetadata("jvm_name");
SubDataType type = (SubDataType) data.getType(SubDataType.buildId(typeId, jvmName));
if (type != null) {
return type;
}
else if ("GCMEM".equals(typeId)) {
type = new SubDataType("GCMEM", jvmName, "GC Memory Stats", "requested", "total_freed", "nursery_freed",
"tenured_freed", "flipped", "flipped_bytes", "tenured", "tenured_bytes", "moved", "moved_bytes");
}
else if ("GCSTAT".equals(typeId)) {
type = new SubDataType("GCSTAT", jvmName, "GC Memory References", "finalizers", "soft", "weak", "phantom",
"tiltratio");
}
else if ("GCTIME".equals(typeId)) {
type = new SubDataType("GCTIME", jvmName, "GC Times (ms)", "total_ms", "nursery_ms", "tenured_ms",
"mark_ms", "sweep_ms", "compact_ms", "exclusive_ms");
}
else if ("GCSINCE".equals(typeId)) {
type = new SubDataType("GCSINCE", jvmName, "Time Since Last", "af_nursery", "af_tenured", "gc_scavenger",
"gc_global", "gc_system", "con_mark");
}
else if ("GCBEF".equals(typeId)) {
type = new SubDataType("GCBEF", jvmName, "Sizes Before GC", "total", "free", "used", "total_nursery",
"free_nursery", "used_nursery", "total_tenured", "free_tenured", "used_tenured");
}
else if ("GCAFT".equals(typeId)) {
type = new SubDataType("GCAFT", jvmName, "Sizes After GC", "total", "free", "used", "total_nursery",
"free_nursery", "used_nursery", "total_tenured", "free_tenured", "used_tenured");
}
else if ("GCCOUNT".equals(typeId)) {
type = new SubDataType("GCCOUNT", jvmName, "GC Counts", "total_count", "nursery_count", "tenured_count",
"compaction_count", "system_count");
}
else {
throw new IllegalArgumentException("invalid type " + typeId);
}
data.addType(type);
return type;
}
}