1 13 package mondrian.rolap.agg; 14 15 import mondrian.olap.*; 16 import mondrian.rolap.*; 17 18 import java.sql.*; 19 import java.util.*; 20 import java.io.PrintWriter ; 21 22 72 class Segment { 73 private static int nextId = 0; 75 final int id; private String desc; 77 final Aggregation aggregation; 78 final RolapStar.Measure measure; 79 80 final Aggregation.Axis[] axes; 81 private SegmentDataset data; 82 private final CellKey cellKey; 84 85 private State state; 86 87 93 private final List<Region> excludedRegions; 94 95 103 Segment( 104 Aggregation aggregation, 105 RolapStar.Measure measure, 106 Aggregation.Axis[] axes, 107 List<Region> excludedRegions) 108 { 109 this.id = nextId++; 110 this.aggregation = aggregation; 111 this.measure = measure; 112 this.axes = axes; 113 this.cellKey = CellKey.Generator.newCellKey(axes.length); 114 this.state = State.Loading; 115 this.excludedRegions = excludedRegions; 116 for (Region region : excludedRegions) { 117 assert region.getPredicates().size() == axes.length; 118 } 119 } 120 121 125 synchronized void setData( 126 SegmentDataset data, 127 RolapAggregationManager.PinSet pinnedSegments) { 128 Util.assertTrue(this.data == null); 129 Util.assertTrue(this.state == State.Loading); 130 131 this.data = data; 132 this.state = State.Ready; 133 notifyAll(); 134 } 135 136 140 synchronized void setFailed() { 141 switch (state) { 142 case Loading: 143 Util.assertTrue(this.data == null); 144 this.state = State.Failed; 145 notifyAll(); 146 break; 147 case Ready: 148 break; 150 default: 151 throw Util.badValue(state); 152 } 153 } 154 155 public boolean isReady() { 156 return (state == State.Ready); 157 } 158 159 private void makeDescription(StringBuilder buf, boolean values) { 160 final String sep = Util.nl + " "; 161 buf.append("Segment #"); 162 buf.append(id); 163 buf.append(" {"); 164 buf.append(sep); 165 buf.append("measure="); 166 buf.append(measure.getAggregator().getExpression( 167 measure.getExpression().getGenericExpression())); 168 169 RolapStar.Column[] columns = aggregation.getColumns(); 170 for (int i = 0; i < columns.length; i++) { 171 buf.append(sep); 172 buf.append(columns[i].getExpression().getGenericExpression()); 173 final Aggregation.Axis axis = axes[i]; 174 axis.getPredicate().describe(buf); 175 if (values) { 176 Object [] keys = axis.getKeys(); 177 buf.append(", values={"); 178 for (int j = 0; j < keys.length; j++) { 179 if (j > 0) { 180 buf.append(", "); 181 } 182 Object key = keys[j]; 183 buf.append(key); 184 } 185 buf.append("}"); 186 } 187 } 188 if (!excludedRegions.isEmpty()) { 189 buf.append(sep); 190 buf.append("excluded={"); 191 int k = 0; 192 for (Region excludedRegion : excludedRegions) { 193 if (k++ > 0) { 194 buf.append(", "); 195 } 196 excludedRegion.describe(buf); 197 } 198 buf.append('}'); 199 } 200 buf.append('}'); 201 } 202 203 public String toString() { 204 if (this.desc == null) { 205 StringBuilder buf = new StringBuilder (64); 206 makeDescription(buf, false); 207 this.desc = buf.toString(); 208 } 209 return this.desc; 210 } 211 212 231 Object getCellValue(Object [] keys) { 232 assert keys.length == axes.length; 233 int missed = 0; 234 for (int i = 0; i < keys.length; i++) { 235 Object key = keys[i]; 236 int offset = axes[i].getOffset(key); 237 if (offset < 0) { 238 if (axes[i].getPredicate().evaluate(key)) { 239 missed++; 241 continue; 242 } else { 243 return null; 246 } 247 } 248 cellKey.setAxis(i, offset); 249 } 250 if (isExcluded(keys)) { 251 return null; 254 } 255 if (missed > 0) { 256 return Util.nullValue; 259 } else { 260 Object o = data.get(cellKey); 261 if (o == null) { 262 o = Util.nullValue; 263 } 264 return o; 265 } 266 } 267 268 272 boolean wouldContain(Object [] keys) { 273 Util.assertTrue(keys.length == axes.length); 274 for (int i = 0; i < keys.length; i++) { 275 Object key = keys[i]; 276 if (!axes[i].getPredicate().evaluate(key)) { 277 return false; 278 } 279 } 280 return !isExcluded(keys); 281 } 282 283 286 private boolean isExcluded(Object [] keys) { 287 for (Region excludedRegion : excludedRegions) { 288 if (excludedRegion.wouldContain(keys)) { 289 return true; 290 } 291 } 292 return false; 293 } 294 295 305 static void load( 306 final Segment[] segments, 307 final BitKey levelBitKey, 308 final BitKey measureBitKey, 309 final RolapAggregationManager.PinSet pinnedSegments, 310 final Aggregation.Axis[] axes) 311 { 312 String sql = AggregationManager.instance().generateSql( 313 segments, 314 levelBitKey, 315 measureBitKey); 316 Segment segment0 = segments[0]; 317 RolapStar star = segment0.aggregation.getStar(); 318 RolapStar.Column[] columns = segment0.aggregation.getColumns(); 319 int arity = columns.length; 320 321 SortedSet<Comparable <?>>[] axisValueSets = new SortedSet[arity]; 323 boolean[] axisContainsNull = new boolean[arity]; 324 for (int i = 0; i < axisValueSets.length; i++) { 325 if (Util.PreJdk15) { 326 assert !(Comparable .class.isAssignableFrom(Boolean .class)); 329 axisValueSets[i] = 330 new TreeSet( 331 new Comparator() { 332 public int compare(Object o1, Object o2) { 333 if (o1 instanceof Boolean ) { 334 Boolean b1 = (Boolean ) o1; 335 if (o2 instanceof Boolean ) { 336 Boolean b2 = (Boolean ) o2; 337 return (b1 == b2 ? 0 : (b1 ? 1 : -1)); 338 } else { 339 return -1; 340 } 341 } else { 342 return ((Comparable ) o1).compareTo(o2); 343 } 344 } 345 } 346 ); 347 } else { 348 assert Comparable .class.isAssignableFrom(Boolean .class); 349 axisValueSets[i] = new TreeSet<Comparable <?>>(); 350 } 351 } 352 353 SqlStatement stmt = 355 RolapUtil.executeQuery( 356 star.getDataSource(), sql, "Segment.load", 357 "Error while loading segment"); 358 final int measureCount = segments.length; 359 try { 360 List<Object []> rows = new ArrayList<Object []>(); 361 ResultSet resultSet = stmt.getResultSet(); 362 while (resultSet.next()) { 363 ++stmt.rowCount; 364 Object [] row = new Object [arity + measureCount]; 365 int k = 1; 367 for (int i = 0; i < arity; i++) { 368 Object o = resultSet.getObject(k++); 369 if (o == null) { 370 o = RolapUtil.sqlNullValue; 371 axisContainsNull[i] = true; 372 } else { 373 axisValueSets[i].add(Aggregation.Axis.wrap(o)); 374 } 375 row[i] = o; 376 } 377 for (int i = 0; i < measureCount; i++) { 379 Object o = resultSet.getObject(k++); 380 if (o == null) { 381 o = Util.nullValue; } else if (segments[i].measure.getDatatype().isNumeric()) { 383 if (o instanceof Double ) { 384 } else if (o instanceof Number ) { 386 o = ((Number ) o).doubleValue(); 387 } else if (o instanceof byte[]) { 388 o = Double.parseDouble(new String ((byte []) o)); 391 } else { 392 o = Double.parseDouble(o.toString()); 393 } 394 } 395 row[arity + i] = o; 396 } 397 rows.add(row); 398 } 399 400 boolean sparse = false; 403 int n = 1; 404 for (int i = 0; i < arity; i++) { 405 Aggregation.Axis axis = axes[i]; 406 SortedSet<Comparable <?>> valueSet = axisValueSets[i]; 407 int size = axis.loadKeys(valueSet, axisContainsNull[i]); 408 409 int previous = n; 410 n *= size; 411 if ((n < previous) || (n < size)) { 412 n = Integer.MAX_VALUE; 414 sparse = true; 415 } 416 } 417 sparse = sparse || useSparse((double) n, (double) rows.size()); 418 419 final SegmentDataset[] dataSets; 420 final SparseSegmentDataset[] sparseDatasets; 421 final DenseSegmentDataset[] denseDatasets; 422 if (sparse) { 423 sparseDatasets = new SparseSegmentDataset[segments.length]; 424 dataSets = sparseDatasets; 425 denseDatasets = null; 426 } else { 427 denseDatasets = new DenseSegmentDataset[segments.length]; 428 dataSets = denseDatasets; 429 sparseDatasets = null; 430 } 431 432 if (sparse) { 433 for (int i = 0; i < segments.length; i++) { 434 sparseDatasets[i] = new SparseSegmentDataset(segments[i]); 435 } 436 } else { 437 for (int i = 0; i < segments.length; i++) { 438 denseDatasets[i] = new DenseSegmentDataset( 439 segments[i], new Object [n]); 440 } 441 } 442 int[] pos = new int[arity]; 444 for (int i = 0, count = rows.size(); i < count; i++) { 445 Object [] row = rows.get(i); 446 int k = 0; 447 for (int j = 0; j < arity; j++) { 448 k *= axes[j].getKeys().length; 449 Object o = row[j]; 450 Aggregation.Axis axis = axes[j]; 451 int offset = axis.getOffset(o); 452 pos[j] = offset; 453 k += offset; 454 } 455 CellKey key; 456 if (sparse) { 457 key = CellKey.Generator.newCellKey(pos); 458 for (int j = 0; j < segments.length; j++) { 459 final Object o = row[arity + j]; 460 sparseDatasets[j].put(key, o); 461 } 462 } else { 463 for (int j = 0; j < segments.length; j++) { 464 final Object o = row[arity + j]; 465 denseDatasets[j].set(k, o); 466 } 467 } 468 } 469 470 for (int i = 0; i < segments.length; i++) { 471 segments[i].setData(dataSets[i], pinnedSegments); 472 } 473 474 } catch (SQLException e) { 475 throw stmt.handle(e); 476 } finally { 477 stmt.close(); 478 for (Segment segment : segments) { 480 segment.setFailed(); 481 } 482 } 483 } 484 485 494 private static boolean useSparse( 495 final double possibleCount, 496 final double actualCount) { 497 final MondrianProperties properties = MondrianProperties.instance(); 498 double densityThreshold = properties.SparseSegmentDensityThreshold.get(); 499 if (densityThreshold < 0) { 500 densityThreshold = 0; 501 } 502 if (densityThreshold > 1) { 503 densityThreshold = 1; 504 } 505 int countThreshold = properties.SparseSegmentCountThreshold.get(); 506 if (countThreshold < 0) { 507 countThreshold = 0; 508 } 509 boolean sparse = 510 (possibleCount - countThreshold) * densityThreshold > actualCount; 511 if (possibleCount < countThreshold) { 512 assert !sparse : 513 "Should never use sparse if count is less " + 514 "than threshold, possibleCount=" + possibleCount + 515 ", actualCount=" + actualCount + 516 ", countThreshold=" + countThreshold + 517 ", densityThreshold=" + densityThreshold; 518 } 519 if (possibleCount == actualCount) { 520 assert !sparse : 521 "Should never use sparse if result is 100% dense: " + 522 "possibleCount=" + possibleCount + 523 ", actualCount=" + actualCount + 524 ", countThreshold=" + countThreshold + 525 ", densityThreshold=" + densityThreshold; 526 } 527 return sparse; 528 } 529 530 534 public synchronized void waitUntilLoaded() { 535 if (!isReady()) { 536 try { 537 wait(); 538 } catch (InterruptedException e) { 539 } 540 switch (state) { 541 case Ready: 542 return; case Failed: 544 throw Util.newError("Pending segment failed to load: " 545 + toString()); 546 default: 547 throw Util.badValue(state); 548 } 549 } 550 } 551 552 558 public void print(PrintWriter pw) { 559 final StringBuilder buf = new StringBuilder (); 560 makeDescription(buf, true); 561 pw.print(buf.toString()); 562 pw.println(); 563 } 564 565 public List<Region> getExcludedRegions() { 566 return excludedRegions; 567 } 568 569 580 public int getCellCount() { 581 int cellCount = 1; 582 for (Aggregation.Axis axis : axes) { 583 cellCount *= axis.getKeys().length; 584 } 585 for (Region excludedRegion : excludedRegions) { 586 cellCount -= excludedRegion.cellCount; 587 } 588 return cellCount; 589 } 590 591 605 Segment createSubSegment( 606 BitSet[] axisKeepBitSets, 607 int bestColumn, 608 StarColumnPredicate bestPredicate, 609 List<Segment.Region> excludedRegions) { 610 assert axisKeepBitSets.length == axes.length; 611 612 final Aggregation.Axis[] newAxes = axes.clone(); 616 617 final Map<Integer ,Integer >[] axisPosMaps = new Map[axes.length]; 619 620 int valueCount = 1; 621 for (int j = 0; j < axes.length; j++) { 622 Aggregation.Axis axis = axes[j]; 623 StarColumnPredicate newPredicate = axis.getPredicate(); 624 if (j == bestColumn) { 625 newPredicate = bestPredicate; 626 } 627 final Comparable <?>[] axisKeys = axis.getKeys(); 628 BitSet keepBitSet = axisKeepBitSets[j]; 629 int firstClearBit = keepBitSet.nextClearBit(0); 630 Comparable <?>[] newAxisKeys; 631 if (firstClearBit >= axisKeys.length) { 632 newAxisKeys = axisKeys; 634 axisPosMaps[j] = null; } else { 636 List<Object > newAxisKeyList = new ArrayList<Object >(); 637 Map<Integer , Integer > map 638 = axisPosMaps[j] 639 = new HashMap<Integer , Integer >(); 640 for (int bit = keepBitSet.nextSetBit(0); 641 bit >= 0; 642 bit = keepBitSet.nextSetBit(bit + 1)) { 643 map.put(bit, newAxisKeyList.size()); 644 newAxisKeyList.add(axisKeys[bit]); 645 } 646 newAxisKeys = 647 newAxisKeyList.toArray( 648 new Comparable <?>[newAxisKeyList.size()]); 649 assert newAxisKeys.length > 0; 650 } 651 final Aggregation.Axis newAxis = 652 new Aggregation.Axis(newPredicate, newAxisKeys); 653 newAxes[j] = newAxis; 654 valueCount *= newAxisKeys.length; 655 } 656 657 final Segment newSegment = 659 new Segment(aggregation, measure, newAxes, excludedRegions); 660 661 SegmentDataset newData; 667 if (data instanceof SparseSegmentDataset) { 668 newData = 669 new SparseSegmentDataset( 670 newSegment); 671 } else { 672 Object [] newValues = new Object [valueCount]; 673 newData = 674 new DenseSegmentDataset( 675 newSegment, 676 newValues); 677 } 678 679 int[] pos = new int[axes.length]; 682 CellKey newKey = CellKey.Generator.newRefCellKey(pos); 683 data: 684 for (Map.Entry<CellKey, Object > entry : data) { 685 CellKey key = entry.getKey(); 686 687 for (int i = 0; i < pos.length; i++) { 691 int ordinal = key.getAxis(i); 692 693 Map<Integer , Integer > axisPosMap = axisPosMaps[i]; 694 if (axisPosMap == null) { 695 pos[i] = ordinal; 696 } else { 697 Integer integer = axisPosMap.get(ordinal); 698 if (integer == null) { 699 continue data; 700 } 701 pos[i] = integer; 702 } 703 } 704 newData.put(newKey, entry.getValue()); 705 } 706 newSegment.setData(newData, null); 707 708 return newSegment; 709 } 710 711 715 SegmentDataset getData() { 716 return data; 717 } 718 719 723 private static enum State { 724 Initial, Loading, Ready, Failed 725 } 726 727 753 static class Region { 754 private final StarColumnPredicate[] predicates; 755 private final StarPredicate[] multiColumnPredicates; 756 private final int cellCount; 757 758 Region( 759 List<StarColumnPredicate> predicateList, 760 List<StarPredicate> multiColumnPredicateList, 761 int cellCount) 762 { 763 this.predicates = 764 predicateList.toArray( 765 new StarColumnPredicate[predicateList.size()]); 766 this.multiColumnPredicates = 767 multiColumnPredicateList.toArray( 768 new StarPredicate[multiColumnPredicateList.size()]); 769 this.cellCount = cellCount; 770 } 771 772 public List<StarColumnPredicate> getPredicates() { 773 return Collections.unmodifiableList(Arrays.asList(predicates)); 774 } 775 776 public List<StarPredicate> getMultiColumnPredicates() { 777 return Collections.unmodifiableList( 778 Arrays.asList(multiColumnPredicates)); 779 } 780 781 public int getCellCount() { 782 return cellCount; 783 } 784 785 public boolean wouldContain(Object [] keys) { 786 assert keys.length == predicates.length; 787 for (int i = 0; i < keys.length; i++) { 788 final Object key = keys[i]; 789 final StarColumnPredicate predicate = predicates[i]; 790 if (!predicate.evaluate(key)) { 791 return false; 792 } 793 } 794 return true; 795 } 796 797 public boolean equals(Object obj) { 798 if (obj instanceof Region) { 799 Region that = (Region) obj; 800 return Arrays.equals( 801 this.predicates, that.predicates) && 802 Arrays.equals( 803 this.multiColumnPredicates, 804 that.multiColumnPredicates); 805 } else { 806 return false; 807 } 808 } 809 810 public int hashCode() { 811 return Arrays.hashCode(multiColumnPredicates) ^ 812 Arrays.hashCode(predicates); 813 } 814 815 819 public void describe(StringBuilder buf) { 820 int k = 0; 821 for (StarColumnPredicate predicate : predicates) { 822 if (predicate instanceof LiteralStarPredicate && 823 ((LiteralStarPredicate) predicate).getValue()) { 824 continue; 825 } 826 if (k++ > 0) { 827 buf.append(" AND "); 828 } 829 predicate.describe(buf); 830 } 831 for (StarPredicate predicate : multiColumnPredicates) { 832 if (predicate instanceof LiteralStarPredicate && 833 ((LiteralStarPredicate) predicate).getValue()) { 834 continue; 835 } 836 if (k++ > 0) { 837 buf.append(" AND "); 838 } 839 predicate.describe(buf); 840 } 841 } 842 } 843 } 844 845 | Popular Tags |