blob: 6a3f6b8d6b035fb4d30116f937c80e4ad93c9e1c [file] [log] [blame]
package xdc.rta;
import xdc.runtime.LoggerBufDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Vector;
/*
* ======== MixedDecoder ========
* This class decodes and filters log entries from multiple logger types.
* It takes byte arrays of both xdc.runtime.Log records and
* xdc.runtime.LoggerBuf entries, properly decodes them based on the logger
* id, then filters the results to eliminate any redundant or out-of-order
* records.
*/
public class MixedDecoder {
private MetaData meta;
private LoggerBufDecoder loggerBufDec;
private Decoder logDec;
/*
* This hash map tracks the highest sequence number we have seen
* for a given logger.
*/
private HashMap<Integer, Long> highestSeen;
/*
* Multiple logger Ids may map to the same log (due to run mode and
* stop mode, for example). This HashMap maps those logger ids to a
* common value to support filtering.
*/
private HashMap<Integer, Integer> filterIds;
/*
* ======== Constructor ========
*/
public MixedDecoder (MetaData meta, LoggerBufDecoder loggerBufDec,
Decoder logDec)
{
this.meta = meta;
this.loggerBufDec = loggerBufDec;
this.logDec = logDec;
filterIds = new HashMap<Integer, Integer>();
highestSeen = new HashMap<Integer, Long>();
}
/*
* ======== addLog ========
*/
public void addLog(int[] logIds)
{
/* Use the first log id in the list as the common log number. */
int commonNum = logIds[0];
/* Map the common log id to itself. */
filterIds.put(commonNum, commonNum);
/* Map the rest of the logger Ids to the common one. */
for (int i = 1; i < logIds.length; i++) {
filterIds.put(logIds[i], commonNum);
}
/* Initialize the 'highestSeen' value for the common log id. */
highestSeen.put(commonNum, -1l);
}
/*
* ======== mapDecoder ========
*/
// TODO - Make MixedDecoder generic.
//public void mapDecoder(int logId, IDecoder decoder)
/*
* ======== decode ========
* This API decodes the given byte array based on the logger id. It
* filters the decoded records to eleminate redundant and out-of-order
* records.
*/
public HostEvent[] decode(byte[] buffer, int offset, int length, int logId)
{
HostEvent[] evts;
/*
* If these are stop mode entries (indicated by the log id)
* decode using the LoggerBufDecoder.
* TODO - To be generic, the MixedDecoder should have a general
* mapping of log id to decoder. This will require an IDecoder
* interface.
*/
if (logId >= meta.getLoggerNames().length) {
evts = loggerBufDec.decodeBuffer(buffer, offset, length);
/* It's possible that there are no entries in the logger buf. */
if (evts.length == 0) {
return (evts);
}
}
/* Otherwise, they are just Log records */
else {
int recSize = meta.getTargetEventRecSize();
int numRecs = length / recSize;
evts = new HostEvent[numRecs];
/* Decode each of the records individually. */
for (int i = 0; i < numRecs; i++) {
evts[i] = logDec.apply(buffer, offset + (i * recSize));
}
/* Sort the records in case they are out of order. */
Arrays.sort(evts, evts[0].new CompareRecs());
}
/* Filter the events. */
return (filterEvents(evts, logId));
}
/*
* ======== filterEvents ========
* This API takes an array of HostEvents and filters out any records which
* are out of order or have already been seen.
* To accomplish this, it simply filters out any records whose sequence
* number is lower than the highest number which has been so far (per
* logger instance)
*/
private HostEvent[] filterEvents(HostEvent[] events, int loggerId)
{
Vector<HostEvent> results = new Vector<HostEvent>();
/* Get the common log id */
int logId = filterIds.get(loggerId);
/* Get the highest sequence number we've seen so far for this log. */
long max = highestSeen.get(logId);
/* For each of the records... */
for (int i = 0; i < events.length; i++) {
/*
* If this record's sequence number is higher than any previously
* seen, update the 'max' and add the record to the results.
*/
if (events[i].sequenceNum > max) {
max = events[i].sequenceNum;
results.add(events[i]);
}
}
/* Update the highest sequence number seen. */
highestSeen.put(logId, max);
return (results.toArray(new HostEvent[0]));
}
}