kfaraz commented on code in PR #15015:
URL: https://github.com/apache/druid/pull/15015#discussion_r1330986915


##########
server/src/main/java/org/apache/druid/server/coordinator/rules/PeriodDropBeforeRule.java:
##########
@@ -63,4 +64,18 @@ public boolean appliesTo(Interval theInterval, DateTime 
referenceTimestamp)
     final DateTime periodAgo = referenceTimestamp.minus(period);
     return theInterval.getEndMillis() <= periodAgo.getMillis();
   }
+
+  @Override
+  public Interval getEligibleInterval(DateTime referenceTimestamp)
+  {
+    return new Interval(DateTimes.utc(Long.MIN_VALUE), 
referenceTimestamp.minus(period));

Review Comment:
   Maybe use `JodaUtils.MIN_INSTANT` instead of `Long.MIN_VALUE` for alignment 
with `Intervals.ETERNITY`.



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/Rule.java:
##########
@@ -50,4 +50,12 @@ public interface Rule
   boolean appliesTo(Interval interval, DateTime referenceTimestamp);
 
   void run(DataSegment segment, SegmentActionHandler segmentHandler);
+
+  /**
+   * Return an eligible interval from the reference timestamp. Implemntations

Review Comment:
   Typo:
   ```suggestion
      * Return an eligible interval from the reference timestamp. 
Implementations
   ```



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/Rule.java:
##########
@@ -50,4 +50,11 @@ public interface Rule
   boolean appliesTo(Interval interval, DateTime referenceTimestamp);
 
   void run(DataSegment segment, SegmentActionHandler segmentHandler);
+
+  /**
+   * Return an eligible interval from the reference timestamp. Implementations
+   * must return a valid interval based on the rule type.
+   * @param referenceTimestamp base timestamp
+   */

Review Comment:
   ```suggestion
     /**
      * Returns the interval eligible for this rule. The interval is computed 
based on the
      * {@code referenceTimestamp}, which is typically the current time when 
the rule is
      * being evaluated.
      */
   ```



##########
server/src/test/java/org/apache/druid/server/http/RulesResourceTest.java:
##########
@@ -151,6 +166,286 @@ public void testGetDatasourceRuleHistoryWithWrongCount()
     EasyMock.verify(auditManager);
   }
 
+  @Test
+  public void testSetDatasourceRulesWithEffectivelyNoRule()
+  {
+    EasyMock.expect(databaseRuleManager.overrideRule(EasyMock.anyObject(), 
EasyMock.anyObject(), EasyMock.anyObject()))
+                .andReturn(true).times(2);
+    EasyMock.replay(databaseRuleManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final Response resp1 = rulesResource.setDatasourceRules("dataSource1", 
null, null, null, EasyMock.createMock(HttpServletRequest.class));
+    Assert.assertEquals(200, resp1.getStatus());
+
+    final Response resp2 = rulesResource.setDatasourceRules("dataSource1", new 
ArrayList<>(), null, null, EasyMock.createMock(HttpServletRequest.class));
+    Assert.assertEquals(200, resp2.getStatus());
+    EasyMock.verify(databaseRuleManager);
+  }
+
+  @Test
+  public void testSetDatasourceRulesWithInvalidLoadRules()
+  {
+    EasyMock.replay(auditManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final HttpServletRequest req = 
EasyMock.createMock(HttpServletRequest.class);
+
+    final IntervalLoadRule loadInterval1 = new IntervalLoadRule(
+        Intervals.of("2023-07-29T01:00:00Z/2023-12-30T01:00:00Z"),
+        null,
+        null
+    );
+    final IntervalLoadRule loadInterval2 = new IntervalLoadRule(
+        Intervals.of("2023-09-29T01:00:00Z/2023-10-30T01:00:00Z"),
+        null,
+        null
+    );
+    final PeriodLoadRule loadPT1H = new PeriodLoadRule(new Period("PT1H"), 
null, null, null);
+    final PeriodLoadRule loadP3M = new PeriodLoadRule(new Period("P3M"), null, 
null, null);
+    final PeriodLoadRule loadP6M = new PeriodLoadRule(new Period("P6M"), null, 
null, null);
+    final ForeverLoadRule loadForever = new ForeverLoadRule(null, null);
+
+    final List<Rule> rules = new ArrayList<>();
+    rules.add(loadP6M);
+    rules.add(loadP3M);
+    rules.add(loadForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadP6M, loadP3M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadP3M);
+    rules.add(loadForever);
+    rules.add(loadP6M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadForever, loadP6M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadForever);
+    rules.add(loadPT1H);
+    rules.add(loadInterval2);
+    rules.add(loadP6M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadForever, loadPT1H)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadPT1H);
+    rules.add(loadPT1H);
+    rules.add(loadP6M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadPT1H, loadPT1H)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadInterval1);
+    rules.add(loadInterval2);
+    rules.add(loadP6M);
+    rules.add(loadForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadInterval1, loadInterval2)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadP6M);
+    rules.add(loadInterval1);
+    rules.add(loadForever);
+    rules.add(loadInterval2);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadForever, loadInterval2)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+  }
+
+  @Test
+  public void testDatasourceRulesWithInvalidDropRules()
+  {
+    EasyMock.replay(auditManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final HttpServletRequest req = 
EasyMock.createMock(HttpServletRequest.class);
+
+    final PeriodDropBeforeRule dropBeforeP3M = new PeriodDropBeforeRule(new 
Period("P3M"));
+    final PeriodDropBeforeRule dropBeforeP6M = new PeriodDropBeforeRule(new 
Period("P6M"));
+    final PeriodDropRule dropByP1M = new PeriodDropRule(new Period("P1M"), 
true);
+    final PeriodDropRule dropByP2M = new PeriodDropRule(new Period("P2M"), 
true);
+    final ForeverDropRule dropForever = new ForeverDropRule();
+
+    final List<Rule> rules = new ArrayList<>();
+    rules.add(dropBeforeP3M);
+    rules.add(dropBeforeP6M);
+    rules.add(dropByP1M);
+    rules.add(dropForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", dropBeforeP3M, dropBeforeP6M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(dropByP2M);
+    rules.add(dropByP1M);
+    rules.add(dropForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", dropByP2M, dropByP1M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(dropForever);
+    rules.add(dropByP1M);
+    rules.add(dropByP2M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", dropForever, dropByP1M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+  }
+
+  @Test
+  public void testDatasourceRulesWithInvalidBroadcastRules()
+  {
+    EasyMock.replay(auditManager);

Review Comment:
   Testing Suggestion:
   
   It might be simpler to add a `RulesTest` class and validate all the possible 
scenarios there rather than validating all scenarios against `RulesResource` 
itself.
   
   Only a couple of cases validated against `RulesResource` should be enough, I 
think.
   
   Whether the tests are kept in `RulesTest` or `RulesResourceTest`, the 
duplicate logic in the tests should be commoned out such that each test case 
reads something like:
   ```
   Test Case 1. A list of rules A, B, C is valid.
   Test Case 2. A list of rules D, E, F throws so and so exception.
   ```
   
   and so on.



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/PeriodBroadcastDistributionRule.java:
##########
@@ -65,6 +65,13 @@ public boolean appliesTo(Interval interval, DateTime 
referenceTimestamp)
     return Rules.eligibleForLoad(period, interval, referenceTimestamp, 
includeFuture);
   }
 
+  @Override
+  public Interval getEligibleInterval(DateTime referenceTimestamp)
+  {
+    return includeFuture ? new Interval(referenceTimestamp.minus(period), 
referenceTimestamp.plus(period))

Review Comment:
   When `includeFuture` is true, we include everything in the future, not just 
upto the `period`.



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/PeriodDropRule.java:
##########
@@ -80,4 +80,19 @@ public boolean appliesTo(Interval theInterval, DateTime 
referenceTimestamp)
       return currInterval.contains(theInterval);
     }
   }
+
+  @Override
+  public Interval getEligibleInterval(DateTime referenceTimestamp)
+  {
+    return new Interval(referenceTimestamp.minus(period), referenceTimestamp);

Review Comment:
   ```suggestion
       return new Interval(period, referenceTimestamp);
   ```



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/PeriodLoadRule.java:
##########
@@ -85,6 +83,12 @@ public boolean appliesTo(Interval interval, DateTime 
referenceTimestamp)
     return Rules.eligibleForLoad(period, interval, referenceTimestamp, 
includeFuture);
   }
 
+  @Override
+  public Interval getEligibleInterval(DateTime referenceTimestamp)
+  {
+    return new Interval(referenceTimestamp.minus(period), referenceTimestamp);

Review Comment:
   ```suggestion
       return new Interval(period, referenceTimestamp);
   ```



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/PeriodDropRule.java:
##########
@@ -80,4 +81,20 @@ public boolean appliesTo(Interval theInterval, DateTime 
referenceTimestamp)
       return currInterval.contains(theInterval);
     }
   }
+
+  @Override
+  public Interval getEligibleInterval(DateTime referenceTimestamp)
+  {
+    return includeFuture ? new Interval(referenceTimestamp.minus(period), 
referenceTimestamp.plus(period))

Review Comment:
   Same comment about `includeFuture`.



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/Rules.java:
##########
@@ -43,4 +48,40 @@ public static boolean eligibleForLoad(Period period, 
Interval interval, DateTime
   private Rules()
   {
   }
+
+  /**
+   * Validate rules. This method throws an exception if a rule contain an 
interval that
+   * will fully cover the next rules' interval in the list. Rules that will be 
evaluated at some point
+   * are considered to be legitimate.
+   * @param rules Datasource rules.
+   */

Review Comment:
   Rephrased a bit, removed the `@param` tag as it is not adding any new info, 
add `@throws` tag.
   ```suggestion
     /**
      * Validates the given list of retention rules for a datasource (or 
cluster default).
      * A rule is considered valid only if:
      * <ul>
      * <li>It will be evaluated at some point, i.e. its eligible interval is 
not fully covered by the eligible interval of any preceding rule in the 
list.</li>
      * </ul>
      * @throws DruidException with error code "invalidInput" if any of the 
given rules is not valid. 
      */
   ```



##########
server/src/test/java/org/apache/druid/server/http/RulesResourceTest.java:
##########
@@ -151,6 +166,286 @@ public void testGetDatasourceRuleHistoryWithWrongCount()
     EasyMock.verify(auditManager);
   }
 
+  @Test
+  public void testSetDatasourceRulesWithEffectivelyNoRule()
+  {
+    EasyMock.expect(databaseRuleManager.overrideRule(EasyMock.anyObject(), 
EasyMock.anyObject(), EasyMock.anyObject()))
+                .andReturn(true).times(2);
+    EasyMock.replay(databaseRuleManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final Response resp1 = rulesResource.setDatasourceRules("dataSource1", 
null, null, null, EasyMock.createMock(HttpServletRequest.class));
+    Assert.assertEquals(200, resp1.getStatus());
+
+    final Response resp2 = rulesResource.setDatasourceRules("dataSource1", new 
ArrayList<>(), null, null, EasyMock.createMock(HttpServletRequest.class));
+    Assert.assertEquals(200, resp2.getStatus());
+    EasyMock.verify(databaseRuleManager);
+  }
+
+  @Test
+  public void testSetDatasourceRulesWithInvalidLoadRules()
+  {
+    EasyMock.replay(auditManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final HttpServletRequest req = 
EasyMock.createMock(HttpServletRequest.class);
+
+    final IntervalLoadRule loadInterval1 = new IntervalLoadRule(
+        Intervals.of("2023-07-29T01:00:00Z/2023-12-30T01:00:00Z"),
+        null,
+        null
+    );
+    final IntervalLoadRule loadInterval2 = new IntervalLoadRule(
+        Intervals.of("2023-09-29T01:00:00Z/2023-10-30T01:00:00Z"),
+        null,
+        null
+    );
+    final PeriodLoadRule loadPT1H = new PeriodLoadRule(new Period("PT1H"), 
null, null, null);
+    final PeriodLoadRule loadP3M = new PeriodLoadRule(new Period("P3M"), null, 
null, null);
+    final PeriodLoadRule loadP6M = new PeriodLoadRule(new Period("P6M"), null, 
null, null);
+    final ForeverLoadRule loadForever = new ForeverLoadRule(null, null);
+
+    final List<Rule> rules = new ArrayList<>();
+    rules.add(loadP6M);
+    rules.add(loadP3M);
+    rules.add(loadForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadP6M, loadP3M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadP3M);
+    rules.add(loadForever);
+    rules.add(loadP6M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadForever, loadP6M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadForever);
+    rules.add(loadPT1H);
+    rules.add(loadInterval2);
+    rules.add(loadP6M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadForever, loadPT1H)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadPT1H);
+    rules.add(loadPT1H);
+    rules.add(loadP6M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadPT1H, loadPT1H)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadInterval1);
+    rules.add(loadInterval2);
+    rules.add(loadP6M);
+    rules.add(loadForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadInterval1, loadInterval2)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(loadP6M);
+    rules.add(loadInterval1);
+    rules.add(loadForever);
+    rules.add(loadInterval2);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", loadForever, loadInterval2)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+  }
+
+  @Test
+  public void testDatasourceRulesWithInvalidDropRules()
+  {
+    EasyMock.replay(auditManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final HttpServletRequest req = 
EasyMock.createMock(HttpServletRequest.class);
+
+    final PeriodDropBeforeRule dropBeforeP3M = new PeriodDropBeforeRule(new 
Period("P3M"));
+    final PeriodDropBeforeRule dropBeforeP6M = new PeriodDropBeforeRule(new 
Period("P6M"));
+    final PeriodDropRule dropByP1M = new PeriodDropRule(new Period("P1M"), 
true);
+    final PeriodDropRule dropByP2M = new PeriodDropRule(new Period("P2M"), 
true);
+    final ForeverDropRule dropForever = new ForeverDropRule();
+
+    final List<Rule> rules = new ArrayList<>();
+    rules.add(dropBeforeP3M);
+    rules.add(dropBeforeP6M);
+    rules.add(dropByP1M);
+    rules.add(dropForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", dropBeforeP3M, dropBeforeP6M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(dropByP2M);
+    rules.add(dropByP1M);
+    rules.add(dropForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", dropByP2M, dropByP1M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();
+    rules.add(dropForever);
+    rules.add(dropByP1M);
+    rules.add(dropByP2M);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", dropForever, dropByP1M)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+  }
+
+  @Test
+  public void testDatasourceRulesWithInvalidBroadcastRules()
+  {
+    EasyMock.replay(auditManager);
+
+    final RulesResource rulesResource = new RulesResource(databaseRuleManager, 
auditManager);
+    final HttpServletRequest req = 
EasyMock.createMock(HttpServletRequest.class);
+
+    final ForeverBroadcastDistributionRule broadcastForever = new 
ForeverBroadcastDistributionRule();
+    final PeriodBroadcastDistributionRule broadcastPeriodPT1H = new 
PeriodBroadcastDistributionRule(new Period("PT1H"), true);
+    final PeriodBroadcastDistributionRule broadcastPeriodPT2H = new 
PeriodBroadcastDistributionRule(new Period("PT2H"), true);
+    final IntervalBroadcastDistributionRule broadcastInterval1 = new 
IntervalBroadcastDistributionRule(
+        Intervals.of("2000-09-29T01:00:00Z/2050-10-30T01:00:00Z")
+    );
+    final IntervalBroadcastDistributionRule broadcastInterval2 = new 
IntervalBroadcastDistributionRule(
+        Intervals.of("2010-09-29T01:00:00Z/2020-10-30T01:00:00Z")
+    );
+
+    final List<Rule> rules = new ArrayList<>();
+    rules.add(broadcastInterval1);
+    rules.add(broadcastInterval2);
+    rules.add(broadcastForever);
+
+    DruidExceptionMatcher.invalidInput().expectMessageContains(
+        StringUtils.format("Rule[%s] has an interval that contains interval 
for rule[%s].", broadcastInterval1, broadcastInterval2)
+    ).assertThrowsAndMatches(() -> 
rulesResource.setDatasourceRules("dataSource1", rules, null, null, req));
+
+    rules.clear();

Review Comment:
   It would be nicer to have this in a separate test case rather than clearing 
the list of rules. See other comment.



##########
server/src/main/java/org/apache/druid/server/coordinator/rules/Rules.java:
##########
@@ -43,4 +48,40 @@ public static boolean eligibleForLoad(Period period, 
Interval interval, DateTime
   private Rules()
   {
   }
+
+  /**
+   * Validate rules. This method throws an exception if a rule contain an 
interval that
+   * will fully cover the next rules' interval in the list. Rules that will be 
evaluated at some point
+   * are considered to be legitimate.
+   * @param rules Datasource rules.
+   */
+  public static void validateRules(final List<Rule> rules)
+  {
+    if (rules == null) {
+      return;
+    }
+    final DateTime now = DateTimes.nowUtc();
+    for (int i = 0; i < rules.size() - 1; i++) {
+      final Rule currRule = rules.get(i);
+      final Rule nextRule = rules.get(i + 1);
+      final Interval currInterval = currRule.getEligibleInterval(now);
+      final Interval nextInterval = nextRule.getEligibleInterval(now);
+      if (currInterval.contains(nextInterval)) {
+        // If the current rule has an eternity interval, it covers everything 
following it.
+        // Or if the current rule still covers the next rule at the current 
interval boundaries, then the
+        // next rule will never fire at any time, so throw an exception.
+        if (Intervals.ETERNITY.equals(currInterval) ||
+            
(currRule.getEligibleInterval(currInterval.getStart()).contains(nextRule.getEligibleInterval(currInterval.getStart()))
+             && 
currRule.getEligibleInterval(currInterval.getEnd()).contains(nextRule.getEligibleInterval(currInterval.getEnd()))))
 {
+          throw InvalidInput.exception(
+              "Rule[%s] has an interval that contains interval for rule[%s]. 
The interval[%s] also covers interval[%s].",
+              currRule,
+              nextRule,
+              currInterval,
+              nextInterval

Review Comment:
   Yes, I agree. Rule #3 would never be applied on any segment irrespective of 
the rule types.
   While evaluating retention rules, as soon as a rule applies to a segment, we 
break and don't look at the other rules.
   
   Also, in general, I am not entirely sure of the validation logic here. 
   - For one, the set thing suggested by @LakshSingla makes sense. But we would 
have to ensure that the `fully covered` check is done correctly.
     - Additive logic (cleaner to implement): Say your set contains intervals 
`A [4, 10)` and `B [15, 20)` and a new interval `C [8, 17)` comes in. Adding 
this new interval C should merge all of A, B and C into one interval `[4, 17)`.
     - Subtractive logic: To check if an interval has any part which is not 
fully covered by the preceding intervals, remove all parts of it that overlap 
with intervals already encountered. If you are left with an empty interval, the 
rule is not valid.
   - Secondly, all of this is easy to follow when we are dealing with 
`ForeverXyzRule` or `IntervalXyzRule` (rule with fixed interval). For 
`PeriodXyzRule`, I am not entirely sure of the boundaries that would need to be 
checked. The proposed change does compute the `eligibleInterval` at both start 
and end of the `currInterval` but I need to give it some more thought.
   - There could even be other types of rules in the future, but I guess we 
need not worry about them now.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to