/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.core.context.subselect;
import com.espertech.esper.client.EPException;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.collection.Pair;
import com.espertech.esper.core.context.factory.StatementAgentInstancePostLoad;
import com.espertech.esper.core.context.factory.StatementAgentInstancePostLoadIndexVisitor;
import com.espertech.esper.core.context.util.AgentInstanceContext;
import com.espertech.esper.core.context.util.AgentInstanceViewFactoryChainContext;
import com.espertech.esper.core.service.EPServicesContext;
import com.espertech.esper.core.start.EPStatementStartMethodHelperPrevious;
import com.espertech.esper.core.start.EPStatementStartMethodHelperPrior;
import com.espertech.esper.epl.agg.service.AggregationService;
import com.espertech.esper.epl.agg.service.AggregationServiceFactoryDesc;
import com.espertech.esper.epl.core.StreamTypeServiceImpl;
import com.espertech.esper.epl.core.ViewResourceDelegateVerified;
import com.espertech.esper.epl.expression.core.ExprEvaluator;
import com.espertech.esper.epl.expression.core.ExprNode;
import com.espertech.esper.epl.expression.core.ExprNodeUtility;
import com.espertech.esper.epl.expression.prev.ExprPreviousEvalStrategy;
import com.espertech.esper.epl.expression.prev.ExprPreviousNode;
import com.espertech.esper.epl.expression.prior.ExprPriorEvalStrategy;
import com.espertech.esper.epl.expression.prior.ExprPriorNode;
import com.espertech.esper.epl.join.plan.QueryGraph;
import com.espertech.esper.epl.join.table.EventTable;
import com.espertech.esper.epl.join.table.EventTableFactory;
import com.espertech.esper.epl.join.table.EventTableFactoryTableIdentAgentInstanceSubq;
import com.espertech.esper.epl.lookup.SubordTableLookupStrategy;
import com.espertech.esper.epl.lookup.SubordTableLookupStrategyFactory;
import com.espertech.esper.epl.lookup.SubordTableLookupStrategyNullRow;
import com.espertech.esper.epl.named.NamedWindowProcessor;
import com.espertech.esper.epl.named.NamedWindowProcessorInstance;
import com.espertech.esper.epl.named.NamedWindowTailViewInstance;
import com.espertech.esper.epl.spec.NamedWindowConsumerStreamSpec;
import com.espertech.esper.epl.subquery.*;
import com.espertech.esper.util.StopCallback;
import com.espertech.esper.view.View;
import com.espertech.esper.view.ViewFactory;
import com.espertech.esper.view.ViewServiceCreateResult;
import com.espertech.esper.view.Viewable;
import com.espertech.esper.view.internal.BufferView;
import com.espertech.esper.view.internal.PriorEventViewFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* Entry holding lookup resource references for use by {@link SubSelectActivationCollection}.
*/
public class SubSelectStrategyFactoryLocalViewPreloaded implements SubSelectStrategyFactory {
private static Logger log = LoggerFactory.getLogger(SubSelectStrategyFactoryLocalViewPreloaded.class);
private final static SubordTableLookupStrategyNullRow NULL_ROW_STRATEGY = new SubordTableLookupStrategyNullRow();
private final int subqueryNumber;
private final SubSelectActivationHolder subSelectHolder;
private final Pair<EventTableFactory, SubordTableLookupStrategyFactory> pair;
private final ExprNode filterExprNode;
private final ExprEvaluator filterExprEval;
private final boolean correlatedSubquery;
private final AggregationServiceFactoryDesc aggregationServiceFactory;
private final ViewResourceDelegateVerified viewResourceDelegate;
private final ExprEvaluator[] groupKeys;
public SubSelectStrategyFactoryLocalViewPreloaded(int subqueryNumber, SubSelectActivationHolder subSelectHolder, Pair<EventTableFactory, SubordTableLookupStrategyFactory> pair, ExprNode filterExprNode, ExprEvaluator filterExprEval, boolean correlatedSubquery, AggregationServiceFactoryDesc aggregationServiceFactory, ViewResourceDelegateVerified viewResourceDelegate, ExprEvaluator[] groupKeys) {
this.subqueryNumber = subqueryNumber;
this.subSelectHolder = subSelectHolder;
this.pair = pair;
this.filterExprNode = filterExprNode;
this.filterExprEval = filterExprEval;
this.correlatedSubquery = correlatedSubquery;
this.aggregationServiceFactory = aggregationServiceFactory;
this.viewResourceDelegate = viewResourceDelegate;
this.groupKeys = groupKeys;
}
public SubSelectStrategyRealization instantiate(final EPServicesContext services,
Viewable viewableRoot,
final AgentInstanceContext agentInstanceContext,
List<StopCallback> stopCallbackList,
int subqueryNumber, boolean isRecoveringResilient) {
List<ViewFactory> viewFactoryChain = subSelectHolder.getViewFactoryChain().getViewFactoryChain();
// add "prior" view factory
boolean hasPrior = viewResourceDelegate.getPerStream()[0].getPriorRequests() != null && !viewResourceDelegate.getPerStream()[0].getPriorRequests().isEmpty();
if (hasPrior) {
PriorEventViewFactory priorEventViewFactory = EPStatementStartMethodHelperPrior.getPriorEventViewFactory(agentInstanceContext.getStatementContext(), 1024 + this.subqueryNumber, viewFactoryChain.isEmpty(), true, subqueryNumber);
viewFactoryChain = new ArrayList<ViewFactory>(viewFactoryChain);
viewFactoryChain.add(priorEventViewFactory);
}
// create factory chain context to hold callbacks specific to "prior" and "prev"
AgentInstanceViewFactoryChainContext viewFactoryChainContext = AgentInstanceViewFactoryChainContext.create(viewFactoryChain, agentInstanceContext, viewResourceDelegate.getPerStream()[0]);
// make view
ViewServiceCreateResult createResult = services.getViewService().createViews(viewableRoot, viewFactoryChain, viewFactoryChainContext, false);
final Viewable subselectView = createResult.getFinalViewable();
// make aggregation service
AggregationService aggregationService = null;
if (aggregationServiceFactory != null) {
aggregationService = aggregationServiceFactory.getAggregationServiceFactory().makeService(agentInstanceContext, agentInstanceContext.getStatementContext().getEngineImportService(), true, subqueryNumber);
}
// handle "prior" nodes and their strategies
Map<ExprPriorNode, ExprPriorEvalStrategy> priorNodeStrategies = EPStatementStartMethodHelperPrior.compilePriorNodeStrategies(viewResourceDelegate, new AgentInstanceViewFactoryChainContext[]{viewFactoryChainContext});
// handle "previous" nodes and their strategies
Map<ExprPreviousNode, ExprPreviousEvalStrategy> previousNodeStrategies = EPStatementStartMethodHelperPrevious.compilePreviousNodeStrategies(viewResourceDelegate, new AgentInstanceViewFactoryChainContext[]{viewFactoryChainContext});
// handle aggregated and non-correlated queries: there is no strategy or index
if (aggregationServiceFactory != null && !correlatedSubquery) {
View aggregatorView;
if (groupKeys == null) {
if (filterExprEval == null) {
aggregatorView = new SubselectAggregatorViewUnfilteredUngrouped(aggregationService, filterExprEval, agentInstanceContext, null);
} else {
aggregatorView = new SubselectAggregatorViewFilteredUngrouped(aggregationService, filterExprEval, agentInstanceContext, null, filterExprNode);
}
} else {
if (filterExprEval == null) {
aggregatorView = new SubselectAggregatorViewUnfilteredGrouped(aggregationService, filterExprEval, agentInstanceContext, groupKeys);
} else {
aggregatorView = new SubselectAggregatorViewFilteredGrouped(aggregationService, filterExprEval, agentInstanceContext, groupKeys, filterExprNode);
}
}
subselectView.addView(aggregatorView);
if (services.getEventTableIndexService().allowInitIndex(isRecoveringResilient)) {
preload(services, null, aggregatorView, agentInstanceContext);
}
return new SubSelectStrategyRealization(NULL_ROW_STRATEGY, null, aggregationService, priorNodeStrategies, previousNodeStrategies, subselectView, null);
}
// create index/holder table
final EventTable[] index = pair.getFirst().makeEventTables(new EventTableFactoryTableIdentAgentInstanceSubq(agentInstanceContext, this.subqueryNumber), agentInstanceContext);
stopCallbackList.add(new SubqueryStopCallback(index));
// create strategy
SubordTableLookupStrategy strategy = pair.getSecond().makeStrategy(index, null);
SubselectAggregationPreprocessorBase subselectAggregationPreprocessor = null;
// handle unaggregated or correlated queries or
if (aggregationServiceFactory != null) {
if (groupKeys == null) {
if (filterExprEval == null) {
subselectAggregationPreprocessor = new SubselectAggregationPreprocessorUnfilteredUngrouped(aggregationService, filterExprEval, null);
} else {
subselectAggregationPreprocessor = new SubselectAggregationPreprocessorFilteredUngrouped(aggregationService, filterExprEval, null);
}
} else {
if (filterExprEval == null) {
subselectAggregationPreprocessor = new SubselectAggregationPreprocessorUnfilteredGrouped(aggregationService, filterExprEval, groupKeys);
} else {
subselectAggregationPreprocessor = new SubselectAggregationPreprocessorFilteredGrouped(aggregationService, filterExprEval, groupKeys);
}
}
}
// preload when allowed
StatementAgentInstancePostLoad postLoad;
if (services.getEventTableIndexService().allowInitIndex(isRecoveringResilient)) {
preload(services, index, subselectView, agentInstanceContext);
postLoad = new StatementAgentInstancePostLoad() {
public void executePostLoad() {
preload(services, index, subselectView, agentInstanceContext);
}
public void acceptIndexVisitor(StatementAgentInstancePostLoadIndexVisitor visitor) {
for (EventTable table : index) {
visitor.visit(table);
}
}
};
} else {
postLoad = new StatementAgentInstancePostLoad() {
public void executePostLoad() {
// no post-load
}
public void acceptIndexVisitor(StatementAgentInstancePostLoadIndexVisitor visitor) {
for (EventTable table : index) {
visitor.visit(table);
}
}
};
}
BufferView bufferView = new BufferView(subSelectHolder.getStreamNumber());
bufferView.setObserver(new SubselectBufferObserver(index, agentInstanceContext));
subselectView.addView(bufferView);
return new SubSelectStrategyRealization(strategy, subselectAggregationPreprocessor, aggregationService, priorNodeStrategies, previousNodeStrategies, subselectView, postLoad);
}
private void preload(EPServicesContext services, EventTable[] eventIndex, Viewable subselectView, AgentInstanceContext agentInstanceContext) {
if (subSelectHolder.getStreamSpecCompiled() instanceof NamedWindowConsumerStreamSpec) {
NamedWindowConsumerStreamSpec namedSpec = (NamedWindowConsumerStreamSpec) subSelectHolder.getStreamSpecCompiled();
NamedWindowProcessor processor = services.getNamedWindowMgmtService().getProcessor(namedSpec.getWindowName());
if (processor == null) {
throw new RuntimeException("Failed to find named window by name '" + namedSpec.getWindowName() + "'");
}
NamedWindowProcessorInstance processorInstance = processor.getProcessorInstance(agentInstanceContext);
if (processorInstance == null) {
throw new EPException("Named window '" + namedSpec.getWindowName() + "' is associated to context '" + processor.getContextName() + "' that is not available for querying");
}
NamedWindowTailViewInstance consumerView = processorInstance.getTailViewInstance();
// preload view for stream
Collection<EventBean> eventsInWindow;
if (namedSpec.getFilterExpressions() != null && !namedSpec.getFilterExpressions().isEmpty()) {
StreamTypeServiceImpl types = new StreamTypeServiceImpl(consumerView.getEventType(), consumerView.getEventType().getName(), false, services.getEngineURI());
QueryGraph queryGraph = ExprNodeUtility.validateFilterGetQueryGraphSafe(ExprNodeUtility.connectExpressionsByLogicalAndWhenNeeded(namedSpec.getFilterExpressions()), agentInstanceContext.getStatementContext(), types);
Collection<EventBean> snapshot = consumerView.snapshotNoLock(queryGraph, agentInstanceContext.getStatementContext().getAnnotations());
eventsInWindow = new ArrayList<EventBean>(snapshot.size());
ExprNodeUtility.applyFilterExpressionsIterable(snapshot, namedSpec.getFilterExpressions(), agentInstanceContext, eventsInWindow);
} else {
eventsInWindow = new ArrayList<EventBean>();
for (Iterator<EventBean> it = consumerView.iterator(); it.hasNext(); ) {
eventsInWindow.add(it.next());
}
}
EventBean[] newEvents = eventsInWindow.toArray(new EventBean[eventsInWindow.size()]);
if (subselectView != null) {
((com.espertech.esper.view.View) subselectView).update(newEvents, null);
}
if (eventIndex != null) {
for (EventTable table : eventIndex) {
table.add(newEvents, agentInstanceContext); // fill index
}
}
} else {
// preload from the data window that sit on top
// Start up event table from the iterator
Iterator<EventBean> it = subselectView.iterator();
if ((it != null) && (it.hasNext())) {
ArrayList<EventBean> preloadEvents = new ArrayList<EventBean>();
for (; it.hasNext(); ) {
preloadEvents.add(it.next());
}
if (eventIndex != null) {
for (EventTable table : eventIndex) {
table.add(preloadEvents.toArray(new EventBean[preloadEvents.size()]), agentInstanceContext);
}
}
}
}
}
}