Skip to content

Commit

Permalink
MONDRIAN - Added a new property, IterationLimit, that limits the number
Browse files Browse the repository at this point in the history
       of iterations when evaluating an aggregate.  Also created separate
       exceptions for the different types of limitation exceptions.

[git-p4: depot-paths = "//open/mondrian/": change = 8493]
  • Loading branch information
Zelaine Fong committed Jan 9, 2007
1 parent 869154a commit a7e15e9
Show file tree
Hide file tree
Showing 25 changed files with 226 additions and 21 deletions.
8 changes: 8 additions & 0 deletions doc/configuration.html
Expand Up @@ -277,6 +277,14 @@ <h3>1.1 Property list<a name="Property_list">&nbsp;</a></h3>
and will be treated as a null member if they are later referenced in
a query.</td>
</tr>
<tr>
<td><a href="api/mondrian/olap/MondrianProperties.html#IterationLimit">
<code>mondrian.rolap.IterationLimit</code></a></td>
<td>int</td>
<td>0</td>
<td>If > 0, the maximum number of iterations allowed when evaluating an
aggregate. If 0, there is no limit.</td>
</tr>
<tr>
<td colspan="4">

Expand Down
6 changes: 6 additions & 0 deletions mondrian.properties
Expand Up @@ -259,4 +259,10 @@ RoleXX='California manager';
# treated as a null member.
mondrian.rolap.ignoreInvalidMembers=false

###############################################################################
# Integer property indicating the maximum number of iterations allowed when
# iterating over members to compute aggregates. Default of 0 indicates no
# limit.
mondrian.rolap.iterationLimit=0

# End mondrian.properties
12 changes: 12 additions & 0 deletions src/main/mondrian/olap/Evaluator.java
Expand Up @@ -189,6 +189,18 @@ public interface Evaluator {
* not set.
*/
Object getParameterValue(ParameterSlot slot);

/**
* @return the iteration length of the current context
*/
int getIterationLength();

/**
* Sets the iteration length for the current evaluator context
*
* @param length length to be set
*/
void setIterationLength(int length);
}

// End Evaluator.java
6 changes: 6 additions & 0 deletions src/main/mondrian/olap/MondrianProperties.java
Expand Up @@ -801,6 +801,12 @@ public Property getPropertyDefinition(String path) {
*/
public final BooleanProperty IgnoreInvalidMembers = new BooleanProperty(
this, "mondrian.rolap.ignoreInvalidMembers", false);

/**
* Iteration limit when computing an aggregate; 0 indicates unlimited
*/
public final IntegerProperty IterationLimit = new IntegerProperty(
this, "mondrian.rolap.iterationLimit", 0);
}

// End MondrianProperties.java
23 changes: 23 additions & 0 deletions src/main/mondrian/olap/QueryCanceledException.java
@@ -0,0 +1,23 @@
/*
// $Id$
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2004-2005 TONBELLER AG
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.olap;

/**
* Exception which indicates query was canceled
*
* @version $Id$
*/
public class QueryCanceledException extends ResultLimitExceeded {
public QueryCanceledException(String message) {
super(message);
}
}

// End QueryCanceledException.java
23 changes: 23 additions & 0 deletions src/main/mondrian/olap/QueryTimeoutException.java
@@ -0,0 +1,23 @@
/*
// $Id$
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2004-2005 TONBELLER AG
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.olap;

/**
* Exception which indicates query timeout was hit
*
* @version $Id$
*/
public class QueryTimeoutException extends ResultLimitExceeded {
public QueryTimeoutException(String message) {
super(message);
}
}

// End QueryTimeoutException.java
23 changes: 23 additions & 0 deletions src/main/mondrian/olap/ResourceLimitExceeded.java
@@ -0,0 +1,23 @@
/*
// $Id$
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2004-2005 TONBELLER AG
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.olap;

/**
* Exception which indicates some resource limit was exceeded.
*
* @version $Id$
*/
public class ResourceLimitExceeded extends ResultLimitExceeded {
public ResourceLimitExceeded(String message) {
super(message);
}
}

// End ResourceLimitExceeded.java
4 changes: 2 additions & 2 deletions src/main/mondrian/olap/ResultLimitExceeded.java
Expand Up @@ -10,11 +10,11 @@
package mondrian.olap;

/**
* Exception which indicates the ResultLimit was exceeded.
* Abstract base class for exceptions that indicate some limit was exceeded.
*
* @version $Id$
*/
public class ResultLimitExceeded extends MondrianException {
public abstract class ResultLimitExceeded extends MondrianException {
public ResultLimitExceeded(String message) {
super(message);
}
Expand Down
45 changes: 45 additions & 0 deletions src/main/mondrian/olap/fun/AbstractAggregateFunDef.java
Expand Up @@ -9,9 +9,13 @@
*/
package mondrian.olap.fun;

import mondrian.calc.*;
import mondrian.olap.*;
import mondrian.resource.MondrianResource;
import mondrian.mdx.UnresolvedFunCall;

import java.util.*;

/**
* Abstract base class for all aggregate functions (<code>Aggregate</code>,
* <code>Sum</code>, <code>Avg</code>, et cetera).
Expand Down Expand Up @@ -41,6 +45,47 @@ protected Exp validateArg(
}
return super.validateArg(validator, args, i, category);
}

/**
* Evaluates the list of members used in computing the aggregate.
* Keeps track of the number of iterations that will be required to
* iterate over the members needed to compute the aggregate within the
* current context. In doing so, also determines if the cross product
* of all iterations across all parent evaluation contexts will exceed the
* limit set in the properties file.
*
* @param listCalc calculator used to evaluate the member list
* @param evaluator current evalutor
*
* @return list of evaluated members
*/
protected List evaluateCurrentList(ListCalc listCalc, Evaluator evaluator)
{
List memberList = listCalc.evaluateList(evaluator);
int currLen = memberList.size();
long iterationLimit =
MondrianProperties.instance().IterationLimit.get();
if (iterationLimit > 0) {
int productLen = crossProd(evaluator, currLen);
if (productLen > iterationLimit) {
throw
MondrianResource.instance().
IterationLimitExceeded.ex(iterationLimit);
}
}
evaluator.setIterationLength(currLen);
return memberList;
}

private int crossProd(Evaluator evaluator, int currLen) {
int productLen = currLen;
Evaluator parent = evaluator.getParent();
while (parent != null) {
productLen *= parent.getIterationLength();
parent = parent.getParent();
}
return productLen;
}
}

// End AbstractAggregateFunDef.java
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/AggregateFunDef.java
Expand Up @@ -53,7 +53,7 @@ public Object evaluate(Evaluator evaluator) {
if (rollup == null) {
throw newEvalException(null, "Don't know how to rollup aggregator '" + aggregator + "'");
}
final List list = listCalc.evaluateList(evaluator);
final List list = evaluateCurrentList(listCalc, evaluator);
return rollup.aggregate(evaluator.push(), list, calc);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/AvgFunDef.java
Expand Up @@ -48,7 +48,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return avg(evaluator.push(), memberList, calc);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/CorrelationFunDef.java
Expand Up @@ -50,7 +50,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc1, calc2}) {
public double evaluateDouble(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return correlation(evaluator.push(),
memberList, calc1, calc2);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/CountFunDef.java
Expand Up @@ -54,7 +54,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
call, new Calc[] {memberListCalc}) {
public int evaluateInteger(Evaluator evaluator) {
List memberList =
memberListCalc.evaluateList(evaluator);
evaluateCurrentList(memberListCalc, evaluator);
return count(evaluator, memberList, includeEmpty);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/MedianFunDef.java
Expand Up @@ -48,7 +48,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return median(evaluator.push(), memberList, calc);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/MinMaxFunDef.java
Expand Up @@ -58,7 +58,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return max ?
max(evaluator.push(), memberList, calc) :
min(evaluator.push(), memberList, calc);
Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/StdevFunDef.java
Expand Up @@ -56,7 +56,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return stdev(evaluator.push(), memberList, calc, false);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/StdevPFunDef.java
Expand Up @@ -58,7 +58,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return stdev(evaluator.push(), memberList, calc, true);
}

Expand Down
6 changes: 2 additions & 4 deletions src/main/mondrian/olap/fun/SumFunDef.java
Expand Up @@ -9,9 +9,7 @@
*/
package mondrian.olap.fun;

import mondrian.olap.FunDef;
import mondrian.olap.Evaluator;
import mondrian.olap.Dimension;
import mondrian.olap.*;
import mondrian.calc.Calc;
import mondrian.calc.ExpCompiler;
import mondrian.calc.ListCalc;
Expand Down Expand Up @@ -48,7 +46,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractDoubleCalc(call, new Calc[] {listCalc, calc}) {
public double evaluateDouble(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return sumDouble(evaluator.push(), memberList, calc);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/VarFunDef.java
Expand Up @@ -55,7 +55,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return var(evaluator.push(), memberList, calc, false);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/VarPFunDef.java
Expand Up @@ -56,7 +56,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractCalc(call) {
public Object evaluate(Evaluator evaluator) {
List memberList = listCalc.evaluateList(evaluator);
List memberList = evaluateCurrentList(listCalc, evaluator);
return var(evaluator.push(), memberList, calc, true);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/extra/NthQuartileFunDef.java
Expand Up @@ -65,7 +65,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
new ValueCalc(call);
return new AbstractDoubleCalc(call, new Calc[] {listCalc, doubleCalc}) {
public double evaluateDouble(Evaluator evaluator) {
List members = listCalc.evaluateList(evaluator);
List members = evaluateCurrentList(listCalc, evaluator);
return quartile(evaluator.push(), members, doubleCalc, range);
}

Expand Down
12 changes: 8 additions & 4 deletions src/main/mondrian/resource/MondrianResource.xml
Expand Up @@ -474,22 +474,26 @@
<!-- ====================================================================== -->
<!-- Runtime limit overflow -->

<exception id="600010" name="LimitExceededDuringCrossjoin" className="mondrian.olap.ResultLimitExceeded">
<exception id="600010" name="LimitExceededDuringCrossjoin" className="mondrian.olap.ResourceLimitExceeded">
<text>Size of CrossJoin result ({0,number}) exceeded limit ({1,number})</text>
</exception>

<exception id="600020" name="MemberFetchLimitExceeded" className="mondrian.olap.ResultLimitExceeded">
<exception id="600020" name="MemberFetchLimitExceeded" className="mondrian.olap.ResourceLimitExceeded">
<text>Number of members to be read exceeded limit ({0,number})</text>
</exception>

<exception id="600030" name="QueryCanceled" className="mondrian.olap.ResultLimitExceeded">
<exception id="600030" name="QueryCanceled" className="mondrian.olap.QueryCanceledException">
<text>Query canceled</text>
</exception>

<exception id="600040" name="QueryTimeout" className="mondrian.olap.ResultLimitExceeded">
<exception id="600040" name="QueryTimeout" className="mondrian.olap.QueryTimeoutException">
<text>Query timeout of {0,number} seconds reached</text>
</exception>

<exception id="600050" name="IterationLimitExceeded" className="mondrian.olap.ResourceLimitExceeded">
<text>Number of iterations exceeded limit of {0,number} </text>
</exception>

<!-- empty ,invalid Dimension -->

<exception id="601010" name="InvalidHierarchyCondition" className="mondrian.olap.InvalidHierarchy">
Expand Down
8 changes: 8 additions & 0 deletions src/main/mondrian/rolap/RolapConnection.java
Expand Up @@ -360,6 +360,14 @@ public Object getProperty(String name) {
return connectInfo.get(name);
}

/**
* @throws ResourceLimitExceeded if some resource limit specified in the
* property file was exceeded
* @throws QueryCanceledException if query was canceled in the middle of
* execution
* @throws QueryTimeoutException if query exceeded timeout specified in
* the property file
*/
public Result execute(Query query) {
try {
if (LOGGER.isDebugEnabled()) {
Expand Down

0 comments on commit a7e15e9

Please sign in to comment.