Skip to content

Commit

Permalink
MONDRIAN: [MONDRIAN-918]
Browse files Browse the repository at this point in the history
Adds approxRowCount to AggTable elements and associated classes. Also adds logic to use approxRowCount when supplied instead of issuing a count() query.

Also fixes a very rare race-condition bug where the segment cache might clear an entry between the calls to contains() and get().

Also modifies the visibility of some functions of BatchTestCase for easier testing.

[git-p4: depot-paths = "//open/mondrian/": change = 14429]
  • Loading branch information
lucboudreau committed Jul 6, 2011
1 parent 2a02ece commit 8fd7981
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 28 deletions.
12 changes: 12 additions & 0 deletions src/main/mondrian/olap/Mondrian.xml
Expand Up @@ -1674,10 +1674,22 @@ Revision is $Id$
The Table name of a Specific aggregate table.
</Doc>
</Attribute>
<Attribute name="approxRowCount" required="false">
<Doc>
The estimated number of rows in this aggregation
table. Setting this property improves the
performance of the aggregation optimizer and
prevents it from issuing a 'select count(*)'
query over the aggregation table.
</Doc>
</Attribute>
<Code>
public String getNameAttribute() {
return name;
}
public String getApproxRowCountAttribute() {
return approxRowCount;
}
</Code>
</Element>

Expand Down
26 changes: 14 additions & 12 deletions src/main/mondrian/rolap/agg/SegmentLoader.java
Expand Up @@ -186,19 +186,21 @@ private void loadSegmentsFromCache(
if (SegmentCacheWorker.contains(sh)) {
final SegmentBody sb =
SegmentCacheWorker.get(sh);

// Load the axis keys for this segment
for (int i = 0; i < segment.axes.length; i++) {
Aggregation.Axis axis = segment.axes[i];
axis.loadKeys(
sb.getAxisValueSets()[i],
sb.getNullAxisFlags()[i]);
// Make sure to dereference as the cache might have removed
// the data between calls to contains() and get().
if (sb != null) {
// Load the axis keys for this segment
for (int i = 0; i < segment.axes.length; i++) {
Aggregation.Axis axis = segment.axes[i];
axis.loadKeys(
sb.getAxisValueSets()[i],
sb.getNullAxisFlags()[i]);
}
final SegmentDataset dataSet =
sb.createSegmentDataset(segment);
segment.setData(dataSet, pinnedSegments);
segmentsToRemove.add(segment);
}

final SegmentDataset dataSet =
sb.createSegmentDataset(segment);
segment.setData(dataSet, pinnedSegments);
segmentsToRemove.add(segment);
}
}
groupingSet.getSegments().removeAll(segmentsToRemove);
Expand Down
19 changes: 15 additions & 4 deletions src/main/mondrian/rolap/aggmatcher/AggStar.java
Expand Up @@ -60,9 +60,10 @@ static Logger getLogger() {
public static AggStar makeAggStar(
final RolapStar star,
final JdbcSchema.Table dbTable,
final MessageRecorder msgRecorder)
final MessageRecorder msgRecorder,
final int approxRowCount)
{
AggStar aggStar = new AggStar(star, dbTable);
AggStar aggStar = new AggStar(star, dbTable, approxRowCount);
AggStar.FactTable aggStarFactTable = aggStar.getFactTable();

// 1. load fact count
Expand Down Expand Up @@ -201,9 +202,15 @@ private static void collectLevels(
*/
private final BitKey distinctMeasureBitKey;
private final AggStar.Table.Column[] columns;
private final int approxRowCount;

AggStar(final RolapStar star, final JdbcSchema.Table aggTable) {
AggStar(
final RolapStar star,
final JdbcSchema.Table aggTable,
final int approxRowCount)
{
this.star = star;
this.approxRowCount = approxRowCount;
this.bitKey = BitKey.Factory.makeBitKey(star.getColumnCount());
this.levelBitKey = bitKey.emptyCopy();
this.measureBitKey = bitKey.emptyCopy();
Expand Down Expand Up @@ -1074,7 +1081,7 @@ public int getTotalColumnSize() {
* Get the number of rows in this aggregate table.
*/
public int getNumberOfRows() {
if (numberOfRows == -1) {
if (numberOfRows < 0) {
makeNumberOfRows();
}
return numberOfRows;
Expand Down Expand Up @@ -1297,6 +1304,10 @@ public void print(final PrintWriter pw, final String prefix) {
}

private void makeNumberOfRows() {
if (approxRowCount >= 0) {
numberOfRows = approxRowCount;
return;
}
SqlQuery query = getSqlQuery();
query.addSelect("count(*)", null);
query.addFrom(getRelation(), getName(), false);
Expand Down
8 changes: 5 additions & 3 deletions src/main/mondrian/rolap/aggmatcher/AggTableManager.java
Expand Up @@ -251,6 +251,7 @@ private void loadRolapStarAggregates() throws SQLException {
ExplicitRules.getIncludeByTableDef(name, aggGroups);

boolean makeAggStar = false;
int approxRowCount = Integer.MIN_VALUE;
// Is it handled by the ExplicitRules
if (tableDef != null) {
// load columns
Expand All @@ -260,6 +261,7 @@ private void loadRolapStarAggregates() throws SQLException {
dbFactTable,
dbTable,
msgRecorder);
approxRowCount = tableDef.getApproxRowCount();
}
if (! makeAggStar) {
// Is it handled by the DefaultRules
Expand All @@ -277,16 +279,16 @@ private void loadRolapStarAggregates() throws SQLException {
if (makeAggStar) {
dbTable.setTableUsageType(
JdbcSchema.TableUsageType.AGG);
String alias = null;
dbTable.table = new MondrianDef.Table(
schema,
name,
alias,
null, // null alias
null); // don't know about table hints
AggStar aggStar = AggStar.makeAggStar(
star,
dbTable,
msgRecorder);
msgRecorder,
approxRowCount);
if (aggStar.getSize() > 0) {
star.addAggStar(aggStar);
} else {
Expand Down
25 changes: 22 additions & 3 deletions src/main/mondrian/rolap/aggmatcher/ExplicitRules.java
Expand Up @@ -848,6 +848,7 @@ private static int nextId() {
private Map<String, String> foreignKeyMap;
private List<Level> levels;
private List<Measure> measures;
protected int approxRowCount = Integer.MIN_VALUE;

protected TableDef(
final boolean ignoreCase,
Expand All @@ -863,10 +864,13 @@ protected TableDef(
}

/**
* TODO: This does not seemed to be used anywhere???
* Returns an approximate number of rows in this table.
* A negative value indicates that no estimate is available.
* @return An estimated row count, or a negative value if no
* row count approximation was available.
*/
public int getId() {
return this.id;
public int getApproxRowCount() {
return approxRowCount;
}

/**
Expand Down Expand Up @@ -1221,6 +1225,7 @@ static ExplicitRules.NameTableDef make(
ExplicitRules.NameTableDef name =
new ExplicitRules.NameTableDef(
aggName.getNameAttribute(),
aggName.getApproxRowCountAttribute(),
aggName.isIgnoreCase(),
group);

Expand All @@ -1233,11 +1238,25 @@ static ExplicitRules.NameTableDef make(

public NameTableDef(
final String name,
final String approxRowCount,
final boolean ignoreCase,
final ExplicitRules.Group group)
{
super(ignoreCase, group);
this.name = name;
this.approxRowCount = loadApproxRowCount(approxRowCount);
}

private int loadApproxRowCount(String approxRowCount) {
boolean notNullAndNumeric =
approxRowCount != null
&& approxRowCount.matches("^\\d+$");
if (notNullAndNumeric) {
return Integer.parseInt(approxRowCount);
} else {
// if approxRowCount is not set, return MIN_VALUE to indicate
return Integer.MIN_VALUE;
}
}

/**
Expand Down
38 changes: 32 additions & 6 deletions testsrc/main/mondrian/rolap/BatchTestCase.java
Expand Up @@ -190,9 +190,33 @@ protected GroupingSet getGroupingSet(
* @param requests Sequence of cell requests
* @param patterns Set of patterns
*/
void assertRequestSql(
protected void assertRequestSql(
CellRequest[] requests,
SqlPattern[] patterns)
{
assertRequestSql(requests, patterns, false);
}

/**
* Checks that a given sequence of cell requests results in a
* particular SQL statement being generated.
*
* <p>Always clears the cache before running the requests.
*
* <p>Runs the requests once for each SQL pattern in the current
* dialect. If there are multiple patterns, runs the MDX query multiple
* times, and expects to see each SQL statement appear. If there are no
* patterns in this dialect, the test trivially succeeds.
*
* @param requests Sequence of cell requests
* @param patterns Set of patterns
* @param negative Set to false in order to 'expect' a query or
* true to 'forbid' a query.
*/
protected void assertRequestSql(
CellRequest[] requests,
SqlPattern[] patterns,
boolean negative)
{
final RolapStar star = requests[0].getMeasure().getStar();
final String cubeName = requests[0].getMeasure().getCubeName();
Expand Down Expand Up @@ -247,8 +271,10 @@ void assertRequestSql(
} finally {
RolapUtil.threadHooks.set(null);
}
if (bomb == null) {
if (!negative && bomb == null) {
fail("expected query [" + sql + "] did not occur");
} else if (negative && bomb != null) {
fail("forbidden query [" + sql + "] detected");
}
TestContext.assertEqualsVerbose(
replaceQuotes(sql),
Expand Down Expand Up @@ -492,7 +518,7 @@ private static String replaceQuotes(String s) {
return s;
}

CellRequest createRequest(
protected CellRequest createRequest(
final String cube, final String measure,
final String table, final String column, final String value)
{
Expand All @@ -501,7 +527,7 @@ CellRequest createRequest(
new String[]{table}, new String[]{column}, new String[]{value});
}

CellRequest createRequest(
protected CellRequest createRequest(
final String cube, final String measureName,
final String[] tables, final String[] columns, final String[] values)
{
Expand All @@ -523,7 +549,7 @@ CellRequest createRequest(
return request;
}

CellRequest createRequest(
protected CellRequest createRequest(
final String cube, final String measure,
final String table, final String column, final String value,
CellRequestConstraint aggConstraint)
Expand All @@ -534,7 +560,7 @@ CellRequest createRequest(
aggConstraint);
}

CellRequest createRequest(
protected CellRequest createRequest(
final String cube, final String measureName,
final String[] tables, final String[] columns, final String[] values,
CellRequestConstraint aggConstraint)
Expand Down

0 comments on commit 8fd7981

Please sign in to comment.