com.espertech.esper.epl.named.NamedWindowTailViewInstance Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esper Show documentation
Show all versions of esper Show documentation
Complex event processing and event series analysis component
The newest version!
/*
***************************************************************************************
* 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.epl.named;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.annotation.AuditEnum;
import com.espertech.esper.client.hook.VirtualDataWindowEventConsumerAdd;
import com.espertech.esper.client.hook.VirtualDataWindowEventConsumerRemove;
import com.espertech.esper.collection.ArrayEventIterator;
import com.espertech.esper.core.context.util.AgentInstanceContext;
import com.espertech.esper.core.context.util.EPStatementAgentInstanceHandle;
import com.espertech.esper.epl.expression.core.ExprNodeUtilityCore;
import com.espertech.esper.epl.expression.core.ExprEvaluatorContext;
import com.espertech.esper.epl.expression.core.ExprNode;
import com.espertech.esper.epl.join.plan.QueryGraph;
import com.espertech.esper.epl.updatehelper.EventBeanUpdateHelper;
import com.espertech.esper.epl.virtualdw.VirtualDWView;
import com.espertech.esper.util.CollectionUtil;
import com.espertech.esper.view.ViewSupport;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* This view is hooked into a named window's view chain as the last view and handles dispatching of named window
* insert and remove stream results via {@link NamedWindowMgmtService} to consuming statements.
*/
public class NamedWindowTailViewInstance extends ViewSupport implements Iterable {
private final NamedWindowRootViewInstance rootViewInstance;
private final NamedWindowTailView tailView;
private final NamedWindowProcessor namedWindowProcessor;
private final AgentInstanceContext agentInstanceContext;
private final NamedWindowConsumerLatchFactory latchFactory;
private volatile Map> consumersInContext; // handles as copy-on-write
private volatile long numberOfEvents;
public NamedWindowTailViewInstance(NamedWindowRootViewInstance rootViewInstance, NamedWindowTailView tailView, NamedWindowProcessor namedWindowProcessor, AgentInstanceContext agentInstanceContext) {
this.rootViewInstance = rootViewInstance;
this.tailView = tailView;
this.namedWindowProcessor = namedWindowProcessor;
this.agentInstanceContext = agentInstanceContext;
this.consumersInContext = NamedWindowUtil.createConsumerMap(tailView.isPrioritized());
this.latchFactory = tailView.makeLatchFactory();
}
public void update(EventBean[] newData, EventBean[] oldData) {
// Only old data (remove stream) needs to be removed from indexes (kept by root view), if any
if (oldData != null) {
rootViewInstance.removeOldData(oldData);
numberOfEvents -= oldData.length;
}
if ((newData != null) && (!tailView.isParentBatchWindow())) {
rootViewInstance.addNewData(newData);
}
if (newData != null) {
numberOfEvents += newData.length;
}
// Post to child views, only if there are listeners or subscribers
if (tailView.getStatementResultService().isMakeNatural() || tailView.getStatementResultService().isMakeSynthetic()) {
updateChildren(newData, oldData);
}
NamedWindowDeltaData delta = new NamedWindowDeltaData(newData, oldData);
tailView.addDispatches(latchFactory, consumersInContext, delta, agentInstanceContext);
}
public NamedWindowConsumerView addConsumer(NamedWindowConsumerDesc consumerDesc, boolean isSubselect) {
NamedWindowConsumerCallback consumerCallback = new NamedWindowConsumerCallback() {
public Iterator getIterator() {
NamedWindowProcessorInstance instance = namedWindowProcessor.getProcessorInstance(agentInstanceContext);
if (instance == null) {
// this can happen on context-partition "output when terminated"
return NamedWindowTailViewInstance.this.iterator();
}
return instance.getTailViewInstance().iterator();
}
public void stopped(NamedWindowConsumerView namedWindowConsumerView) {
removeConsumer(namedWindowConsumerView);
}
};
// Construct consumer view, allow a callback to this view to remove the consumer
boolean audit = AuditEnum.STREAM.getAudit(consumerDesc.getAgentInstanceContext().getStatementContext().getAnnotations()) != null;
NamedWindowConsumerView consumerView = new NamedWindowConsumerView(consumerDesc.getFilterEvaluators(), consumerDesc.getOptPropertyEvaluator(), tailView.getEventType(), consumerCallback, consumerDesc.getAgentInstanceContext(), audit);
// indicate to virtual data window that a consumer was added
VirtualDWView virtualDWView = rootViewInstance.getVirtualDataWindow();
if (virtualDWView != null) {
virtualDWView.getVirtualDataWindow().handleEvent(
new VirtualDataWindowEventConsumerAdd(tailView.getEventType().getName(), consumerView, consumerDesc.getAgentInstanceContext().getStatementName(), consumerDesc.getAgentInstanceContext().getAgentInstanceId(), consumerDesc.getFilterExpressions(), agentInstanceContext));
}
// Keep a list of consumer views per statement to accommodate joins and subqueries
List viewsPerStatements = consumersInContext.get(consumerDesc.getAgentInstanceContext().getEpStatementAgentInstanceHandle());
if (viewsPerStatements == null) {
viewsPerStatements = new CopyOnWriteArrayList();
// avoid concurrent modification as a thread may currently iterate over consumers as its dispatching
// without the engine lock
Map> newConsumers = NamedWindowUtil.createConsumerMap(tailView.isPrioritized());
newConsumers.putAll(consumersInContext);
newConsumers.put(consumerDesc.getAgentInstanceContext().getEpStatementAgentInstanceHandle(), viewsPerStatements);
consumersInContext = newConsumers;
}
if (isSubselect) {
viewsPerStatements.add(0, consumerView);
} else {
viewsPerStatements.add(consumerView);
}
return consumerView;
}
/**
* Called by the consumer view to indicate it was stopped or destroyed, such that the
* consumer can be deregistered and further dispatches disregard this consumer.
*
* @param namedWindowConsumerView is the consumer representative view
*/
public void removeConsumer(NamedWindowConsumerView namedWindowConsumerView) {
EPStatementAgentInstanceHandle handleRemoved = null;
// Find the consumer view
for (Map.Entry> entry : consumersInContext.entrySet()) {
boolean foundAndRemoved = entry.getValue().remove(namedWindowConsumerView);
// Remove the consumer view
if (foundAndRemoved && (entry.getValue().size() == 0)) {
// Remove the handle if this list is now empty
handleRemoved = entry.getKey();
break;
}
}
if (handleRemoved != null) {
Map> newConsumers = NamedWindowUtil.createConsumerMap(tailView.isPrioritized());
newConsumers.putAll(consumersInContext);
newConsumers.remove(handleRemoved);
consumersInContext = newConsumers;
}
// indicate to virtual data window that a consumer was added
VirtualDWView virtualDWView = rootViewInstance.getVirtualDataWindow();
if (virtualDWView != null && handleRemoved != null) {
virtualDWView.getVirtualDataWindow().handleEvent(new VirtualDataWindowEventConsumerRemove(tailView.getEventType().getName(), namedWindowConsumerView, handleRemoved.getStatementHandle().getStatementName(), handleRemoved.getAgentInstanceId()));
}
}
public EventType getEventType() {
return tailView.getEventType();
}
public Iterator iterator() {
if (tailView.getRevisionProcessor() != null) {
Collection coll = tailView.getRevisionProcessor().getSnapshot(agentInstanceContext.getEpStatementAgentInstanceHandle(), parent);
return coll.iterator();
}
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().acquireReadLock();
try {
Iterator it = parent.iterator();
if (!it.hasNext()) {
return CollectionUtil.NULL_EVENT_ITERATOR;
}
ArrayList list = new ArrayList();
while (it.hasNext()) {
list.add(it.next());
}
return new ArrayEventIterator(list.toArray(new EventBean[list.size()]));
} finally {
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().releaseReadLock();
}
}
/**
* Returns a snapshot of window contents, thread-safely
*
* @param queryGraph query graph
* @param annotations annotations
* @return window contents
*/
public Collection snapshot(QueryGraph queryGraph, Annotation[] annotations) {
if (tailView.getRevisionProcessor() != null) {
return tailView.getRevisionProcessor().getSnapshot(agentInstanceContext.getEpStatementAgentInstanceHandle(), parent);
}
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().acquireReadLock();
try {
return snapshotNoLock(queryGraph, annotations);
} finally {
releaseTableLocks(agentInstanceContext);
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().releaseReadLock();
}
}
public EventBean[] snapshotUpdate(QueryGraph queryGraph, ExprNode optionalWhereClause, EventBeanUpdateHelper updateHelper, Annotation[] annotations) {
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().acquireReadLock();
try {
Collection events = snapshotNoLockWithFilter(queryGraph, annotations, optionalWhereClause, agentInstanceContext);
if (events.isEmpty()) {
return CollectionUtil.EVENTBEANARRAY_EMPTY;
}
EventBean[] eventsPerStream = new EventBean[3];
EventBean[] updated = new EventBean[events.size()];
int count = 0;
for (EventBean event : events) {
updated[count++] = updateHelper.updateWCopy(event, eventsPerStream, agentInstanceContext);
}
EventBean[] deleted = events.toArray(new EventBean[events.size()]);
rootViewInstance.update(updated, deleted);
return updated;
} finally {
releaseTableLocks(agentInstanceContext);
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().releaseReadLock();
}
}
public EventBean[] snapshotDelete(QueryGraph queryGraph, ExprNode filterExpr, Annotation[] annotations) {
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().acquireReadLock();
try {
Collection events = snapshotNoLockWithFilter(queryGraph, annotations, filterExpr, agentInstanceContext);
if (events.isEmpty()) {
return CollectionUtil.EVENTBEANARRAY_EMPTY;
}
EventBean[] eventsDeleted = events.toArray(new EventBean[events.size()]);
rootViewInstance.update(null, eventsDeleted);
return eventsDeleted;
} finally {
releaseTableLocks(agentInstanceContext);
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock().releaseReadLock();
}
}
public Collection snapshotNoLock(QueryGraph queryGraph, Annotation[] annotations) {
if (tailView.getRevisionProcessor() != null) {
return tailView.getRevisionProcessor().getSnapshot(agentInstanceContext.getEpStatementAgentInstanceHandle(), parent);
}
Collection indexedResult = rootViewInstance.snapshot(queryGraph, annotations);
if (indexedResult != null) {
return indexedResult;
}
Iterator it = parent.iterator();
if (!it.hasNext()) {
return Collections.EMPTY_LIST;
}
ArrayDeque list = new ArrayDeque();
while (it.hasNext()) {
list.add(it.next());
}
return list;
}
public Collection snapshotNoLockWithFilter(QueryGraph queryGraph, Annotation[] annotations, ExprNode filterExpr, ExprEvaluatorContext exprEvaluatorContext) {
if (tailView.getRevisionProcessor() != null) {
return tailView.getRevisionProcessor().getSnapshot(agentInstanceContext.getEpStatementAgentInstanceHandle(), parent);
}
Collection indexedResult = rootViewInstance.snapshot(queryGraph, annotations);
if (indexedResult != null) {
if (indexedResult.isEmpty()) {
return indexedResult;
}
if (filterExpr == null) {
return indexedResult;
}
ArrayDeque deque = new ArrayDeque(Math.min(indexedResult.size(), 16));
ExprNodeUtilityCore.applyFilterExpressionIterable(indexedResult.iterator(), filterExpr.getForge().getExprEvaluator(), exprEvaluatorContext, deque);
return deque;
}
// fall back to window operator if snapshot doesn't resolve successfully
Iterator it = parent.iterator();
if (!it.hasNext()) {
return Collections.EMPTY_LIST;
}
ArrayDeque list = new ArrayDeque();
if (filterExpr != null) {
ExprNodeUtilityCore.applyFilterExpressionIterable(it, filterExpr.getForge().getExprEvaluator(), agentInstanceContext, list);
} else {
while (it.hasNext()) {
list.add(it.next());
}
}
return list;
}
public AgentInstanceContext getAgentInstanceContext() {
return agentInstanceContext;
}
/**
* Destroy the view.
*/
public void destroy() {
consumersInContext = NamedWindowUtil.createConsumerMap(tailView.isPrioritized());
}
/**
* Returns the number of events held.
*
* @return number of events
*/
public long getNumberOfEvents() {
return numberOfEvents;
}
public NamedWindowTailView getTailView() {
return tailView;
}
private void releaseTableLocks(AgentInstanceContext agentInstanceContext) {
agentInstanceContext.getStatementContext().getTableExprEvaluatorContext().releaseAcquiredLocks();
}
public void stop() {
// no action
}
}