/*
* StreamCruncher: Copyright (c) 2006-2008, Ashwin Jayaprakash. All Rights Reserved.
* Contact: ashwin {dot} jayaprakash {at} gmail {dot} com
* Web: http://www.StreamCruncher.com
*
* This file is part of StreamCruncher.
*
* StreamCruncher is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* StreamCruncher is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with StreamCruncher. If not, see <http://www.gnu.org/licenses/>.
*/
package streamcruncher.api;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import streamcruncher.innards.core.filter.FilteredTable;
import streamcruncher.util.FixedKeyHashMap;
/*
* Author: Ashwin Jayaprakash Date: Jul 3, 2006 Time: 10:04:57 PM
*/
/**
* <p>
* Each registered Query has a configuration object that can be retrieved after
* parsing or at any time during the life of the Query from the API provided.
* </p>
* <p>
* A handle to the instance must not be serialized and stored through a restart,
* but must be retrieved afresh after the Kernel restarts. Any changes made to
* the configuration will take effect immediately. This class <b>is Thread-safe</b>.
* All values have defaults.
* </p>
*/
public abstract class QueryConfig implements Serializable {
public static final QuerySchedulePolicy defaultSchPolicy = QuerySchedulePolicy.ATLEAST_OR_SOONER;
/**
* {@value}
*/
public static final long defaultSchTimeMillis = 1500;
/**
* {@value}
*/
public static final float defaultEventWeight = 1.0f;
/**
* {@value}
*/
public static final int defaultAllowedPendingEvents = Integer.MAX_VALUE;
/**
* {@value}
*/
public static final long defaultForceScheduleMarginMsecs = 250;
/**
* {@value}
*/
public static final long defaultResumeCheckTimeMsecs = 5000;
/**
* {@value}
*/
public static final long defaultStuckJobIntTimeMsecs = 45 * 1000;
// ------------
protected final FilteredTable[] filteredTables;
// ------------
protected volatile QuerySchedulePolicyValue querySchedulePolicy;
protected final Set<String> keys;
protected final FixedKeyHashMap<String, Float> unprocessedEventWeights;
protected final FixedKeyHashMap<String, Integer> allowedPendingEvents;
// ------------
protected transient volatile long queryLastRanAt;
protected transient volatile int queryRunCount;
protected transient volatile int queryErrorCount;
// ------------
protected volatile boolean paused;
protected volatile long forceScheduleMarginMsecs;
protected volatile long resumeCheckTimeMsecs;
protected volatile long stuckJobInterruptionTimeMsecs;
// ------------
protected QueryConfig(FilteredTable[] filteredTables) {
this.filteredTables = filteredTables;
HashSet<String> fqns = new HashSet<String>();
for (FilteredTable table : filteredTables) {
String fqn = table.getSourceTableFQN().getFQN();
fqns.add(fqn);
}
this.keys = Collections.unmodifiableSet(fqns);
querySchedulePolicy = new QuerySchedulePolicyValue(defaultSchPolicy, defaultSchTimeMillis);
unprocessedEventWeights = new FixedKeyHashMap<String, Float>(keys, defaultEventWeight);
allowedPendingEvents = new FixedKeyHashMap<String, Integer>(keys,
defaultAllowedPendingEvents);
resumeCheckTimeMsecs = defaultResumeCheckTimeMsecs;
stuckJobInterruptionTimeMsecs = defaultStuckJobIntTimeMsecs;
}
// ------------
/**
* @return Time in Milliseconds at which this Query ran successfully.
*/
public long getQueryLastRanAt() {
return queryLastRanAt;
}
/**
* @return Number of <b>consecutive</b> Runs that faced errors. Resets to
* zero as soon as a Round succeeds.
*/
public int getQueryErrorCount() {
return queryErrorCount;
}
/**
* @return Number of Runs that were successful.
*/
public int getQueryRunCount() {
return queryRunCount;
}
// ------------
/**
* @return Unmodifiable Set of Keys that are used in Event-weights and
* Pending-events.
*/
public Set<String> getKeys() {
return keys;
}
// ------------
public QuerySchedulePolicyValue getQuerySchedulePolicy() {
return querySchedulePolicy;
}
/**
* Set the Query's scheduling policy. The change will reflect only in the
* next cycle, whenever it is due, based on the current policy value.
*
* @param policyValue
*/
public void setQuerySchedulePolicy(QuerySchedulePolicyValue policyValue) {
if (policyValue != null) {
this.querySchedulePolicy = policyValue;
}
}
// ------------
public float getUnprocessedEventWeight(String key) {
return unprocessedEventWeights.get(key);
}
public Set<String> getUnprocessedEventWeightKeys() {
return unprocessedEventWeights.getKeys();
}
/**
* @param key
* The fully-qualified-name (Ex: "stocks.symbols", "traffic" etc)
* of the Input Stream/Table that supplies Events to this Query
* system.
* @param weight
*/
public void setUnprocessedEventWeight(String key, float weight) {
unprocessedEventWeights.put(key, weight);
}
// ------------
public int getAllowedPendingEvents(String key) {
return allowedPendingEvents.get(key);
}
public Set<String> getAllowedPendingEventsKeys() {
return allowedPendingEvents.getKeys();
}
/**
* @param key
* The fully-qualified-name (Ex: "stocks.symbols", "traffic" etc)
* of the Input-Stream/Table that supplies events to this Query
* system.
* @param events
*/
public void setAllowedPendingEvents(String key, int events) {
allowedPendingEvents.put(key, events);
}
// ------------
public boolean isQueryPaused() {
return paused;
}
public void pauseQuery() {
this.paused = true;
}
public void resumeQuery() {
this.paused = false;
}
// ------------
public long getForceScheduleMarginMsecs() {
return forceScheduleMarginMsecs;
}
/**
* The duration in milliseconds below which a forced schedule will not
* occur, even if the event-weights have crossed <code>1.0</code> if the
* time left before a natural/periodic schedule occurs is less than or equal
* to this margin.
*
* @param forceScheduleMarginMsecs
*/
public void setForceScheduleMarginMsecs(long forceScheduleMarginMsecs) {
this.forceScheduleMarginMsecs = (forceScheduleMarginMsecs <= 0) ? defaultForceScheduleMarginMsecs
: forceScheduleMarginMsecs;
}
// ------------
public long getResumeCheckTimeMsecs() {
return resumeCheckTimeMsecs;
}
/**
* The duration in milliseconds after which the Query wakes up to check if
* it has been resumed. If it has not been resumed, then it goes back to
* sleep.
*
* @param resumeCheckTimeMsecs
*/
public void setResumeCheckTimeMsecs(long resumeCheckTimeMsecs) {
this.resumeCheckTimeMsecs = (resumeCheckTimeMsecs <= 0) ? defaultResumeCheckTimeMsecs
: resumeCheckTimeMsecs;
}
// ------------
public long getStuckJobInterruptionTimeMsecs() {
return stuckJobInterruptionTimeMsecs;
}
/**
* Some parts of the Query processing are multi-threaded. If some Threads do
* not complete, then they will be interrupted. The current cycle of the
* Query will stop but does not affect subsequent runs.
*
* @param stuckJobInterruptionTimeMsecs
*/
public void setStuckJobInterruptionTimeMsecs(long stuckJobInterruptionTimeMsecs) {
this.stuckJobInterruptionTimeMsecs = (stuckJobInterruptionTimeMsecs <= 0) ? defaultStuckJobIntTimeMsecs
: stuckJobInterruptionTimeMsecs;
}
// ------------
public static enum QuerySchedulePolicy {
/**
* Query executes strictly at the specified intervals.
*/
FIXED,
/**
* Query executes at the intervals specified or sooner if the combined
* weight ({@link QueryConfig#getUnprocessedEventWeight(String)}) of
* the unprocessed Events go above 0, or if an Event in a Time-based or
* Latest Rows Window is about to expire.
*/
ATLEAST_OR_SOONER;
}
public static class QuerySchedulePolicyValue implements Serializable {
private static final long serialVersionUID = 1L;
protected final QuerySchedulePolicy policy;
protected final long timeMillis;
public QuerySchedulePolicyValue(QuerySchedulePolicy policy, long timeMillis) {
this.policy = (policy == null) ? defaultSchPolicy : policy;
this.timeMillis = (timeMillis <= 0) ? defaultSchTimeMillis : timeMillis;
}
public QuerySchedulePolicy getPolicy() {
return policy;
}
public long getTimeMillis() {
return timeMillis;
}
}
}