segment.java

来自「数据仓库展示程序」· Java 代码 · 共 438 行 · 第 1/2 页

JAVA
438
字号
/*
// $Id: //open/mondrian/src/main/mondrian/rolap/agg/Segment.java#33 $
// 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.
// Copyright (C) 2002-2005 Kana Software, Inc. and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//
// jhyde, 21 March, 2002
*/
package mondrian.rolap.agg;

import mondrian.olap.*;
import mondrian.rolap.*;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * A <code>Segment</code> is a collection of cell values parameterized by
 * a measure, and a set of (column, value) pairs. An example of a segment is</p>
 *
 * <blockquote>
 *   <p>(Unit sales, Gender = 'F', State in {'CA','OR'}, Marital Status = <i>
 *   anything</i>)</p>
 * </blockquote>
 *
 * <p>All segments over the same set of columns belong to an Aggregation, in this
 * case</p>
 *
 * <blockquote>
 *   <p>('Sales' Star, Gender, State, Marital Status)</p>
 * </blockquote>
 *
 * <p>Note that different measures (in the same Star) occupy the same Aggregation.
 * Aggregations belong to the AggregationManager, a singleton.</p>
 * <p>Segments are pinned during the evaluation of a single MDX query. The query
 * evaluates the expressions twice. The first pass, it finds which cell values it
 * needs, pins the segments containing the ones which are already present (one
 * pin-count for each cell value used), and builds a {@link CellRequest
 * cell request} for those which are not present. It executes
 * the cell request to bring the required cell values into the cache, again,
 * pinned. Then it evalutes the query a second time, knowing that all cell values
 * are available. Finally, it releases the pins.</p>
 *
 * @author jhyde
 * @since 21 March, 2002
 * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/Segment.java#33 $
 **/
class Segment {

    /**
     * <code>State</code> enumerates the allowable values of a segment's
     * state.
     */
    private static class State extends EnumeratedValues {
        public static final State instance = new State();
        private State() {
            super(new String[] {"init","loading","ready","failed"});
        }
        public static final int Initial = 0;
        public static final int Loading = 1;
        public static final int Ready = 2;
        public static final int Failed = 3;
    }

    private static int nextId = 0; // generator for "id"

    private final int id; // for debug
    private String desc;
    final Aggregation aggregation;
    final RolapStar.Measure measure;

    final Aggregation.Axis[] axes;
    private SegmentDataset data;
    private final CellKey cellKey; // workspace
    /** State of the segment, values are described by {@link State}. */
    private int state;

    /**
     * Creates a <code>Segment</code>; it's not loaded yet.
     *
     * @param aggregation The aggregation that this <code>Segment</code>
     *    belongs to
     * @param constraintses For each column, either an array of values
     *    to fetch or null, indicating that the column is unconstrained
     **/
    Segment(Aggregation aggregation,
            RolapStar.Measure measure,
            ColumnConstraint[][] constraintses,
            Aggregation.Axis[] axes) {
        this.id = nextId++;
        this.aggregation = aggregation;
        this.measure = measure;
        this.axes = axes;
        this.cellKey = new CellKey(new int[axes.length]);
        this.state = State.Loading;
    }

    /**
     * Sets the data, and notifies any threads which are blocked in
     * {@link #waitUntilLoaded}.
     */
    synchronized void setData(SegmentDataset data,
                              Collection pinnedSegments) {
        Util.assertTrue(this.data == null);
        Util.assertTrue(this.state == State.Loading);

        this.data = data;
        this.state = State.Ready;
        notifyAll();
    }

    /**
     * If this segment is still loading, signals that it failed to load, and
     * notifies any threads which are blocked in {@link #waitUntilLoaded}.
     */
    synchronized void setFailed() {
        switch (state) {
        case State.Loading:
            Util.assertTrue(this.data == null);
            this.state = State.Failed;
            notifyAll();
            break;
        case State.Ready:
            // The segment loaded just fine.
            break;
        default:
            throw State.instance.badValue(state);
        }
    }

    public boolean isReady() {
        return (state == State.Ready);
    }

    private String makeDescription() {
        StringBuffer buf = new StringBuffer(64);
        buf.append("Segment #");
        buf.append(id);
        buf.append(" {measure=");
        buf.append(measure.getAggregator().getExpression(
                        measure.getExpression().getGenericExpression()));

        RolapStar.Column[] columns = aggregation.getColumns();
        for (int i = 0; i < columns.length; i++) {
            buf.append(", ");
            buf.append(columns[i].getExpression().getGenericExpression());
            ColumnConstraint[] constraints = axes[i].getConstraints();
            if (constraints == null) {
                buf.append("=any");
            } else {
                buf.append("={");
                for (int j = 0; j < constraints.length; j++) {
                    if (j > 0) {
                        buf.append(", ");
                    }
                    buf.append(constraints[j].getValue().toString());
                }
                buf.append('}');
            }
        }
        buf.append('}');
        return buf.toString();
    }

    public String toString() {
        if (this.desc == null) {
            this.desc = makeDescription();
        }
        return this.desc;
    }

    /**
     * Retrieves the value at the location identified by
     * <code>keys</code>. Returns {@link Util#nullValue} if the cell value
     * is null (because no fact table rows met those criteria), and
     * <code>null</code> if the value is not supposed to be in this segment
     * (because one or more of the keys do not pass the axis criteria).
     *
     * <p>Note: Must be called from a synchronized context, because uses the
     * <code>cellKey[]</code> as workspace.</p>
     **/
    Object get(Object[] keys) {
        Util.assertTrue(keys.length == axes.length);
        int missed = 0;
        for (int i = 0; i < keys.length; i++) {
            Object key = keys[i];
            Integer integer = axes[i].getOffset(key);
            if (integer == null) {
                if (axes[i].contains(key)) {
                    // see whether this segment should contain this value
                    missed++;
                    continue;
                } else {
                    // this value should not appear in this segment; we
                    // should be looking in a different segment
                    return null;
                }
            }
            cellKey.ordinals[i] = integer.intValue();
        }
        if (missed > 0) {
            // the value should be in this segment, but isn't, because one
            // or more of its keys does have any values
            return Util.nullValue;
        } else {
            Object o = data.get(cellKey);
            if (o == null) {
                o = Util.nullValue;
            }
            return o;
        }
    }

    /**
     * Returns whether the given set of key values will be in this segment

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?