You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lens.apache.org by am...@apache.org on 2015/04/07 14:21:11 UTC
incubator-lens git commit: LENS-462 : Handle the case when a table
property becomes large for a timeline (Rajat Khandelwal via amareshwari)
Repository: incubator-lens
Updated Branches:
refs/heads/master 07492f187 -> 21102e6b9
LENS-462 : Handle the case when a table property becomes large for a timeline (Rajat Khandelwal via amareshwari)
Project: http://git-wip-us.apache.org/repos/asf/incubator-lens/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-lens/commit/21102e6b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-lens/tree/21102e6b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-lens/diff/21102e6b
Branch: refs/heads/master
Commit: 21102e6b96c3139563ef02449a6857bf48d983c4
Parents: 07492f1
Author: Rajat Khandelwal <pr...@apache.org>
Authored: Tue Apr 7 17:50:48 2015 +0530
Committer: Amareshwari Sriramadasu <am...@apache.org>
Committed: Tue Apr 7 17:50:48 2015 +0530
----------------------------------------------------------------------
.../lens/cube/metadata/CubeMetastoreClient.java | 95 ++++++++------
.../lens/cube/metadata/MetastoreUtil.java | 16 ++-
.../lens/cube/metadata/TimePartition.java | 77 ++---------
.../lens/cube/metadata/TimePartitionRange.java | 130 +++++++++++++++++++
.../timeline/EndsAndHolesPartitionTimeline.java | 9 +-
.../timeline/RangesPartitionTimeline.java | 27 ++--
.../timeline/StoreAllPartitionTimeline.java | 5 +-
.../lens/cube/parse/StorageTableResolver.java | 2 +-
.../lens/cube/metadata/TestTimePartition.java | 94 ++++++++++++--
.../timeline/TestPartitionTimelines.java | 38 ++++--
.../apache/lens/cube/parse/CubeTestSetup.java | 6 +-
11 files changed, 335 insertions(+), 164 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
index 1835d2f..11ef7ec 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/CubeMetastoreClient.java
@@ -186,56 +186,72 @@ public class CubeMetastoreClient {
if (get(storageTableName) == null) {
synchronized (this) {
if (get(storageTableName) == null) {
- log.info("loading timeline from all partitions for storage table: " + storageTableName);
- // not found in memory, try loading from table properties.
Table storageTable = getTable(storageTableName);
- if (!"true".equalsIgnoreCase(
- storageTable.getParameters().get(MetastoreUtil.getPartitoinTimelineCachePresenceKey()))) {
- // Not found in table properties either, compute from all partitions of the fact-storage table.
- // First make sure all combinations of update period and partition column have an entry even
- // if no partitions exist
- log.info("loading from all partitions");
- if (getCubeFact(fact).getUpdatePeriods() != null && getCubeFact(fact).getUpdatePeriods().get(
- storage) != null) {
- for (UpdatePeriod updatePeriod : getCubeFact(fact).getUpdatePeriods().get(storage)) {
- for (String partCol : getTimePartsOfTable(storageTable)) {
- partitionTimelineCache.ensureEntry(storageTableName, updatePeriod, partCol);
- }
- }
- }
- // Then add all existing partitions for batch addition in respective timelines.
- List<String> timeParts = getTimePartsOfTable(storageTable);
- List<FieldSchema> partCols = storageTable.getPartCols();
- for (Partition partition : getPartitionsByFilter(storageTableName, null)) {
- UpdatePeriod period = deduceUpdatePeriod(partition);
- List<String> values = partition.getValues();
- for (int i = 0; i < partCols.size(); i++) {
- if (timeParts.contains(partCols.get(i).getName())) {
- partitionTimelineCache.addForBatchAddition(storageTableName, period, partCols.get(i).getName(),
- values.get(i));
- }
- }
+ if ("true".equalsIgnoreCase(storageTable.getParameters().get(
+ MetastoreUtil.getPartitoinTimelineCachePresenceKey()))) {
+ try {
+ loadTimelinesFromTableProperties(fact, storage);
+ } catch (Exception e) {
+ // Ideally this should never come. But since we have another source,
+ // let's piggyback on that for loading timeline
+ log.error("Error while loading timelines from table properties.", e);
+ loadTimelinesFromAllPartitions(fact, storage);
}
- // commit all batch addition for the storage table,
- // which will in-turn commit all batch additions in all it's timelines.
- commitAllBatchAdditions(storageTableName);
} else {
- // found in table properties, load from there.
- log.info("loading from table properties");
- for (UpdatePeriod updatePeriod : getCubeFact(fact).getUpdatePeriods().get(storage)) {
- for (String partCol : getTimePartsOfTable(storageTableName)) {
- ensureEntry(storageTableName, updatePeriod, partCol).init(storageTable);
- }
- }
+ loadTimelinesFromAllPartitions(fact, storage);
}
}
}
+ log.info("timeline for " + storageTableName + " is: " + get(storageTableName));
}
// return the final value from memory
return get(storageTableName);
// RESUME CHECKSTYLE CHECK DoubleCheckedLockingCheck
}
+ private void loadTimelinesFromAllPartitions(String fact, String storage) throws HiveException, LensException {
+ // Not found in table properties either, compute from all partitions of the fact-storage table.
+ // First make sure all combinations of update period and partition column have an entry even
+ // if no partitions exist
+ String storageTableName = MetastoreUtil.getStorageTableName(fact, Storage.getPrefix(storage));
+ log.info("loading from all partitions: " + storageTableName);
+ Table storageTable = getTable(storageTableName);
+ if (getCubeFact(fact).getUpdatePeriods() != null && getCubeFact(fact).getUpdatePeriods().get(
+ storage) != null) {
+ for (UpdatePeriod updatePeriod : getCubeFact(fact).getUpdatePeriods().get(storage)) {
+ for (String partCol : getTimePartsOfTable(storageTable)) {
+ ensureEntry(storageTableName, updatePeriod, partCol);
+ }
+ }
+ }
+ // Then add all existing partitions for batch addition in respective timelines.
+ List<String> timeParts = getTimePartsOfTable(storageTable);
+ List<FieldSchema> partCols = storageTable.getPartCols();
+ for (Partition partition : getPartitionsByFilter(storageTableName, null)) {
+ UpdatePeriod period = deduceUpdatePeriod(partition);
+ List<String> values = partition.getValues();
+ for (int i = 0; i < partCols.size(); i++) {
+ if (timeParts.contains(partCols.get(i).getName())) {
+ addForBatchAddition(storageTableName, period, partCols.get(i).getName(), values.get(i));
+ }
+ }
+ }
+ // commit all batch addition for the storage table,
+ // which will in-turn commit all batch additions in all it's timelines.
+ commitAllBatchAdditions(storageTableName);
+ }
+
+ private void loadTimelinesFromTableProperties(String fact, String storage) throws HiveException, LensException {
+ // found in table properties, load from there.
+ String storageTableName = MetastoreUtil.getStorageTableName(fact, Storage.getPrefix(storage));
+ log.info("loading from table properties: " + storageTableName);
+ for (UpdatePeriod updatePeriod : getCubeFact(fact).getUpdatePeriods().get(storage)) {
+ for (String partCol : getTimePartsOfTable(storageTableName)) {
+ ensureEntry(storageTableName, updatePeriod, partCol).init(getTable(storageTableName));
+ }
+ }
+ }
+
/**
* Adds given partition(for storageTable, updatePeriod, partitionColum=partition) for batch addition in an
* appropriate timeline object. Ignore if partition is not valid.
@@ -277,8 +293,7 @@ public class CubeMetastoreClient {
get(storageTable).get(updatePeriod).put(partitionColumn, PartitionTimelineFactory.get(
CubeMetastoreClient.this, storageTable, updatePeriod, partitionColumn));
}
- PartitionTimeline ret = get(storageTable).get(updatePeriod).get(partitionColumn);
- return ret;
+ return get(storageTable).get(updatePeriod).get(partitionColumn);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/MetastoreUtil.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/MetastoreUtil.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/MetastoreUtil.java
index 0be8e5f..203ff58 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/MetastoreUtil.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/MetastoreUtil.java
@@ -402,12 +402,18 @@ public class MetastoreUtil {
}
public static String getNamedStringValue(Map<String, String> props, String key) {
- int size = Integer.parseInt(props.get(key + ".size"));
- StringBuilder valueStr = new StringBuilder();
- for (int i = 0; i < size; i++) {
- valueStr.append(props.get(key + i));
+ if (props.containsKey(key + ".size")) {
+ int size = Integer.parseInt(props.get(key + ".size"));
+ StringBuilder valueStr = new StringBuilder();
+ for (int i = 0; i < size; i++) {
+ valueStr.append(props.get(key + i));
+ }
+ return valueStr.toString();
+ } else if (props.containsKey(key)) {
+ return props.get(key);
+ } else {
+ return null;
}
- return valueStr.toString();
}
public static String getObjectStr(Collection<?> set) {
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartition.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartition.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartition.java
index b948467..8f088c0 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartition.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartition.java
@@ -21,7 +21,6 @@ package org.apache.lens.cube.metadata;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
-import java.util.Iterator;
import org.apache.lens.api.LensException;
@@ -32,7 +31,7 @@ import lombok.NonNull;
/** stores a partition's update period, date and string representation. Provides some utility methods around it */
@Data
-public class TimePartition implements Comparable<TimePartition> {
+public class TimePartition implements Comparable<TimePartition>, Named {
private static final String UPDATE_PERIOD_WRONG_ERROR_MESSAGE = "Update period %s not correct for parsing %s";
private final UpdatePeriod updatePeriod;
private final Date date;
@@ -89,6 +88,9 @@ public class TimePartition implements Comparable<TimePartition> {
public TimePartition partitionAtDiff(int increment) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
+ if (getUpdatePeriod().equals(UpdatePeriod.QUARTERLY)) {
+ increment *= 3;
+ }
cal.add(updatePeriod.calendarField(), increment);
return new TimePartition(updatePeriod, cal.getTime());
}
@@ -125,78 +127,21 @@ public class TimePartition implements Comparable<TimePartition> {
return String.format(UPDATE_PERIOD_WRONG_ERROR_MESSAGE, up, dateString);
}
- public TimePartitionRange rangeUpto(TimePartition to) {
+ public TimePartitionRange rangeUpto(TimePartition to) throws LensException {
return new TimePartitionRange(this, to);
}
- public TimePartitionRange rangeFrom(TimePartition from) {
+ public TimePartitionRange rangeFrom(TimePartition from) throws LensException {
return new TimePartitionRange(from, this);
}
- public TimePartitionRange singletonRange() {
+ public TimePartitionRange singletonRange() throws LensException {
return rangeUpto(next());
}
- /**
- * Range of time partition. [begin,end). i.e. inclusive begin and exclusive end.
- */
- @Data
- public static class TimePartitionRange implements Iterable<TimePartition> {
- private TimePartition begin;
- private TimePartition end;
-
- public TimePartitionRange(TimePartition from, TimePartition to) {
- this.begin = from;
- this.end = to;
- }
-
- @Override
- public String toString() {
- return "[" + begin.getDateString() + ", " + end.getDateString() + ")";
- }
-
- /**
- * returns TimePartition objects starting from begin and upto(excluding) end. interval of iteration is the update
- * period of the partitions. Assumes both partitions have same update period.
- */
- @Override
- public Iterator<TimePartition> iterator() {
-
- return new Iterator<TimePartition>() {
- TimePartition current = begin;
-
- @Override
- public boolean hasNext() {
- return current.before(end);
- }
-
- @Override
- public TimePartition next() {
- TimePartition ret = current;
- current = current.next();
- return ret;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException("remove not supported");
- }
- };
- }
-
- /**
- * @param partition
- * @return begin <= partition < end
- */
- public boolean contains(TimePartition partition) {
- return !partition.before(begin) && partition.before(end);
- }
-
- /**
- * @return if range is empty range.
- */
- public boolean isEmpty() {
- return begin.equals(end);
- }
+ @Override
+ public String getName() {
+ return getDateString();
}
+
}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartitionRange.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartitionRange.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartitionRange.java
new file mode 100644
index 0000000..86c3453
--- /dev/null
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/TimePartitionRange.java
@@ -0,0 +1,130 @@
+/**
+ * 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.lens.cube.metadata;
+
+import java.util.Iterator;
+
+import org.apache.lens.api.LensException;
+import org.apache.lens.cube.parse.DateUtil;
+
+import lombok.Data;
+
+/**
+ * Range of time partition. [begin,end). i.e. inclusive begin and exclusive end.
+ */
+@Data
+public class TimePartitionRange implements Iterable<TimePartition>, Named {
+ private TimePartition begin;
+ private TimePartition end;
+
+ public TimePartitionRange(TimePartition begin, TimePartition end) throws LensException {
+ if (end.before(begin)) {
+ throw new LensException("condition of creation of timepartition failed: end>=begin");
+ }
+ if (end.getUpdatePeriod() != begin.getUpdatePeriod()) {
+ throw new LensException("update periods are not same");
+ }
+ this.begin = begin;
+ this.end = end;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + begin.getDateString() + ", " + end.getDateString() + ")";
+ }
+
+ /**
+ * returns TimePartition objects starting from begin and upto(excluding) end. interval of iteration is the update
+ * period of the partitions. Assumes both partitions have same update period.
+ */
+ @Override
+ public Iterator<TimePartition> iterator() {
+
+ return new Iterator<TimePartition>() {
+ TimePartition current = begin;
+
+ @Override
+ public boolean hasNext() {
+ return current.before(end);
+ }
+
+ @Override
+ public TimePartition next() {
+ TimePartition ret = current;
+ current = current.next();
+ return ret;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("remove not supported");
+ }
+ };
+ }
+
+ /**
+ * @param partition
+ * @return begin <= partition < end
+ */
+ public boolean contains(TimePartition partition) {
+ return !partition.before(begin) && partition.before(end);
+ }
+
+ /**
+ * @return if range is empty range.
+ */
+ public boolean isEmpty() {
+ return begin.equals(end);
+ }
+
+ @Override
+ public String getName() {
+ return toString();
+ }
+
+ public static TimePartitionRange parseFrom(UpdatePeriod updatePeriod, String from, String to) throws LensException {
+ boolean incrementFrom = false;
+ boolean incrementTo = false;
+ if (from.charAt(0) == '[') {
+ from = from.substring(1);
+ } else if (from.charAt(0) == '(') {
+ from = from.substring(1);
+ incrementFrom = true;
+ }
+ if (to.charAt(to.length() - 1) == ']') {
+ to = to.substring(0, to.length() - 1);
+ incrementTo = true;
+ } else if (to.charAt(to.length() - 1) == ')') {
+ to = to.substring(0, to.length() - 1);
+ }
+ TimePartition fromPartition = TimePartition.of(updatePeriod, from);
+ TimePartition toPartition = TimePartition.of(updatePeriod, to);
+ if (incrementFrom) {
+ fromPartition = fromPartition.next();
+ }
+ if (incrementTo) {
+ toPartition = toPartition.next();
+ }
+ return new TimePartitionRange(fromPartition, toPartition);
+ }
+
+ public long size() {
+ return DateUtil.getTimeDiff(begin.getDate(), end.getDate(), begin.getUpdatePeriod());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/EndsAndHolesPartitionTimeline.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/EndsAndHolesPartitionTimeline.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/EndsAndHolesPartitionTimeline.java
index 79e8a62..5867587 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/EndsAndHolesPartitionTimeline.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/EndsAndHolesPartitionTimeline.java
@@ -22,12 +22,11 @@ package org.apache.lens.cube.metadata.timeline;
import java.util.*;
import org.apache.lens.api.LensException;
+import org.apache.lens.cube.metadata.MetastoreUtil;
import org.apache.lens.cube.metadata.TimePartition;
import org.apache.lens.cube.metadata.UpdatePeriod;
import org.apache.lens.cube.parse.TimeRange;
-import org.apache.commons.lang.StringUtils;
-
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -99,12 +98,12 @@ public class EndsAndHolesPartitionTimeline extends PartitionTimeline {
@Override
public Map<String, String> toProperties() {
HashMap<String, String> ret = Maps.newHashMap();
+ MetastoreUtil.addNameStrings(ret, "holes", holes);
if (isEmpty()) {
return ret;
}
ret.put("first", first.getDateString());
ret.put("latest", latest.getDateString());
- ret.put("holes", StringUtils.join(holes, ","));
return ret;
}
@@ -115,7 +114,7 @@ public class EndsAndHolesPartitionTimeline extends PartitionTimeline {
holes.clear();
String firstStr = properties.get("first");
String latestStr = properties.get("latest");
- String holesStr = properties.get("holes");
+ String holesStr = MetastoreUtil.getNamedStringValue(properties, "holes");
if (!Strings.isNullOrEmpty(firstStr)) {
first = TimePartition.of(getUpdatePeriod(), firstStr);
}
@@ -124,7 +123,7 @@ public class EndsAndHolesPartitionTimeline extends PartitionTimeline {
}
holes = Sets.newTreeSet();
if (!Strings.isNullOrEmpty(holesStr)) {
- for (String hole : properties.get("holes").split("\\s*,\\s*")) {
+ for (String hole : holesStr.split("\\s*,\\s*")) {
holes.add(TimePartition.of(getUpdatePeriod(), hole));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/RangesPartitionTimeline.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/RangesPartitionTimeline.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/RangesPartitionTimeline.java
index fb2d0a8..8d80f0b 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/RangesPartitionTimeline.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/RangesPartitionTimeline.java
@@ -25,7 +25,9 @@ import java.util.List;
import java.util.Map;
import org.apache.lens.api.LensException;
+import org.apache.lens.cube.metadata.MetastoreUtil;
import org.apache.lens.cube.metadata.TimePartition;
+import org.apache.lens.cube.metadata.TimePartitionRange;
import org.apache.lens.cube.metadata.UpdatePeriod;
import com.google.common.base.Strings;
@@ -42,7 +44,7 @@ import lombok.ToString;
@Data
@ToString(callSuper = true)
public class RangesPartitionTimeline extends PartitionTimeline {
- private List<TimePartition.TimePartitionRange> ranges = Lists.newArrayList();
+ private List<TimePartitionRange> ranges = Lists.newArrayList();
public RangesPartitionTimeline(String storageTableName, UpdatePeriod updatePeriod,
String partCol) {
@@ -103,7 +105,7 @@ public class RangesPartitionTimeline extends PartitionTimeline {
private void mergeRanges() {
for (int i = 0; i < ranges.size() - 1; i++) {
if (ranges.get(i).getEnd().equals(ranges.get(i + 1).getBegin())) {
- TimePartition.TimePartitionRange removed = ranges.remove(i + 1);
+ TimePartitionRange removed = ranges.remove(i + 1);
ranges.get(i).setEnd(removed.getEnd());
i--; // check again at same index
}
@@ -143,32 +145,21 @@ public class RangesPartitionTimeline extends PartitionTimeline {
@Override
public Map<String, String> toProperties() {
HashMap<String, String> ret = Maps.newHashMap();
- if (isEmpty()) {
- return ret;
- }
- StringBuilder sb = new StringBuilder();
- String sep = "";
- for (TimePartition.TimePartitionRange range : ranges) {
- sb.append(sep);
- sep = ",";
- sb.append(range.getBegin()).append(sep).append(range.getEnd());
- }
- ret.put("ranges", sb.toString());
+ MetastoreUtil.addNameStrings(ret, "ranges", ranges);
return ret;
}
@Override
public boolean initFromProperties(Map<String, String> properties) throws LensException {
ranges.clear();
- String rangesStr = properties.get("ranges");
+ String rangesStr = MetastoreUtil.getNamedStringValue(properties, "ranges");
if (!Strings.isNullOrEmpty(rangesStr)) {
String[] split = rangesStr.split("\\s*,\\s*");
if (split.length % 2 == 1) {
throw new LensException("Ranges incomplete");
}
for (int i = 0; i < split.length; i += 2) {
- ranges.add(TimePartition.of(getUpdatePeriod(), split[i]).rangeUpto(TimePartition.of(getUpdatePeriod(),
- split[i + 1])));
+ ranges.add(TimePartitionRange.parseFrom(getUpdatePeriod(), split[i], split[i + 1]));
}
}
return isConsistent();
@@ -203,7 +194,7 @@ public class RangesPartitionTimeline extends PartitionTimeline {
if (isEmpty()) {
return false;
}
- for (TimePartition.TimePartitionRange range : ranges) {
+ for (TimePartitionRange range : ranges) {
if (range.contains(toCheck)) {
return true;
}
@@ -215,7 +206,7 @@ public class RangesPartitionTimeline extends PartitionTimeline {
public Iterator<TimePartition> iterator() {
return new Iterator<TimePartition>() {
- Iterator<TimePartition.TimePartitionRange> uber = ranges.iterator();
+ Iterator<TimePartitionRange> uber = ranges.iterator();
Iterator<TimePartition> cur = null;
@Override
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/StoreAllPartitionTimeline.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/StoreAllPartitionTimeline.java b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/StoreAllPartitionTimeline.java
index d6ee0a1..2364400 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/StoreAllPartitionTimeline.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/metadata/timeline/StoreAllPartitionTimeline.java
@@ -21,6 +21,7 @@ package org.apache.lens.cube.metadata.timeline;
import java.util.*;
import org.apache.lens.api.LensException;
+import org.apache.lens.cube.metadata.MetastoreUtil;
import org.apache.lens.cube.metadata.TimePartition;
import org.apache.lens.cube.metadata.UpdatePeriod;
@@ -70,14 +71,14 @@ public class StoreAllPartitionTimeline extends PartitionTimeline {
@Override
public Map<String, String> toProperties() {
HashMap<String, String> map = Maps.newHashMap();
- map.put("partitions", StringUtils.join(allPartitions, ","));
+ MetastoreUtil.addNameStrings(map, "partitions", allPartitions);
return map;
}
@Override
public boolean initFromProperties(Map<String, String> properties) throws LensException {
allPartitions.clear();
- String partitionsStr = properties.get("partitions");
+ String partitionsStr = MetastoreUtil.getNamedStringValue(properties, "partitions");
if (partitionsStr == null) {
return true;
}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/main/java/org/apache/lens/cube/parse/StorageTableResolver.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/main/java/org/apache/lens/cube/parse/StorageTableResolver.java b/lens-cube/src/main/java/org/apache/lens/cube/parse/StorageTableResolver.java
index 96ca82c..ab2c3f9 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/StorageTableResolver.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/StorageTableResolver.java
@@ -334,7 +334,7 @@ class StorageTableResolver implements ContextRewriter {
Set<String> nonExistingParts = Sets.newHashSet();
if (!missingPartitionRanges.isEmpty()) {
for (UpdatePeriod period : missingPartitionRanges.keySet()) {
- for (TimePartition.TimePartitionRange range : missingPartitionRanges.get(period).getRanges()) {
+ for (TimePartitionRange range : missingPartitionRanges.get(period).getRanges()) {
nonExistingParts.add(range.toString());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestTimePartition.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestTimePartition.java b/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestTimePartition.java
index 4c98d84..9d5d08b 100644
--- a/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestTimePartition.java
+++ b/lens-cube/src/test/java/org/apache/lens/cube/metadata/TestTimePartition.java
@@ -18,25 +18,36 @@
*/
package org.apache.lens.cube.metadata;
+import static org.testng.Assert.*;
+
+import java.util.Calendar;
import java.util.Date;
import org.apache.lens.api.LensException;
-import org.testng.Assert;
import org.testng.annotations.Test;
public class TestTimePartition {
+ public static final Date NOW = new Date();
+
@Test
public void test() throws LensException {
- Date now = new Date();
+ // Test for all update periods
for (UpdatePeriod up : UpdatePeriod.values()) {
- String nowStr = up.format().format(now);
- TimePartition nowPartition = TimePartition.of(up, now);
+ // Normal date object parsable
+ String nowStr = up.format().format(NOW);
+
+ // Create partition by date object or it's string representation -- both should be same.
+ TimePartition nowPartition = TimePartition.of(up, NOW);
TimePartition nowStrPartition = TimePartition.of(up, nowStr);
- Assert.assertEquals(nowPartition, nowStrPartition);
- Assert.assertTrue(nowPartition.next().after(nowPartition));
- Assert.assertTrue(nowPartition.previous().before(nowPartition));
- Assert.assertEquals(getLensExceptionFromPartitionParsing(up, "garbage").getMessage(),
+ assertEquals(nowPartition, nowStrPartition);
+
+ // Test next and previous
+ assertTrue(nowPartition.next().after(nowPartition));
+ assertTrue(nowPartition.previous().before(nowPartition));
+
+ // date parse failures should give lens exception
+ assertEquals(getLensExceptionFromPartitionParsing(up, "garbage").getMessage(),
TimePartition.getWrongUpdatePeriodMessage(up, "garbage"));
getLensExceptionFromPartitionParsing(up, (Date) null);
getLensExceptionFromPartitionParsing(up, (String) null);
@@ -48,7 +59,8 @@ public class TestTimePartition {
if (up.formatStr().equals(up2.formatStr())) {
continue;
}
- Assert.assertEquals(getLensExceptionFromPartitionParsing(up2, nowStr).getMessage(),
+ // Parsing a string representation with differnet update period should give lens exception.
+ assertEquals(getLensExceptionFromPartitionParsing(up2, nowStr).getMessage(),
TimePartition.getWrongUpdatePeriodMessage(up2, nowStr));
}
}
@@ -57,7 +69,7 @@ public class TestTimePartition {
private LensException getLensExceptionFromPartitionParsing(UpdatePeriod up, String dateStr) {
try {
TimePartition.of(up, dateStr);
- Assert.fail("Should have thrown LensException");
+ fail("Should have thrown LensException");
} catch (LensException e) {
return e;
}
@@ -67,10 +79,70 @@ public class TestTimePartition {
private LensException getLensExceptionFromPartitionParsing(UpdatePeriod up, Date date) {
try {
TimePartition.of(up, date);
- Assert.fail("Should have thrown LensException");
+ fail("Should have thrown LensException");
} catch (LensException e) {
return e;
}
return null; // redundant
}
+
+
+ public static Date timeAtDiff(Date date, UpdatePeriod period, int d) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ if (period.equals(UpdatePeriod.QUARTERLY)) {
+ d *= 3;
+ }
+ cal.add(period.calendarField(), d);
+ return cal.getTime();
+ }
+
+ @Test
+ public void testTimeRange() throws LensException {
+ // test for all update periods
+ for (UpdatePeriod up : UpdatePeriod.values()) {
+ // create two partition of different time
+ TimePartition nowPartition = TimePartition.of(up, NOW);
+ TimePartition tenLater = TimePartition.of(up, timeAtDiff(NOW, up, 10));
+
+ // a.upto(b) == b.from(a)
+ TimePartitionRange range = nowPartition.rangeUpto(tenLater);
+ assertEquals(range, tenLater.rangeFrom(nowPartition));
+ // size check
+ assertEquals(range.size(), 10);
+ // test singleton range
+ assertEquals(nowPartition.singletonRange().size(), 1);
+ // test begin belongs to [begin, end) and end doesn't belong
+ assertTrue(range.contains(nowPartition));
+ assertFalse(range.contains(tenLater));
+ // test partition parsing for string arguments.
+ // a,b == [a,b)
+ // Other possible arguments: [a,b), [a,b], (a,b), (a,b]
+ String nowStr = nowPartition.getDateString();
+ String tenLaterStr = tenLater.getDateString();
+ assertEquals(TimePartitionRange.parseFrom(up, nowStr, tenLaterStr), range);
+ assertEquals(TimePartitionRange.parseFrom(up, "[" + nowStr, tenLaterStr + ")"), range);
+ assertEquals(TimePartitionRange.parseFrom(up, "[" + nowStr, tenLaterStr + "]"),
+ nowPartition.rangeUpto(tenLater.next()));
+ assertEquals(TimePartitionRange.parseFrom(up, "(" + nowStr, tenLaterStr + "]"),
+ nowPartition.next().rangeUpto(
+ tenLater.next()));
+ assertEquals(TimePartitionRange.parseFrom(up, "(" + nowStr, tenLaterStr + ")"),
+ nowPartition.next().rangeUpto(tenLater));
+ }
+ }
+
+ @Test(expectedExceptions = LensException.class)
+ public void testPartitionRangeValidity() throws LensException {
+ // begin and end partitions should follow begin <= end
+ TimePartition.of(UpdatePeriod.HOURLY, NOW)
+ .rangeFrom(TimePartition.of(UpdatePeriod.HOURLY, timeAtDiff(NOW, UpdatePeriod.HOURLY, 10)));
+ }
+
+ @Test(expectedExceptions = LensException.class)
+ public void testTimeRangeCreationWithDifferentUpdatePeriod() throws LensException {
+ // begin and end partitions should have same update period for range creation to succeed.
+ TimePartition.of(UpdatePeriod.HOURLY, NOW).rangeUpto(TimePartition.of(UpdatePeriod.DAILY, NOW));
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/test/java/org/apache/lens/cube/metadata/timeline/TestPartitionTimelines.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/test/java/org/apache/lens/cube/metadata/timeline/TestPartitionTimelines.java b/lens-cube/src/test/java/org/apache/lens/cube/metadata/timeline/TestPartitionTimelines.java
index 50b75e3..c87050f 100644
--- a/lens-cube/src/test/java/org/apache/lens/cube/metadata/timeline/TestPartitionTimelines.java
+++ b/lens-cube/src/test/java/org/apache/lens/cube/metadata/timeline/TestPartitionTimelines.java
@@ -21,7 +21,7 @@ package org.apache.lens.cube.metadata.timeline;
import java.util.*;
import org.apache.lens.api.LensException;
-import org.apache.lens.cube.metadata.CubeMetastoreClient;
+import org.apache.lens.cube.metadata.TestTimePartition;
import org.apache.lens.cube.metadata.TimePartition;
import org.apache.lens.cube.metadata.UpdatePeriod;
@@ -31,11 +31,9 @@ import org.testng.annotations.Test;
import com.beust.jcommander.internal.Lists;
public class TestPartitionTimelines {
- CubeMetastoreClient client = null;
private static final String TABLE_NAME = "storage_fact";
- private static final UpdatePeriod PERIOD = UpdatePeriod.HOURLY;
+ public static final UpdatePeriod PERIOD = UpdatePeriod.HOURLY;
private static final String PART_COL = "pt";
- private static final Date DATE = new Date();
private static final List<Class<? extends PartitionTimeline>> TIMELINE_IMPLEMENTATIONS = Arrays.asList(
StoreAllPartitionTimeline.class,
EndsAndHolesPartitionTimeline.class,
@@ -60,7 +58,8 @@ public class TestPartitionTimelines {
final List<TimePartition> addedPartitions = Lists.newArrayList();
for (int i = 0; i < 200; i++) {
int randomInt = randomGenerator.nextInt(100) - 50;
- TimePartition part = TimePartition.of(PERIOD, timeAtHourDiff(randomInt));
+ TimePartition part = TimePartition.of(PERIOD, TestTimePartition.timeAtDiff(TestTimePartition.NOW, PERIOD,
+ randomInt));
addedPartitions.add(part);
for (PartitionTimeline timeline : timelines) {
timeline.add(part);
@@ -98,12 +97,6 @@ public class TestPartitionTimelines {
}
}
- private Date timeAtHourDiff(int d) {
- Calendar cal = Calendar.getInstance();
- cal.setTime(DATE);
- cal.add(PERIOD.calendarField(), d);
- return cal.getTime();
- }
private <T extends PartitionTimeline> T getInstance(Class<T> clz) {
try {
@@ -116,22 +109,41 @@ public class TestPartitionTimelines {
}
private <T extends PartitionTimeline> void testPropertiesContract(Class<T> clz) throws LensException {
+ // Make two instances, one to modify, other to validate against
T inst1 = getInstance(clz);
T inst2 = getInstance(clz);
+ // whenever we'll init from props, timeline should become empty.
Map<String, String> props = inst1.toProperties();
Assert.assertTrue(inst2.initFromProperties(props));
+ // init from props of an empty timeline: should succeed and make the timeline empty
Assert.assertEquals(inst1, inst2);
Assert.assertTrue(inst1.isEmpty());
Assert.assertTrue(inst2.isEmpty());
- Assert.assertTrue(inst1.add(TimePartition.of(PERIOD, DATE)));
+ // Add single partition and test for non-equivalence
+ Assert.assertTrue(inst1.add(TimePartition.of(PERIOD, TestTimePartition.NOW)));
Assert.assertFalse(inst1.equals(inst2));
- Assert.assertTrue(inst2.add(TimePartition.of(PERIOD, DATE)));
+ // add same parittion in other timeline, test for equality
+ Assert.assertTrue(inst2.add(TimePartition.of(PERIOD, TestTimePartition.NOW)));
Assert.assertTrue(inst1.isConsistent());
Assert.assertTrue(inst2.isConsistent());
Assert.assertEquals(inst1, inst2);
+ // init with blank properties. Should become empty
Assert.assertTrue(inst2.initFromProperties(props));
Assert.assertFalse(inst1.equals(inst2));
+ // init from properties of timeline with single partition.
Assert.assertTrue(inst2.initFromProperties(inst1.toProperties()));
Assert.assertEquals(inst1, inst2);
+ // clear timelines
+ inst1.initFromProperties(props);
+ inst2.initFromProperties(props);
+ // Make sparse partition range in one, init other from its properties. Test equality.
+ for (int i = 0; i < 5000; i++) {
+ Assert.assertTrue(inst1.add(TimePartition.of(PERIOD, TestTimePartition.timeAtDiff(TestTimePartition.NOW, PERIOD,
+ i * 2))));
+ }
+ Assert.assertTrue(inst1.isConsistent());
+ inst2.initFromProperties(inst1.toProperties());
+ Assert.assertTrue(inst2.isConsistent());
+ Assert.assertEquals(inst1, inst2);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/21102e6b/lens-cube/src/test/java/org/apache/lens/cube/parse/CubeTestSetup.java
----------------------------------------------------------------------
diff --git a/lens-cube/src/test/java/org/apache/lens/cube/parse/CubeTestSetup.java b/lens-cube/src/test/java/org/apache/lens/cube/parse/CubeTestSetup.java
index b2ae9b5..62b2c95 100644
--- a/lens-cube/src/test/java/org/apache/lens/cube/parse/CubeTestSetup.java
+++ b/lens-cube/src/test/java/org/apache/lens/cube/parse/CubeTestSetup.java
@@ -1001,10 +1001,10 @@ public class CubeTestSetup {
Assert.assertEquals(table.getParameters().get(
MetastoreUtil.getPartitionTimelineStorageClassKey(UpdatePeriod.YEARLY, "ttd2")),
EndsAndHolesPartitionTimeline.class.getCanonicalName());
- Assert.assertEquals(table.getParameters().get(
+ Assert.assertEquals(MetastoreUtil.getNamedStringValue(table.getParameters(),
MetastoreUtil.getPartitionInfoKeyPrefix(UpdatePeriod.HOURLY, "ttd") + "partitions"),
StringUtils.join(partitions, ","));
- Assert.assertEquals(table.getParameters().get(
+ Assert.assertEquals(MetastoreUtil.getNamedStringValue(table.getParameters(),
MetastoreUtil.getPartitionInfoKeyPrefix(UpdatePeriod.HOURLY, "ttd2") + "partitions"),
StringUtils.join(partitions, ","));
// Add all hourly partitions for TWO_DAYS_RANGE_BEFORE_4_DAYS
@@ -2045,7 +2045,7 @@ public class CubeTestSetup {
for (String p : Arrays.asList("et", "it", "pt")) {
String first = params.get(prefix + up + "." + p + "." + "first");
String latest = params.get(prefix + up + "." + p + "." + "latest");
- String holes = params.get(prefix + up + "." + p + "." + "holes");
+ String holes = MetastoreUtil.getNamedStringValue(params, prefix + up + "." + p + "." + "holes");
String storageClass = params.get(prefix + up + "." + p + "." + "storage.class");
Assert.assertNotNull(first);
Assert.assertNotNull(latest);