1 13 14 package mondrian.rolap.agg; 15 16 import mondrian.olap.*; 17 import mondrian.rolap.*; 18 19 import java.lang.ref.SoftReference ; 20 import java.util.*; 21 import java.io.PrintWriter ; 22 23 58 public class Aggregation { 59 private int maxConstraints; 60 61 private final RolapStar star; 62 63 67 private final BitKey constrainedColumnsBitKey; 68 69 73 private final List<SoftReference <Segment>> segmentRefs; 74 75 76 81 private final Date creationTimestamp; 82 83 90 private RolapStar.Column[] columns; 91 92 99 public Aggregation( 100 RolapStar star, 101 BitKey constrainedColumnsBitKey) 102 { 103 this.star = star; 104 this.constrainedColumnsBitKey = constrainedColumnsBitKey; 105 this.segmentRefs = new ArrayList<SoftReference <Segment>>(); 106 this.maxConstraints = 107 MondrianProperties.instance().MaxConstraints.get(); 108 this.creationTimestamp = new Date(); 109 } 110 111 114 public Date getCreationTimestamp() { 115 return creationTimestamp; 116 } 117 118 131 public synchronized void load( 132 RolapStar.Column[] columns, 133 RolapStar.Measure[] measures, 134 StarColumnPredicate[] predicates, 135 RolapAggregationManager.PinSet pinnedSegments) { 136 this.columns = columns; 138 139 BitKey measureBitKey = constrainedColumnsBitKey.emptyCopy(); 140 int axisCount = columns.length; 141 Util.assertTrue(predicates.length == axisCount); 142 143 Aggregation.Axis[] axes = new Aggregation.Axis[axisCount]; 146 for (int i = 0; i < axisCount; i++) { 147 axes[i] = new Aggregation.Axis(predicates[i]); 148 } 149 150 Segment[] segments = new Segment[measures.length]; 151 for (int i = 0; i < measures.length; i++) { 152 RolapStar.Measure measure = measures[i]; 153 measureBitKey.set(measure.getBitPosition()); 154 List<Segment.Region> excludedRegions = Collections.emptyList(); 155 Segment segment = 156 new Segment(this, measure, axes, excludedRegions); 157 segments[i] = segment; 158 SoftReference <Segment> ref = new SoftReference <Segment>(segment); 159 segmentRefs.add(ref); 160 ((AggregationManager.PinSetImpl) pinnedSegments).add(segment); 161 } 162 BitKey levelBitKey = constrainedColumnsBitKey; 164 Segment.load( 165 segments, levelBitKey, 166 measureBitKey, pinnedSegments, axes); 167 } 168 169 173 public synchronized StarColumnPredicate[] optimizePredicates( 174 RolapStar.Column[] columns, 175 StarColumnPredicate[] predicates) { 176 177 Util.assertTrue(predicates.length == columns.length); 178 StarColumnPredicate[] newPredicates = predicates.clone(); 179 double[] bloats = new double[columns.length]; 180 181 List<Member> potentialParents = new ArrayList<Member>(); 185 for (final StarColumnPredicate predicate : predicates) { 186 Member m; 187 if (predicate instanceof MemberColumnPredicate) { 188 m = ((MemberColumnPredicate) predicate).getMember(); 189 potentialParents.add(m); 190 } 191 } 192 193 for (int i = 0; i < newPredicates.length; i++) { 194 if (!(newPredicates[i] instanceof ListColumnPredicate)) { 196 bloats[i] = 0.0; 197 continue; 198 } 199 200 final ListColumnPredicate newPredicate = 201 (ListColumnPredicate) newPredicates[i]; 202 final List<StarColumnPredicate> predicateList = 203 newPredicate.getPredicates(); 204 final int valueCount = predicateList.size(); 205 if (valueCount < 2) { 206 bloats[i] = 0.0; 207 continue; 208 } 209 210 if (valueCount > maxConstraints) { 211 bloats[i] = 1.0; continue; 217 } 218 219 double constraintLength = (double) valueCount; 221 Member parent = null; 222 Level level = null; 223 for (int j = 0; j < valueCount; j++) { 224 Object value = predicateList.get(j); 225 if (value instanceof MemberColumnPredicate) { 226 MemberColumnPredicate memberColumnPredicate = 227 (MemberColumnPredicate) value; 228 Member m = memberColumnPredicate.getMember(); 229 if (j == 0) { 230 parent = m.getParentMember(); 231 level = m.getLevel(); 232 } else { 233 if (parent != null 234 && !parent.equals(m.getParentMember())) { 235 parent = null; } 237 if (level != null 238 && !level.equals(m.getLevel())) { 239 level = null; 241 } 242 } 243 } else { 244 parent = null; 247 level = null; 248 bloats[i] = constraintLength / columns[i].getCardinality(); 249 break; 250 } 251 } 252 boolean done = false; 253 if (parent != null) { 254 if (parent.isAll() || potentialParents.contains(parent) ) { 256 SchemaReader scr = star.getSchema().getSchemaReader(); 263 int childCount = scr.getChildrenCountFromCache(parent); 264 if (childCount == -1) { 265 if (!parent.isAll()) { 267 bloats[i] = 0.0; 271 done = true; 272 } 273 } else { 274 bloats[i] = constraintLength / childCount; 275 done = true; 276 } 277 } 278 } 279 280 if (!done && level != null) { 281 SchemaReader scr = star.getSchema().getSchemaReader(); 283 int memberCount = scr.getLevelCardinality(level, true, false); 284 if (memberCount > 0) { 285 bloats[i] = constraintLength / memberCount; 286 done = true; 287 } 288 } 289 290 if (!done) { 291 bloats[i] = constraintLength / columns[i].getCardinality(); 292 } 293 } 294 295 ConstraintComparator comparator = new ConstraintComparator(bloats); 297 Integer [] indexes = new Integer [columns.length]; 298 for (int i = 0; i < columns.length; i++) { 299 indexes[i] = i; 300 } 301 302 Arrays.sort(indexes, comparator); 304 305 311 double abloat = 1.0; 312 final double aBloatLimit = 0.5; 313 for (Integer j : indexes) { 314 abloat = abloat * bloats[j]; 315 if (abloat <= aBloatLimit) { 316 break; 317 } 318 newPredicates[j] = new LiteralStarPredicate(columns[j], true); 320 } 321 return newPredicates; 322 } 323 324 public String toString() { 325 java.io.StringWriter sw = new java.io.StringWriter (256); 326 PrintWriter pw = new PrintWriter (sw); 327 print(pw); 328 pw.flush(); 329 return sw.toString(); 330 } 331 332 336 public void print(PrintWriter pw) { 337 List<Segment> segmentList = new ArrayList<Segment>(); 338 for (SoftReference <Segment> ref : segmentRefs) { 339 Segment segment = ref.get(); 340 if (segment == null) { 341 continue; 342 } 343 segmentList.add(segment); 344 } 345 346 Collections.sort( 348 segmentList, 349 new Comparator<Segment>() { 350 public int compare(Segment o1, Segment o2) { 351 return o1.id - o2.id; 352 } 353 }); 354 355 for (Segment segment : segmentList) { 356 segment.print(pw); 357 } 358 } 359 360 public void flush( 361 CacheControl cacheControl, 362 RolapCacheRegion cacheRegion) 363 { 364 final boolean bitmapsIntersect = 391 cacheRegion.getConstrainedColumnsBitKey().intersects( 392 constrainedColumnsBitKey); 393 394 List<SoftReference <Segment>> newSegmentRefs = 396 new ArrayList<SoftReference <Segment>>(); 397 segmentLoop: 398 for (SoftReference <Segment> segmentRef : segmentRefs) { 399 Segment segment = segmentRef.get(); 400 if (segment == null) { 401 cacheControl.trace("discarding garbage collected segment"); 403 continue; 404 } 405 if (!bitmapsIntersect) { 406 cacheControl.trace( 410 "discard segment - it has no columns in common: " + 411 segment); 412 continue; 413 } 414 415 BitSet[] axisKeepBitSets = new BitSet[columns.length]; 418 for (int i = 0; i < columns.length; i++) { 419 final Axis axis = segment.axes[i]; 420 int keyCount = axis.getKeys().length; 421 final BitSet axisKeepBitSet 422 = axisKeepBitSets[i] 423 = new BitSet(keyCount); 424 final StarColumnPredicate predicate = axis.predicate; 425 assert predicate != null; 426 427 RolapStar.Column column = columns[i]; 428 if (!cacheRegion.getConstrainedColumnsBitKey().get( 429 column.getBitPosition())) { 430 axisKeepBitSet.set(0, keyCount); 431 continue; 432 } 433 StarColumnPredicate flushPredicate = 434 cacheRegion.getPredicate(column.getBitPosition()); 435 436 if (flushPredicate == null) { 439 axisKeepBitSet.set(0, keyCount); 440 continue; 441 } 442 443 if (!flushPredicate.mightIntersect(predicate)) { 449 newSegmentRefs.add(segmentRef); 450 continue segmentLoop; 451 } 452 453 final Object [] axisKeys = axis.getKeys(); 475 for (int k = 0; k < axisKeys.length; k++) { 476 Object key = axisKeys[k]; 477 if (!flushPredicate.evaluate(key)) { 478 axisKeepBitSet.set(k); 479 } 480 } 481 } 482 483 for (StarPredicate predicate : cacheRegion.getPredicates()) { 486 ValuePruner pruner = 487 new ValuePruner( 488 predicate, 489 segment.axes, 490 segment.getData()); 491 pruner.go(axisKeepBitSets); 492 } 493 494 float bestRetention = 0f; 496 int bestColumn = -1; 497 for (int i = 0; i < columns.length; i++) { 498 RolapStar.Column column = columns[i]; 504 final int bitPosition = column.getBitPosition(); 505 if (!cacheRegion.getConstrainedColumnsBitKey().get(bitPosition)) { 506 continue; 507 } 508 509 final BitSet axisBitSet = axisKeepBitSets[i]; 510 final Axis axis = segment.axes[i]; 511 final Object [] axisKeys = axis.getKeys(); 512 513 if (axisBitSet.cardinality() == 0) { 514 continue segmentLoop; 517 } 518 519 float retention = 520 (float) axisBitSet.cardinality() / 521 (float) axisKeys.length; 522 523 if (bestColumn == -1 || retention > bestRetention) { 524 bestRetention = retention; 528 bestColumn = i; 529 } 530 } 531 532 List<StarColumnPredicate> regionPredicates = 534 new ArrayList<StarColumnPredicate>(); 535 int cellCount = 1; 536 for (int i = 0; i < this.columns.length; i++) { 537 RolapStar.Column column = this.columns[i]; 538 Axis axis = segment.axes[i]; 539 final int pos = column.getBitPosition(); 540 StarColumnPredicate flushPredicate = 541 cacheRegion.getPredicate(pos); 542 int keysMatched; 543 if (flushPredicate == null) { 544 flushPredicate = LiteralStarPredicate.TRUE; 545 keysMatched = axis.getKeys().length; 546 } else { 547 keysMatched = axis.getMatchCount(flushPredicate); 548 } 549 cellCount *= keysMatched; 550 regionPredicates.add(flushPredicate); 551 } 552 553 for (StarPredicate p : cacheRegion.getPredicates()) { 557 cellCount *= .5; 558 } 559 Segment.Region region = 560 new Segment.Region( 561 regionPredicates, 562 new ArrayList<StarPredicate>(cacheRegion.getPredicates()), 563 cellCount); 564 565 int remainingCellCount = segment.getCellCount(); 570 if (remainingCellCount - cellCount <= 0) { 571 continue; 572 } 573 574 final List<Segment.Region> excludedRegions = 580 new ArrayList<Segment.Region>(segment.getExcludedRegions()); 581 if (!excludedRegions.contains(region)) { 582 excludedRegions.add(region); 583 } 584 585 StarColumnPredicate bestColumnPredicate; 586 if (bestColumn >= 0) { 587 RolapStar.Column column = columns[bestColumn]; 589 final int bitPosition = column.getBitPosition(); 590 StarColumnPredicate flushPredicate = 591 cacheRegion.getPredicate(bitPosition); 592 final Axis axis = segment.axes[bestColumn]; 593 bestColumnPredicate = axis.predicate; 594 if (flushPredicate != null) { 595 bestColumnPredicate = 596 bestColumnPredicate.minus(flushPredicate); 597 } 598 } else { 599 bestColumnPredicate = null; 600 } 601 602 final Segment newSegment = 603 segment.createSubSegment( 604 axisKeepBitSets, 605 bestColumn, 606 bestColumnPredicate, 607 excludedRegions); 608 609 newSegmentRefs.add(new SoftReference <Segment>(newSegment)); 610 } 611 612 segmentRefs.clear(); 616 segmentRefs.addAll(newSegmentRefs); 617 } 618 619 631 public synchronized Object getCellValue( 632 RolapStar.Measure measure, 633 Object [] keys, 634 RolapAggregationManager.PinSet pinSet) 635 { 636 for (Iterator<SoftReference <Segment>> it = segmentRefs.iterator(); it.hasNext();) { 637 SoftReference <Segment> ref = it.next(); 638 Segment segment = ref.get(); 639 if (segment == null) { 640 it.remove(); 641 continue; } 643 if (segment.measure != measure) { 644 continue; 645 } 646 if (segment.isReady()) { 647 Object o = segment.getCellValue(keys); 648 if (o != null) { 649 if (pinSet != null) { 650 ((AggregationManager.PinSetImpl) pinSet).add(segment); 651 } 652 return o; 653 } 654 } else { 655 if (pinSet != null 657 && !((AggregationManager.PinSetImpl) pinSet).contains(segment) 658 && segment.wouldContain(keys)) 659 { 660 ((AggregationManager.PinSetImpl) pinSet).add(segment); 661 } 662 } 663 } 664 return null; 666 } 667 668 671 public RolapStar.Column[] getColumns() { 672 return columns; 673 } 674 675 678 public RolapStar getStar() { 679 return star; 680 } 681 682 686 public BitKey getConstrainedColumnsBitKey() { 687 return constrainedColumnsBitKey; 688 } 689 690 692 static class Axis { 693 694 697 private final StarColumnPredicate predicate; 698 699 705 private final Map<Comparable <?>, Integer > mapKeyToOffset = 706 new HashMap<Comparable <?>, Integer >(); 707 708 711 private Comparable <?>[] keys; 712 private boolean hasNull; 713 714 721 Axis(StarColumnPredicate predicate) { 722 this.predicate = predicate; 723 assert predicate != null; 724 } 725 726 734 Axis(StarColumnPredicate predicate, Comparable <?>[] keys) { 735 this(predicate); 736 this.keys = keys; 737 for (int i = 0; i < keys.length; i++) { 738 Comparable <?> key = keys[i]; 739 mapKeyToOffset.put(key, i); 740 assert i == 0 || 741 ((Comparable ) keys[i - 1]).compareTo(keys[i]) < 0; 742 } 743 } 744 745 StarColumnPredicate getPredicate() { 746 return predicate; 747 } 748 749 Comparable <?>[] getKeys() { 750 return this.keys; 751 } 752 753 761 int loadKeys(SortedSet<Comparable <?>> valueSet, boolean hasNull) { 762 this.hasNull = hasNull; 763 int size = valueSet.size(); 764 this.keys = valueSet.toArray(new Comparable <?>[size]); 765 for (int i = 0; i < size; i++) { 766 mapKeyToOffset.put(keys[i], i); 767 } 768 if (hasNull) { 769 mapKeyToOffset.put(RolapUtil.sqlNullValue, size); 770 ++size; 771 } 772 return size; 773 } 774 775 static final Comparable wrap(Object o) { 776 if (Util.PreJdk15 && o instanceof Boolean ) { 777 return Integer.valueOf((Boolean ) o ? 1 : 0); 778 } else { 779 return (Comparable ) o; 780 } 781 } 782 783 final int getOffset(Object o) { 784 return getOffset(wrap(o)); 785 } 786 787 final int getOffset(Comparable key) { 788 Integer ordinal = mapKeyToOffset.get(key); 789 if (ordinal == null) { 790 return -1; 791 } 792 return ordinal.intValue(); 793 } 794 795 805 boolean contains(Object key) { 806 return predicate.evaluate(key); 807 } 808 809 815 public int getMatchCount(StarColumnPredicate predicate) { 816 int matchCount = 0; 817 for (Object key : keys) { 818 if (predicate.evaluate(key)) { 819 ++matchCount; 820 } 821 } 822 return matchCount; 823 } 824 } 825 826 852 private class ValuePruner { 853 858 private final StarPredicate flushPredicate; 859 860 private final int arity; 861 865 private final Axis[] axes; 866 870 private final BitSet[] keepBitSets; 871 875 private final int[] axisInverseOrdinals; 876 879 private final Object [] values; 880 883 private final List<Object > valueList; 884 888 private final int[] ordinals; 889 890 private final SegmentDataset data; 891 892 private final CellKey cellKey; 893 894 903 ValuePruner( 904 StarPredicate flushPredicate, 905 Axis[] segmentAxes, 906 SegmentDataset data) 907 { 908 this.flushPredicate = flushPredicate; 909 this.arity = flushPredicate.getConstrainedColumnList().size(); 910 this.axes = new Axis[arity]; 911 this.keepBitSets = new BitSet[arity]; 912 this.axisInverseOrdinals = new int[segmentAxes.length]; 913 Arrays.fill(axisInverseOrdinals, -1); 914 this.values = new Object [arity]; 915 this.valueList = Arrays.asList(values); 916 this.ordinals = new int[arity]; 917 assert data != null; 918 this.data = data; 919 this.cellKey = CellKey.Generator.newCellKey(segmentAxes.length); 920 921 for (int i = 0; i < arity; i++) { 926 RolapStar.Column column = 927 flushPredicate.getConstrainedColumnList().get(i); 928 int axisOrdinal = 929 findAxis(segmentAxes, column.getBitPosition()); 930 if (axisOrdinal < 0) { 931 this.axes[i] = null; 932 values[i] = StarPredicate.WILDCARD; 933 keepBitSets[i] = new BitSet(1); } else { 935 axes[i] = segmentAxes[axisOrdinal]; 936 axisInverseOrdinals[axisOrdinal] = i; 937 final int keyCount = axes[i].getKeys().length; 938 keepBitSets[i] = new BitSet(keyCount); 939 } 940 } 941 } 942 943 private int findAxis(Axis[] axes, int bitPosition) { 944 for (int i = 0; i < axes.length; i++) { 945 Axis axis = axes[i]; 946 if (axis.getPredicate().getConstrainedColumn().getBitPosition() 947 == bitPosition) { 948 return i; 949 } 950 } 951 return -1; 952 } 953 954 961 void go(BitSet[] axisKeepBitSets) 962 { 963 evaluatePredicate(0); 964 965 for (int i = 0; i < axisKeepBitSets.length; i++) { 969 if (axisInverseOrdinals[i] < 0) { 970 continue; 971 } 972 BitSet axisKeepBitSet = axisKeepBitSets[axisInverseOrdinals[i]]; 973 final BitSet keepBitSet = keepBitSets[i]; 974 axisKeepBitSet.and(keepBitSet); 975 } 976 } 977 978 987 private void evaluatePredicate(int axisOrdinal) 988 { 989 if (axisOrdinal == arity) { 990 if (!flushPredicate.evaluate(valueList)) { 999 if (data.get(cellKey) != null) { 1000 for (int k = 0; k < arity; k++) { 1001 keepBitSets[k].set(ordinals[k]); 1002 } 1003 } 1004 } 1005 } else { 1006 final Axis axis = axes[axisOrdinal]; 1007 if (axis == null) { 1008 evaluatePredicate(axisOrdinal + 1); 1009 } else { 1010 for (int keyOrdinal = 0; keyOrdinal < axis.keys.length; keyOrdinal++) { 1011 Object key = axis.keys[keyOrdinal]; 1012 values[axisOrdinal] = key; 1013 ordinals[axisOrdinal] = keyOrdinal; 1014 cellKey.setAxis( 1015 axisInverseOrdinals[axisOrdinal], 1016 keyOrdinal); 1017 evaluatePredicate(axisOrdinal + 1); 1018 } 1019 } 1020 } 1021 } 1022 } 1023 1024 private class ConstraintComparator implements Comparator<Integer > { 1025 private final double[] bloats; 1026 1027 ConstraintComparator(double[] bloats) { 1028 this.bloats = bloats; 1029 } 1030 1031 public int compare(Integer o0, Integer o1) { 1034 double bloat0 = bloats[o0]; 1035 double bloat1 = bloats[o1]; 1036 return (bloat0 == bloat1) 1037 ? 0 1038 : (bloat0 < bloat1) 1039 ? 1 1040 : -1; 1041 } 1042 } 1043 1044 1045} 1046 1047 | Popular Tags |