diff --git a/examples/quickstart/tutorial/rollup-index.json b/examples/quickstart/tutorial/rollup-index.json index 7c0b5815d2c..a978c2a76d2 100644 --- a/examples/quickstart/tutorial/rollup-index.json +++ b/examples/quickstart/tutorial/rollup-index.json @@ -20,7 +20,7 @@ ], "granularitySpec" : { "type" : "uniform", - "segmentGranularity" : "week", + "segmentGranularity" : "day", "queryGranularity" : "minute", "intervals" : ["2018-01-01/2018-01-03"], "rollup" : true diff --git a/examples/quickstart/tutorial/transform-index.json b/examples/quickstart/tutorial/transform-index.json index caebb9ff9c5..14c6b9ae6d4 100644 --- a/examples/quickstart/tutorial/transform-index.json +++ b/examples/quickstart/tutorial/transform-index.json @@ -20,7 +20,7 @@ ], "granularitySpec" : { "type" : "uniform", - "segmentGranularity" : "week", + "segmentGranularity" : "day", "queryGranularity" : "minute", "intervals" : ["2018-01-01/2018-01-03"], "rollup" : true diff --git a/examples/quickstart/tutorial/updates-append-index.json b/examples/quickstart/tutorial/updates-append-index.json index 9ba53a0b311..9cfb3b7d07a 100644 --- a/examples/quickstart/tutorial/updates-append-index.json +++ b/examples/quickstart/tutorial/updates-append-index.json @@ -18,7 +18,7 @@ ], "granularitySpec": { "type": "uniform", - "segmentGranularity": "week", + "segmentGranularity": "day", "queryGranularity": "minute", "intervals": ["2018-01-01/2018-01-03"], "rollup": true diff --git a/examples/quickstart/tutorial/updates-append-index2.json b/examples/quickstart/tutorial/updates-append-index2.json index 921b8cf0e2d..3f97ca31712 100644 --- a/examples/quickstart/tutorial/updates-append-index2.json +++ b/examples/quickstart/tutorial/updates-append-index2.json @@ -18,7 +18,7 @@ ], "granularitySpec" : { "type" : "uniform", - "segmentGranularity" : "week", + "segmentGranularity" : "day", "queryGranularity" : "minute", "intervals" : ["2018-01-01/2018-01-03"], "rollup" : true diff --git a/examples/quickstart/tutorial/updates-init-index.json b/examples/quickstart/tutorial/updates-init-index.json index ed4b349c6e0..52c0950e1d8 100644 --- a/examples/quickstart/tutorial/updates-init-index.json +++ b/examples/quickstart/tutorial/updates-init-index.json @@ -18,7 +18,7 @@ ], "granularitySpec" : { "type" : "uniform", - "segmentGranularity" : "week", + "segmentGranularity" : "day", "queryGranularity" : "minute", "intervals" : ["2018-01-01/2018-01-03"], "rollup" : true diff --git a/examples/quickstart/tutorial/updates-overwrite-index.json b/examples/quickstart/tutorial/updates-overwrite-index.json index b2545f04dd1..59e88bc9c6d 100644 --- a/examples/quickstart/tutorial/updates-overwrite-index.json +++ b/examples/quickstart/tutorial/updates-overwrite-index.json @@ -18,7 +18,7 @@ ], "granularitySpec" : { "type" : "uniform", - "segmentGranularity" : "week", + "segmentGranularity" : "day", "queryGranularity" : "minute", "intervals" : ["2018-01-01/2018-01-03"], "rollup" : true diff --git a/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentAllocateAction.java b/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentAllocateAction.java index f0fae4a8617..280f4199e7b 100644 --- a/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentAllocateAction.java +++ b/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentAllocateAction.java @@ -52,9 +52,13 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; /** - * Allocates a pending segment for a given timestamp. The preferredSegmentGranularity is used if there are no prior - * segments for the given timestamp, or if the prior segments for the given timestamp are already at the - * preferredSegmentGranularity. Otherwise, the prior segments will take precedence. + * Allocates a pending segment for a given timestamp. + * If a visible chunk of used segments contains the interval with the query granularity containing the timestamp, + * the pending segment is allocated with its interval. + * Else, if the interval with the preferred segment granularity containing the timestamp has no overlap + * with the existing used segments, the preferred segment granularity is used. + * Else, find the coarsest segment granularity, containing the interval with the query granularity for the timestamp, + * that does not overlap with the existing used segments. This granularity is used for allocation if it exists. *

* This action implicitly acquires some task locks when it allocates segments. You do not have to acquire them * beforehand, although you *do* have to release them yourself. (Note that task locks are automatically released when @@ -62,6 +66,8 @@ import java.util.stream.Collectors; *

* If this action cannot acquire an appropriate task lock, or if it cannot expand an existing segment set, it returns * null. + *

+ * Do NOT allocate WEEK granularity segments unless the preferred segment granularity is WEEK. */ public class SegmentAllocateAction implements TaskAction { diff --git a/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/SegmentAllocateActionTest.java b/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/SegmentAllocateActionTest.java index 4ccb8707750..05760fd46ca 100644 --- a/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/SegmentAllocateActionTest.java +++ b/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/SegmentAllocateActionTest.java @@ -59,6 +59,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.IOException; +import java.time.Duration; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -995,6 +996,66 @@ public class SegmentAllocateActionTest Assert.assertEquals(Intervals.ETERNITY, id2.getInterval()); } + @Test + public void testAllocateWeekOnlyWhenWeekIsPreferred() + { + final Task task = NoopTask.create(); + taskActionTestKit.getTaskLockbox().add(task); + + final SegmentIdWithShardSpec id1 = allocate( + task, + DateTimes.of("2023-12-16"), + Granularities.MINUTE, + Granularities.HOUR, + "s1", + null + ); + + final SegmentIdWithShardSpec id2 = allocate( + task, + DateTimes.of("2023-12-18"), + Granularities.MINUTE, + Granularities.WEEK, + "s2", + null + ); + + Assert.assertNotNull(id1); + Assert.assertNotNull(id2); + Assert.assertEquals(Duration.ofHours(1).toMillis(), id1.getInterval().toDurationMillis()); + Assert.assertEquals(Duration.ofDays(7).toMillis(), id2.getInterval().toDurationMillis()); + } + + @Test + public void testAllocateDayWhenMonthNotPossible() + { + final Task task = NoopTask.create(); + taskActionTestKit.getTaskLockbox().add(task); + + final SegmentIdWithShardSpec id1 = allocate( + task, + DateTimes.of("2023-12-16"), + Granularities.MINUTE, + Granularities.HOUR, + "s1", + null + ); + + final SegmentIdWithShardSpec id2 = allocate( + task, + DateTimes.of("2023-12-18"), + Granularities.MINUTE, + Granularities.MONTH, + "s2", + null + ); + + Assert.assertNotNull(id1); + Assert.assertNotNull(id2); + Assert.assertEquals(Duration.ofHours(1).toMillis(), id1.getInterval().toDurationMillis()); + Assert.assertEquals(Duration.ofDays(1).toMillis(), id2.getInterval().toDurationMillis()); + } + private SegmentIdWithShardSpec allocate( final Task task, final DateTime timestamp, diff --git a/processing/src/main/java/org/apache/druid/java/util/common/granularity/Granularity.java b/processing/src/main/java/org/apache/druid/java/util/common/granularity/Granularity.java index 572467f7c74..b841eb54193 100644 --- a/processing/src/main/java/org/apache/druid/java/util/common/granularity/Granularity.java +++ b/processing/src/main/java/org/apache/druid/java/util/common/granularity/Granularity.java @@ -106,6 +106,8 @@ public abstract class Granularity implements Cacheable * ALL will not be returned unless the provided granularity is ALL. NONE will never be returned, even if the * provided granularity is NONE. This is because the main usage of this function in production is segment * allocation, and we do not wish to generate NONE-granular segments. + * + * The list of granularities returned contains WEEK only if the requested granularity is WEEK. */ public static List granularitiesFinerThan(final Granularity gran0) { @@ -117,6 +119,9 @@ public abstract class Granularity implements Cacheable if ((gran == GranularityType.ALL && !gran0.equals(Granularities.ALL)) || gran == GranularityType.NONE) { continue; } + if (gran == GranularityType.WEEK && !gran0.equals(Granularities.WEEK)) { + continue; + } final Granularity segmentGranularity = gran.create(origin, tz); final long segmentGranularityDurationMillis = segmentGranularity.bucket(DateTimes.EPOCH).toDurationMillis(); final long gran0DurationMillis = gran0.bucket(DateTimes.EPOCH).toDurationMillis(); diff --git a/processing/src/test/java/org/apache/druid/java/util/common/GranularityTest.java b/processing/src/test/java/org/apache/druid/java/util/common/GranularityTest.java index 392a43149fb..f4106fe99d1 100644 --- a/processing/src/test/java/org/apache/druid/java/util/common/GranularityTest.java +++ b/processing/src/test/java/org/apache/druid/java/util/common/GranularityTest.java @@ -1002,6 +1002,27 @@ public class GranularityTest ); } + @Test + public void testGranularitiesFinerThanWeek() + { + Assert.assertEquals( + ImmutableList.of( + Granularities.WEEK, + Granularities.DAY, + Granularities.EIGHT_HOUR, + Granularities.SIX_HOUR, + Granularities.HOUR, + Granularities.THIRTY_MINUTE, + Granularities.FIFTEEN_MINUTE, + Granularities.TEN_MINUTE, + Granularities.FIVE_MINUTE, + Granularities.MINUTE, + Granularities.SECOND + ), + Granularity.granularitiesFinerThan(Granularities.WEEK) + ); + } + @Test public void testGranularitiesFinerThanAll() { @@ -1011,7 +1032,6 @@ public class GranularityTest Granularities.YEAR, Granularities.QUARTER, Granularities.MONTH, - Granularities.WEEK, Granularities.DAY, Granularities.EIGHT_HOUR, Granularities.SIX_HOUR,