Skip to content

Commit

Permalink
MONDRIAN: Stack-based evaluation context. Previously, each change in the
Browse files Browse the repository at this point in the history
    evaluation context would create a new evaluator. That was expensive. Now the
    evaluation context maintains a stack of commands that can be executed to
    restore state to a savepoint. It should allow us to add more state to the
    evaluator, in particular, building a list of (column, value) pairs, and
    thereby reducing the cost of making a CellRequest.

    Some methods of RolapEvaluator are now deprecated.

[git-p4: depot-paths = "//open/mondrian/": change = 14242]
  • Loading branch information
julianhyde committed May 2, 2011
1 parent ac2e622 commit 394a83d
Show file tree
Hide file tree
Showing 63 changed files with 1,791 additions and 813 deletions.
11 changes: 10 additions & 1 deletion src/main/mondrian/calc/TupleList.java
Expand Up @@ -19,8 +19,17 @@
* <h2>Design notes</h2>
*
* <ul>
* </ul>
*
* <li>Consider changing
* {@link TupleCalc#evaluateTuple(mondrian.olap.Evaluator)}
* and {@link mondrian.olap.Evaluator.NamedSetEvaluator#currentTuple()}
* to List&lt;Member&gt;</li>
*
* <li>Search for potential uses of {@link TupleList#get(int, int)}</li>
*
* <li>Worth creating {@link TupleList}.addAll(TupleIterator)?</li>
*
* </ul>
*
* @version $Id$
* @author jhyde
Expand Down
7 changes: 3 additions & 4 deletions src/main/mondrian/calc/impl/AbstractCalc.java
Expand Up @@ -3,7 +3,7 @@
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// Copyright (C) 2006-2009 Julian Hyde
// Copyright (C) 2006-2011 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
Expand Down Expand Up @@ -222,10 +222,9 @@ public static Evaluator simplifyEvaluator(Calc calc, Evaluator evaluator) {
continue;
}
if (changeCount++ == 0) {
ev = evaluator.push(unconstrainedMember);
} else {
ev.setContext(unconstrainedMember);
ev = evaluator.push();
}
ev.setContext(unconstrainedMember);
}
return ev;
}
Expand Down
9 changes: 6 additions & 3 deletions src/main/mondrian/calc/impl/AbstractExpCompiler.java
Expand Up @@ -396,7 +396,9 @@ public Calc compileScalar(Exp exp, boolean specific) {
TupleCalc tupleCalc = compileTuple(exp);
final TupleValueCalc scalarCalc =
new TupleValueCalc(
new DummyExp(tupleType.getValueType()), tupleCalc);
new DummyExp(tupleType.getValueType()),
tupleCalc,
getEvaluator().mightReturnNullForUnrelatedDimension());
return scalarCalc.optimize();
} else if (type instanceof ScalarType) {
if (specific) {
Expand Down Expand Up @@ -424,9 +426,10 @@ private Calc hierarchyToScalar(HierarchyCalc hierarchyCalc) {

private Calc memberToScalar(MemberCalc memberCalc) {
MemberType memberType = (MemberType) memberCalc.getType();
return new MemberValueCalc(
return MemberValueCalc.create(
new DummyExp(memberType.getValueType()),
new MemberCalc[] {memberCalc});
new MemberCalc[] {memberCalc},
getEvaluator().mightReturnNullForUnrelatedDimension());
}

public ParameterSlot registerParameter(Parameter parameter) {
Expand Down
115 changes: 115 additions & 0 deletions src/main/mondrian/calc/impl/MemberArrayValueCalc.java
@@ -0,0 +1,115 @@
/*
// $Id$
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// Copyright (C) 2011-2011 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.calc.impl;

import mondrian.calc.Calc;
import mondrian.calc.MemberCalc;
import mondrian.olap.*;
import mondrian.olap.type.ScalarType;
import mondrian.olap.type.Type;

/**
* Expression which evaluates a few member expressions,
* sets the dimensional context to the result of those expressions,
* then yields the value of the current measure in the current
* dimensional context.
*
* <p>The evaluator's context is preserved.
*
* <p>Note that a MemberValueCalc with 0 member expressions is equivalent to a
* {@link ValueCalc}; see also {@link TupleValueCalc}.
*
* @author jhyde
* @version $Id$
*/
public class MemberArrayValueCalc extends GenericCalc {
private final MemberCalc[] memberCalcs;
private final Member[] members;
private final boolean nullCheck;

/**
* Creates a MemberArrayValueCalc.
*
* <p>Clients outside this package should use the
* {@link MemberValueCalc#create(mondrian.olap.Exp,
* mondrian.calc.MemberCalc[], boolean)}
* factory method.
*
* @param exp Expression
* @param memberCalcs Array of compiled expressions
* @param nullCheck Whether to check for null values due to non-joining
* dimensions in a virtual cube
*/
MemberArrayValueCalc(Exp exp, MemberCalc[] memberCalcs, boolean nullCheck) {
super(exp);
this.nullCheck = nullCheck;
final Type type = exp.getType();
assert type instanceof ScalarType : exp;
this.memberCalcs = memberCalcs;
this.members = new Member[memberCalcs.length];
}

public Object evaluate(Evaluator evaluator) {
final int savepoint = evaluator.savepoint();
for (int i = 0; i < memberCalcs.length; i++) {
MemberCalc memberCalc = memberCalcs[i];
final Member member = memberCalc.evaluateMember(evaluator);
if (member == null
|| member.isNull())
{
// This method needs to leave the evaluator in the same state
// it found it.
evaluator.restore(savepoint);
return null;
}
evaluator.setContext(member);
members[i] = member;
}
if (nullCheck
&& evaluator.needToReturnNullForUnrelatedDimension(members))
{
evaluator.restore(savepoint);
return null;
}

final Object result = evaluator.evaluateCurrent();
evaluator.restore(savepoint);
return result;
}

public Calc[] getCalcs() {
return memberCalcs;
}

public boolean dependsOn(Hierarchy hierarchy) {
if (super.dependsOn(hierarchy)) {
return true;
}
for (MemberCalc memberCalc : memberCalcs) {
// If the expression definitely includes the dimension (in this
// case, that means it is a member of that dimension) then we
// do not depend on the dimension. For example, the scalar value of
// [Store].[USA]
// does not depend on [Store].
//
// If the dimensionality of the expression is unknown, then the
// expression MIGHT include the dimension, so to be safe we have to
// say that it depends on the given dimension. For example,
// Dimensions(3).CurrentMember.Parent
// may depend on [Store].
if (memberCalc.getType().usesHierarchy(hierarchy, true)) {
return false;
}
}
return true;
}
}

// End MemberArrayValueCalc.java
121 changes: 73 additions & 48 deletions src/main/mondrian/calc/impl/MemberValueCalc.java
Expand Up @@ -3,14 +3,13 @@
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// Copyright (C) 2006-2009 Julian Hyde
// Copyright (C) 2006-2011 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.calc.impl;

import mondrian.calc.Calc;
import mondrian.calc.MemberCalc;
import mondrian.calc.*;
import mondrian.olap.*;
import mondrian.olap.type.ScalarType;
import mondrian.olap.type.Type;
Expand All @@ -31,72 +30,98 @@
* @since Sep 27, 2005
*/
public class MemberValueCalc extends GenericCalc {
private final MemberCalc[] memberCalcs;
private final Member[] savedMembers;
private final MemberCalc memberCalc;
private final boolean nullCheck;

public MemberValueCalc(Exp exp, MemberCalc[] memberCalcs) {
/**
* Creates a MemberArrayValueCalc.
*
* <p>Clients outside this package should use the
* {@link MemberValueCalc#create(mondrian.olap.Exp,
* mondrian.calc.MemberCalc[], boolean)}
* factory method.
*
* @param exp Expression
* @param memberCalc Compiled expression
* @param nullCheck Whether to check for null values due to non-joining
* dimensions in a virtual cube
*/
public MemberValueCalc(Exp exp, MemberCalc memberCalc, boolean nullCheck) {
super(exp);
this.nullCheck = nullCheck;
final Type type = exp.getType();
assert type instanceof ScalarType : exp;
this.memberCalcs = memberCalcs;
this.savedMembers = new Member[memberCalcs.length];
this.memberCalc = memberCalc;
}

/**
* Creates a {@link ValueCalc}, {@link MemberValueCalc} or
* {@link MemberArrayValueCalc}.
*
* @param exp Expression
* @param memberCalcs Array of members to evaluate
* @param nullCheck Whether to check for null values due to non-joining
* dimensions in a virtual cube
* @return Compiled expression to evaluate each member expression, set
* evaluator context to each resulting member, then evaluate the current
* context
*/
public static GenericCalc create(
Exp exp,
MemberCalc[] memberCalcs,
boolean nullCheck)
{
switch (memberCalcs.length) {
case 0:
return new ValueCalc(exp);
case 1:
return new MemberValueCalc(exp, memberCalcs[0], nullCheck);
default:
return new MemberArrayValueCalc(exp, memberCalcs, nullCheck);
}
}

public Object evaluate(Evaluator evaluator) {
Member[] members = new Member[memberCalcs.length];
for (int i = 0; i < memberCalcs.length; i++) {
MemberCalc memberCalc = memberCalcs[i];
final Member member = memberCalc.evaluateMember(evaluator);
if (member == null
|| member.isNull())
{
// This method needs to leave the evaluator in the same state
// it found it.
for (int j = 0; j < i; j++) {
evaluator.setContext(savedMembers[j]);
}
return null;
}
savedMembers[i] = evaluator.setContext(member);
members[i] = member;
final int savepoint = evaluator.savepoint();
final Member member = memberCalc.evaluateMember(evaluator);
if (member == null
|| member.isNull())
{
return null;
}
final boolean needToReturnNull =
evaluator.needToReturnNullForUnrelatedDimension(members);
if (needToReturnNull) {
evaluator.setContext(savedMembers);
evaluator.setContext(member);
if (nullCheck
&& evaluator.needToReturnNullForUnrelatedDimension(
new Member[] {member}))
{
evaluator.restore(savepoint);
return null;
}

final Object result = evaluator.evaluateCurrent();
evaluator.setContext(savedMembers);
evaluator.restore(savepoint);
return result;
}

public Calc[] getCalcs() {
return memberCalcs;
return new MemberCalc[] {memberCalc};
}

public boolean dependsOn(Hierarchy hierarchy) {
if (super.dependsOn(hierarchy)) {
return true;
}
for (MemberCalc memberCalc : memberCalcs) {
// If the expression definitely includes the dimension (in this
// case, that means it is a member of that dimension) then we
// do not depend on the dimension. For example, the scalar value of
// [Store].[USA]
// does not depend on [Store].
//
// If the dimensionality of the expression is unknown, then the
// expression MIGHT include the dimension, so to be safe we have to
// say that it depends on the given dimension. For example,
// Dimensions(3).CurrentMember.Parent
// may depend on [Store].
if (memberCalc.getType().usesHierarchy(hierarchy, true)) {
return false;
}
}
return true;
// If the expression definitely includes the dimension (in this
// case, that means it is a member of that dimension) then we
// do not depend on the dimension. For example, the scalar value of
// [Store].[USA]
// does not depend on [Store].
//
// If the dimensionality of the expression is unknown, then the
// expression MIGHT include the dimension, so to be safe we have to
// say that it depends on the given dimension. For example,
// Dimensions(3).CurrentMember.Parent
// may depend on [Store].
return !memberCalc.getType().usesHierarchy(hierarchy, true);
}
}

Expand Down

0 comments on commit 394a83d

Please sign in to comment.