/*
* *************************************************************************************
* 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.rowregex;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.collection.MultiKeyUntyped;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.expression.ExprEvaluatorContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Partition-by implementation for partition state.
*/
public class RegexPartitionStateRepoGroup implements RegexPartitionStateRepo
{
/**
* Empty state collection initial threshold.
*/
public final static int INITIAL_COLLECTION_MIN = 100;
private final RegexPartitionStateRandomAccessGetter getter;
private final Map<Object, RegexPartitionState> states;
private final boolean hasInterval;
private final ExprEvaluator[] partitionExpressions;
private final EventBean[] eventsPerStream = new EventBean[1];
private final ExprEvaluatorContext exprEvaluatorContext;
private int currentCollectionSize = INITIAL_COLLECTION_MIN;
/**
* Ctor.
* @param getter for "prev" function access
* @param partitionExpressions expressions for computing group key
* @param hasInterval true for interval
* @param exprEvaluatorContext context for evaluating expressions
*/
public RegexPartitionStateRepoGroup(RegexPartitionStateRandomAccessGetter getter,
ExprEvaluator[] partitionExpressions,
boolean hasInterval,
ExprEvaluatorContext exprEvaluatorContext)
{
this.getter = getter;
this.partitionExpressions = partitionExpressions;
this.hasInterval = hasInterval;
this.states = new HashMap<Object, RegexPartitionState>();
this.exprEvaluatorContext = exprEvaluatorContext;
}
public void removeState(Object partitionKey) {
states.remove(partitionKey);
}
public RegexPartitionStateRepo copyForIterate()
{
RegexPartitionStateRepoGroup copy = new RegexPartitionStateRepoGroup(getter, partitionExpressions, hasInterval, exprEvaluatorContext);
for (Map.Entry<Object, RegexPartitionState> entry : states.entrySet())
{
copy.states.put(entry.getKey(), new RegexPartitionState(entry.getValue().getRandomAccess(), entry.getKey(), hasInterval));
}
return copy;
}
public void removeOld(EventBean[] oldData, boolean isEmpty, boolean[] found)
{
if (isEmpty)
{
if (getter == null)
{
// no "prev" used, clear all state
states.clear();
}
else
{
for (Map.Entry<Object, RegexPartitionState> entry : states.entrySet())
{
entry.getValue().getCurrentStates().clear();
}
}
// clear "prev" state
if (getter != null)
{
// we will need to remove event-by-event
for (int i = 0; i < oldData.length; i++)
{
RegexPartitionState partitionState = getState(oldData[i], true);
if (partitionState == null)
{
continue;
}
partitionState.removeEventFromPrev(oldData);
}
}
return;
}
// we will need to remove event-by-event
for (int i = 0; i < oldData.length; i++)
{
RegexPartitionState partitionState = getState(oldData[i], true);
if (partitionState == null)
{
continue;
}
if (found[i])
{
boolean cleared = partitionState.removeEventFromState(oldData[i]);
if (cleared)
{
if (getter == null)
{
states.remove(partitionState.getOptionalKeys());
}
}
}
partitionState.removeEventFromPrev(oldData[i]);
}
}
public RegexPartitionState getState(Object key)
{
return states.get(key);
}
public RegexPartitionState getState(EventBean theEvent, boolean isCollect)
{
// collect unused states
if ((isCollect) && (states.size() >= currentCollectionSize))
{
List<Object> removeList = new ArrayList<Object>();
for (Map.Entry<Object, RegexPartitionState> entry : states.entrySet())
{
if ((entry.getValue().getCurrentStates().isEmpty()) &&
(entry.getValue().getRandomAccess() == null || entry.getValue().getRandomAccess().isEmpty()))
{
removeList.add(entry.getKey());
}
}
for (Object removeKey : removeList)
{
states.remove(removeKey);
}
if (removeList.size() < (currentCollectionSize / 5))
{
currentCollectionSize *= 2;
}
}
Object key = getKeys(theEvent);
RegexPartitionState state = states.get(key);
if (state != null)
{
return state;
}
state = new RegexPartitionState(getter, new ArrayList<RegexNFAStateEntry>(), key, hasInterval);
states.put(key, state);
return state;
}
private Object getKeys(EventBean theEvent)
{
eventsPerStream[0] = theEvent;
if (partitionExpressions.length == 1) {
return partitionExpressions[0].evaluate(eventsPerStream, true, exprEvaluatorContext);
}
Object[] keys = new Object[partitionExpressions.length];
int count = 0;
for (ExprEvaluator node : partitionExpressions)
{
keys[count++] = node.evaluate(eventsPerStream, true, exprEvaluatorContext);
}
return new MultiKeyUntyped(keys);
}
}