package edu.sc.seis.sod.source.event; import org.w3c.dom.Element; import edu.iris.Fissures.model.MicroSecondDate; import edu.iris.Fissures.model.TimeInterval; import edu.iris.Fissures.model.UnitImpl; import edu.sc.seis.fissuresUtil.chooser.ClockUtil; import edu.sc.seis.fissuresUtil.database.NotFound; import edu.sc.seis.fissuresUtil.display.configuration.DOMHelper; import edu.sc.seis.fissuresUtil.time.MicroSecondTimeRange; import edu.sc.seis.sod.ConfigurationException; import edu.sc.seis.sod.QueryTime; import edu.sc.seis.sod.SodUtil; import edu.sc.seis.sod.Start; import edu.sc.seis.sod.hibernate.SodDB; import edu.sc.seis.sod.source.AbstractSource; import edu.sc.seis.sod.source.network.AbstractNetworkSource; public abstract class AbstractEventSource extends AbstractSource implements EventSource { public AbstractEventSource(String name, int retries) { super(name, retries); refreshInterval = Start.getRunProps().getEventRefreshInterval(); lag = Start.getRunProps().getEventLag(); increment = Start.getRunProps().getEventQueryIncrement(); } public AbstractEventSource(Element config, String defaultName) throws ConfigurationException { super(config, defaultName, -1); if(DOMHelper.hasElement(config, AbstractNetworkSource.REFRESH_ELEMENT)) { refreshInterval = SodUtil.loadTimeInterval(SodUtil.getElement(config, AbstractNetworkSource.REFRESH_ELEMENT)); } else { refreshInterval = Start.getRunProps().getEventRefreshInterval(); } if(DOMHelper.hasElement(config, AbstractEventSource.EVENT_QUERY_INCREMENT)) { increment = SodUtil.loadTimeInterval(SodUtil.getElement(config, AbstractEventSource.EVENT_QUERY_INCREMENT)); } else { increment = Start.getRunProps().getEventQueryIncrement(); } if(DOMHelper.hasElement(config, AbstractEventSource.EVENT_LAG)) { lag = SodUtil.loadTimeInterval(SodUtil.getElement(config, AbstractEventSource.EVENT_LAG)); } else { lag = Start.getRunProps().getEventLag(); } } @Override public TimeInterval getWaitBeforeNext() { MicroSecondDate now = ClockUtil.now(); if (! caughtUpWithRealtime()) { return new TimeInterval(0, UnitImpl.SECOND); } if (lastQueryTime == null) { // on null, make time old enough to force a query lastQueryTime = now.subtract(refreshInterval).subtract(nearRealTimeInterval); } TimeInterval sleepTime = now.subtract(lastQueryTime).add(refreshInterval); if (sleepTime.getValue() < 0) { caughtUpToRealtime = false; } logger.debug("getWaitBeforeNext() lq="+lastQueryTime+" sleep="+sleepTime.getValue(UnitImpl.SECOND)+" now="+now+" refesh="+refreshInterval.getValue(UnitImpl.SECOND)); return sleepTime; } protected boolean caughtUpWithRealtime() { return caughtUpToRealtime; } protected boolean isEverCaughtUpToRealtime() { return everCaughtUpToRealtime; } /** * @return - the next time to start asking for events */ protected MicroSecondDate getQueryStart() { try { return getQueryEdge(); } catch (edu.sc.seis.fissuresUtil.database.NotFound e) { logger.debug("the query times database didn't have an entry for our server/dns combo, just use the time in the config file"); setQueryEdge(getEventTimeRange().getBeginTime()); return getEventTimeRange().getBeginTime(); } } /** * @return - the next time range to be queried for events */ protected MicroSecondTimeRange getQueryTime() { MicroSecondDate now = ClockUtil.now(); MicroSecondDate queryStart = getQueryStart(); if (caughtUpWithRealtime()) { // have caught up with real time, so go back by lag queryStart = resetQueryTimeForLag(); caughtUpToRealtime = false; } MicroSecondDate queryEnd = queryStart.add(increment); if (getEventTimeRange().getEndTime().before(queryEnd)) { queryEnd = getEventTimeRange().getEndTime(); logger.debug("Caught up with edge of event time range."); caughtUpToRealtime = true; everCaughtUpToRealtime = true; } if (now.before(queryEnd)) { logger.info("Caught up with now."); queryEnd = now; caughtUpToRealtime = true; everCaughtUpToRealtime = true; } if (queryStart.after(ClockUtil.wayFuture())) { throw new RuntimeException("start way in future: qs="+queryStart+" lag="+getLag()+" end="+queryEnd); } if (queryEnd.subtract(queryStart).lessThan(new TimeInterval(1, UnitImpl.MINUTE))) { logger.warn("Query for very short time window: start:"+queryStart+" end:"+queryEnd+" inc:"+increment+" now:"+now+" cuwrt:"+caughtUpToRealtime+" ecuwrt:"+everCaughtUpToRealtime+" tot end:"+getEventTimeRange().getEndTime()); } return new MicroSecondTimeRange(queryStart, queryEnd); } public void increaseQueryTimeWidth() { increment = (TimeInterval)increment.multiplyBy(2); } /** decrease the time increment for queries, but only if it is larger than the minimum = 1Day * to avoid many tiny queries to the server. */ public void decreaseQueryTimeWidth() { if (getIncrement().greaterThan(MIN_INCREMENT)) { increment = (TimeInterval)increment.multiplyBy(.75); } } /** * Scoots the query time back by the event lag amount from the run * properties to the query start time at the earliest */ protected MicroSecondDate resetQueryTimeForLag() { MicroSecondDate newEdge = getQueryStart().subtract(lag); if (newEdge.before(getEventTimeRange().getBeginTime())) { newEdge = getEventTimeRange().getBeginTime(); } return newEdge; } /** * @return - latest time queried */ protected MicroSecondDate getQueryEdge() throws NotFound { SodDB sdb = SodDB.getSingleton(); QueryTime t = sdb.getQueryTime(getName(), NO_DNS); SodDB.commit(); if (t == null) {throw new NotFound();} return new MicroSecondDate(t.getTime()); } /** * sets the latest time queried */ protected void setQueryEdge(MicroSecondDate edge) { lastQueryTime = ClockUtil.now(); SodDB sdb = SodDB.getSingleton(); QueryTime qt = sdb.getQueryTime(getName(), NO_DNS); if (qt != null) { qt.setTime( edge.getTimestamp()); SodDB.getSession().saveOrUpdate(qt); } else { sdb.putQueryTime(new QueryTime(getName(), NO_DNS, edge.getTimestamp())); } SodDB.commit(); } protected void updateQueryEdge(MicroSecondTimeRange queryTime) { setQueryEdge(queryTime.getEndTime()); } public MicroSecondDate getSleepUntilTime() { return sleepUntilTime; } public TimeInterval getLag() { return lag; } public TimeInterval getIncrement() { return increment; } public void setIncrement(TimeInterval increment) { this.increment = increment; } public void setLag(TimeInterval lag) { this.lag = lag; } public TimeInterval getRefreshInterval() { return refreshInterval; } protected boolean caughtUpToRealtime = false; protected boolean everCaughtUpToRealtime = false; protected MicroSecondDate lastQueryTime = null; public static final String NO_DNS = "NO_DNS"; protected MicroSecondDate sleepUntilTime = null; protected TimeInterval increment, lag; protected TimeInterval refreshInterval = new TimeInterval(10, UnitImpl.MINUTE); protected TimeInterval nearRealTimeInterval = new TimeInterval(2, UnitImpl.MINUTE); private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AbstractEventSource.class); public static final String EVENT_QUERY_INCREMENT = "eventQueryIncrement"; public static final String EVENT_REFRESH_INTERVAL = "eventRefreshInterval"; public static final String EVENT_LAG = "eventLag"; public static final TimeInterval MIN_INCREMENT = new TimeInterval(1, UnitImpl.DAY); }