KYLIN-2783 Refactor CuboidScheduler to be extensible Signed-off-by: Li Yang <liy...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/465c5070 Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/465c5070 Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/465c5070 Branch: refs/heads/ranger Commit: 465c5070dcc27c6d42c2590cf0685ab154b40e7b Parents: 084a6fb Author: Zhong <nju_y...@apache.org> Authored: Thu Aug 17 20:17:26 2017 +0800 Committer: Li Yang <liy...@apache.org> Committed: Sun Sep 10 07:47:20 2017 +0800 ---------------------------------------------------------------------- .../org/apache/kylin/cube/CubeDescManager.java | 3 - .../org/apache/kylin/cube/CubeInstance.java | 18 +- .../java/org/apache/kylin/cube/CubeManager.java | 17 +- .../java/org/apache/kylin/cube/CubeSegment.java | 5 + .../kylin/cube/common/RowKeySplitter.java | 4 +- .../org/apache/kylin/cube/cuboid/Cuboid.java | 180 +++-------- .../org/apache/kylin/cube/cuboid/CuboidCLI.java | 20 +- .../kylin/cube/cuboid/CuboidScheduler.java | 25 +- .../cube/cuboid/DefaultCuboidScheduler.java | 162 +++++++++- .../kylin/cube/cuboid/TreeCuboidScheduler.java | 322 +++++++++++++++++++ .../inmemcubing/AbstractInMemCubeBuilder.java | 17 +- .../cube/inmemcubing/DoggedCubeBuilder.java | 9 +- .../cube/inmemcubing/InMemCubeBuilder.java | 11 +- .../org/apache/kylin/cube/kv/RowKeyDecoder.java | 4 +- .../org/apache/kylin/cube/kv/RowKeyEncoder.java | 11 +- .../kylin/cube/model/AggregationGroup.java | 4 +- .../org/apache/kylin/cube/model/CubeDesc.java | 33 +- .../cube/model/CubeJoinedFlatTableEnrich.java | 3 +- .../org/apache/kylin/cube/util/CubingUtils.java | 2 +- .../kylin/cube/cuboid/CuboidSchedulerTest.java | 26 +- .../apache/kylin/cube/cuboid/CuboidTest.java | 60 ++-- .../apache/kylin/cube/kv/RowKeyDecoderTest.java | 2 +- .../apache/kylin/cube/kv/RowKeyEncoderTest.java | 6 +- .../gtrecord/GTCubeStorageQueryBase.java | 6 +- .../kylin/storage/translate/HBaseKeyRange.java | 2 +- .../kylin/engine/mr/BatchCubingJobBuilder.java | 2 +- .../kylin/engine/mr/BatchCubingJobBuilder2.java | 2 +- .../engine/mr/common/BaseCuboidBuilder.java | 14 +- .../kylin/engine/mr/common/CubeStatsReader.java | 7 +- .../mr/steps/FactDistinctColumnsMapper.java | 2 +- .../engine/mr/steps/InMemCuboidMapper.java | 3 +- .../kylin/engine/mr/steps/KVGTRecordWriter.java | 2 +- .../engine/mr/steps/MergeCuboidMapper.java | 2 +- .../kylin/engine/mr/steps/NDCuboidMapper.java | 6 +- .../apache/kylin/engine/spark/SparkCubing.java | 9 +- .../kylin/engine/spark/SparkCubingByLayer.java | 12 +- .../spark/cube/DefaultTupleConverter.java | 2 +- .../ITDoggedCubeBuilderStressTest.java | 2 +- .../inmemcubing/ITDoggedCubeBuilderTest.java | 4 +- .../inmemcubing/ITInMemCubeBuilderTest.java | 2 +- .../storage/hbase/steps/HBaseCuboidWriter.java | 4 +- .../cube/MeasureTypeOnlyAggrInBaseTest.java | 4 +- 42 files changed, 738 insertions(+), 293 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java b/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java index 6635366..f49c9be 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java @@ -171,7 +171,6 @@ public class CubeDescManager { CubeDesc ndesc = loadCubeDesc(CubeDesc.concatResourcePath(name), false); cubeDescMap.putLocal(ndesc.getName(), ndesc); - Cuboid.reloadCache(name); // if related cube is in DESCBROKEN state before, change it back to DISABLED CubeManager cubeManager = CubeManager.getInstance(config); @@ -297,13 +296,11 @@ public class CubeDescManager { String path = cubeDesc.getResourcePath(); getStore().deleteResource(path); cubeDescMap.remove(cubeDesc.getName()); - Cuboid.reloadCache(cubeDesc.getName()); } // remove cubeDesc public void removeLocalCubeDesc(String name) throws IOException { cubeDescMap.removeLocal(name); - Cuboid.reloadCache(name); } private void reloadAllCubeDesc() throws IOException { http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/CubeInstance.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeInstance.java b/core-cube/src/main/java/org/apache/kylin/cube/CubeInstance.java index fad942c..246cbf6 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/CubeInstance.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeInstance.java @@ -26,6 +26,7 @@ import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.KylinConfigExt; import org.apache.kylin.common.persistence.ResourceStore; import org.apache.kylin.common.persistence.RootPersistentEntity; +import org.apache.kylin.cube.cuboid.CuboidScheduler; import org.apache.kylin.cube.model.CubeDesc; import org.apache.kylin.metadata.model.ColumnDesc; import org.apache.kylin.metadata.model.DataModelDesc; @@ -95,11 +96,26 @@ public class CubeInstance extends RootPersistentEntity implements IRealization, @JsonProperty("create_time_utc") private long createTimeUTC; + // cuboid scheduler lazy built + transient private CuboidScheduler cuboidScheduler; + // default constructor for jackson public CubeInstance() { } - public Segments<CubeSegment> getBuildingSegments() { + public CuboidScheduler getCuboidScheduler() { + if (cuboidScheduler != null) + return cuboidScheduler; + + synchronized (this) { + if (cuboidScheduler == null) { + cuboidScheduler = getDescriptor().getInitialCuboidScheduler(); + } + } + return cuboidScheduler; + } + + public List<CubeSegment> getBuildingSegments() { return segments.getBuildingSegments(); } http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java index b782a5e..6ebfd99 100755 --- a/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java @@ -43,6 +43,7 @@ import org.apache.kylin.common.persistence.ResourceStore; import org.apache.kylin.common.persistence.Serializer; import org.apache.kylin.common.util.Dictionary; import org.apache.kylin.common.util.Pair; +import org.apache.kylin.cube.cuboid.Cuboid; import org.apache.kylin.cube.model.CubeDesc; import org.apache.kylin.cube.model.DictionaryDesc; import org.apache.kylin.dict.DictionaryInfo; @@ -306,13 +307,14 @@ public class CubeManager implements IRealizationProvider { // delete cube instance and cube desc CubeInstance cube = getCube(cubeName); - if (deleteDesc && cube.getDescriptor() != null) { - CubeDescManager.getInstance(config).removeCubeDesc(cube.getDescriptor()); - } - // remove cube and update cache getStore().deleteResource(cube.getResourcePath()); cubeMap.remove(cube.getName()); + Cuboid.reloadCache(cube); + + if (deleteDesc && cube.getDescriptor() != null) { + CubeDescManager.getInstance(config).removeCubeDesc(cube.getDescriptor()); + } // delete cube from project ProjectManager.getInstance(config).removeRealizationsFromProjects(RealizationType.CUBE, cubeName); @@ -629,17 +631,20 @@ public class CubeManager implements IRealizationProvider { * @param cubeName */ public CubeInstance reloadCubeLocal(String cubeName) { - return reloadCubeLocalAt(CubeInstance.concatResourcePath(cubeName)); + CubeInstance cubeInstance = reloadCubeLocalAt(CubeInstance.concatResourcePath(cubeName)); + Cuboid.reloadCache(cubeInstance); + return cubeInstance; } public void removeCubeLocal(String cubeName) { CubeInstance cube = cubeMap.get(cubeName); if (cube != null) { + cubeMap.removeLocal(cubeName); for (CubeSegment segment : cube.getSegments()) { usedStorageLocation.remove(segment.getUuid()); } + Cuboid.reloadCache(cube); } - cubeMap.removeLocal(cubeName); } public LookupStringTable getLookupTable(CubeSegment cubeSegment, JoinDesc join) { http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/CubeSegment.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeSegment.java b/core-cube/src/main/java/org/apache/kylin/cube/CubeSegment.java index 358183e..495f9c0 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/CubeSegment.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeSegment.java @@ -32,6 +32,7 @@ import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.persistence.ResourceStore; import org.apache.kylin.common.util.Dictionary; import org.apache.kylin.common.util.ShardingHash; +import org.apache.kylin.cube.cuboid.CuboidScheduler; import org.apache.kylin.cube.kv.CubeDimEncMap; import org.apache.kylin.cube.kv.RowConstants; import org.apache.kylin.cube.model.CubeDesc; @@ -127,6 +128,10 @@ public class CubeSegment implements IBuildable, ISegment, Serializable { return getCubeInstance().getDescriptor(); } + public CuboidScheduler getCuboidScheduler() { + return getCubeInstance().getCuboidScheduler(); + } + public static String makeSegmentName(TSRange tsRange, SegmentRange segRange) { if (tsRange == null && segRange == null) { return "FULL_BUILD"; http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/common/RowKeySplitter.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/common/RowKeySplitter.java b/core-cube/src/main/java/org/apache/kylin/cube/common/RowKeySplitter.java index acebce4..cd26347 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/common/RowKeySplitter.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/common/RowKeySplitter.java @@ -32,6 +32,7 @@ import org.apache.kylin.metadata.model.TblColRef; public class RowKeySplitter implements java.io.Serializable { + private CubeSegment cubeSegment; private CubeDesc cubeDesc; private RowKeyColumnIO colIO; @@ -63,6 +64,7 @@ public class RowKeySplitter implements java.io.Serializable { } public RowKeySplitter(CubeSegment cubeSeg, int splitLen, int bytesLen) { + this.cubeSegment = cubeSeg; this.enableSharding = cubeSeg.isEnableSharding(); this.cubeDesc = cubeSeg.getCubeDesc(); IDimensionEncodingMap dimEncoding = new CubeDimEncMap(cubeSeg); @@ -113,7 +115,7 @@ public class RowKeySplitter implements java.io.Serializable { offset += RowConstants.ROWKEY_CUBOIDID_LEN; long lastSplittedCuboidId = Bytes.toLong(cuboidIdSplit.value, 0, cuboidIdSplit.length); - Cuboid cuboid = Cuboid.findById(cubeDesc, lastSplittedCuboidId); + Cuboid cuboid = Cuboid.findById(cubeSegment, lastSplittedCuboidId); // rowkey columns for (int i = 0; i < cuboid.getColumns().size(); i++) { http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/cuboid/Cuboid.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/Cuboid.java b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/Cuboid.java index b71608c..fa83775 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/Cuboid.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/Cuboid.java @@ -21,15 +21,15 @@ package org.apache.kylin.cube.cuboid; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.StringUtils; import org.apache.kylin.common.util.Bytes; +import org.apache.kylin.cube.CubeInstance; +import org.apache.kylin.cube.CubeSegment; import org.apache.kylin.cube.gridtable.CuboidToGridTableMapping; import org.apache.kylin.cube.model.AggregationGroup; import org.apache.kylin.cube.model.AggregationGroup.HierarchyMask; @@ -38,16 +38,15 @@ import org.apache.kylin.cube.model.RowKeyColDesc; import org.apache.kylin.metadata.model.FunctionDesc; import org.apache.kylin.metadata.model.TblColRef; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ComparisonChain; -import com.google.common.collect.Lists; +import com.google.common.collect.Maps; @SuppressWarnings("serial") public class Cuboid implements Comparable<Cuboid>, Serializable { - private final static Map<String, Map<Long, Cuboid>> CUBOID_CACHE = new ConcurrentHashMap<String, Map<Long, Cuboid>>(); + //TODO Guava cache may be better + private final static Map<String, Map<Long, Cuboid>> CUBOID_CACHE = Maps.newConcurrentMap(); // smaller is better public final static Comparator<Long> cuboidSelectComparator = new Comparator<Long>() { @@ -57,10 +56,22 @@ public class Cuboid implements Comparable<Cuboid>, Serializable { } }; - // this is the only entry point for query to find the right cuboid - public static Cuboid identifyCuboid(CubeDesc cubeDesc, Set<TblColRef> dimensions, Collection<FunctionDesc> metrics) { - long cuboidID = identifyCuboidId(cubeDesc, dimensions, metrics); - return Cuboid.findById(cubeDesc, cuboidID); + // this is the only entry point for query to find the right cuboid for a segment + public static Cuboid identifyCuboid(CubeSegment cubeSegment, Set<TblColRef> dimensions, + Collection<FunctionDesc> metrics) { + return identifyCuboid(cubeSegment.getCuboidScheduler(), dimensions, metrics); + } + + // this is the only entry point for query to find the right cuboid for a cube instance + public static Cuboid identifyCuboid(CubeInstance cubeInstance, Set<TblColRef> dimensions, + Collection<FunctionDesc> metrics) { + return identifyCuboid(cubeInstance.getCuboidScheduler(), dimensions, metrics); + } + + public static Cuboid identifyCuboid(CuboidScheduler cuboidScheduler, Set<TblColRef> dimensions, + Collection<FunctionDesc> metrics) { + long cuboidID = identifyCuboidId(cuboidScheduler.getCubeDesc(), dimensions, metrics); + return Cuboid.findById(cuboidScheduler, cuboidID); } public static long identifyCuboidId(CubeDesc cubeDesc, Set<TblColRef> dimensions, Collection<FunctionDesc> metrics) { @@ -77,140 +88,49 @@ public class Cuboid implements Comparable<Cuboid>, Serializable { return cuboidID; } - // for full cube, no need to translate cuboid - public static Cuboid findForFullCube(CubeDesc cube, long cuboidID) { + // for mandatory cuboid, no need to translate cuboid + public static Cuboid findForMandatory(CubeDesc cube, long cuboidID) { return new Cuboid(cube, cuboidID, cuboidID); } - public static Cuboid findById(CubeDesc cube, byte[] cuboidID) { - return findById(cube, Bytes.toLong(cuboidID)); + public static Cuboid findById(CuboidScheduler cuboidScheduler, byte[] cuboidID) { + return findById(cuboidScheduler, Bytes.toLong(cuboidID)); } - public static Cuboid findById(CubeDesc cube, long cuboidID) { - Map<Long, Cuboid> cubeCache = CUBOID_CACHE.get(cube.getName()); + public static Cuboid findById(CubeSegment cubeSegment, long cuboidID) { + return findById(cubeSegment.getCuboidScheduler(), cuboidID); + } + + public static Cuboid findById(CubeInstance cubeInstance, long cuboidID) { + return findById(cubeInstance.getCuboidScheduler(), cuboidID); + } + + @VisibleForTesting + static Cuboid findById(CubeDesc cubeDesc, long cuboidID) { + return findById(cubeDesc.getInitialCuboidScheduler(), cuboidID); + } + + public static Cuboid findById(CuboidScheduler cuboidScheduler, long cuboidID) { + Map<Long, Cuboid> cubeCache = CUBOID_CACHE.get(cuboidScheduler.getResponsibleKey()); if (cubeCache == null) { - cubeCache = new ConcurrentHashMap<Long, Cuboid>(); - CUBOID_CACHE.put(cube.getName(), cubeCache); + cubeCache = Maps.newConcurrentMap(); + CUBOID_CACHE.put(cuboidScheduler.getResponsibleKey(), cubeCache); } Cuboid cuboid = cubeCache.get(cuboidID); if (cuboid == null) { - long validCuboidID = translateToValidCuboid(cube, cuboidID); - cuboid = new Cuboid(cube, cuboidID, validCuboidID); + long validCuboidID = cuboidScheduler.findBestMatchCuboid(cuboidID); + cuboid = new Cuboid(cuboidScheduler.getCubeDesc(), cuboidID, validCuboidID); cubeCache.put(cuboidID, cuboid); } return cuboid; } - public static boolean isValid(CubeDesc cube, long cuboidID) { - return cube.getAllCuboids().contains(cuboidID); - } - public static long getBaseCuboidId(CubeDesc cube) { return cube.getRowkey().getFullMask(); } public static Cuboid getBaseCuboid(CubeDesc cube) { - return findById(cube, getBaseCuboidId(cube)); - } - - static long translateToValidCuboid(CubeDesc cubeDesc, long cuboidID) { - long baseCuboidId = getBaseCuboidId(cubeDesc); - if (cubeDesc.getAllCuboids().contains(cuboidID)) { - return cuboidID; - } - List<Long> onTreeCandidates = Lists.newArrayList(); - for (AggregationGroup agg : cubeDesc.getAggregationGroups()) { - Long candidate = translateToOnTreeCuboid(agg, cuboidID); - if (candidate != null) { - onTreeCandidates.add(candidate); - } - } - - if (onTreeCandidates.size() == 0) { - return baseCuboidId; - } - - long onTreeCandi = Collections.min(onTreeCandidates, cuboidSelectComparator); - if (isValid(cubeDesc, onTreeCandi)) { - return onTreeCandi; - } - - return cubeDesc.getCuboidScheduler().findBestMatchCuboid(onTreeCandi); - } - - private static Long translateToOnTreeCuboid(AggregationGroup agg, long cuboidID) { - if ((cuboidID & ~agg.getPartialCubeFullMask()) > 0) { - //the partial cube might not contain all required dims - return null; - } - - // add mandantory - cuboidID = cuboidID | agg.getMandatoryColumnMask(); - - // add hierarchy - for (HierarchyMask hierarchyMask : agg.getHierarchyMasks()) { - long fullMask = hierarchyMask.fullMask; - long intersect = cuboidID & fullMask; - if (intersect != 0 && intersect != fullMask) { - - boolean startToFill = false; - for (int i = hierarchyMask.dims.length - 1; i >= 0; i--) { - if (startToFill) { - cuboidID |= hierarchyMask.dims[i]; - } else { - if ((cuboidID & hierarchyMask.dims[i]) != 0) { - startToFill = true; - cuboidID |= hierarchyMask.dims[i]; - } - } - } - } - } - - // add joint dims - for (Long joint : agg.getJoints()) { - if (((cuboidID | joint) != cuboidID) && ((cuboidID & ~joint) != cuboidID)) { - cuboidID = cuboidID | joint; - } - } - - if (!agg.isOnTree(cuboidID)) { - // no column, add one column - long nonJointDims = removeBits((agg.getPartialCubeFullMask() ^ agg.getMandatoryColumnMask()), agg.getJoints()); - if (nonJointDims != 0) { - long nonJointNonHierarchy = removeBits(nonJointDims, Collections2.transform(agg.getHierarchyMasks(), new Function<HierarchyMask, Long>() { - @Override - public Long apply(HierarchyMask input) { - return input.fullMask; - } - })); - if (nonJointNonHierarchy != 0) { - //there exists dim that does not belong to any joint or any hierarchy, that's perfect - return cuboidID | Long.lowestOneBit(nonJointNonHierarchy); - } else { - //choose from a hierarchy that does not intersect with any joint dim, only check level 1 - long allJointDims = agg.getJointDimsMask(); - for (HierarchyMask hierarchyMask : agg.getHierarchyMasks()) { - long dim = hierarchyMask.allMasks[0]; - if ((dim & allJointDims) == 0) { - return cuboidID | dim; - } - } - } - } - - cuboidID = cuboidID | Collections.min(agg.getJoints(), cuboidSelectComparator); - Preconditions.checkState(agg.isOnTree(cuboidID)); - } - return cuboidID; - } - - private static long removeBits(long original, Collection<Long> toRemove) { - long ret = original; - for (Long joint : toRemove) { - ret = ret & ~joint; - } - return ret; + return findForMandatory(cube, getBaseCuboidId(cube)); } // ============================================================================ @@ -310,8 +230,12 @@ public class Cuboid implements Comparable<Cuboid>, Serializable { CUBOID_CACHE.clear(); } - public static void reloadCache(String cubeDescName) { - CUBOID_CACHE.remove(cubeDescName); + public static void reloadCache(CubeInstance cubeInstance) { + reloadCache(cubeInstance.getCuboidScheduler()); + } + + private static void reloadCache(CuboidScheduler cuboidScheduler) { + CUBOID_CACHE.remove(cuboidScheduler.getResponsibleKey()); } @Override http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidCLI.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidCLI.java b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidCLI.java index d657a43..4300a6c 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidCLI.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidCLI.java @@ -44,7 +44,7 @@ public class CuboidCLI { } public static int simulateCuboidGeneration(CubeDesc cubeDesc, boolean validate) { - CuboidScheduler scheduler = cubeDesc.getCuboidScheduler(); + CuboidScheduler scheduler = cubeDesc.getInitialCuboidScheduler(); long baseCuboid = Cuboid.getBaseCuboidId(cubeDesc); Collection<Long> cuboidSet = new TreeSet<Long>(); cuboidSet.add(baseCuboid); @@ -88,28 +88,28 @@ public class CuboidCLI { //check all valid and invalid for (long i = 0; i < baseCuboid; ++i) { if (cuboidSet.contains(i)) { - if (!Cuboid.isValid(cubeDesc, i)) { + if (!cubeDesc.getInitialCuboidScheduler().isValid(i)) { throw new RuntimeException(); } - if (Cuboid.translateToValidCuboid(cubeDesc, i) != i) { + if (cubeDesc.getInitialCuboidScheduler().findBestMatchCuboid(i) != i) { throw new RuntimeException(); } } else { - if (Cuboid.isValid(cubeDesc, i)) { + if (cubeDesc.getInitialCuboidScheduler().isValid(i)) { throw new RuntimeException(); } - long corrected = Cuboid.translateToValidCuboid(cubeDesc, i); + long corrected = cubeDesc.getInitialCuboidScheduler().findBestMatchCuboid(i); if (corrected == i) { throw new RuntimeException(); } - if (!Cuboid.isValid(cubeDesc, corrected)) { + if (!cubeDesc.getInitialCuboidScheduler().isValid(corrected)) { throw new RuntimeException(); } - if (Cuboid.translateToValidCuboid(cubeDesc, corrected) != corrected) { + if (cubeDesc.getInitialCuboidScheduler().findBestMatchCuboid(corrected) != corrected) { throw new RuntimeException(); } } @@ -125,7 +125,7 @@ public class CuboidCLI { long baseCuboid = Cuboid.getBaseCuboidId(cube); TreeSet<Long> expectedCuboids = new TreeSet<Long>(); for (long cuboid = 0; cuboid <= baseCuboid; cuboid++) { - if (Cuboid.isValid(cube, cuboid)) { + if (cube.getInitialCuboidScheduler().isValid(cuboid)) { expectedCuboids.add(cuboid); } } @@ -133,10 +133,10 @@ public class CuboidCLI { } public static int[] calculateAllLevelCount(CubeDesc cube) { - int levels = cube.getBuildLevel(); + int levels = cube.getInitialBuildLevel(); int[] allLevelCounts = new int[levels + 1]; - CuboidScheduler scheduler = cube.getCuboidScheduler(); + CuboidScheduler scheduler = cube.getInitialCuboidScheduler(); LinkedList<Long> nextQueue = new LinkedList<Long>(); LinkedList<Long> currentQueue = new LinkedList<Long>(); long baseCuboid = Cuboid.getBaseCuboidId(cube); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidScheduler.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidScheduler.java b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidScheduler.java index e802230..cef0f77 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidScheduler.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/CuboidScheduler.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Set; import org.apache.kylin.common.util.ClassUtil; -import org.apache.kylin.cube.model.AggregationGroup; import org.apache.kylin.cube.model.CubeDesc; import com.google.common.base.Preconditions; @@ -63,14 +62,25 @@ abstract public class CuboidScheduler { /** Returns a cuboid on the tree that best matches the request cuboid. */ abstract public long findBestMatchCuboid(long requestCuboid); - - /** (AggGroupScheduler) Calculate the cuboid set defined by an aggregation group. */ - abstract public Set<Long> calculateCuboidsForAggGroup(AggregationGroup agg); + + /** Returns whether requestCuboid is valid or not*/ + abstract public boolean isValid(long requestCuboid); + + /** Returns the key for what this cuboid scheduler responsible for*/ + abstract public String getResponsibleKey(); // ============================================================================ private transient List<List<Long>> cuboidsByLayer; + public long getBaseCuboidId() { + return Cuboid.getBaseCuboidId(cubeDesc); + } + + public CubeDesc getCubeDesc() { + return cubeDesc; + } + /** * Get cuboids by layer. It's built from pre-expanding tree. * @return layered cuboids @@ -105,4 +115,11 @@ abstract public class CuboidScheduler { return cuboidsByLayer; } + /** + * Get cuboid level count except base cuboid + * @return + */ + public int getBuildLevel() { + return getCuboidsByLayer().size() - 1; + } } http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java index f7d22da..cba417a 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java @@ -35,10 +35,14 @@ import javax.annotation.Nullable; import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.util.Pair; import org.apache.kylin.cube.model.AggregationGroup; +import org.apache.kylin.cube.model.AggregationGroup.HierarchyMask; import org.apache.kylin.cube.model.CubeDesc; import org.apache.kylin.cube.model.TooManyCuboidException; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -83,14 +87,48 @@ public class DefaultCuboidScheduler extends CuboidScheduler { return Sets.newHashSet(allCuboidIds); } + @Override + public boolean isValid(long requestCuboid) { + return allCuboidIds.contains(requestCuboid); + } + /** - * Get the parent cuboid really on the spanning tree. - * @param child an on-tree cuboid + * Get the parent cuboid rely on the spanning tree. + * @param cuboid an on-tree cuboid * @return */ @Override - public long findBestMatchCuboid(long child) { - long parent = getOnTreeParent(child); + public long findBestMatchCuboid(long cuboid) { + return findBestMatchCuboid1(cuboid); + } + + public long findBestMatchCuboid1(long cuboid) { + if (isValid(cuboid)) { + return cuboid; + } + + List<Long> onTreeCandidates = Lists.newArrayList(); + for (AggregationGroup agg : cubeDesc.getAggregationGroups()) { + Long candidate = translateToOnTreeCuboid(agg, cuboid); + if (candidate != null) { + onTreeCandidates.add(candidate); + } + } + + if (onTreeCandidates.size() == 0) { + return getBaseCuboidId(); + } + + long onTreeCandi = Collections.min(onTreeCandidates, Cuboid.cuboidSelectComparator); + if (isValid(onTreeCandi)) { + return onTreeCandi; + } + + return doFindBestMatchCuboid1(onTreeCandi); + } + + public long doFindBestMatchCuboid1(long cuboid) { + long parent = getOnTreeParent(cuboid); while (parent > 0) { if (cubeDesc.getAllCuboids().contains(parent)) { break; @@ -99,11 +137,88 @@ public class DefaultCuboidScheduler extends CuboidScheduler { } if (parent <= 0) { - throw new IllegalStateException("Can't find valid parent for Cuboid " + child); + throw new IllegalStateException("Can't find valid parent for Cuboid " + cuboid); } return parent; } + private static Long translateToOnTreeCuboid(AggregationGroup agg, long cuboidID) { + if ((cuboidID & ~agg.getPartialCubeFullMask()) > 0) { + //the partial cube might not contain all required dims + return null; + } + + // add mandantory + cuboidID = cuboidID | agg.getMandatoryColumnMask(); + + // add hierarchy + for (HierarchyMask hierarchyMask : agg.getHierarchyMasks()) { + long fullMask = hierarchyMask.fullMask; + long intersect = cuboidID & fullMask; + if (intersect != 0 && intersect != fullMask) { + + boolean startToFill = false; + for (int i = hierarchyMask.dims.length - 1; i >= 0; i--) { + if (startToFill) { + cuboidID |= hierarchyMask.dims[i]; + } else { + if ((cuboidID & hierarchyMask.dims[i]) != 0) { + startToFill = true; + cuboidID |= hierarchyMask.dims[i]; + } + } + } + } + } + + // add joint dims + for (Long joint : agg.getJoints()) { + if (((cuboidID | joint) != cuboidID) && ((cuboidID & ~joint) != cuboidID)) { + cuboidID = cuboidID | joint; + } + } + + if (!agg.isOnTree(cuboidID)) { + // no column, add one column + long nonJointDims = removeBits((agg.getPartialCubeFullMask() ^ agg.getMandatoryColumnMask()), + agg.getJoints()); + if (nonJointDims != 0) { + long nonJointNonHierarchy = removeBits(nonJointDims, + Collections2.transform(agg.getHierarchyMasks(), new Function<HierarchyMask, Long>() { + @Override + public Long apply(HierarchyMask input) { + return input.fullMask; + } + })); + if (nonJointNonHierarchy != 0) { + //there exists dim that does not belong to any joint or any hierarchy, that's perfect + return cuboidID | Long.lowestOneBit(nonJointNonHierarchy); + } else { + //choose from a hierarchy that does not intersect with any joint dim, only check level 1 + long allJointDims = agg.getJointDimsMask(); + for (HierarchyMask hierarchyMask : agg.getHierarchyMasks()) { + long dim = hierarchyMask.allMasks[0]; + if ((dim & allJointDims) == 0) { + return cuboidID | dim; + } + } + } + } + + cuboidID = cuboidID | Collections.min(agg.getJoints(), Cuboid.cuboidSelectComparator); + Preconditions.checkState(agg.isOnTree(cuboidID)); + } + return cuboidID; + } + + private static long removeBits(long original, Collection<Long> toRemove) { + long ret = original; + for (Long joint : toRemove) { + ret = ret & ~joint; + } + return ret; + } + private long getOnTreeParent(long child) { Collection<Long> candidates = getOnTreeParents(child); if (candidates == null || candidates.isEmpty()) { @@ -259,7 +374,6 @@ public class DefaultCuboidScheduler extends CuboidScheduler { * @param agg agg group * @return cuboidId list */ - @Override public Set<Long> calculateCuboidsForAggGroup(AggregationGroup agg) { Set<Long> cuboidHolder = new HashSet<>(); @@ -352,4 +466,40 @@ public class DefaultCuboidScheduler extends CuboidScheduler { return Long.bitCount(cuboidID) <= dimCap; } + public long findBestMatchCuboid2(long cuboid) { + long bestParent = doFindBestMatchCuboid2(cuboid, Cuboid.getBaseCuboidId(cubeDesc)); + if (bestParent < -1) { + throw new IllegalStateException("Cannot find the parent of the cuboid:" + cuboid); + } + return bestParent; + } + + private long doFindBestMatchCuboid2(long cuboid, long parent) { + if (!canDerive(cuboid, parent)) { + return -1; + } + List<Long> children = parent2child.get(parent); + List<Long> candidates = Lists.newArrayList(); + if (children != null) { + for (long child : children) { + long candidate = doFindBestMatchCuboid2(cuboid, child); + if (candidate > 0) { + candidates.add(candidate); + } + } + } + if (candidates.isEmpty()) { + candidates.add(parent); + } + + return Collections.min(candidates, Cuboid.cuboidSelectComparator); + } + + private boolean canDerive(long cuboidId, long parentCuboid) { + return (cuboidId & ~parentCuboid) == 0; + } + + public String getResponsibleKey() { + return CubeDesc.class.getName() + "-" + cubeDesc.getName(); + } } http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/cuboid/TreeCuboidScheduler.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/TreeCuboidScheduler.java b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/TreeCuboidScheduler.java new file mode 100644 index 0000000..414fc4a --- /dev/null +++ b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/TreeCuboidScheduler.java @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.apache.kylin.cube.cuboid; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.apache.kylin.cube.CubeInstance; +import org.apache.kylin.cube.model.CubeDesc; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; + +public class TreeCuboidScheduler extends CuboidScheduler { + + final private CuboidTree cuboidTree; + + public TreeCuboidScheduler(CubeDesc cubeDesc, List<Long> allCuboidIds, Comparator<Long> cuboidComparator) { + super(cubeDesc); + cuboidTree = CuboidTree.createFromCuboids(allCuboidIds, cuboidComparator); + } + + @Override + public Set<Long> getAllCuboidIds() { + return cuboidTree.getAllCuboidIds(); + } + + @Override + public int getCuboidCount() { + return cuboidTree.getCuboidCount(Cuboid.getBaseCuboidId(cubeDesc)); + } + + @Override + public List<Long> getSpanningCuboid(long cuboidId) { + return cuboidTree.getSpanningCuboid(cuboidId); + } + + @Override + public long findBestMatchCuboid(long cuboidId) { + return cuboidTree.findBestMatchCuboid(cuboidId); + } + + @Override + public boolean isValid(long requestCuboid) { + return cuboidTree.isValid(requestCuboid); + } + + public static class CuboidTree { + private int treeLevels; + + private TreeNode root; + + private Comparator<Long> cuboidComparator; + + private Map<Long, TreeNode> index = new HashMap<>(); + + @VisibleForTesting + static CuboidTree createFromCuboids(List<Long> allCuboidIds) { + return createFromCuboids(allCuboidIds, Cuboid.cuboidSelectComparator); + } + + @VisibleForTesting + static CuboidTree createFromCuboids(List<Long> allCuboidIds, Comparator<Long> cuboidComparator) { + // sort the cuboid ids in descending order, so that don't need to adjust + // the cuboid tree when adding cuboid id to the tree. + Collections.sort(allCuboidIds, new Comparator<Long>() { + @Override + public int compare(Long o1, Long o2) { + return Long.compare(o2, o1); + } + }); + long basicCuboidId = allCuboidIds.get(0); + CuboidTree cuboidTree = new CuboidTree(cuboidComparator); + cuboidTree.setRoot(basicCuboidId); + + for (long cuboidId : allCuboidIds) { + cuboidTree.addCuboid(cuboidId); + } + cuboidTree.buildIndex(); + return cuboidTree; + } + + private CuboidTree(Comparator<Long> cuboidComparator) { + this.cuboidComparator = cuboidComparator; + } + + public Set<Long> getAllCuboidIds() { + return index.keySet(); + } + + public List<Long> getSpanningCuboid(long cuboidId) { + TreeNode node = index.get(cuboidId); + if (node == null) { + throw new IllegalArgumentException("the cuboid:" + cuboidId + " is not exist in the tree"); + } + + return Lists.transform(node.children, new Function<TreeNode, Long>() { + @Nullable + @Override + public Long apply(@Nullable TreeNode input) { + return input.cuboidId; + } + }); + } + + public long findBestMatchCuboid(long cuboidId) { + // exactly match + if (isValid(cuboidId)) { + return cuboidId; + } + + return findBestParent(cuboidId).cuboidId; + } + + public boolean isValid(long cuboidId) { + return index.containsKey(cuboidId); + } + + private int getCuboidCount(long cuboidId) { + int r = 1; + for (Long child : getSpanningCuboid(cuboidId)) { + r += getCuboidCount(child); + } + return r; + } + + public void print(PrintWriter out) { + int dimensionCnt = Long.bitCount(root.cuboidId); + doPrint(root, dimensionCnt, 0, out); + } + + private void doPrint(TreeNode node, int dimensionCount, int depth, PrintWriter out) { + printCuboid(node.cuboidId, dimensionCount, depth, out); + + for (TreeNode child : node.children) { + doPrint(child, dimensionCount, depth + 1, out); + } + } + + private void printCuboid(long cuboidID, int dimensionCount, int depth, PrintWriter out) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < depth; i++) { + sb.append(" "); + } + String cuboidName = Cuboid.getDisplayName(cuboidID, dimensionCount); + sb.append("|---- Cuboid ").append(cuboidName).append("(" + cuboidID + ")"); + out.println(sb.toString()); + } + + private void setRoot(long basicCuboidId) { + this.root = new TreeNode(basicCuboidId, 0); + this.treeLevels = 0; + } + + private void buildIndex() { + LinkedList<TreeNode> queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + TreeNode node = queue.removeFirst(); + index.put(node.cuboidId, node); + for (TreeNode child : node.children) { + queue.add(child); + } + } + } + + private void addCuboid(long cuboidId) { + TreeNode parent = findBestParent(cuboidId); + if (parent != null && parent.cuboidId != cuboidId) { + parent.addChild(cuboidId, parent.level); + this.treeLevels = Math.max(this.treeLevels, parent.level + 1); + } + } + + private TreeNode findBestParent(long cuboidId) { + TreeNode bestParent = doFindBestParent(cuboidId, root); + if (bestParent == null) { + throw new IllegalStateException("Cannot find the parent of the cuboid:" + cuboidId); + } + return bestParent; + } + + private TreeNode doFindBestParent(long cuboidId, TreeNode parentCuboid) { + if (!canDerive(cuboidId, parentCuboid.cuboidId)) { + return null; + } + + List<TreeNode> candidates = Lists.newArrayList(); + for (TreeNode childCuboid : parentCuboid.children) { + TreeNode candidate = doFindBestParent(cuboidId, childCuboid); + if (candidate != null) { + candidates.add(candidate); + } + } + if (candidates.isEmpty()) { + candidates.add(parentCuboid); + } + + return Collections.min(candidates, new Comparator<TreeNode>() { + @Override + public int compare(TreeNode o1, TreeNode o2) { + return cuboidComparator.compare(o1.cuboidId, o2.cuboidId); + } + }); + } + + private boolean canDerive(long cuboidId, long parentCuboid) { + return (cuboidId & ~parentCuboid) == 0; + } + } + + public static class TreeNode { + @JsonProperty("cuboid_id") + long cuboidId; + @JsonIgnore + int level; + @JsonProperty("children") + List<TreeNode> children = new ArrayList<>(); + + public long getCuboidId() { + return cuboidId; + } + + public int getLevel() { + return level; + } + + public List<TreeNode> getChildren() { + return children; + } + + TreeNode(long cuboidId, int level) { + this.cuboidId = cuboidId; + this.level = level; + } + + void addChild(long childId, int parentlevel) { + this.children.add(new TreeNode(childId, parentlevel + 1)); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (cuboidId ^ (cuboidId >>> 32)); + result = prime * result + level; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TreeNode other = (TreeNode) obj; + if (cuboidId != other.cuboidId) + return false; + if (level != other.level) + return false; + return true; + } + } + + /** + * Compare cuboid according to the cuboid data row count + */ + public static class CuboidCostComparator implements Comparator<Long> { + private Map<Long, Long> cuboidStatistics; + + public CuboidCostComparator(Map<Long, Long> cuboidStatistics) { + Preconditions.checkArgument(cuboidStatistics != null, + "the input " + cuboidStatistics + " should not be null!!!"); + this.cuboidStatistics = cuboidStatistics; + } + + @Override + public int compare(Long cuboid1, Long cuboid2) { + Long rowCnt1 = cuboidStatistics.get(cuboid1); + Long rowCnt2 = cuboidStatistics.get(cuboid2); + if (rowCnt2 == null || rowCnt1 == null) { + return Cuboid.cuboidSelectComparator.compare(cuboid1, cuboid2); + } + return Long.compare(rowCnt1, rowCnt2); + } + } + + public String getResponsibleKey() { + return CubeInstance.class.getName() + "-" + cubeDesc.getName(); + } +} http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/AbstractInMemCubeBuilder.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/AbstractInMemCubeBuilder.java b/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/AbstractInMemCubeBuilder.java index c7a4a05..ae38261 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/AbstractInMemCubeBuilder.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/AbstractInMemCubeBuilder.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.concurrent.BlockingQueue; import org.apache.kylin.common.util.Dictionary; +import org.apache.kylin.cube.cuboid.CuboidScheduler; import org.apache.kylin.cube.model.CubeDesc; import org.apache.kylin.gridtable.GTRecord; import org.apache.kylin.gridtable.GTScanRequest; @@ -42,6 +43,7 @@ abstract public class AbstractInMemCubeBuilder { private static Logger logger = LoggerFactory.getLogger(AbstractInMemCubeBuilder.class); + final protected CuboidScheduler cuboidScheduler; final protected IJoinedFlatTableDesc flatDesc; final protected CubeDesc cubeDesc; final protected Map<TblColRef, Dictionary<String>> dictionaryMap; @@ -49,16 +51,23 @@ abstract public class AbstractInMemCubeBuilder { protected int taskThreadCount = 1; protected int reserveMemoryMB = 100; - public AbstractInMemCubeBuilder(CubeDesc cubeDesc, IJoinedFlatTableDesc flatDesc, Map<TblColRef, Dictionary<String>> dictionaryMap) { - if (flatDesc == null) + // @Deprecated + // public AbstractInMemCubeBuilder(CubeDesc cubeDesc, IJoinedFlatTableDesc flatDesc, Map<TblColRef, Dictionary<String>> dictionaryMap) { + // this(cubeDesc.getInitialCuboidScheduler(), cubeDesc, flatDesc, dictionaryMap); + // } + + protected AbstractInMemCubeBuilder(CuboidScheduler cuboidScheduler, IJoinedFlatTableDesc flatDesc, + Map<TblColRef, Dictionary<String>> dictionaryMap) { + if (cuboidScheduler == null) throw new NullPointerException(); - if (cubeDesc == null) + if (flatDesc == null) throw new NullPointerException(); if (dictionaryMap == null) throw new IllegalArgumentException("dictionary cannot be null"); + this.cuboidScheduler = cuboidScheduler; this.flatDesc = flatDesc; - this.cubeDesc = cubeDesc; + this.cubeDesc = cuboidScheduler.getCubeDesc(); this.dictionaryMap = dictionaryMap; } http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/DoggedCubeBuilder.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/DoggedCubeBuilder.java b/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/DoggedCubeBuilder.java index a9211da..dd92a2b 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/DoggedCubeBuilder.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/DoggedCubeBuilder.java @@ -35,7 +35,7 @@ import org.apache.kylin.common.util.ByteArray; import org.apache.kylin.common.util.Dictionary; import org.apache.kylin.common.util.ImmutableBitSet; import org.apache.kylin.common.util.MemoryBudgetController; -import org.apache.kylin.cube.model.CubeDesc; +import org.apache.kylin.cube.cuboid.CuboidScheduler; import org.apache.kylin.gridtable.GTRecord; import org.apache.kylin.gridtable.GTScanRequestBuilder; import org.apache.kylin.gridtable.IGTScanner; @@ -57,8 +57,9 @@ public class DoggedCubeBuilder extends AbstractInMemCubeBuilder { private int splitRowThreshold = Integer.MAX_VALUE; private int unitRows = 1000; - public DoggedCubeBuilder(CubeDesc cubeDesc, IJoinedFlatTableDesc flatDesc, Map<TblColRef, Dictionary<String>> dictionaryMap) { - super(cubeDesc, flatDesc, dictionaryMap); + public DoggedCubeBuilder(CuboidScheduler cuboidScheduler, IJoinedFlatTableDesc flatDesc, + Map<TblColRef, Dictionary<String>> dictionaryMap) { + super(cuboidScheduler, flatDesc, dictionaryMap); // check memory more often if a single row is big if (cubeDesc.hasMemoryHungryMeasures()) @@ -276,7 +277,7 @@ public class DoggedCubeBuilder extends AbstractInMemCubeBuilder { RuntimeException exception; public SplitThread() { - this.builder = new InMemCubeBuilder(cubeDesc, flatDesc, dictionaryMap); + this.builder = new InMemCubeBuilder(cuboidScheduler, flatDesc, dictionaryMap); this.builder.setConcurrentThreads(taskThreadCount); this.builder.setReserveMemoryMB(reserveMemoryMB); } http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/InMemCubeBuilder.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/InMemCubeBuilder.java b/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/InMemCubeBuilder.java index 93736c9..684c26b 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/InMemCubeBuilder.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/inmemcubing/InMemCubeBuilder.java @@ -39,7 +39,6 @@ import org.apache.kylin.cube.cuboid.Cuboid; import org.apache.kylin.cube.cuboid.CuboidScheduler; import org.apache.kylin.cube.gridtable.CubeGridTable; import org.apache.kylin.cube.kv.CubeDimEncMap; -import org.apache.kylin.cube.model.CubeDesc; import org.apache.kylin.gridtable.GTAggregateScanner; import org.apache.kylin.gridtable.GTBuilder; import org.apache.kylin.gridtable.GTInfo; @@ -71,7 +70,6 @@ public class InMemCubeBuilder extends AbstractInMemCubeBuilder { private static final double DERIVE_AGGR_CACHE_CONSTANT_FACTOR = 0.1; private static final double DERIVE_AGGR_CACHE_VARIABLE_FACTOR = 0.9; - private final CuboidScheduler cuboidScheduler; private final long baseCuboidId; private final int totalCuboidCount; private final String[] metricsAggrFuncs; @@ -90,9 +88,9 @@ public class InMemCubeBuilder extends AbstractInMemCubeBuilder { private Object[] totalSumForSanityCheck; private ICuboidCollector resultCollector; - public InMemCubeBuilder(CubeDesc cubeDesc, IJoinedFlatTableDesc flatDesc, Map<TblColRef, Dictionary<String>> dictionaryMap) { - super(cubeDesc, flatDesc, dictionaryMap); - this.cuboidScheduler = cubeDesc.getCuboidScheduler(); + public InMemCubeBuilder(CuboidScheduler cuboidScheduler, IJoinedFlatTableDesc flatDesc, + Map<TblColRef, Dictionary<String>> dictionaryMap) { + super(cuboidScheduler, flatDesc, dictionaryMap); this.baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); this.totalCuboidCount = cuboidScheduler.getCuboidCount(); @@ -109,8 +107,7 @@ public class InMemCubeBuilder extends AbstractInMemCubeBuilder { } private GridTable newGridTableByCuboidID(long cuboidID) throws IOException { - GTInfo info = CubeGridTable.newGTInfo( - Cuboid.findById(cubeDesc, cuboidID), + GTInfo info = CubeGridTable.newGTInfo(Cuboid.findById(cuboidScheduler, cuboidID), new CubeDimEncMap(cubeDesc, dictionaryMap) ); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyDecoder.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyDecoder.java b/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyDecoder.java index d5948d4..5a1f668 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyDecoder.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyDecoder.java @@ -36,6 +36,7 @@ import org.apache.kylin.metadata.model.TblColRef; */ public class RowKeyDecoder { + private final CubeSegment cubeSegment; private final CubeDesc cubeDesc; private final RowKeyColumnIO colIO; private final RowKeySplitter rowKeySplitter; @@ -44,6 +45,7 @@ public class RowKeyDecoder { private List<String> values; public RowKeyDecoder(CubeSegment cubeSegment) { + this.cubeSegment = cubeSegment; this.cubeDesc = cubeSegment.getCubeDesc(); this.rowKeySplitter = new RowKeySplitter(cubeSegment, 65, 255); this.colIO = new RowKeyColumnIO(cubeSegment.getDimensionEncodingMap()); @@ -73,7 +75,7 @@ public class RowKeyDecoder { if (this.cuboid != null && this.cuboid.getId() == cuboidID) { return; } - this.cuboid = Cuboid.findById(cubeDesc, cuboidID); + this.cuboid = Cuboid.findById(cubeSegment, cuboidID); } private void collectValue(TblColRef col, byte[] valueBytes, int length) throws IOException { http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyEncoder.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyEncoder.java b/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyEncoder.java index a669fb1..40cda76 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyEncoder.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/kv/RowKeyEncoder.java @@ -18,7 +18,11 @@ package org.apache.kylin.cube.kv; -import com.google.common.base.Preconditions; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.kylin.common.util.ByteArray; import org.apache.kylin.common.util.BytesUtil; import org.apache.kylin.common.util.ImmutableBitSet; @@ -28,10 +32,7 @@ import org.apache.kylin.cube.cuboid.Cuboid; import org.apache.kylin.gridtable.GTRecord; import org.apache.kylin.metadata.model.TblColRef; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; +import com.google.common.base.Preconditions; public class RowKeyEncoder extends AbstractRowKeyEncoder implements java.io.Serializable { http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/model/AggregationGroup.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/AggregationGroup.java b/core-cube/src/main/java/org/apache/kylin/cube/model/AggregationGroup.java index af026af..852451d 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/model/AggregationGroup.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/AggregationGroup.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.TreeSet; import org.apache.kylin.cube.cuboid.Cuboid; +import org.apache.kylin.cube.cuboid.DefaultCuboidScheduler; import org.apache.kylin.metadata.model.TblColRef; import com.fasterxml.jackson.annotation.JsonAutoDetect; @@ -295,7 +296,8 @@ public class AggregationGroup implements Serializable { long combination = 1; if (this.getDimCap() > 0) { - combination = cubeDesc.getCuboidScheduler().calculateCuboidsForAggGroup(this).size(); + DefaultCuboidScheduler cuboidScheduler = cubeDesc.getInitialCuboidScheduler(); + combination = cuboidScheduler.calculateCuboidsForAggGroup(this).size(); } else { Set<String> includeDims = new TreeSet<>(Arrays.asList(includes)); Set<String> mandatoryDims = new TreeSet<>(Arrays.asList(selectRule.mandatoryDims)); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java index 3cbba50..dff3485 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java @@ -51,7 +51,7 @@ import org.apache.kylin.common.persistence.RootPersistentEntity; import org.apache.kylin.common.util.Array; import org.apache.kylin.common.util.JsonUtil; import org.apache.kylin.common.util.Pair; -import org.apache.kylin.cube.cuboid.CuboidScheduler; +import org.apache.kylin.cube.cuboid.DefaultCuboidScheduler; import org.apache.kylin.measure.MeasureType; import org.apache.kylin.measure.extendedcolumn.ExtendedColumnMeasureType; import org.apache.kylin.metadata.MetadataConstants; @@ -189,8 +189,6 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { @JsonInclude(JsonInclude.Include.NON_NULL) private int parentForward = 3; - transient private CuboidScheduler cuboidScheduler = null; - public boolean isEnableSharding() { //in the future may extend to other storage that is shard-able return storageType != IStorageAware.ID_HBASE && storageType != IStorageAware.ID_HYBRID; @@ -459,14 +457,6 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { return true; } - /** - * Get cuboid level count except base cuboid - * @return - */ - public int getBuildLevel() { - return getCuboidScheduler().getCuboidsByLayer().size() - 1; - } - @Override public int hashCode() { int result = 0; @@ -560,7 +550,6 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { hostToDerivedMap = Maps.newHashMap(); extendedColumnToHosts = Maps.newHashMap(); cuboidBlackSet = Sets.newHashSet(); - cuboidScheduler = null; } public void init(KylinConfig config) { @@ -618,16 +607,16 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { amendAllColumns(); } - public CuboidScheduler getCuboidScheduler() { - if (cuboidScheduler != null) - return cuboidScheduler; + public DefaultCuboidScheduler getInitialCuboidScheduler() { + return new DefaultCuboidScheduler(this); + } - synchronized (this) { - if (cuboidScheduler == null) { - cuboidScheduler = CuboidScheduler.getInstance(this); - } - return cuboidScheduler; - } + /** + * Get cuboid level count except base cuboid + * @return + */ + public int getInitialBuildLevel() { + return getInitialCuboidScheduler().getCuboidsByLayer().size() - 1; } public boolean isBlackedCuboid(long cuboidID) { @@ -1169,7 +1158,7 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { } public Set<Long> getAllCuboids() { - return getCuboidScheduler().getAllCuboidIds(); + return getInitialCuboidScheduler().getAllCuboidIds(); } public int getParentForward() { http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/model/CubeJoinedFlatTableEnrich.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeJoinedFlatTableEnrich.java b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeJoinedFlatTableEnrich.java index 223df7c..73da802 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeJoinedFlatTableEnrich.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeJoinedFlatTableEnrich.java @@ -53,8 +53,7 @@ public class CubeJoinedFlatTableEnrich implements IJoinedFlatTableDesc, Serializ // check what columns from hive tables are required, and index them private void parseCubeDesc() { - long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); - Cuboid baseCuboid = Cuboid.findById(cubeDesc, baseCuboidId); + Cuboid baseCuboid = Cuboid.getBaseCuboid(cubeDesc); // build index for rowkey columns List<TblColRef> cuboidColumns = baseCuboid.getColumns(); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/main/java/org/apache/kylin/cube/util/CubingUtils.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/util/CubingUtils.java b/core-cube/src/main/java/org/apache/kylin/cube/util/CubingUtils.java index 1c3c395..ec4c04a 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/util/CubingUtils.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/util/CubingUtils.java @@ -57,7 +57,7 @@ public class CubingUtils { public static Map<Long, HLLCounter> sampling(CubeDesc cubeDesc, IJoinedFlatTableDesc flatDescIn, Iterable<List<String>> streams) { final CubeJoinedFlatTableEnrich flatDesc = new CubeJoinedFlatTableEnrich(flatDescIn, cubeDesc); final int rowkeyLength = cubeDesc.getRowkey().getRowKeyColumns().length; - final Set<Long> allCuboidIds = cubeDesc.getCuboidScheduler().getAllCuboidIds(); + final Set<Long> allCuboidIds = cubeDesc.getInitialCuboidScheduler().getAllCuboidIds(); final long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); final Map<Long, Integer[]> allCuboidsBitSet = Maps.newHashMap(); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidSchedulerTest.java ---------------------------------------------------------------------- diff --git a/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidSchedulerTest.java b/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidSchedulerTest.java index 58c0edb..3f3a7c4 100644 --- a/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidSchedulerTest.java +++ b/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidSchedulerTest.java @@ -115,7 +115,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { System.out.println("Spanning result for " + cuboidId + "(" + Long.toBinaryString(cuboidId) + "): " + toString(spannings)); for (long child : spannings) { - assertTrue(Cuboid.isValid(cube, child)); + assertTrue(scheduler.isValid(child)); } } @@ -128,7 +128,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testGetSpanningCuboid2() { CubeDesc cube = getTestKylinCubeWithSeller(); - CuboidScheduler scheduler = cube.getCuboidScheduler(); + CuboidScheduler scheduler = cube.getInitialCuboidScheduler(); // generate 8d System.out.println("Spanning for 8D Cuboids"); @@ -156,7 +156,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testGetSpanningCuboid1() { CubeDesc cube = getTestKylinCubeWithoutSeller(); - CuboidScheduler scheduler = cube.getCuboidScheduler(); + CuboidScheduler scheduler = cube.getInitialCuboidScheduler(); // generate 7d System.out.println("Spanning for 7D Cuboids"); @@ -228,7 +228,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testCuboidCounts1() { CubeDesc cube = getTestKylinCubeWithoutSeller(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); int[] counts = CuboidCLI.calculateAllLevelCount(cube); printCount(counts); int sum = 0; @@ -241,7 +241,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testCuboidCounts2() { CubeDesc cube = getTestKylinCubeWithoutSellerLeftJoin(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); int[] counts = CuboidCLI.calculateAllLevelCount(cube); printCount(counts); int sum = 0; @@ -254,7 +254,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testCuboidCounts3() { CubeDesc cube = getTestKylinCubeWithSeller(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); int[] counts = CuboidCLI.calculateAllLevelCount(cube); printCount(counts); int sum = 0; @@ -267,7 +267,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testCuboidCounts4() { CubeDesc cube = getTestKylinCubeWithSellerLeft(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); int[] counts = CuboidCLI.calculateAllLevelCount(cube); printCount(counts); int sum = 0; @@ -280,7 +280,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testCuboidCounts5() { CubeDesc cube = getStreamingCubeDesc(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); int[] counts = CuboidCLI.calculateAllLevelCount(cube); printCount(counts); int sum = 0; @@ -293,7 +293,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testCuboidCounts6() { CubeDesc cube = getCIInnerJoinCube(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); int[] counts = CuboidCLI.calculateAllLevelCount(cube); printCount(counts); int sum = 0; @@ -306,7 +306,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { @Test public void testLargeCube() { CubeDesc cube = getFiftyDimCubeDesc(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); long start = System.currentTimeMillis(); System.out.println(cuboidScheduler.getCuboidCount()); System.out.println("build tree takes: " + (System.currentTimeMillis() - start) + "ms"); @@ -317,7 +317,7 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { File twentyFile = new File(new File(LocalFileMetadataTestCase.LOCALMETA_TEMP_DATA, "cube_desc"), "twenty_dim"); twentyFile.renameTo(new File(twentyFile.getPath().substring(0, twentyFile.getPath().length() - 4))); CubeDesc cube = getTwentyDimCubeDesc(); - CuboidScheduler cuboidScheduler = cube.getCuboidScheduler(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); cuboidScheduler.getCuboidCount(); twentyFile.renameTo(new File(twentyFile.getPath() + ".bad")); } @@ -332,10 +332,10 @@ public class CuboidSchedulerTest extends LocalFileMetadataTestCase { } CubeDescManager.clearCache(); CubeDesc cube = getCubeDescManager().getCubeDesc("ut_large_dimension_number"); - CuboidScheduler scheduler = cube.getCuboidScheduler(); + CuboidScheduler scheduler = cube.getInitialCuboidScheduler(); Cuboid baseCuboid = Cuboid.getBaseCuboid(cube); - assertTrue(Cuboid.isValid(cube, baseCuboid.getId())); + assertTrue(scheduler.isValid(baseCuboid.getId())); List<Long> spanningChild = scheduler.getSpanningCuboid(baseCuboid.getId()); assertTrue(spanningChild.size() > 0); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidTest.java ---------------------------------------------------------------------- diff --git a/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidTest.java b/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidTest.java index 2e64791..8dc944b 100644 --- a/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidTest.java +++ b/core-cube/src/test/java/org/apache/kylin/cube/cuboid/CuboidTest.java @@ -73,25 +73,26 @@ public class CuboidTest extends LocalFileMetadataTestCase { public void testIsValid() { CubeDesc cube = getTestKylinCubeWithSeller(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); // base - assertEquals(false, Cuboid.isValid(cube, 0)); - assertEquals(true, Cuboid.isValid(cube, toLong("111111111"))); + assertEquals(false, cuboidScheduler.isValid(0)); + assertEquals(true, cuboidScheduler.isValid(toLong("111111111"))); // mandatory column - assertEquals(false, Cuboid.isValid(cube, toLong("011111110"))); - assertEquals(false, Cuboid.isValid(cube, toLong("100000000"))); + assertEquals(false, cuboidScheduler.isValid(toLong("011111110"))); + assertEquals(false, cuboidScheduler.isValid(toLong("100000000"))); // zero tail - assertEquals(true, Cuboid.isValid(cube, toLong("111111000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("111111000"))); // aggregation group & zero tail - assertEquals(true, Cuboid.isValid(cube, toLong("110000111"))); - assertEquals(true, Cuboid.isValid(cube, toLong("110111000"))); - assertEquals(true, Cuboid.isValid(cube, toLong("111110111"))); - assertEquals(false, Cuboid.isValid(cube, toLong("111110001"))); - assertEquals(false, Cuboid.isValid(cube, toLong("111110100"))); - assertEquals(false, Cuboid.isValid(cube, toLong("110000100"))); + assertEquals(true, cuboidScheduler.isValid(toLong("110000111"))); + assertEquals(true, cuboidScheduler.isValid(toLong("110111000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("111110111"))); + assertEquals(false, cuboidScheduler.isValid(toLong("111110001"))); + assertEquals(false, cuboidScheduler.isValid(toLong("111110100"))); + assertEquals(false, cuboidScheduler.isValid(toLong("110000100"))); } @Test @@ -124,41 +125,45 @@ public class CuboidTest extends LocalFileMetadataTestCase { @Test public void testIsValid2() { CubeDesc cube = getTestKylinCubeWithoutSeller(); - assertEquals(false, Cuboid.isValid(cube, toLong("111111111"))); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); + + assertEquals(false, cuboidScheduler.isValid(toLong("111111111"))); // base - assertEquals(false, Cuboid.isValid(cube, 0)); - assertEquals(true, Cuboid.isValid(cube, toLong("11111111"))); + assertEquals(false, cuboidScheduler.isValid(0)); + assertEquals(true, cuboidScheduler.isValid(toLong("11111111"))); // aggregation group & zero tail - assertEquals(true, Cuboid.isValid(cube, toLong("10000111"))); - assertEquals(false, Cuboid.isValid(cube, toLong("10001111"))); - assertEquals(false, Cuboid.isValid(cube, toLong("11001111"))); - assertEquals(true, Cuboid.isValid(cube, toLong("10000001"))); - assertEquals(true, Cuboid.isValid(cube, toLong("10000101"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10000111"))); + assertEquals(false, cuboidScheduler.isValid(toLong("10001111"))); + assertEquals(false, cuboidScheduler.isValid(toLong("11001111"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10000001"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10000101"))); // hierarchy - assertEquals(true, Cuboid.isValid(cube, toLong("10100000"))); - assertEquals(true, Cuboid.isValid(cube, toLong("10110000"))); - assertEquals(true, Cuboid.isValid(cube, toLong("10111000"))); - assertEquals(false, Cuboid.isValid(cube, toLong("10001000"))); - assertEquals(false, Cuboid.isValid(cube, toLong("10011000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10100000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10110000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10111000"))); + assertEquals(false, cuboidScheduler.isValid(toLong("10001000"))); + assertEquals(false, cuboidScheduler.isValid(toLong("10011000"))); } @Test public void testIsValid3() { CubeDesc cube = getSSBCubeDesc(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); - assertEquals(false, Cuboid.isValid(cube, toLong("10000000000"))); + assertEquals(false, cuboidScheduler.isValid(toLong("10000000000"))); // the 4th is mandatory and isMandatoryOnlyValid is true - assertEquals(true, Cuboid.isValid(cube, toLong("10000001000"))); - assertEquals(true, Cuboid.isValid(cube, toLong("00000001000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("10000001000"))); + assertEquals(true, cuboidScheduler.isValid(toLong("00000001000"))); } @Test public void testFindCuboidByIdWithSingleAggrGroup2() { CubeDesc cube = getTestKylinCubeWithSeller(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); Cuboid cuboid; cuboid = Cuboid.findById(cube, 0); @@ -186,6 +191,7 @@ public class CuboidTest extends LocalFileMetadataTestCase { @Test public void testFindCuboidByIdWithMultiAggrGroup() { CubeDesc cube = getTestKylinCubeWithoutSellerLeftJoin(); + CuboidScheduler cuboidScheduler = cube.getInitialCuboidScheduler(); Cuboid cuboid; cuboid = Cuboid.findById(cube, toLong("111111110")); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyDecoderTest.java ---------------------------------------------------------------------- diff --git a/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyDecoderTest.java b/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyDecoderTest.java index 1d1d147..ec1f221 100644 --- a/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyDecoderTest.java +++ b/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyDecoderTest.java @@ -91,7 +91,7 @@ public class RowKeyDecoderTest extends LocalFileMetadataTestCase { data[7] = "15"; long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); - Cuboid baseCuboid = Cuboid.findById(cubeDesc, baseCuboidId); + Cuboid baseCuboid = Cuboid.findById(cube, baseCuboidId); RowKeyEncoder rowKeyEncoder = new RowKeyEncoder(cube.getFirstSegment(), baseCuboid); byte[] encodedKey = rowKeyEncoder.encode(data); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyEncoderTest.java ---------------------------------------------------------------------- diff --git a/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyEncoderTest.java b/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyEncoderTest.java index 75e2458..5af8d8a 100644 --- a/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyEncoderTest.java +++ b/core-cube/src/test/java/org/apache/kylin/cube/kv/RowKeyEncoderTest.java @@ -66,7 +66,7 @@ public class RowKeyEncoderTest extends LocalFileMetadataTestCase { data[7] = "15"; long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); - Cuboid baseCuboid = Cuboid.findById(cubeDesc, baseCuboidId); + Cuboid baseCuboid = Cuboid.findById(cube, baseCuboidId); RowKeyEncoder rowKeyEncoder = new RowKeyEncoder(cube.getFirstSegment(), baseCuboid); byte[] encodedKey = rowKeyEncoder.encode(data); @@ -97,7 +97,7 @@ public class RowKeyEncoderTest extends LocalFileMetadataTestCase { data[8] = "15"; long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); - Cuboid baseCuboid = Cuboid.findById(cubeDesc, baseCuboidId); + Cuboid baseCuboid = Cuboid.findById(cube, baseCuboidId); RowKeyEncoder rowKeyEncoder = new RowKeyEncoder(cube.getFirstSegment(), baseCuboid); byte[] encodedKey = rowKeyEncoder.encode(data); @@ -133,7 +133,7 @@ public class RowKeyEncoderTest extends LocalFileMetadataTestCase { data[8] = null; long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); - Cuboid baseCuboid = Cuboid.findById(cubeDesc, baseCuboidId); + Cuboid baseCuboid = Cuboid.findById(cube, baseCuboidId); RowKeyEncoder rowKeyEncoder = new RowKeyEncoder(cube.getFirstSegment(), baseCuboid); byte[] encodedKey = rowKeyEncoder.encode(data); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java ---------------------------------------------------------------------- diff --git a/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java b/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java index a3af511..a1a39be 100644 --- a/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java +++ b/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java @@ -131,7 +131,7 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { Set<TblColRef> dimensionsD = new LinkedHashSet<TblColRef>(); dimensionsD.addAll(groupsD); dimensionsD.addAll(otherDimsD); - Cuboid cuboid = findCuboid(cubeDesc, dimensionsD, metrics); + Cuboid cuboid = findCuboid(cubeInstance, dimensionsD, metrics); context.setCuboid(cuboid); // set whether to aggr at storage @@ -171,8 +171,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { protected abstract String getGTStorage(); - protected Cuboid findCuboid(CubeDesc cubeDesc, Set<TblColRef> dimensionsD, Set<FunctionDesc> metrics) { - return Cuboid.identifyCuboid(cubeDesc, dimensionsD, metrics); + protected Cuboid findCuboid(CubeInstance cubeInstance, Set<TblColRef> dimensionsD, Set<FunctionDesc> metrics) { + return Cuboid.identifyCuboid(cubeInstance, dimensionsD, metrics); } protected ITupleConverter newCubeTupleConverter(CubeSegment cubeSeg, Cuboid cuboid, http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/core-storage/src/main/java/org/apache/kylin/storage/translate/HBaseKeyRange.java ---------------------------------------------------------------------- diff --git a/core-storage/src/main/java/org/apache/kylin/storage/translate/HBaseKeyRange.java b/core-storage/src/main/java/org/apache/kylin/storage/translate/HBaseKeyRange.java index 5db3611..85678ac 100644 --- a/core-storage/src/main/java/org/apache/kylin/storage/translate/HBaseKeyRange.java +++ b/core-storage/src/main/java/org/apache/kylin/storage/translate/HBaseKeyRange.java @@ -84,7 +84,7 @@ public class HBaseKeyRange implements Comparable<HBaseKeyRange> { public HBaseKeyRange(Collection<TblColRef> dimensionColumns, Collection<ColumnValueRange> andDimensionRanges, CubeSegment cubeSeg, CubeDesc cubeDesc) { this.cubeSeg = cubeSeg; long cuboidId = this.calculateCuboidID(cubeDesc, dimensionColumns); - this.cuboid = Cuboid.findById(cubeDesc, cuboidId); + this.cuboid = Cuboid.findById(cubeSeg, cuboidId); this.flatOrAndFilter = Lists.newLinkedList(); this.flatOrAndFilter.add(andDimensionRanges); init(andDimensionRanges); http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder.java ---------------------------------------------------------------------- diff --git a/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder.java b/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder.java index 1ec23b6..f64365a 100644 --- a/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder.java +++ b/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder.java @@ -64,7 +64,7 @@ public class BatchCubingJobBuilder extends JobBuilderSupport { // Phase 3: Build Cube RowKeyDesc rowKeyDesc = seg.getCubeDesc().getRowkey(); - final int groupRowkeyColumnsCount = seg.getCubeDesc().getBuildLevel(); + final int groupRowkeyColumnsCount = seg.getCuboidScheduler().getBuildLevel(); // base cuboid step result.addTask(createBaseCuboidStep(getCuboidOutputPathsByLevel(cuboidRootPath, 0), jobId)); // n dim cuboid steps http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder2.java ---------------------------------------------------------------------- diff --git a/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder2.java b/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder2.java index 106077c..51c9056 100644 --- a/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder2.java +++ b/engine-mr/src/main/java/org/apache/kylin/engine/mr/BatchCubingJobBuilder2.java @@ -76,7 +76,7 @@ public class BatchCubingJobBuilder2 extends JobBuilderSupport { } protected void addLayerCubingSteps(final CubingJob result, final String jobId, final String cuboidRootPath) { - final int maxLevel = seg.getCubeDesc().getBuildLevel(); + final int maxLevel = seg.getCuboidScheduler().getBuildLevel(); // base cuboid step result.addTask(createBaseCuboidStep(getCuboidOutputPathsByLevel(cuboidRootPath, 0), jobId)); // n dim cuboid steps http://git-wip-us.apache.org/repos/asf/kylin/blob/465c5070/engine-mr/src/main/java/org/apache/kylin/engine/mr/common/BaseCuboidBuilder.java ---------------------------------------------------------------------- diff --git a/engine-mr/src/main/java/org/apache/kylin/engine/mr/common/BaseCuboidBuilder.java b/engine-mr/src/main/java/org/apache/kylin/engine/mr/common/BaseCuboidBuilder.java index 07b636b..40f1ac5 100644 --- a/engine-mr/src/main/java/org/apache/kylin/engine/mr/common/BaseCuboidBuilder.java +++ b/engine-mr/src/main/java/org/apache/kylin/engine/mr/common/BaseCuboidBuilder.java @@ -18,7 +18,11 @@ package org.apache.kylin.engine.mr.common; -import com.google.common.collect.Sets; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.util.Dictionary; import org.apache.kylin.cube.CubeSegment; @@ -35,10 +39,7 @@ import org.apache.kylin.metadata.model.TblColRef; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.ByteBuffer; -import java.util.List; -import java.util.Map; -import java.util.Set; +import com.google.common.collect.Sets; /** */ @@ -88,8 +89,7 @@ public class BaseCuboidBuilder implements java.io.Serializable { } private void init() { - long baseCuboidId = Cuboid.getBaseCuboidId(cubeDesc); - baseCuboid = Cuboid.findById(cubeDesc, baseCuboidId); + baseCuboid = Cuboid.getBaseCuboid(cubeDesc); initNullBytes(); }