package com.linkedin.camus.etl.kafka.common; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Map; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.MapWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.UTF8; import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.WritableComparable; import com.linkedin.camus.etl.IEtlKey; /** * The key for the mapreduce job to pull kafka. Contains offsets and the * checksum. */ public class EtlKey implements WritableComparable<EtlKey>, IEtlKey { public static final Text SERVER = new Text("server"); public static final Text SERVICE = new Text("service"); public static EtlKey DUMMY_KEY = new EtlKey(); private String leaderId = ""; private int partition = 0; private long beginOffset = 0; private long offset = 0; private long checksum = 0; private String topic = ""; private long time = 0; private String server = ""; private String service = ""; private long totalMessageSize = 0; private MapWritable partitionMap = new MapWritable(); /** * dummy empty constructor */ public EtlKey() { this("dummy", "0", 0, 0, 0, 0); } public EtlKey(EtlKey other) { this.partition = other.partition; this.beginOffset = other.beginOffset; this.offset = other.offset; this.checksum = other.checksum; this.topic = other.topic; this.time = other.time; this.server = other.server; this.service = other.service; this.partitionMap = new MapWritable(other.partitionMap); } public EtlKey(String topic, String leaderId, int partition) { this.set(topic, leaderId, partition, 0, 0, 0); } public EtlKey(String topic, String leaderId, int partition, long beginOffset, long offset) { this.set(topic, leaderId, partition, beginOffset, offset, 0); } public EtlKey(String topic, String leaderId, int partition, long beginOffset, long offset, long checksum) { this.set(topic, leaderId, partition, beginOffset, offset, checksum); } public void set(String topic, String leaderId, int partition, long beginOffset, long offset, long checksum) { this.leaderId = leaderId; this.partition = partition; this.beginOffset = beginOffset; this.offset = offset; this.checksum = checksum; this.topic = topic; this.time = System.currentTimeMillis(); // if event can't be decoded, // this time will be used for // debugging. } public void clear() { leaderId = ""; partition = 0; beginOffset = 0; offset = 0; checksum = 0; topic = ""; time = 0; server = ""; service = ""; partitionMap = new MapWritable(); } public String getServer() { return partitionMap.get(SERVER).toString(); } public void setServer(String newServer) { partitionMap.put(SERVER, new Text(newServer)); } public String getService() { return partitionMap.get(SERVICE).toString(); } public void setService(String newService) { partitionMap.put(SERVICE, new Text(newService)); } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public String getTopic() { return topic; } public String getLeaderId() { return leaderId; } public int getPartition() { return this.partition; } public long getBeginOffset() { return this.beginOffset; } public void setOffset(long offset) { this.offset = offset; } public long getOffset() { return this.offset; } public long getChecksum() { return this.checksum; } @Override public long getMessageSize() { Text key = new Text("message.size"); if (this.partitionMap.containsKey(key)) return ((LongWritable) this.partitionMap.get(key)).get(); else return 1024; //default estimated size } public long getTotalMessageSize() { if (this.totalMessageSize == 0) { this.totalMessageSize = this.getMessageSize(); } return this.totalMessageSize; } public void setTotalMessageSize(long totalMessageSize) { this.totalMessageSize = totalMessageSize; } public void setMessageSize(long messageSize) { Text key = new Text("message.size"); put(key, new LongWritable(messageSize)); } public void put(Writable key, Writable value) { this.partitionMap.put(key, value); } public void addAllPartitionMap(MapWritable partitionMap) { this.partitionMap.putAll(partitionMap); } public MapWritable getPartitionMap() { return partitionMap; } @Override public void readFields(DataInput in) throws IOException { this.leaderId = UTF8.readString(in); this.partition = in.readInt(); this.beginOffset = in.readLong(); this.offset = in.readLong(); this.checksum = in.readLong(); this.topic = in.readUTF(); this.time = in.readLong(); this.server = in.readUTF(); // left for legacy this.service = in.readUTF(); // left for legacy this.partitionMap = new MapWritable(); try { this.partitionMap.readFields(in); } catch (IOException e) { this.setServer(this.server); this.setService(this.service); } } @Override public void write(DataOutput out) throws IOException { UTF8.writeString(out, this.leaderId); out.writeInt(this.partition); out.writeLong(this.beginOffset); out.writeLong(this.offset); out.writeLong(this.checksum); out.writeUTF(this.topic); out.writeLong(this.time); out.writeUTF(this.server); // left for legacy out.writeUTF(this.service); // left for legacy this.partitionMap.write(out); } @Override public int compareTo(EtlKey o) { if (partition != o.partition) { return partition = o.partition; } else { if (offset > o.offset) { return 1; } else if (offset < o.offset) { return -1; } else { if (checksum > o.checksum) { return 1; } else if (checksum < o.checksum) { return -1; } else { return 0; } } } } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("topic="); builder.append(topic); builder.append(" partition="); builder.append(partition); builder.append("leaderId="); builder.append(leaderId); builder.append(" server="); builder.append(server); builder.append(" service="); builder.append(service); builder.append(" beginOffset="); builder.append(beginOffset); builder.append(" offset="); builder.append(offset); builder.append(" msgSize="); builder.append(getMessageSize()); builder.append(" server="); builder.append(server); builder.append(" checksum="); builder.append(checksum); builder.append(" time="); builder.append(time); for (Map.Entry<Writable, Writable> e : partitionMap.entrySet()) { builder.append(" " + e.getKey() + "="); builder.append(e.getValue().toString()); } return builder.toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof EtlKey)) { return false; } EtlKey etlKey = (EtlKey) o; if (beginOffset != etlKey.beginOffset) { return false; } if (checksum != etlKey.checksum) { return false; } if (offset != etlKey.offset) { return false; } if (partition != etlKey.partition) { return false; } if (time != etlKey.time) { return false; } if (!leaderId.equals(etlKey.leaderId)) { return false; } if (!partitionMap.equals(etlKey.partitionMap)) { return false; } if (!server.equals(etlKey.server)) { return false; } if (!service.equals(etlKey.service)) { return false; } if (!topic.equals(etlKey.topic)) { return false; } return true; } @Override public int hashCode() { int result = leaderId.hashCode(); result = 31 * result + partition; result = 31 * result + (int) (beginOffset ^ (beginOffset >>> 32)); result = 31 * result + (int) (offset ^ (offset >>> 32)); result = 31 * result + (int) (checksum ^ (checksum >>> 32)); result = 31 * result + topic.hashCode(); result = 31 * result + (int) (time ^ (time >>> 32)); result = 31 * result + server.hashCode(); result = 31 * result + service.hashCode(); result = 31 * result + partitionMap.hashCode(); return result; } }