/* *************************************************************************************** * 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.core.context.factory.StatementAgentInstancePostLoadIndexVisitor; import com.espertech.esper.core.context.util.AgentInstanceContext; import com.espertech.esper.epl.expression.core.ExprValidationException; import com.espertech.esper.epl.fafquery.FireAndForgetQueryExec; import com.espertech.esper.epl.join.plan.QueryGraph; import com.espertech.esper.epl.join.plan.QueryPlanIndexItem; import com.espertech.esper.epl.join.table.EventTable; import com.espertech.esper.epl.join.table.EventTableUtil; import com.espertech.esper.epl.lookup.*; import com.espertech.esper.epl.virtualdw.VirtualDWView; import com.espertech.esper.util.CollectionUtil; import com.espertech.esper.view.ViewSupport; import com.espertech.esper.view.Viewable; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * The root window in a named window plays multiple roles: It holds the indexes for deleting rows, if any on-delete statement * requires such indexes. Such indexes are updated when events arrive, or remove from when a data window * or on-delete statement expires events. The view keeps track of on-delete statements their indexes used. */ public class NamedWindowRootViewInstance extends ViewSupport { private final NamedWindowRootView rootView; private final AgentInstanceContext agentInstanceContext; private final EventTableIndexRepository indexRepository; private final Map<SubordWMatchExprLookupStrategy, EventTable[]> tablePerMultiLookup; private Iterable<EventBean> dataWindowContents; public NamedWindowRootViewInstance(NamedWindowRootView rootView, AgentInstanceContext agentInstanceContext, EventTableIndexMetadata eventTableIndexMetadata) { this.rootView = rootView; this.agentInstanceContext = agentInstanceContext; this.indexRepository = new EventTableIndexRepository(eventTableIndexMetadata); for (Map.Entry<IndexMultiKey, EventTableIndexMetadataEntry> entry : eventTableIndexMetadata.getIndexes().entrySet()) { if (entry.getValue().getQueryPlanIndexItem() != null) { EventTable index = EventTableUtil.buildIndex(agentInstanceContext, 0, entry.getValue().getQueryPlanIndexItem(), rootView.getEventType(), true, entry.getKey().isUnique(), entry.getValue().getOptionalIndexName(), null, false); indexRepository.addIndex(entry.getKey(), new EventTableIndexRepositoryEntry(entry.getValue().getOptionalIndexName(), index)); } } this.tablePerMultiLookup = new HashMap<SubordWMatchExprLookupStrategy, EventTable[]>(); } public AgentInstanceContext getAgentInstanceContext() { return agentInstanceContext; } public EventTableIndexRepository getIndexRepository() { return indexRepository; } public IndexMultiKey[] getIndexes() { return indexRepository.getIndexDescriptors(); } public Iterable<EventBean> getDataWindowContents() { return dataWindowContents; } /** * Sets the iterator to use to obtain current named window data window contents. * * @param dataWindowContents iterator over events help by named window */ public void setDataWindowContents(Iterable<EventBean> dataWindowContents) { this.dataWindowContents = dataWindowContents; } /** * Called by tail view to indicate that the data window view exired events that must be removed from index tables. * * @param oldData removed stream of the data window */ public void removeOldData(EventBean[] oldData) { if (rootView.getRevisionProcessor() != null) { rootView.getRevisionProcessor().removeOldData(oldData, indexRepository, agentInstanceContext); } else { for (EventTable table : indexRepository.getTables()) { table.remove(oldData, agentInstanceContext); } } } /** * Called by tail view to indicate that the data window view has new events that must be added to index tables. * * @param newData new event */ public void addNewData(EventBean[] newData) { if (rootView.getRevisionProcessor() == null) { // Update indexes for fast deletion, if there are any for (EventTable table : indexRepository.getTables()) { table.add(newData, agentInstanceContext); } } } // Called by deletion strategy and also the insert-into for new events only public void update(EventBean[] newData, EventBean[] oldData) { if (rootView.getRevisionProcessor() != null) { rootView.getRevisionProcessor().onUpdate(newData, oldData, this, indexRepository); } else { // Update indexes for fast deletion, if there are any for (EventTable table : indexRepository.getTables()) { if (rootView.isChildBatching()) { table.add(newData, agentInstanceContext); } } // Update child views updateChildren(newData, oldData); } } public void setParent(Viewable parent) { super.setParent(parent); } public EventType getEventType() { return rootView.getEventType(); } public Iterator<EventBean> iterator() { return null; } /** * Destroy and clear resources. */ public void destroy() { indexRepository.destroy(); tablePerMultiLookup.clear(); if (isVirtualDataWindow()) { getVirtualDataWindow().handleStopWindow(); } } /** * Return a snapshot using index lookup filters. * * @param annotations annotations * @param queryGraph query graph * @return events */ public Collection<EventBean> snapshot(QueryGraph queryGraph, Annotation[] annotations) { VirtualDWView virtualDataWindow = null; if (isVirtualDataWindow()) { virtualDataWindow = getVirtualDataWindow(); } return FireAndForgetQueryExec.snapshot(queryGraph, annotations, virtualDataWindow, indexRepository, rootView.isQueryPlanLogging(), NamedWindowRootView.getQueryPlanLog(), rootView.getEventType().getName(), agentInstanceContext); } /** * Add an explicit index. * * @param explicitIndexDesc index descriptor * @param isRecoveringResilient indicator for recovering * @param explicitIndexName index name * @throws com.espertech.esper.epl.expression.core.ExprValidationException if the index fails to be valid */ public synchronized void addExplicitIndex(String explicitIndexName, QueryPlanIndexItem explicitIndexDesc, boolean isRecoveringResilient) throws ExprValidationException { boolean initIndex = agentInstanceContext.getStatementContext().getEventTableIndexService().allowInitIndex(isRecoveringResilient); Iterable<EventBean> initializeFrom = initIndex ? this.dataWindowContents : CollectionUtil.NULL_EVENT_ITERABLE; indexRepository.validateAddExplicitIndex(explicitIndexName, explicitIndexDesc, rootView.getEventType(), initializeFrom, agentInstanceContext, isRecoveringResilient, null); } public boolean isVirtualDataWindow() { return this.getViews()[0] instanceof VirtualDWView; } public VirtualDWView getVirtualDataWindow() { if (!isVirtualDataWindow()) { return null; } return (VirtualDWView) this.getViews()[0]; } public void postLoad() { EventBean[] events = new EventBean[1]; for (EventBean event : dataWindowContents) { events[0] = event; for (EventTable table : indexRepository.getTables()) { table.add(events, agentInstanceContext); } } } public void visitIndexes(StatementAgentInstancePostLoadIndexVisitor visitor) { visitor.visit(indexRepository.getTables()); } public boolean isQueryPlanLogging() { return rootView.isQueryPlanLogging(); } public void stop() { if (isVirtualDataWindow()) { getVirtualDataWindow().handleStopWindow(); } } }