package org.act.tstream.stats.rolling; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.act.tstream.callback.RunnableCallback; import org.act.tstream.utils.TimeUtils; public class RollingWindow { private RunnableCallback updater; private RunnableCallback merger; private RunnableCallback extractor; private Integer bucket_size_secs; private Integer num_buckets; // <TimeSecond, Map<streamId, staticsValue>> private Map<Integer, Map> buckets; public RunnableCallback getUpdater() { return updater; } public void setUpdater(RunnableCallback updater) { this.updater = updater; } public RunnableCallback getMerger() { return merger; } public void setMerger(RunnableCallback merger) { this.merger = merger; } public RunnableCallback getExtractor() { return extractor; } public void setExtractor(RunnableCallback extractor) { this.extractor = extractor; } public Integer getBucket_size_secs() { return bucket_size_secs; } public void setBucket_size_secs(Integer bucket_size_secs) { this.bucket_size_secs = bucket_size_secs; } public Integer getNum_buckets() { return num_buckets; } public void setNum_buckets(Integer num_buckets) { this.num_buckets = num_buckets; } public Map<Integer, Map> getBuckets() { return buckets; } public void setBuckets(Map<Integer, Map> buckets) { this.buckets = buckets; } public Integer curr_time_bucket(Integer time_secs) { return (Integer) (bucket_size_secs * (time_secs / bucket_size_secs)); } // num_buckets == StatFunction.NUM_STAT_BUCKETS public static RollingWindow rolling_window(RunnableCallback updater, RunnableCallback merger, RunnableCallback extractor, Integer bucket_size_secs, Integer num_buckets) { RollingWindow rtn = new RollingWindow(); rtn.setUpdater(updater); rtn.setMerger(merger); rtn.setExtractor(extractor); rtn.setBucket_size_secs(bucket_size_secs); rtn.setNum_buckets(num_buckets); rtn.setBuckets(new HashMap<Integer, Map>()); return rtn; } /** * * @param time_secs * @param args * Object[0] -- key, Object[1] -- value * @return */ public RollingWindow update_rolling_window(Integer time_secs, Object[] args) { synchronized (this) { Integer time_bucket = curr_time_bucket(time_secs); Map curr = buckets.get(time_bucket); UpdateParams p = new UpdateParams(); p.setArgs(args); p.setCurr(curr); curr = (Map) updater.execute((Object) p); buckets.put(time_bucket, curr); return this; } } /** * * @return <streamId, counter/statics> */ public Object value_rolling_window() { synchronized (this) { // <TimeSecond, Map<streamId, staticsValue>> buckets List<Map> values = new ArrayList<Map>(); for (Entry<Integer, Map> entry : buckets.entrySet()) { values.add(entry.getValue()); } // <streamId, counter> -- result Object result = merger.execute(values); return extractor.execute(result); } } public RollingWindow cleanup_rolling_window(int cutoff) { synchronized (this) { List<Integer> toremove = new ArrayList<Integer>(); for (Entry<Integer, Map> entry : buckets.entrySet()) { Integer key = entry.getKey(); if (key < cutoff) { toremove.add(key); } } for (Integer i : toremove) { buckets.remove(i); } return this; } } /** * clean old data in the buckets before (now - bucket_size_secs * * num_buckets) * * @param cutoff * @return */ public RollingWindow cleanup_rolling_window() { int cutoff = TimeUtils.current_time_secs() - rolling_window_size(); return cleanup_rolling_window(cutoff); } public int rolling_window_size() { return bucket_size_secs * num_buckets; } }