/** * Makes a quick request to the aggregation manager to see whether the cell value required by a * particular cell request is in external cache. * * <p>'Quick' is relative. It is an asynchronous request (due to the aggregation manager being an * actor) and therefore somewhat slow. If the segment is in cache, will save batching up future * requests and re-executing the query. Win should be particularly noticeable for queries running * on a populated cache. Without this feature, every query would require at least two iterations. * * <p>Request does not issue SQL to populate the segment. Nor does it try to find existing * segments for rollup. Those operations can wait until next phase. * * <p>Client is responsible for adding the segment to its private cache. * * @param request Cell request * @return Segment with data, or null if not in cache */ public SegmentWithData peek(final CellRequest request) { final SegmentCacheManager.PeekResponse response = execute(new PeekCommand(request, Locus.peek())); for (SegmentHeader header : response.headerMap.keySet()) { final SegmentBody body = compositeCache.get(header); if (body != null) { final SegmentBuilder.SegmentConverter converter = response.converterMap.get(SegmentCacheIndexImpl.makeConverterKey(header)); if (converter != null) { return converter.convert(header, body); } } } for (Map.Entry<SegmentHeader, Future<SegmentBody>> entry : response.headerMap.entrySet()) { final Future<SegmentBody> bodyFuture = entry.getValue(); if (bodyFuture != null) { final SegmentBody body = Util.safeGet(bodyFuture, "Waiting for segment to load"); final SegmentHeader header = entry.getKey(); final SegmentBuilder.SegmentConverter converter = response.converterMap.get(SegmentCacheIndexImpl.makeConverterKey(header)); if (converter != null) { return converter.convert(header, body); } } } return null; }
public PeekResponse call() { final RolapStar.Measure measure = request.getMeasure(); final RolapStar star = measure.getStar(); final RolapSchema schema = star.getSchema(); final AggregationKey key = new AggregationKey(request); final List<SegmentHeader> headers = indexRegistry .getIndex(star) .locate( schema.getName(), schema.getChecksum(), measure.getCubeName(), measure.getName(), star.getFactTable().getAlias(), request.getConstrainedColumnsBitKey(), request.getMappedCellValues(), AggregationKey.getCompoundPredicateStringList( star, key.getCompoundPredicateList())); final Map<SegmentHeader, Future<SegmentBody>> headerMap = new HashMap<SegmentHeader, Future<SegmentBody>>(); final Map<List, SegmentBuilder.SegmentConverter> converterMap = new HashMap<List, SegmentBuilder.SegmentConverter>(); // Is there a pending segment? (A segment that has been created and // is loading via SQL.) for (final SegmentHeader header : headers) { final Future<SegmentBody> bodyFuture = indexRegistry.getIndex(star).getFuture(header); if (bodyFuture != null) { // Check if the DataSourceChangeListener wants us to clear // the current segment if (star.getChangeListener() != null && star.getChangeListener().isAggregationChanged(key)) { /* * We can't satisfy this request, and we must clear the * data from our cache. We clear it from the index * first, then queue up a job in the background * to remove the data from all the caches. */ indexRegistry.getIndex(star).remove(header); Util.safeGet( cacheExecutor.submit( new Runnable() { public void run() { try { compositeCache.remove(header); } catch (Throwable e) { LOGGER.warn("remove header failed: " + header, e); } } }), "SegmentCacheManager.peek"); } converterMap.put( SegmentCacheIndexImpl.makeConverterKey(header), getConverter(star, header)); headerMap.put(header, bodyFuture); } } return new PeekResponse(headerMap, converterMap); }