/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.chukwa.analysis.salsa.fsm;
import java.io.IOException;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.Set;
import org.apache.hadoop.io.WritableComparable;
/*
* FSM Intermediate State Entry
*
* Each state corresponds to two of these entries:
* One corresponding to the start of the state, one corresponding to the end of the state
*
* Intermediate data-structure passed from Maps to Reduces
*
*/
public class FSMIntermedEntry
implements Cloneable, WritableComparable
{
private final char DELIM = 1;
/* Begin fields */
public StateType state_type;
public MapRedState state_mapred;
public HDFSState state_hdfs;
public FSMType fsm_type;
public String state_name;
public String identifier;
public String unique_id; // state name + unique identifier
// (state-dependent)
// this id should also correspond
// to the k2 value between
// mappers and reducers
public String timestamp;
public String time_start;
public String time_end;
public String host_exec;
public String host_other; // for instance, source host for shuffle,
// src/dest host for dfs read/write
// These values filled in by splitting the original
// ChukwaRecordKey from Demux
public String time_orig_epoch;
public String time_orig;
public String job_id; // we get this for free from the CRK
TreeMap<String,String> add_info; // additional information
// e.g. locality information
/* End of fields */
public FSMIntermedEntry() {
this.state_mapred = new MapRedState(MapRedState.NONE);
this.state_hdfs = new HDFSState(HDFSState.NONE);
this.state_type = new StateType(StateType.STATE_NOOP);
this.add_info = new TreeMap<String, String>();
this.host_other = new String("");
this.job_id = new String("");
this.time_orig_epoch = new String("");
this.time_orig = new String("");
}
public String getUniqueID()
{
return new String(this.unique_id);
}
public String getFriendlyID()
{
return new String(this.identifier);
}
/**
* Set state_type and identifier before calling
*/
public void generateUniqueID()
{
if (this.fsm_type.val == FSMType.MAPREDUCE_FSM ||
this.fsm_type.val == FSMType.MAPREDUCE_FSM_INCOMPLETE)
{
this.state_name = new String(this.state_mapred.toString());
} else if (this.fsm_type.val == FSMType.MAPREDUCE_FSM ||
this.fsm_type.val == FSMType.MAPREDUCE_FSM_INCOMPLETE)
{
this.state_name = new String(this.state_hdfs.toString());
}
this.unique_id = new String(this.state_name + "@" + this.identifier);
}
public void write(DataOutput out) throws IOException {
Set<String> mapKeys;
out.writeInt(this.state_type.val);
out.writeInt(this.state_mapred.val);
out.writeInt(this.state_hdfs.val);
out.writeInt(this.fsm_type.val);
out.writeChar(DELIM);
out.writeInt(state_name.length());
if (state_name.length() > 0) out.writeUTF(state_name);
out.writeInt(unique_id.length());
if (unique_id.length() > 0) out.writeUTF(unique_id);
out.writeInt(timestamp.length());
if (timestamp.length() > 0) out.writeUTF(timestamp);
out.writeInt(time_start.length());
if (time_start.length() > 0) out.writeUTF(time_start);
out.writeInt(time_end.length());
if (time_end.length() > 0) out.writeUTF(time_end);
out.writeInt(host_exec.length());
if (host_exec.length() > 0) out.writeUTF(host_exec);
out.writeInt(host_other.length());
if (host_other.length() > 0) out.writeUTF(host_other);
out.writeInt(time_orig_epoch.length());
if (time_orig_epoch.length() > 0) out.writeUTF(time_orig_epoch);
out.writeInt(time_orig.length());
if (time_orig.length() > 0) out.writeUTF(time_orig);
out.writeInt(job_id.length());
if (job_id.length() > 0) out.writeUTF(job_id);
out.writeInt(identifier.length());
if (identifier.length() > 0) out.writeUTF(identifier);
mapKeys = this.add_info.keySet();
out.writeInt(mapKeys.size());
Iterator<String> keyIter = mapKeys.iterator();
for (int i = 0; i < mapKeys.size(); i++) {
assert(keyIter.hasNext());
String currKey = keyIter.next();
if (currKey != null) {
String currvalue = this.add_info.get(currKey);
out.writeUTF(currKey);
out.writeInt(currvalue.length());
if (currvalue.length() > 0) {
out.writeUTF(currvalue);
}
} else {
out.writeUTF(new String("NULL"));
out.writeInt(0);
}
}
}
public void readFields(DataInput in) throws IOException {
int currlen, numkeys;
this.state_type = new StateType(in.readInt());
this.state_mapred = new MapRedState(in.readInt());
this.state_hdfs = new HDFSState(in.readInt());
this.fsm_type = new FSMType(in.readInt());
in.readChar();
currlen = in.readInt();
if (currlen > 0) this.state_name = in.readUTF();
else this.state_name = new String("");
currlen = in.readInt();
if (currlen > 0) this.unique_id = in.readUTF();
else this.unique_id = new String("");
currlen = in.readInt();
if (currlen > 0) this.timestamp = in.readUTF();
else this.timestamp = new String("");
currlen = in.readInt();
if (currlen > 0) this.time_start = in.readUTF();
else this.time_start = new String("");
currlen = in.readInt();
if (currlen > 0) this.time_end = in.readUTF();
else this.time_end = new String("");
currlen = in.readInt();
if (currlen > 0) this.host_exec = in.readUTF();
else this.host_exec = new String("");
currlen = in.readInt();
if (currlen > 0) this.host_other = in.readUTF();
else this.host_other = new String("");
currlen = in.readInt();
if (currlen > 0) this.time_orig_epoch = in.readUTF();
else this.time_orig_epoch = new String("");
currlen = in.readInt();
if (currlen > 0) this.time_orig = in.readUTF();
else this.time_orig = new String("");
currlen = in.readInt();
if (currlen > 0) this.job_id = in.readUTF();
else this.job_id = new String("");
currlen = in.readInt();
if (currlen > 0) this.identifier = in.readUTF();
else this.identifier = new String("");
numkeys = in.readInt();
this.add_info = new TreeMap<String, String>();
if (numkeys > 0) {
for (int i = 0; i < numkeys; i++) {
String currkey, currval;
currkey = in.readUTF();
currlen = in.readInt();
if (currlen > 0) {
currval = in.readUTF();
this.add_info.put(currkey, currval);
}
}
}
}
public boolean equals (Object o) {
FSMIntermedEntry other = (FSMIntermedEntry) o;
return this.unique_id.equals(other.unique_id);
}
public int compareTo (Object o) {
FSMIntermedEntry other = (FSMIntermedEntry) o;
return this.unique_id.compareTo(other.unique_id);
}
/*
* This method is to support convenient creating of new copies
* of states for Reduce to create sub-states ReduceShuffle, ReduceSort, and ReduceReducer
*/
public FSMIntermedEntry clone() throws CloneNotSupportedException {
FSMIntermedEntry newObj = (FSMIntermedEntry) super.clone();
Set<String> mapKeys;
newObj.state_type = new StateType(this.state_type.val);
newObj.state_mapred = new MapRedState(this.state_mapred.val);
newObj.state_hdfs = new HDFSState(this.state_hdfs.val);
newObj.fsm_type = new FSMType(this.fsm_type.val);
/* Deep copy all strings */
newObj.state_name = new String(this.state_name);
newObj.unique_id = new String(this.unique_id);
newObj.timestamp = new String(this.timestamp);
newObj.time_start = new String(this.time_start);
newObj.time_end = new String(this.time_end);
newObj.time_orig_epoch = new String(this.time_orig_epoch);
newObj.time_orig = new String(this.time_orig);
newObj.job_id = new String(this.job_id);
/* Deep copy of TreeMap */
newObj.add_info = new TreeMap<String,String>();
mapKeys = this.add_info.keySet();
Iterator<String> keyIter = mapKeys.iterator();
String currKey = null;
for (int i = 0; i < mapKeys.size(); i++) {
assert(keyIter.hasNext());
currKey = keyIter.next();
if (currKey != null) {
newObj.add_info.put(currKey, this.add_info.get(currKey));
}
}
return newObj;
}
public String toString() {
return new String(this.state_name + "@" + this.unique_id);
}
}