/* // $Id: //guest/julian_hyde/mondrian/src/main/mondrian/rolap/RolapAggregationManager.java#1 $ // 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. // (C) Copyright 2001-2002 Kana Software, Inc. and others. // All Rights Reserved. // You must accept the terms of that agreement to use this software. // // jhyde, 30 August, 2001 */ package mondrian.rolap; import mondrian.olap.*; import java.util.Set; import java.util.Vector; import java.util.Hashtable; import java.util.Iterator; import java.util.Enumeration; import java.util.Collection; /** * <code>RolapAggregationManager</code> manages all {@link RolapAggregation}s * in the system. It is a singleton class. * * @author jhyde * @since 30 August, 2001 * @version $Id: //guest/julian_hyde/mondrian/src/main/mondrian/rolap/RolapAggregationManager.java#1 $ **/ public class RolapAggregationManager { private static RolapAggregationManager instance; Vector aggregations; /** RolapStoredMeasure --> RolapStar (currently 1:1, should be m:1) **/ Hashtable mapMeasureToStar = new Hashtable(); RolapAggregationManager() { this.aggregations = new Vector(); this.mapMeasureToStar = new Hashtable(); } /** Returns or creates the singleton. **/ static synchronized RolapAggregationManager instance() { if (instance == null) { instance = new RolapAggregationManager(); } return instance; } void register(RolapCube cube) { Vector v = new Vector(); Member[] measures = cube.getMeasures(); for (int i = 0; i < measures.length; i++) { if (measures[i] instanceof RolapStoredMeasure) { v.addElement(measures[i]); } } RolapStoredMeasure[] storedMeasures = new RolapStoredMeasure[v.size()]; v.copyInto(storedMeasures); // create a star for each measure (todo: pool them) for (int i = 0; i < storedMeasures.length; i++) { RolapStoredMeasure storedMeasure = storedMeasures[i]; RolapStar star = new RolapStar(); star.jdbcConnection = ((RolapConnection) cube.getConnection()).jdbcConnection; Vector tablesVector = new Vector(); // create a fact table star.factTable = new RolapStar.Table(); star.factTable.star = star; star.factTable.alias = cube.getAlias(); star.factTable.sql = cube.factTable; star.factTable.columns = new RolapStar.Column[1]; RolapStar.Measure measure = new RolapStar.Measure(); measure.table = star.factTable; measure.name = storedMeasure.column; measure.aggregator = storedMeasure.aggregator; measure.isNumeric = true; star.factTable.columns[0] = measure; // create dimension tables RolapDimension[] dimensions = (RolapDimension[]) cube.getDimensions(); for (int j = 0; j < dimensions.length; j++) { RolapDimension dimension = dimensions[j]; RolapHierarchy[] hierarchies = (RolapHierarchy[]) dimension.getHierarchies(); for (int k = 0; k < hierarchies.length; k++) { RolapHierarchy hierarchy = hierarchies[k]; // assume there's one 'table' per hierarchy RolapStar.Table table = new RolapStar.Table(); RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels(); table.star = star; table.alias = hierarchy.getAlias(); table.sql = hierarchy.sql; table.primaryKey = hierarchy.primaryKey; HierarchyUsage hierarchyUsage = hierarchy.getUsage(cube.factTable); table.foreignKey = hierarchyUsage.foreignKey; table.columns = new RolapStar.Column[levels.length]; tablesVector.addElement(table); for (int l = 0; l < levels.length; l++) { RolapLevel level = levels[l]; if (level.column == null) { continue; } RolapStar.Column column = new RolapStar.Column(); column.table = table; column.name = level.column; column.isNumeric = (level.flags & RolapLevel.NUMERIC) != 0; table.columns[l] = column; star.mapLevelToColumn.put(level, column); } } } star.tables = new RolapStar.Table[tablesVector.size()]; tablesVector.copyInto(star.tables); mapMeasureToStar.put(storedMeasure, star); } } /** * Looks through a set of requests and loads aggregations * accordingly. * * @param arity The number of dimensions in the cube, and the number of * members in each key. * @param keys A hashtable whose keys are {@link HashableVector}s * which contain {@link RolapMember}s * @param pinned Writes each loaded aggregation into here. The client must * call {@link CachePool#unpin} on this list. **/ void loadAggregations(int arity, Set keySet, Collection pinnedSegments) { RolapMember[] members = new RolapMember[arity]; Hashtable mapColumnSetToBatch = new Hashtable(); for (Iterator keys = keySet.iterator(); keys.hasNext(); ) { HashableVector key = (HashableVector) keys.next(); key.copyInto(members); RolapStar.CellRequest request = makeRequest(members); if (request == null) { continue; // invalid location -- ignore it } HashableVector columnsVector = request.getBatchKey(); Batch batch = (Batch) mapColumnSetToBatch.get(columnsVector); if (batch == null) { batch = new Batch(); mapColumnSetToBatch.put(columnsVector, batch); } batch.requests.addElement(request); } Enumeration batchEnum = mapColumnSetToBatch.elements(); while (batchEnum.hasMoreElements()) { Batch batch = (Batch) batchEnum.nextElement(); Vector requests = batch.requests; RolapStar.CellRequest firstRequest = (RolapStar.CellRequest) requests.elementAt(0); RolapStar.Column[] columns = firstRequest.getColumns(); RolapStar.Measure measure = firstRequest.getMeasure(); Hashtable[] valueSets = new Hashtable[columns.length]; for (int i = 0; i < valueSets.length; i++) { valueSets[i] = new Hashtable(); } for (int i = 0, count = requests.size(); i < count; i++) { RolapStar.CellRequest request = (RolapStar.CellRequest) requests.elementAt(i); for (int j = 0; j < columns.length; j++) { Object value = request.getValuesVector().elementAt(j); Util.assert( !(value instanceof Object[]), "multi-valued key not valid in this cell request"); Hashtable valueSet = valueSets[j]; if (valueSet.get(value) == null) { valueSet.put(value, value); } } } Object[][] constraintses = new Object[columns.length][]; for (int j = 0; j < columns.length; j++) { Object[] constraints; Hashtable valueSet = valueSets[j]; if (valueSet == null) { constraints = null; } else { int i = 0; constraints = new Object[valueSet.size()]; Enumeration values = valueSet.keys(); while (values.hasMoreElements()) { constraints[i++] = values.nextElement(); } } constraintses[j] = constraints; } // todo: optimize key sets; drop a constraint if more than x% of // the members are requested; whether we should get just the cells // requested or expand to a n-cube loadAggregation(measure, columns, constraintses, pinnedSegments); } } void loadAggregation( RolapStar.Measure measure, RolapStar.Column[] columns, Object[][] constraintses, Collection pinnedSegments) { RolapStar star = measure.table.star; RolapAggregation aggregation = lookupAggregation(columns); if (aggregation == null) { aggregation = new RolapAggregation(star, measure, columns); } constraintses = aggregation.optimizeConstraints(constraintses); aggregation.load(constraintses, pinnedSegments); aggregations.addElement(aggregation); } /** * Looks for an existing aggregation over a given set of columns, or * returns <code>null</code> if there is none. **/ private RolapAggregation lookupAggregation(RolapStar.Column[] columns) { outer: for (int i = 0, count = aggregations.size(); i < count; i++) { RolapAggregation aggregation = (RolapAggregation) aggregations.elementAt(i); if (columns.length != aggregation.columns.length) { continue; } for (int j = 0; j < columns.length; j++) { if (columns[j] != aggregation.columns[j]) { continue outer; } } return aggregation; } return null; } /** * Creates a request to evaluate the cell identified by * <code>members</code>. If any of the members is the null member, returns * null, since there is no cell. **/ RolapStar.CellRequest makeRequest(RolapMember[] members) { RolapMeasure measure = (RolapMeasure) members[0]; Util.assert(measure instanceof RolapStoredMeasure); RolapStar star = (RolapStar) mapMeasureToStar.get(measure); Util.assert(star != null); RolapStar.CellRequest request = new RolapStar.CellRequest( (RolapStar.Measure) star.factTable.columns[0]); // yeuck for (int i = 1; i < members.length; i++) { RolapMember member = members[i]; for (RolapMember m = member; m != null; m = (RolapMember) m.getParentMember()) { if (m.key == null) { if (m == m.getHierarchy().getNullMember()) { // cannot form a request if one of the members is null return null; } else if (m.isAll()) { continue; } else { throw Util.getRes().newInternal("why is key null?"); } } RolapLevel level = (RolapLevel) m.getLevel(); RolapStar.Column column = (RolapStar.Column) star.mapLevelToColumn.get(level); if (column == null) { // This hierarchy is not one which qualifies the measure (this happens in // virtual cubes). The measure only has a value for the 'all' member of // the hierarchy (which this is not). return null; } else { request.addConstrainedColumn(column, m.key); } } } return request; } /** * Returns the value of a cell from an existing aggregation. **/ Object getCellFromCache(RolapMember[] members) { RolapStar.CellRequest request = makeRequest(members); if (request == null) { return Util.nullValue; // request out of bounds } RolapAggregation aggregation = lookupAggregation(request.getColumns()); if (aggregation == null) { return null; // cell is not in any aggregation } return aggregation.get(request.getSingleValues()); } /** * If an existing segment contains a cell value, it pins that segment, and * returns the value. Otherwise it returns null. **/ Object getCellFromCache(RolapMember[] members, Set pinSet) { RolapStar.CellRequest request = makeRequest(members); if (request == null) { return Util.nullValue; // request out of bounds } RolapAggregation aggregation = lookupAggregation(request.getColumns()); if (aggregation == null) { return null; // cell is not in any aggregation } return aggregation.getAndPin(request.getSingleValues(), pinSet); } Object getCell(RolapMember[] members) { RolapStar.CellRequest request = makeRequest(members); RolapMeasure measure = (RolapMeasure) members[0]; RolapStar star = (RolapStar) mapMeasureToStar.get(measure); return star.getCell(request); } // ------------------------------------------------------------------------ static class Batch { Vector requests = new Vector(); }; } // End RolapAggregationManager.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 1603 | Julian Hyde |
mondrian: Add Andreas' taglib; Rename 'mondrian.rolap.Util.assert' to 'assertTrue', because 'assert' is a keyword in jdk 1.4; Fix 'NON EMPTY'; JUnit framework for tests; Add Oracle dataset. |
||
#3 | 1576 | Julian Hyde |
mondrian: fix dataset (add column customer.ordinal); create dataset for oracle; get queries working on oracle; get format strings working; refactor out new packages mondrian.rolap.agg and mondrian.rolap.sql. |
||
#2 | 1496 | Julian Hyde |
Mondrian: Qualify table names with schemas. Add 'Hierarchy.schema', 'Cube.factSchema','Hierarchy.table' attributes. MondrianDef is now generated (so we need boot.jar). |
||
#1 | 1453 | Julian Hyde | mondrian: first source check-in |