package com.zillabyte.motherbrain.flow.collectors.coordinated; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.mutable.MutableInt; import org.apache.commons.lang.mutable.MutableLong; import org.javatuples.Pair; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.zillabyte.motherbrain.flow.collectors.coordinated.support.CoordinatedOutputCollectorSupportFactory; import com.zillabyte.motherbrain.flow.collectors.coordinated.support.TupleIdSet; /*** * * @author jake */ public final class BatchTracker { private Object _batchId; private BatchState _batchState; private CoordinatedOutputCollector _collector; private CoordinatedOutputCollectorSupportFactory _supportFactory; private Map<Integer, TupleIdSet> _unAckedTuples = Maps.newHashMap(); private Map<Integer, TupleIdSet> _processedTupleIds = Maps.newHashMap(); private Map<Integer, TupleIdSet> _localQueuedTupleIds = Maps.newHashMap(); private Map<Integer, TupleIdSet> _remoteQueuedTupleIds = Maps.newHashMap(); private Map<Integer, Long> _downstreamBatchAcksReceived = Maps.newHashMap(); private Map<Integer, Long> _upstreamBatchCompletesReceived = Maps.newHashMap(); private Map<Integer, Pair<MutableInt, MutableLong>> _downstreamBatchCompletesSent = Maps.newHashMap(); private Map<Integer, MutableLong> _failedTupleCounts = Maps.newHashMap(); private Map<Integer, MutableLong> _sentTupleCounts = Maps.newHashMap(); private Map<Integer, Map<Integer, Boolean>> _aggSafe = Maps.newConcurrentMap(); private Map<Integer, Set<Integer>> _siblingsDoneAgg = Maps.newConcurrentMap(); private Map<Integer, Map<Integer, Boolean>> _checkTuple = Maps.newConcurrentMap(); private Long _lastBatchedTupleSeenAt; public BatchTracker(Object batchId, CoordinatedOutputCollector collector) { if (batchId instanceof BatchTracker) throw new IllegalStateException(); _batchId = batchId; _batchState = BatchState.EMITTING; _collector = collector; } /////////////// // BATCH STATE /////////////// public BatchState getBatchState() { return _batchState; } public void setBatchState(BatchState bs) { _batchState = bs; } /////////////// // TUPLE ACKS /////////////// public void addUnAckedTupleSentTo(BatchedTuple tuple, Integer task) { getTupleIdSet(_unAckedTuples, task).add(tuple.getId()); } public void removeUnAckedTupleIds(Integer fromTaskId, TupleIdSet set) { getTupleIdSet(_unAckedTuples, fromTaskId).removeAll(set); } public void resetUnAckedTupleTimestamp(Integer fromTaskId, TupleIdSet set) { getTupleIdSet(_unAckedTuples, fromTaskId).setTimestamp(set, System.currentTimeMillis()); } public boolean hasNoUnAckedTuples() { for(Entry<Integer, TupleIdSet> e : _unAckedTuples.entrySet()) { if (e.getValue().size() > 0) { return false; } } return true; } public Map<Integer, TupleIdSet> getUnAckedTuples() { return _unAckedTuples; } /////////////// // BATCH ACKS /////////////// public void markThatDownstreamBatchAckHasBeenReceived(Integer fromTaskId) { _downstreamBatchAcksReceived.put(fromTaskId, System.currentTimeMillis()); } public boolean hasDownstreamBatchAckBeenReceived(Integer outTask) { return _downstreamBatchAcksReceived.containsKey(outTask); } /////////////// // BATCH COMPLETES - UPSTREAM /////////////// public void markThatBatchCompleteHasBeenReceivedFromUpstreamTask(Integer fromTask) { _upstreamBatchCompletesReceived.put(fromTask, System.currentTimeMillis()); } public boolean hasReceivedBatchCompleteFromUpstreamTask(Integer fromTask) { return _upstreamBatchCompletesReceived.containsKey(fromTask); } /////////////// // BATCH COMPLETES - DOWNSTREAM /////////////// public Long getDownstreamBatchCompleteSentAt(Integer outTask) { if (_downstreamBatchCompletesSent.containsKey(outTask)) { return _downstreamBatchCompletesSent.get(outTask).getValue1().longValue(); } else { return 0L; } } public void resetBatchCompleteAttempts(Integer outTask) { if (_downstreamBatchCompletesSent.containsKey(outTask)) { _downstreamBatchCompletesSent.get(outTask).getValue0().setValue(0); } } public Integer getDownstreamBatchCompleteAttempts(Integer outTask) { if (_downstreamBatchCompletesSent.containsKey(outTask)) { return _downstreamBatchCompletesSent.get(outTask).getValue0().intValue(); } else { return 0; } } public void markThatBatchCompleteHasBeenSentToDownstreamTask(Integer outTask, Long time) { if (_downstreamBatchCompletesSent.containsKey(outTask) == false) { _downstreamBatchCompletesSent.put(outTask, new Pair<MutableInt, MutableLong>(new MutableInt(0), new MutableLong(0))); } Pair<MutableInt, MutableLong> p = _downstreamBatchCompletesSent.get(outTask); p.getValue0().increment(); p.getValue1().setValue(time); } /////////////// // PROCESSED TUPLES /////////////// public Map<Integer, TupleIdSet> getProcessedTupleIds() { return _processedTupleIds; } public void markTupleProcessedFrom(BatchedTuple tuple, Integer originTask) { getTupleIdSet(_processedTupleIds, originTask).add(tuple.getId()); } public boolean hasProcessedTuplesFrom(Integer originTask) { return getTupleIdSet(_processedTupleIds, originTask).size() > 0; } public void removeProcessedTupleIds(Integer task, TupleIdSet acks) { getTupleIdSet(_processedTupleIds, task).removeAll(acks); } public void removeProcessedTupleIds(Map<Integer, TupleIdSet> acks) { for(Entry<Integer, TupleIdSet> e : acks.entrySet()) { removeProcessedTupleIds(e.getKey(), e.getValue()); } } /////////////// // QUEUED TUPLES - LOCAL /////////////// public Map<Integer, TupleIdSet> getLocallyQueuedTupleIds() { return this._localQueuedTupleIds; } public int getLocallyQueuedTupleSize() { int size = 0; for(Entry<Integer, TupleIdSet> e : _localQueuedTupleIds.entrySet()) { size += e.getValue().size(); } return size; } public void markTupleLocallyQueuedFrom(BatchedTuple tuple, Integer originTask) { getTupleIdSet(_localQueuedTupleIds, originTask).add(tuple.getId()); } public void removeLocallyQueuedTupleFrom(BatchedTuple tuple, Integer task) { getTupleIdSet(_localQueuedTupleIds, task).remove(tuple.getId()); } public boolean hasLocallyQueuedTuplesFrom(Integer task) { return getTupleIdSet(_localQueuedTupleIds, task).size() > 0; } /////////////// // QUEUED TUPLES - REMOTE /////////////// public void replaceTuplesRemotelyQueuedAt(TupleIdSet set, Integer originTask) { getTupleIdSet(_remoteQueuedTupleIds, originTask).clear(); getTupleIdSet(_remoteQueuedTupleIds, originTask).addAll(set); } public void removeRemotelyQueuedTupleIds(Integer task, TupleIdSet set) { getTupleIdSet(_remoteQueuedTupleIds, task).removeAll(set); } public TupleIdSet getRemoteQueuedTuples(Integer task) { return getTupleIdSet(_remoteQueuedTupleIds, task); } public Map<Integer, TupleIdSet> getRemotelyQueuedTupleIds() { return this._remoteQueuedTupleIds; } /////////////// // HELPERS /////////////// public void setCurrentFailedTupleCount(Integer task, int size) { if (_failedTupleCounts .containsKey(task) == false) { _failedTupleCounts.put(task, new MutableLong()); } _failedTupleCounts.get(task).setValue(size); } public long getFailedTupleCount(Integer task) { if (_failedTupleCounts.containsKey(task)) { return _failedTupleCounts.get(task).longValue(); } else { return 0; } } public synchronized void setTaskAggSafe(Integer aggStoreKey, Integer task, Boolean state) { Map<Integer, Boolean> aggSafe; if(_aggSafe.containsKey(aggStoreKey)) { aggSafe = _aggSafe.get(aggStoreKey); } else { aggSafe = Maps.newConcurrentMap(); } aggSafe.put(task, state); _aggSafe.put(aggStoreKey, aggSafe); } public synchronized void setSiblingTaskDoneAgg(Integer aggStoreKey, Integer task) { Set<Integer> doneSiblings; if(_siblingsDoneAgg.containsKey(aggStoreKey)) { doneSiblings = _siblingsDoneAgg.get(aggStoreKey); doneSiblings.add(task); } else { doneSiblings = Sets.newHashSet(task); } _siblingsDoneAgg.put(aggStoreKey, doneSiblings); } public synchronized void setCheckTuple(Integer aggStoreKey, Integer task, Boolean state) { Map<Integer, Boolean> checkTuple; if(_checkTuple.containsKey(aggStoreKey)) { checkTuple = _checkTuple.get(aggStoreKey); } else { checkTuple = Maps.newConcurrentMap(); } checkTuple.put(task, state); _checkTuple.put(aggStoreKey, checkTuple); } public Map<Integer, Boolean> getAggregationSafe(Integer aggStoreKey) { return _aggSafe.get(aggStoreKey); } public Set<Integer> getSiblingsDoneAggregation(Integer aggStoreKey) { return _siblingsDoneAgg.get(aggStoreKey); } public Map<Integer, Boolean> getLastTupleCheck(Integer aggStoreKey) { return _checkTuple.get(aggStoreKey); } public void incSentTupleCount(Integer task) { if (_sentTupleCounts .containsKey(task) == false) { _sentTupleCounts.put(task, new MutableLong()); } _sentTupleCounts.get(task).increment(); } public long getSentTupleCount(Integer task) { if (_sentTupleCounts.containsKey(task)) { return _sentTupleCounts.get(task).longValue(); } else { return 0; } } private TupleIdSet getTupleIdSet(Map<Integer, TupleIdSet> map, Integer task) { if (map.containsKey(task) == false) { map.put(task, _collector.getSupportFactory().createTupleIdSet(_collector)); } return map.get(task); } public Object getBatch() { return this._batchId; } public Integer getTask() { return this._collector.getTaskId(); } public void removeDeadTask(Integer task) { // TODO Auto-generated method stub throw new NotImplementedException(); } public void setLastBatchedTupleSeenAt() { _lastBatchedTupleSeenAt = System.currentTimeMillis(); } public Long getLastBatchedTupleSeenAt() { return _lastBatchedTupleSeenAt; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("\n"); sb.append("**********************************");sb.append("\n"); sb.append("* batch: " + _batchId);sb.append("\n"); sb.append("* state: " + _batchState);sb.append("\n"); sb.append("* unacked: " + _unAckedTuples);sb.append("\n"); sb.append("* remote-queued: " + _remoteQueuedTupleIds);sb.append("\n"); sb.append("* local-queued: " + _localQueuedTupleIds);sb.append("\n"); sb.append("* processed: " + _processedTupleIds);sb.append("\n"); sb.append("*- - - - - - - -");sb.append("\n"); sb.append("* upstream_batch-completes_received: " + _upstreamBatchCompletesReceived);sb.append("\n"); sb.append("* downstream_batch-acks_received: " + _downstreamBatchAcksReceived);sb.append("\n"); sb.append("* downstream_batch-completes_sent: " + _downstreamBatchCompletesSent);sb.append("\n"); sb.append("**********************************");sb.append("\n"); return sb.toString(); } public void cleanup() { } }