/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package staticContent.evaluation.traceParser.engine.dataStructure; import java.io.IOException; import java.io.Writer; import java.util.Vector; import staticContent.framework.util.Util; public class FlowGroup { public int flowGroupId; public static int flowGroupIdCounter = 0; public int flowCounter = 0; public int senderId; /** * start replaying this flow group "startDelay" ms after the previous flow * group */ public long startDelay; /** * (start of) first transfer of this flow group; offset from start of trace * (it is NOT required to calculate start + startDelay to get the actual * start) */ public long start; /** * (end of) last transfer of this flow group; offset from start of trace; * use "end - start" to calculate the duration of this flow group (does * not include the "startDelay") */ public long end; public Vector<Flow> flows; public FlowGroup(Flow firstFlow) { this.flowGroupId = flowGroupIdCounter++; this.flows = new Vector<Flow>(); //firstFlow.flowId = flowCounter++; this.flows.add(firstFlow); this.senderId = firstFlow.senderId; this.start = firstFlow.startOfFlow; this.end = firstFlow.endOfFlow; } public FlowGroup(long startDelay, Flow firstFlow) { this(firstFlow); this.startDelay = startDelay; } public FlowGroup(String serializedFlowGroup) { this.flowGroupId = flowGroupIdCounter++; this.flows = new Vector<Flow>(); init(serializedFlowGroup); } public void init(String serializedFlowGroup) { String[] columns = serializedFlowGroup.split("\\|"); if (columns.length < 5) throw new RuntimeException("unrecognized trace file format: " +serializedFlowGroup); this.senderId = Integer.parseInt(columns[0]); this.start = Long.parseLong(columns[1]); this.startDelay = Long.parseLong(columns[2]); this.end = Long.parseLong(columns[3]); int numberOfFlows = columns.length - 4; for (int i=0; i<numberOfFlows; i++) flows.add(new Flow(columns[4 + i])); } public void resetStart(long newStart) { long dif = -1 * (this.start - newStart); this.start += dif; this.end += dif; for (Flow flow: flows) flow.resetStart(flow.startOfFlow + dif); } public long getEndOfLatestFlow() { assert flows != null && flows.size() != 0; long latest = 0; for (Flow flow:flows) if (flow.endOfFlow > latest) latest = flow.endOfFlow; return latest; } /** * removes any flows and transactions of this flow group that start after * "maxEnd". * * @return returns whether the cut off was successful (true) or not * (false). a not successful cut (false) means that the flow group could * not be cut to the desired length as the resulting flow group would * contain no more transactions */ public boolean cutOff(long maxEnd) { if (maxEnd >= this.end) { // already short enough //if (Util.assertionsEnabled()) // for (Flow f:flows) // assert f.endOfFlow <= maxEnd; return true; } for (int i=flows.size()-1; i>=0; i--) { Flow flow = flows.get(i); if (flow.startOfFlow >= maxEnd) { // flow starts later than (or equal to) max end -> drop whole flow flows.remove(i); } else if (flow.endOfFlow > maxEnd) { // flow starts before maxEnd and ends later than maxEnd -> try to cut flow boolean cutSuccessful = flow.cutOff(maxEnd); if (!cutSuccessful) { // drop whole flow flows.remove(i); } else { assert flow.endOfFlow <= maxEnd; } //break; } else { assert flow.endOfFlow <= maxEnd; //break; } } if (flows.size() == 0) { // no flows left return false; } else { end = Long.MIN_VALUE; for (Flow flow:flows) if (flow.endOfFlow > end) end = flow.endOfFlow; assert end <= maxEnd; return true; } } /*@Override public String toString() { return "flowGroup "+flowGroupId +": " +serialize(); }*/ public String serialize() { StringBuffer sb = new StringBuffer(); serialize(sb); return sb.toString(); } public StringBuffer serialize(StringBuffer bufferToAppend) { bufferToAppend.append(senderId +"|"); bufferToAppend.append(start +"|"); bufferToAppend.append(startDelay +"|"); bufferToAppend.append(end +"|"); //int ctr = 0; // reassign flow ids for (int i=0; i<flows.size(); i++) { Flow flow = flows.get(i); //flow.flowId = ctr++; bufferToAppend.append(flow.serialize()); if (i<(flows.size()-1)) bufferToAppend.append("|"); } return bufferToAppend; } public void serialize(Writer destination) throws IOException { destination.write(senderId +"|"); destination.write(start +"|"); destination.write(startDelay +"|"); destination.write(end +"|"); //int ctr = 0; // reassign flow ids for (int i=0; i<flows.size(); i++) { Flow flow = flows.get(i); //flow.flowId = ctr++; destination.write(flow.serialize()); if (i<(flows.size()-1)) destination.write("|"); } } /*@Override public boolean equals(Object obj) { FlowGroup fg = (FlowGroup)obj; if ( fg.senderId == senderId && fg.startDelay == startDelay && fg.start == start && fg.end == end && fg.flows.size() == flows.size() ) return true; return false; }*/ /*public static void sort(String inputFilePath, String outputFilePath) throws IOException { BufferedReader in = null; Writer resultTrace = null; try { in = new BufferedReader(new FileReader(inputFilePath)); resultTrace = new BufferedWriter(new OutputStreamWriter(new DataOutputStream(new FileOutputStream(outputFilePath)))); PriorityQueue<String> entries = new PriorityQueue<String>(1000, new FlowGroupComparator()); String currentLine; while (true) { currentLine = in.readLine(); if (currentLine == null) break; entries.add(currentLine); } in.close(); while (true) { currentLine = entries.poll(); if (currentLine == null) break; resultTrace.write(currentLine); resultTrace.write("\n"); } } catch (IOException e) { // close reader + writer and forward exception try { if (in != null) in.close(); if (resultTrace != null) resultTrace.close(); } catch (Exception e1) {} throw e; } resultTrace.close(); }*/ /** * for fast access of fields of a serialized flow (without creating an instance) * pos 0: senderId (type: int) (get value with Integer.parseInt(String)) * pos 1: start (type: long) (get value with Long.parseLong(String)) * pos 2: startDelay (type: long) (get value with Long.parseLong(String)) * pos 3: end (type: long) (get value with Long.parseLong(String)) * pos 3 + i: ith flow (type: Flow) (get value with new Flow(String)) */ public static String extractField(int position, String serializedFlow) { return Util.extractField(position, "\\|", serializedFlow); } }