Package com.espertech.esper.epl.core

Source Code of com.espertech.esper.epl.core.ResultSetProcessorRowPerGroupRollup$EventArrayAndSortKeyArray

/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
* http://esper.codehaus.org                                                          *
* 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.core;

import com.espertech.esper.client.EPException;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.scopetest.EPAssertionUtil;
import com.espertech.esper.collection.ArrayEventIterator;
import com.espertech.esper.collection.MultiKey;
import com.espertech.esper.collection.MultiKeyUntyped;
import com.espertech.esper.collection.UniformPair;
import com.espertech.esper.core.context.util.AgentInstanceContext;
import com.espertech.esper.epl.agg.service.AggregationRowRemovedCallback;
import com.espertech.esper.epl.agg.service.AggregationService;
import com.espertech.esper.epl.agg.service.AggregationGroupByRollupLevel;
import com.espertech.esper.epl.agg.rollup.GroupByRollupKey;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.expression.ExprValidationException;
import com.espertech.esper.epl.spec.OutputLimitLimitType;
import com.espertech.esper.epl.view.OutputConditionPolled;
import com.espertech.esper.epl.view.OutputConditionPolledFactory;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import com.espertech.esper.view.Viewable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;

public class ResultSetProcessorRowPerGroupRollup implements ResultSetProcessor, AggregationRowRemovedCallback {

    private static final Log log = LogFactory.getLog(ResultSetProcessorRowPerGroupRollup.class);

    protected final ResultSetProcessorRowPerGroupRollupFactory prototype;
    protected final OrderByProcessor orderByProcessor;
    protected final AggregationService aggregationService;
    protected AgentInstanceContext agentInstanceContext;

    // For output rate limiting, as temporary buffer of to keep a representative event for each group
    private final Map<Object, EventBean[]>[] outputLimitGroupRepsPerLevel;

    private final Map<Object, OutputConditionPolled>[] outputState;

    protected final Map<Object, EventBean>[] eventPerGroupBuf;
    private final Map<Object, EventBean[]>[] eventPerGroupJoinBuf;

    private final EventArrayAndSortKeyArray rstreamEventSortArrayPair;

    public ResultSetProcessorRowPerGroupRollup(ResultSetProcessorRowPerGroupRollupFactory prototype, OrderByProcessor orderByProcessor, AggregationService aggregationService, AgentInstanceContext agentInstanceContext) {
        this.prototype = prototype;
        this.orderByProcessor = orderByProcessor;
        this.aggregationService = aggregationService;
        this.agentInstanceContext = agentInstanceContext;
        aggregationService.setRemovedCallback(this);

        int levelCount = prototype.getGroupByRollupDesc().getLevels().length;

        if (prototype.isJoin()) {
            eventPerGroupJoinBuf = (LinkedHashMap<Object, EventBean[]>[]) new LinkedHashMap[levelCount];
            for (int i = 0; i < levelCount; i++) {
                eventPerGroupJoinBuf[i] = new LinkedHashMap<Object, EventBean[]>();
            }
            eventPerGroupBuf = null;
        }
        else {
            eventPerGroupBuf = (LinkedHashMap<Object, EventBean>[]) new LinkedHashMap[levelCount];
            for (int i = 0; i < levelCount; i++) {
                eventPerGroupBuf[i] = new LinkedHashMap<Object, EventBean>();
            }
            eventPerGroupJoinBuf = null;
        }

        if (prototype.getOutputLimitSpec() != null) {
            outputLimitGroupRepsPerLevel = (LinkedHashMap<Object, EventBean[]>[]) new LinkedHashMap[levelCount];
            for (int i = 0; i < levelCount; i++) {
                outputLimitGroupRepsPerLevel[i] = new LinkedHashMap<Object, EventBean[]>();
            }
        }
        else {
            outputLimitGroupRepsPerLevel = null;
        }

        // Allocate output state for output-first
        if (prototype.getOutputLimitSpec() != null && prototype.getOutputLimitSpec().getDisplayLimit() == OutputLimitLimitType.FIRST) {
            outputState = (Map<Object, OutputConditionPolled>[]) new Map[levelCount];
            for (int i = 0; i < levelCount; i++) {
                outputState[i] = new HashMap<Object, OutputConditionPolled>();
            }
        }
        else {
            outputState = null;
        }

        if (prototype.getOutputLimitSpec() != null && (prototype.isSelectRStream() || prototype.getOutputLimitSpec().getDisplayLimit() == OutputLimitLimitType.FIRST)) {
            List<EventBean>[] eventsPerLevel = (List<EventBean>[]) new List[prototype.getGroupByRollupDesc().getLevels().length];
            List<Object>[] sortKeyPerLevel = null;
            if (orderByProcessor != null) {
                sortKeyPerLevel = (List<Object>[]) new List[prototype.getGroupByRollupDesc().getLevels().length];
            }
            for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                eventsPerLevel[level.getLevelNumber()] = new ArrayList<EventBean>();
                if (orderByProcessor != null) {
                    sortKeyPerLevel[level.getLevelNumber()] = new ArrayList<Object>();
                }
            }
            rstreamEventSortArrayPair = new EventArrayAndSortKeyArray(eventsPerLevel, sortKeyPerLevel);
        }
        else {
            rstreamEventSortArrayPair = null;
        }
    }

    public void setAgentInstanceContext(AgentInstanceContext agentInstanceContext) {
        this.agentInstanceContext = agentInstanceContext;
    }

    public EventType getResultEventType()
    {
        return prototype.getResultEventType();
    }

    public UniformPair<EventBean[]> processJoinResult(Set<MultiKey<EventBean>> newEvents, Set<MultiKey<EventBean>> oldEvents, boolean isSynthesize)
    {
        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qResultSetProcessGroupedRowPerGroup();}

        if (prototype.isUnidirectional()) {
            this.clear();
        }

        resetEventPerGroupJoinBuf();
        Object[][] newDataMultiKey = generateGroupKeysJoin(newEvents, eventPerGroupJoinBuf, true);
        Object[][] oldDataMultiKey = generateGroupKeysJoin(oldEvents, eventPerGroupJoinBuf, false);

        EventBean[] selectOldEvents = null;
        if (prototype.isSelectRStream()) {
            selectOldEvents = generateOutputEventsJoin(eventPerGroupJoinBuf, false, isSynthesize);
        }

        // update aggregates
        if (newEvents != null) {
            int count = 0;
            for (MultiKey<EventBean> mk : newEvents) {
                aggregationService.applyEnter(mk.getArray(), newDataMultiKey[count++], agentInstanceContext);
            }
        }
        if (oldEvents != null) {
            int count = 0;
            for (MultiKey<EventBean> mk : oldEvents) {
                aggregationService.applyLeave(mk.getArray(), oldDataMultiKey[count++], agentInstanceContext);
            }
        }

        // generate new events using select expressions
        EventBean[] selectNewEvents = generateOutputEventsJoin(eventPerGroupJoinBuf, true, isSynthesize);

        if ((selectNewEvents != null) || (selectOldEvents != null)) {
            if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aResultSetProcessGroupedRowPerGroup(selectNewEvents, selectOldEvents);}
            return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents);
        }
        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aResultSetProcessGroupedRowPerGroup(null, null);}
        return null;
    }

    public UniformPair<EventBean[]> processViewResult(EventBean[] newData, EventBean[] oldData, boolean isSynthesize)
    {
        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qResultSetProcessGroupedRowPerGroup();}

        resetEventPerGroupBuf();
        Object[][] newDataMultiKey = generateGroupKeysView(newData, eventPerGroupBuf, true);
        Object[][] oldDataMultiKey = generateGroupKeysView(oldData, eventPerGroupBuf, false);

        EventBean[] selectOldEvents = null;
        if (prototype.isSelectRStream()) {
            selectOldEvents = generateOutputEventsView(eventPerGroupBuf, false, isSynthesize);
        }

        // update aggregates
        EventBean[] eventsPerStream = new EventBean[1];
        if (newData != null) {
            for (int i = 0; i < newData.length; i++) {
                eventsPerStream[0] = newData[i];
                aggregationService.applyEnter(eventsPerStream, newDataMultiKey[i], agentInstanceContext);
            }
        }
        if (oldData != null) {
            for (int i = 0; i < oldData.length; i++) {
                eventsPerStream[0] = oldData[i];
                aggregationService.applyLeave(eventsPerStream, oldDataMultiKey[i], agentInstanceContext);
            }
        }

        // generate new events using select expressions
        EventBean[] selectNewEvents = generateOutputEventsView(eventPerGroupBuf, true, isSynthesize);

        if ((selectNewEvents != null) || (selectOldEvents != null)) {
            if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aResultSetProcessGroupedRowPerGroup(selectNewEvents, selectOldEvents);}
            return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents);
        }
        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aResultSetProcessGroupedRowPerGroup(null, null);}
        return null;
    }

    protected EventBean[] generateOutputEventsView(Map<Object, EventBean>[] keysAndEvents, boolean isNewData, boolean isSynthesize)
    {
        EventBean[] eventsPerStream = new EventBean[1];
        ArrayList<EventBean> events = new ArrayList<EventBean>(1);
        List<GroupByRollupKey> currentGenerators = null;
        if(prototype.isSorting()) {
            currentGenerators = new ArrayList<GroupByRollupKey>(4);
        }

        AggregationGroupByRollupLevel[] levels = prototype.getGroupByRollupDesc().getLevels();
        SelectExprProcessor[] selectExprProcessors = prototype.getPerLevelExpression().getSelectExprProcessor();
        ExprEvaluator[] optionalHavingClauses = prototype.getPerLevelExpression().getOptionalHavingNodes();
        for (AggregationGroupByRollupLevel level : levels) {
            for (Map.Entry<Object, EventBean> entry : keysAndEvents[level.getLevelNumber()].entrySet()) {
                Object groupKey = entry.getKey();

                // Set the current row of aggregation states
                aggregationService.setCurrentAccess(groupKey, agentInstanceContext.getAgentInstanceId(), level);
                eventsPerStream[0] = entry.getValue();

                // Filter the having clause
                if (optionalHavingClauses != null)
                {
                    if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qHavingClauseNonJoin(entry.getValue());}
                    Boolean result = (Boolean) optionalHavingClauses[level.getLevelNumber()].evaluate(eventsPerStream, isNewData, agentInstanceContext);
                    if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aHavingClauseNonJoin(result);}
                    if ((result == null) || (!result)) {
                        continue;
                    }
                }
                events.add(selectExprProcessors[level.getLevelNumber()].process(eventsPerStream, isNewData, isSynthesize, agentInstanceContext));

                if(prototype.isSorting()) {
                    EventBean[] currentEventsPerStream = new EventBean[] { entry.getValue() };
                    currentGenerators.add(new GroupByRollupKey(currentEventsPerStream, level, groupKey));
                }
            }
        }

        if (events.isEmpty()) {
            return null;
        }
        EventBean[] outgoing = events.toArray(new EventBean[events.size()]);
        if (outgoing.length > 1 && prototype.isSorting()) {
            return orderByProcessor.sort(outgoing, currentGenerators, isNewData, agentInstanceContext, prototype.getPerLevelExpression().getOptionalOrderByElements());
        }
        return outgoing;
    }

    private EventBean[] generateOutputEventsJoin(Map<Object, EventBean[]>[] eventPairs, boolean isNewData, boolean synthesize) {
        ArrayList<EventBean> events = new ArrayList<EventBean>(1);
        List<GroupByRollupKey> currentGenerators = null;
        if(prototype.isSorting()) {
            currentGenerators = new ArrayList<GroupByRollupKey>(4);
        }

        AggregationGroupByRollupLevel[] levels = prototype.getGroupByRollupDesc().getLevels();
        SelectExprProcessor[] selectExprProcessors = prototype.getPerLevelExpression().getSelectExprProcessor();
        ExprEvaluator[] optionalHavingClauses = prototype.getPerLevelExpression().getOptionalHavingNodes();
        for (AggregationGroupByRollupLevel level : levels) {
            for (Map.Entry<Object, EventBean[]> entry : eventPairs[level.getLevelNumber()].entrySet()) {
                Object groupKey = entry.getKey();

                // Set the current row of aggregation states
                aggregationService.setCurrentAccess(groupKey, agentInstanceContext.getAgentInstanceId(), level);

                // Filter the having clause
                if (optionalHavingClauses != null)
                {
                    if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qHavingClauseJoin(entry.getValue());}
                    Boolean result = (Boolean) optionalHavingClauses[level.getLevelNumber()].evaluate(entry.getValue(), isNewData, agentInstanceContext);
                    if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aHavingClauseJoin(result);}
                    if ((result == null) || (!result)) {
                        continue;
                    }
                }
                events.add(selectExprProcessors[level.getLevelNumber()].process(entry.getValue(), isNewData, synthesize, agentInstanceContext));

                if(prototype.isSorting()) {
                    currentGenerators.add(new GroupByRollupKey(entry.getValue(), level, groupKey));
                }
            }
        }

        if (events.isEmpty()) {
            return null;
        }
        EventBean[] outgoing = events.toArray(new EventBean[events.size()]);
        if (outgoing.length > 1 && prototype.isSorting()) {
            return orderByProcessor.sort(outgoing, currentGenerators, isNewData, agentInstanceContext, prototype.getPerLevelExpression().getOptionalOrderByElements());
        }
        return outgoing;
    }

    public Iterator<EventBean> getIterator(Viewable parent)
    {
        resetEventPerGroupBuf();
        EventBean[] events = EPAssertionUtil.iteratorToArray(parent.iterator());
        generateGroupKeysView(events, eventPerGroupBuf, true);
        EventBean[] output = generateOutputEventsView(eventPerGroupBuf, true, true);
        return new ArrayEventIterator(output);
    }

    public Iterator<EventBean> getIterator(Set<MultiKey<EventBean>> joinSet)
    {
        resetEventPerGroupJoinBuf();
        generateGroupKeysJoin(joinSet, eventPerGroupJoinBuf, true);
        EventBean[] output = generateOutputEventsJoin(eventPerGroupJoinBuf, true, true);
        return new ArrayEventIterator(output);
    }

    public void clear()
    {
        aggregationService.clearResults(agentInstanceContext);
    }

    public UniformPair<EventBean[]> processOutputLimitedJoin(List<UniformPair<Set<MultiKey<EventBean>>>> joinEventsSet, boolean generateSynthetic, OutputLimitLimitType outputLimitLimitType)
    {
        if (outputLimitLimitType == OutputLimitLimitType.DEFAULT) {
            return handleOutputLimitDefaultJoin(joinEventsSet, generateSynthetic);
        }
        else if (outputLimitLimitType == OutputLimitLimitType.ALL) {
            return handleOutputLimitAllJoin(joinEventsSet, generateSynthetic);
        }
        else if (outputLimitLimitType == OutputLimitLimitType.FIRST) {
            return handleOutputLimitFirstJoin(joinEventsSet, generateSynthetic);
        }
        // (outputLimitLimitType == OutputLimitLimitType.LAST) {
        return handleOutputLimitLastJoin(joinEventsSet, generateSynthetic);
    }

    public UniformPair<EventBean[]> processOutputLimitedView(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic, OutputLimitLimitType outputLimitLimitType)
    {
        if (outputLimitLimitType == OutputLimitLimitType.DEFAULT) {
            return handleOutputLimitDefaultView(viewEventsList, generateSynthetic);
        }
        else if (outputLimitLimitType == OutputLimitLimitType.ALL) {
            return handleOutputLimitAllView(viewEventsList, generateSynthetic);
        }
        else if (outputLimitLimitType == OutputLimitLimitType.FIRST) {
            return handleOutputLimitFirstView(viewEventsList, generateSynthetic);
        }
        // (outputLimitLimitType == OutputLimitLimitType.LAST) {
        return handleOutputLimitLastView(viewEventsList, generateSynthetic);
    }

    private UniformPair<EventBean[]> handleOutputLimitFirstView(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic) {

        for (Map<Object, EventBean[]> aGroupRepsView : outputLimitGroupRepsPerLevel) {
            aGroupRepsView.clear();
        }

        rstreamEventSortArrayPair.reset();

        int oldEventCount;
        if (prototype.getPerLevelExpression().getOptionalHavingNodes() == null) {
            oldEventCount = handleOutputLimitFirstViewNoHaving(viewEventsList, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
        }
        else {
            oldEventCount = handleOutputLimitFirstViewHaving(viewEventsList, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
        }

        return generateAndSort(outputLimitGroupRepsPerLevel, generateSynthetic, oldEventCount);
    }

    private UniformPair<EventBean[]> handleOutputLimitFirstJoin(List<UniformPair<Set<MultiKey<EventBean>>>> joinEventsSet, boolean generateSynthetic) {

        for (Map<Object, EventBean[]> aGroupRepsView : outputLimitGroupRepsPerLevel) {
            aGroupRepsView.clear();
        }

        rstreamEventSortArrayPair.reset();

        int oldEventCount;
        if (prototype.getPerLevelExpression().getOptionalHavingNodes() == null) {
            oldEventCount = handleOutputLimitFirstJoinNoHaving(joinEventsSet, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
        }
        else {
            oldEventCount = handleOutputLimitFirstJoinHaving(joinEventsSet, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
        }

        return generateAndSort(outputLimitGroupRepsPerLevel, generateSynthetic, oldEventCount);
    }

    private int handleOutputLimitFirstViewHaving(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic, List<EventBean>[] oldEventsPerLevel, List<Object>[] oldEventsSortKeyPerLevel) {
        int oldEventCount = 0;

        ExprEvaluator[] havingPerLevel = prototype.getPerLevelExpression().getOptionalHavingNodes();

        for (UniformPair<EventBean[]> pair : viewEventsList)
        {
            EventBean[] newData = pair.getFirst();
            EventBean[] oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            EventBean[] eventsPerStream;
            if (newData != null) {
                for (EventBean aNewData : newData) {
                    eventsPerStream = new EventBean[] {aNewData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                    }
                    aggregationService.applyEnter(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (EventBean anOldData : oldData) {
                    eventsPerStream = new EventBean[] {anOldData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                    }
                    aggregationService.applyLeave(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }

            if (newData != null) {
                for (EventBean aNewData : newData) {
                    eventsPerStream = new EventBean[] {aNewData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);

                        aggregationService.setCurrentAccess(groupKey, agentInstanceContext.getAgentInstanceId(), level);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qHavingClauseNonJoin(aNewData);}
                        Boolean result = (Boolean) havingPerLevel[level.getLevelNumber()].evaluate(eventsPerStream, true, agentInstanceContext);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aHavingClauseNonJoin(result);}
                        if ((result == null) || (!result)) {
                            continue;
                        }

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, eventsPerStream, true, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                }
            }
            if (oldData != null) {
                for (EventBean anOldData : oldData) {
                    eventsPerStream = new EventBean[] {anOldData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);

                        aggregationService.setCurrentAccess(groupKey, agentInstanceContext.getAgentInstanceId(), level);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qHavingClauseNonJoin(anOldData);}
                        Boolean result = (Boolean) havingPerLevel[level.getLevelNumber()].evaluate(eventsPerStream, false, agentInstanceContext);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aHavingClauseNonJoin(result);}
                        if ((result == null) || (!result)) {
                            continue;
                        }

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, eventsPerStream, false, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                }
            }
        }
        return oldEventCount;
    }

    private int handleOutputLimitFirstJoinNoHaving(List<UniformPair<Set<MultiKey<EventBean>>>> joinEventSet, boolean generateSynthetic, List<EventBean>[] oldEventsPerLevel, List<Object>[] oldEventsSortKeyPerLevel) {

        int oldEventCount = 0;

        // outer loop is the events
        for (UniformPair<Set<MultiKey<EventBean>>> pair : joinEventSet)
        {
            Set<MultiKey<EventBean>> newData = pair.getFirst();
            Set<MultiKey<EventBean>> oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            EventBean[] eventsPerStream;
            if (newData != null) {
                for (MultiKey<EventBean> aNewData : newData) {
                    Object groupKeyComplete = generateGroupKey(aNewData.getArray(), true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, aNewData.getArray()) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, aNewData.getArray(), true, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                    aggregationService.applyEnter(aNewData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (MultiKey<EventBean> anOldData : oldData) {
                    Object groupKeyComplete = generateGroupKey(anOldData.getArray(), false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, anOldData.getArray()) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, anOldData.getArray(), false, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                    aggregationService.applyLeave(anOldData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
        }
        return oldEventCount;
    }

    private int handleOutputLimitFirstJoinHaving(List<UniformPair<Set<MultiKey<EventBean>>>> joinEventSet, boolean generateSynthetic, List<EventBean>[] oldEventsPerLevel, List<Object>[] oldEventsSortKeyPerLevel) {
        int oldEventCount = 0;

        ExprEvaluator[] havingPerLevel = prototype.getPerLevelExpression().getOptionalHavingNodes();

        for (UniformPair<Set<MultiKey<EventBean>>> pair : joinEventSet)
        {
            Set<MultiKey<EventBean>> newData = pair.getFirst();
            Set<MultiKey<EventBean>> oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            EventBean[] eventsPerStream;
            if (newData != null) {
                for (MultiKey<EventBean> aNewData : newData) {
                    Object groupKeyComplete = generateGroupKey(aNewData.getArray(), true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                    }
                    aggregationService.applyEnter(aNewData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (MultiKey<EventBean> anOldData : oldData) {
                    Object groupKeyComplete = generateGroupKey(anOldData.getArray(), false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                    }
                    aggregationService.applyLeave(anOldData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }

            if (newData != null) {
                for (MultiKey<EventBean> aNewData : newData) {
                    Object groupKeyComplete = generateGroupKey(aNewData.getArray(), true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);

                        aggregationService.setCurrentAccess(groupKey, agentInstanceContext.getAgentInstanceId(), level);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qHavingClauseJoin(aNewData.getArray());}
                        Boolean result = (Boolean) havingPerLevel[level.getLevelNumber()].evaluate(aNewData.getArray(), true, agentInstanceContext);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aHavingClauseJoin(result);}
                        if ((result == null) || (!result)) {
                            continue;
                        }

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, aNewData.getArray()) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, aNewData.getArray(), true, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                }
            }
            if (oldData != null) {
                for (MultiKey<EventBean> anOldData : oldData) {
                    Object groupKeyComplete = generateGroupKey(anOldData.getArray(), false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);

                        aggregationService.setCurrentAccess(groupKey, agentInstanceContext.getAgentInstanceId(), level);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qHavingClauseJoin(anOldData.getArray());}
                        Boolean result = (Boolean) havingPerLevel[level.getLevelNumber()].evaluate(anOldData.getArray(), false, agentInstanceContext);
                        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aHavingClauseJoin(result);}
                        if ((result == null) || (!result)) {
                            continue;
                        }

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, anOldData.getArray()) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, anOldData.getArray(), false, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                }
            }
        }
        return oldEventCount;
    }

    private int handleOutputLimitFirstViewNoHaving(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic, List<EventBean>[] oldEventsPerLevel, List<Object>[] oldEventsSortKeyPerLevel) {

        int oldEventCount = 0;

        // outer loop is the events
        for (UniformPair<EventBean[]> pair : viewEventsList)
        {
            EventBean[] newData = pair.getFirst();
            EventBean[] oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            EventBean[] eventsPerStream;
            if (newData != null) {
                for (EventBean aNewData : newData) {
                    eventsPerStream = new EventBean[] {aNewData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, eventsPerStream, true, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                    aggregationService.applyEnter(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (EventBean anOldData : oldData) {
                    eventsPerStream = new EventBean[] {anOldData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;

                        OutputConditionPolled outputStateGroup = outputState[level.getLevelNumber()].get(groupKey);
                        if (outputStateGroup == null) {
                            try {
                                outputStateGroup = OutputConditionPolledFactory.createCondition(prototype.getOutputLimitSpec(), agentInstanceContext);
                            }
                            catch (ExprValidationException e) {
                                throw handleConditionValidationException(e);
                            }
                            outputState[level.getLevelNumber()].put(groupKey, outputStateGroup);
                        }
                        boolean pass = outputStateGroup.updateOutputCondition(1, 0);
                        if (pass) {
                            if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream) == null) {
                                if (prototype.isSelectRStream()) {
                                    generateOutputBatched(false, groupKey, level, eventsPerStream, false, generateSynthetic, oldEventsPerLevel, oldEventsSortKeyPerLevel);
                                    oldEventCount++;
                                }
                            }
                        }
                    }
                    aggregationService.applyLeave(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
        }
        return oldEventCount;
    }

    private UniformPair<EventBean[]> handleOutputLimitDefaultView(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic) {

        List<EventBean> newEvents = new ArrayList<EventBean>();
        List<Object> newEventsSortKey = null;
        if (orderByProcessor != null) {
            newEventsSortKey = new ArrayList<Object>();
        }

        List<EventBean> oldEvents = null;
        List<Object> oldEventsSortKey = null;
        if (prototype.isSelectRStream()) {
            oldEvents = new ArrayList<EventBean>();
            if (orderByProcessor != null) {
                oldEventsSortKey = new ArrayList<Object>();
            }
        }

        for (UniformPair<EventBean[]> pair : viewEventsList) {
            EventBean[] newData = pair.getFirst();
            EventBean[] oldData = pair.getSecond();

            resetEventPerGroupBuf();
            Object[][] newDataMultiKey = generateGroupKeysView(newData, eventPerGroupBuf, true);
            Object[][] oldDataMultiKey = generateGroupKeysView(oldData, eventPerGroupBuf, false);

            if (prototype.isSelectRStream()) {
                generateOutputBatchedCollectNonJoin(eventPerGroupBuf, false, generateSynthetic, oldEvents, oldEventsSortKey);
            }

            // update aggregates
            EventBean[] eventsPerStream = new EventBean[1];
            if (newData != null) {
                for (int i = 0; i < newData.length; i++) {
                    eventsPerStream[0] = newData[i];
                    aggregationService.applyEnter(eventsPerStream, newDataMultiKey[i], agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (int i = 0; i < oldData.length; i++) {
                    eventsPerStream[0] = oldData[i];
                    aggregationService.applyLeave(eventsPerStream, oldDataMultiKey[i], agentInstanceContext);
                }
            }

            generateOutputBatchedCollectNonJoin(eventPerGroupBuf, true, generateSynthetic, newEvents, newEventsSortKey);
        }

        return convertToArrayMaySort(newEvents, newEventsSortKey, oldEvents, oldEventsSortKey);
    }

    private UniformPair<EventBean[]> handleOutputLimitDefaultJoin(List<UniformPair<Set<MultiKey<EventBean>>>> viewEventsList, boolean generateSynthetic) {

        List<EventBean> newEvents = new ArrayList<EventBean>();
        List<Object> newEventsSortKey = null;
        if (orderByProcessor != null) {
            newEventsSortKey = new ArrayList<Object>();
        }

        List<EventBean> oldEvents = null;
        List<Object> oldEventsSortKey = null;
        if (prototype.isSelectRStream()) {
            oldEvents = new ArrayList<EventBean>();
            if (orderByProcessor != null) {
                oldEventsSortKey = new ArrayList<Object>();
            }
        }

        for (UniformPair<Set<MultiKey<EventBean>>> pair : viewEventsList) {
            Set<MultiKey<EventBean>> newData = pair.getFirst();
            Set<MultiKey<EventBean>> oldData = pair.getSecond();

            resetEventPerGroupJoinBuf();
            Object[][] newDataMultiKey = generateGroupKeysJoin(newData, eventPerGroupJoinBuf, true);
            Object[][] oldDataMultiKey = generateGroupKeysJoin(oldData, eventPerGroupJoinBuf, false);

            if (prototype.isSelectRStream()) {
                generateOutputBatchedCollectJoin(eventPerGroupJoinBuf, false, generateSynthetic, oldEvents, oldEventsSortKey);
            }

            // update aggregates
            if (newData != null) {
                int count = 0;
                for (MultiKey<EventBean> newEvent : newData) {
                    aggregationService.applyEnter(newEvent.getArray(), newDataMultiKey[count++], agentInstanceContext);
                }
            }
            if (oldData != null) {
                int count = 0;
                for (MultiKey<EventBean> oldEvent: oldData) {
                    aggregationService.applyLeave(oldEvent.getArray(), oldDataMultiKey[count++], agentInstanceContext);
                }
            }

            generateOutputBatchedCollectJoin(eventPerGroupJoinBuf, true, generateSynthetic, newEvents, newEventsSortKey);
        }

        return convertToArrayMaySort(newEvents, newEventsSortKey, oldEvents, oldEventsSortKey);
    }

    public boolean hasAggregation() {
        return true;
    }

    public void removed(Object key) {
        throw new UnsupportedOperationException();
    }

    protected Object generateGroupKey(EventBean[] eventsPerStream, boolean isNewData) {
        if (InstrumentationHelper.ENABLED) {
            InstrumentationHelper.get().qResultSetProcessComputeGroupKeys(isNewData, prototype.getGroupKeyNodeExpressions(), eventsPerStream);
            Object keyObject;
            if (prototype.getGroupKeyNode() != null) {
                keyObject = prototype.getGroupKeyNode().evaluate(eventsPerStream, isNewData, agentInstanceContext);
            }
            else {
                ExprEvaluator[] evals = prototype.getGroupKeyNodes();
                Object[] keys = new Object[evals.length];
                for (int i = 0; i < evals.length; i++) {
                    keys[i] = evals[i].evaluate(eventsPerStream, isNewData, agentInstanceContext);
                }
                keyObject = new MultiKeyUntyped(keys);
            }

            InstrumentationHelper.get().aResultSetProcessComputeGroupKeys(isNewData, keyObject);
            return keyObject;
        }

        if (prototype.getGroupKeyNode() != null) {
            return prototype.getGroupKeyNode().evaluate(eventsPerStream, isNewData, agentInstanceContext);
        }
        else {
            ExprEvaluator[] evals = prototype.getGroupKeyNodes();
            Object[] keys = new Object[evals.length];
            for (int i = 0; i < evals.length; i++) {
                keys[i] = evals[i].evaluate(eventsPerStream, isNewData, agentInstanceContext);
            }
            return new MultiKeyUntyped(keys);
        }
    }

    private void generateOutputBatched(boolean join, Object mk, AggregationGroupByRollupLevel level, EventBean[] eventsPerStream, boolean isNewData, boolean isSynthesize, List<EventBean>[] resultEvents, List<Object>[] optSortKeys) {
        List<EventBean> resultList = resultEvents[level.getLevelNumber()];
        List<Object> sortKeys = optSortKeys == null ? null : optSortKeys[level.getLevelNumber()];
        generateOutputBatched(join, mk, level, eventsPerStream, isNewData, isSynthesize, resultList, sortKeys);
    }

    private void generateOutputBatched(boolean join, Object mk, AggregationGroupByRollupLevel level, EventBean[] eventsPerStream, boolean isNewData, boolean isSynthesize, List<EventBean> resultEvents, List<Object> optSortKeys) {
        aggregationService.setCurrentAccess(mk, agentInstanceContext.getAgentInstanceId(), level);

        if (prototype.getPerLevelExpression().getOptionalHavingNodes() != null)
        {
            if (InstrumentationHelper.ENABLED) { if (!join) InstrumentationHelper.get().qHavingClauseNonJoin(eventsPerStream[0]); else InstrumentationHelper.get().qHavingClauseJoin(eventsPerStream);}
            Boolean result = (Boolean) prototype.getPerLevelExpression().getOptionalHavingNodes()[level.getLevelNumber()].evaluate(eventsPerStream, isNewData, agentInstanceContext);
            if (InstrumentationHelper.ENABLED) { if (!join) InstrumentationHelper.get().aHavingClauseNonJoin(result); else InstrumentationHelper.get().aHavingClauseJoin(result);}
            if ((result == null) || (!result)) {
                return;
            }
        }

        resultEvents.add(prototype.getPerLevelExpression().getSelectExprProcessor()[level.getLevelNumber()].process(eventsPerStream, isNewData, isSynthesize, agentInstanceContext));

        if (prototype.isSorting()) {
            optSortKeys.add(orderByProcessor.getSortKey(eventsPerStream, isNewData, agentInstanceContext, prototype.getPerLevelExpression().getOptionalOrderByElements()[level.getLevelNumber()]));
        }
    }

    private UniformPair<EventBean[]> handleOutputLimitLastView(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic) {
        int oldEventCount = 0;
        if (prototype.isSelectRStream()) {
            rstreamEventSortArrayPair.reset();
        }

        for (Map<Object, EventBean[]> aGroupRepsView : outputLimitGroupRepsPerLevel) {
            aGroupRepsView.clear();
        }

        // outer loop is the events
        for (UniformPair<EventBean[]> pair : viewEventsList)
        {
            EventBean[] newData = pair.getFirst();
            EventBean[] oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            EventBean[] eventsPerStream;
            if (newData != null) {
                for (EventBean aNewData : newData) {
                    eventsPerStream = new EventBean[] {aNewData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream) == null) {
                            if (prototype.isSelectRStream()) {
                                generateOutputBatched(false, groupKey, level, eventsPerStream, true, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                                oldEventCount++;
                            }
                        }
                    }
                    aggregationService.applyEnter(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (EventBean anOldData : oldData) {
                    eventsPerStream = new EventBean[] {anOldData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream) == null) {
                            if (prototype.isSelectRStream()) {
                                generateOutputBatched(true, groupKey, level, eventsPerStream, true, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                                oldEventCount++;
                            }
                        }
                    }
                    aggregationService.applyLeave(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
        }

        return generateAndSort(outputLimitGroupRepsPerLevel, generateSynthetic, oldEventCount);
    }

    private UniformPair<EventBean[]> handleOutputLimitLastJoin(List<UniformPair<Set<MultiKey<EventBean>>>> viewEventsList, boolean generateSynthetic) {
        int oldEventCount = 0;
        if (prototype.isSelectRStream()) {
            rstreamEventSortArrayPair.reset();
        }

        for (Map<Object, EventBean[]> aGroupRepsView : outputLimitGroupRepsPerLevel) {
            aGroupRepsView.clear();
        }

        // outer loop is the events
        for (UniformPair<Set<MultiKey<EventBean>>> pair : viewEventsList)
        {
            Set<MultiKey<EventBean>> newData = pair.getFirst();
            Set<MultiKey<EventBean>> oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            if (newData != null) {
                for (MultiKey<EventBean> aNewData : newData) {
                    Object groupKeyComplete = generateGroupKey(aNewData.getArray(), true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, aNewData.getArray()) == null) {
                            if (prototype.isSelectRStream()) {
                                generateOutputBatched(false, groupKey, level, aNewData.getArray(), true, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                                oldEventCount++;
                            }
                        }
                    }
                    aggregationService.applyEnter(aNewData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (MultiKey<EventBean> anOldData : oldData) {
                    Object groupKeyComplete = generateGroupKey(anOldData.getArray(), false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        if (outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, anOldData.getArray()) == null) {
                            if (prototype.isSelectRStream()) {
                                generateOutputBatched(true, groupKey, level, anOldData.getArray(), true, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                                oldEventCount++;
                            }
                        }
                    }
                    aggregationService.applyLeave(anOldData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
        }

        return generateAndSort(outputLimitGroupRepsPerLevel, generateSynthetic, oldEventCount);
    }

    private UniformPair<EventBean[]> handleOutputLimitAllView(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic) {

        int oldEventCount = 0;
        if (prototype.isSelectRStream()) {
            rstreamEventSortArrayPair.reset();

            for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                Map<Object, EventBean[]> groupGenerators = outputLimitGroupRepsPerLevel[level.getLevelNumber()];
                for (Map.Entry<Object, EventBean[]> entry : groupGenerators.entrySet()) {
                    generateOutputBatched(false, entry.getKey(), level, entry.getValue(), false, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                    oldEventCount++;
                }
            }
        }

        // outer loop is the events
        for (UniformPair<EventBean[]> pair : viewEventsList)
        {
            EventBean[] newData = pair.getFirst();
            EventBean[] oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            if (newData != null) {
                for (EventBean aNewData : newData) {
                    EventBean[] eventsPerStream = new EventBean[] {aNewData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        Object existing = outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream);

                        if (existing == null && prototype.isSelectRStream()) {
                            generateOutputBatched(false, groupKey, level, eventsPerStream, true, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                            oldEventCount++;
                        }
                    }
                    aggregationService.applyEnter(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (EventBean anOldData : oldData) {
                    EventBean[] eventsPerStream = new EventBean[] {anOldData};
                    Object groupKeyComplete = generateGroupKey(eventsPerStream, false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        Object existing = outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, eventsPerStream);

                        if (existing == null && prototype.isSelectRStream()) {
                            generateOutputBatched(false, groupKey, level, eventsPerStream, false, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                            oldEventCount++;
                        }
                    }
                    aggregationService.applyLeave(eventsPerStream, groupKeysPerLevel, agentInstanceContext);
                }
            }
        }

        return generateAndSort(outputLimitGroupRepsPerLevel, generateSynthetic, oldEventCount);
    }

    private UniformPair<EventBean[]> handleOutputLimitAllJoin(List<UniformPair<Set<MultiKey<EventBean>>>> joinEventsSet, boolean generateSynthetic) {

        int oldEventCount = 0;
        if (prototype.isSelectRStream()) {
            rstreamEventSortArrayPair.reset();

            for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                Map<Object, EventBean[]> groupGenerators = outputLimitGroupRepsPerLevel[level.getLevelNumber()];
                for (Map.Entry<Object, EventBean[]> entry : groupGenerators.entrySet()) {
                    generateOutputBatched(false, entry.getKey(), level, entry.getValue(), false, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                    oldEventCount++;
                }
            }
        }

        // outer loop is the events
        for (UniformPair<Set<MultiKey<EventBean>>> pair : joinEventsSet)
        {
            Set<MultiKey<EventBean>> newData = pair.getFirst();
            Set<MultiKey<EventBean>> oldData = pair.getSecond();

            // apply to aggregates
            Object[] groupKeysPerLevel = new Object[prototype.getGroupByRollupDesc().getLevels().length];
            if (newData != null) {
                for (MultiKey<EventBean> aNewData : newData) {
                    Object groupKeyComplete = generateGroupKey(aNewData.getArray(), true);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        Object existing = outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, aNewData.getArray());

                        if (existing == null && prototype.isSelectRStream()) {
                            generateOutputBatched(false, groupKey, level, aNewData.getArray(), true, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                            oldEventCount++;
                        }
                    }
                    aggregationService.applyEnter(aNewData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
            if (oldData != null) {
                for (MultiKey<EventBean> anOldData : oldData) {
                    Object groupKeyComplete = generateGroupKey(anOldData.getArray(), false);
                    for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
                        Object groupKey = level.computeSubkey(groupKeyComplete);
                        groupKeysPerLevel[level.getLevelNumber()] = groupKey;
                        Object existing = outputLimitGroupRepsPerLevel[level.getLevelNumber()].put(groupKey, anOldData.getArray());

                        if (existing == null && prototype.isSelectRStream()) {
                            generateOutputBatched(false, groupKey, level, anOldData.getArray(), false, generateSynthetic, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
                            oldEventCount++;
                        }
                    }
                    aggregationService.applyLeave(anOldData.getArray(), groupKeysPerLevel, agentInstanceContext);
                }
            }
        }

        return generateAndSort(outputLimitGroupRepsPerLevel, generateSynthetic, oldEventCount);
    }

    private void generateOutputBatchedCollectNonJoin(Map<Object, EventBean>[] eventPairs, boolean isNewData, boolean generateSynthetic, List<EventBean> events, List<Object> sortKey) {
        AggregationGroupByRollupLevel[] levels = prototype.getGroupByRollupDesc().getLevels();
        EventBean[] eventsPerStream = new EventBean[1];

        for (AggregationGroupByRollupLevel level : levels) {
            Map<Object, EventBean> eventsForLevel = eventPairs[level.getLevelNumber()];
            for (Map.Entry<Object, EventBean> pair : eventsForLevel.entrySet()) {
                eventsPerStream[0] = pair.getValue();
                generateOutputBatched(false, pair.getKey(), level, eventsPerStream, isNewData, generateSynthetic, events, sortKey);
            }
        }
    }

    private void generateOutputBatchedCollectJoin(Map<Object, EventBean[]>[] eventPairs, boolean isNewData, boolean generateSynthetic, List<EventBean> events, List<Object> sortKey) {
        AggregationGroupByRollupLevel[] levels = prototype.getGroupByRollupDesc().getLevels();

        for (AggregationGroupByRollupLevel level : levels) {
            Map<Object, EventBean[]> eventsForLevel = eventPairs[level.getLevelNumber()];
            for (Map.Entry<Object, EventBean[]> pair : eventsForLevel.entrySet()) {
                generateOutputBatched(false, pair.getKey(), level, pair.getValue(), isNewData, generateSynthetic, events, sortKey);
            }
        }
    }

    private void resetEventPerGroupBuf() {
        for (Map<Object, EventBean> anEventPerGroupBuf : eventPerGroupBuf) {
            anEventPerGroupBuf.clear();
        }
    }

    private void resetEventPerGroupJoinBuf() {
        for (Map<Object, EventBean[]> anEventPerGroupBuf : eventPerGroupJoinBuf) {
            anEventPerGroupBuf.clear();
        }
    }

    private EventsAndSortKeysPair getOldEventsSortKeys(int oldEventCount, List<EventBean>[] oldEventsPerLevel, List<Object>[] oldEventsSortKeyPerLevel) {
        EventBean[] oldEventsArr = new EventBean[oldEventCount];
        Object[] oldEventsSortKeys = null;
        if (orderByProcessor != null) {
            oldEventsSortKeys = new Object[oldEventCount];
        }
        int countEvents = 0;
        int countSortKeys = 0;
        for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
            List<EventBean> events = oldEventsPerLevel[level.getLevelNumber()];
            for (EventBean event : events) {
                oldEventsArr[countEvents++] = event;
            }
            if (orderByProcessor != null) {
                List<Object> sortKeys = oldEventsSortKeyPerLevel[level.getLevelNumber()];
                for (Object sortKey : sortKeys) {
                    oldEventsSortKeys[countSortKeys++] = sortKey;
                }
            }
        }
        return new EventsAndSortKeysPair(oldEventsArr, oldEventsSortKeys);
    }

    protected Object[][] generateGroupKeysView(EventBean[] events, Map<Object, EventBean>[] eventPerKey, boolean isNewData)
    {
        if (events == null) {
            return null;
        }

        Object[][] result = new Object[events.length][];
        EventBean[] eventsPerStream = new EventBean[1];

        for (int i = 0; i < events.length; i++) {
            eventsPerStream[0] = events[i];
            Object groupKeyComplete = generateGroupKey(eventsPerStream, isNewData);
            AggregationGroupByRollupLevel[] levels = prototype.getGroupByRollupDesc().getLevels();
            result[i] = new Object[levels.length];
            for (int j = 0; j < levels.length; j++) {
                Object subkey = levels[j].computeSubkey(groupKeyComplete);
                result[i][j] = subkey;
                eventPerKey[levels[j].getLevelNumber()].put(subkey, events[i]);
            }
        }

        return result;
    }

    private Object[][] generateGroupKeysJoin(Set<MultiKey<EventBean>> events, Map<Object, EventBean[]>[] eventPerKey, boolean isNewData)
    {
        if (events == null || events.isEmpty()) {
            return null;
        }

        Object[][] result = new Object[events.size()][];

        int count = -1;
        for (MultiKey<EventBean> eventrow : events) {
            count++;
            Object groupKeyComplete = generateGroupKey(eventrow.getArray(), isNewData);
            AggregationGroupByRollupLevel[] levels = prototype.getGroupByRollupDesc().getLevels();
            result[count] = new Object[levels.length];
            for (int j = 0; j < levels.length; j++) {
                Object subkey = levels[j].computeSubkey(groupKeyComplete);
                result[count][j] = subkey;
                eventPerKey[levels[j].getLevelNumber()].put(subkey, eventrow.getArray());
            }
        }

        return result;
    }

    private UniformPair<EventBean[]> generateAndSort(Map<Object, EventBean[]>[] outputLimitGroupRepsPerLevel, boolean generateSynthetic, int oldEventCount) {
        // generate old events: ordered by level by default
        EventBean[] oldEventsArr = null;
        Object[] oldEventSortKeys = null;
        if (prototype.isSelectRStream() && oldEventCount > 0) {
            EventsAndSortKeysPair pair = getOldEventsSortKeys(oldEventCount, rstreamEventSortArrayPair.getEventsPerLevel(), rstreamEventSortArrayPair.getSortKeyPerLevel());
            oldEventsArr = pair.getEvents();
            oldEventSortKeys = pair.getSortKeys();
        }

        List<EventBean> newEvents = new ArrayList<EventBean>();
        List<Object> newEventsSortKey = null;
        if (orderByProcessor != null) {
            newEventsSortKey = new ArrayList<Object>();
        }

        for (AggregationGroupByRollupLevel level : prototype.getGroupByRollupDesc().getLevels()) {
            Map<Object, EventBean[]> groupGenerators = outputLimitGroupRepsPerLevel[level.getLevelNumber()];
            for (Map.Entry<Object, EventBean[]> entry : groupGenerators.entrySet()) {
                generateOutputBatched(false, entry.getKey(), level, entry.getValue(), true, generateSynthetic, newEvents, newEventsSortKey);
            }
        }

        EventBean[] newEventsArr = (newEvents.isEmpty()) ? null : newEvents.toArray(new EventBean[newEvents.size()]);
        if (orderByProcessor != null) {
            Object[] sortKeysNew = (newEventsSortKey.isEmpty()) ? null : newEventsSortKey.toArray(new Object[newEventsSortKey.size()]);
            newEventsArr = orderByProcessor.sort(newEventsArr, sortKeysNew, agentInstanceContext);
            if (prototype.isSelectRStream()) {
                oldEventsArr = orderByProcessor.sort(oldEventsArr, oldEventSortKeys, agentInstanceContext);
            }
        }

        if ((newEventsArr == null) && (oldEventsArr == null)) {
            return null;
        }
        return new UniformPair<EventBean[]>(newEventsArr, oldEventsArr);
    }

    private UniformPair<EventBean[]> convertToArrayMaySort(List<EventBean> newEvents, List<Object> newEventsSortKey, List<EventBean> oldEvents, List<Object> oldEventsSortKey) {
        EventBean[] newEventsArr = (newEvents.isEmpty()) ? null : newEvents.toArray(new EventBean[newEvents.size()]);
        EventBean[] oldEventsArr = null;
        if (prototype.isSelectRStream()) {
            oldEventsArr = (oldEvents.isEmpty()) ? null : oldEvents.toArray(new EventBean[oldEvents.size()]);
        }

        if (orderByProcessor != null) {
            Object[] sortKeysNew = (newEventsSortKey.isEmpty()) ? null : newEventsSortKey.toArray(new Object[newEventsSortKey.size()]);
            newEventsArr = orderByProcessor.sort(newEventsArr, sortKeysNew, agentInstanceContext);
            if (prototype.isSelectRStream()) {
                Object[] sortKeysOld = (oldEventsSortKey.isEmpty()) ? null : oldEventsSortKey.toArray(new Object[oldEventsSortKey.size()]);
                oldEventsArr = orderByProcessor.sort(oldEventsArr, sortKeysOld, agentInstanceContext);
            }
        }

        if ((newEventsArr == null) && (oldEventsArr == null)) {
            return null;
        }
        return new UniformPair<EventBean[]>(newEventsArr, oldEventsArr);
    }

    private EPException handleConditionValidationException(ExprValidationException e) {
        return new EPException("Error starting output limit for group for statement '" + agentInstanceContext.getStatementContext().getStatementName() + "': " + e.getMessage(), e);
    }

    private static class EventArrayAndSortKeyArray {
        private final List<EventBean>[] eventsPerLevel;
        private final List<Object>[] sortKeyPerLevel;

        private EventArrayAndSortKeyArray(List<EventBean>[] eventsPerLevel, List<Object>[] sortKeyPerLevel) {
            this.eventsPerLevel = eventsPerLevel;
            this.sortKeyPerLevel = sortKeyPerLevel;
        }

        public List<EventBean>[] getEventsPerLevel() {
            return eventsPerLevel;
        }

        public List<Object>[] getSortKeyPerLevel() {
            return sortKeyPerLevel;
        }

       public void reset() {
           for (List<EventBean> anEventsPerLevel : eventsPerLevel) {
               anEventsPerLevel.clear();
           }
           if (sortKeyPerLevel != null) {
               for (List<Object> anSortKeyPerLevel : sortKeyPerLevel) {
                   anSortKeyPerLevel.clear();
               }
           }
       }
    }

    private static class EventsAndSortKeysPair {
        private final EventBean[] events;
        private final Object[] sortKeys;

        private EventsAndSortKeysPair(EventBean[] events, Object[] sortKeys) {
            this.events = events;
            this.sortKeys = sortKeys;
        }

        public EventBean[] getEvents() {
            return events;
        }

        public Object[] getSortKeys() {
            return sortKeys;
        }
    }
}
TOP

Related Classes of com.espertech.esper.epl.core.ResultSetProcessorRowPerGroupRollup$EventArrayAndSortKeyArray

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.