wangxianghu commented on code in PR #19081:
URL: https://github.com/apache/hudi/pull/19081#discussion_r3485154532


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/action/ttl/strategy/KeepByEventTimeStrategy.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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.hudi.table.action.ttl.strategy;
+
+import org.apache.hudi.common.table.timeline.HoodieInstantTimeGenerator;
+import org.apache.hudi.common.util.PartitionPathEncodeUtils;
+import org.apache.hudi.table.HoodieTable;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.ParseException;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.TemporalAccessor;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Event-time based partition TTL strategy.
+ * <p>
+ * Unlike {@link KeepByTimeStrategy} (which keys off the partition's last 
commit time) and
+ * {@link KeepByCreationTimeStrategy} (which keys off the partition creation 
commit time), this
+ * strategy derives the partition's reference time from the partition path 
itself. This makes TTL
+ * decoupled from write behaviour: late-arriving data into an old partition 
will not extend its
+ * lifetime, and backfilled historic partitions are still considered old.
+ * <p>
+ * First-version scope of supported partition path shapes:
+ * <ul>
+ *   <li>Day:  {@code 2026-04-24} / {@code dt=2026-04-24} / {@code 20260424} / 
{@code dt=20260424}</li>
+ *   <li>Hour: {@code 2026-04-05/06} / {@code dt=2026-04-05/hh=06} / {@code 
20260405/06} / {@code dt=20260405/hh=06}</li>
+ * </ul>
+ * The time block may appear at any contiguous segment range of the path. 
Examples like
+ * {@code eventType=login/20250405/05} are supported by setting
+ * {@link 
org.apache.hudi.config.HoodieTTLConfig#EVENT_TIME_PARTITION_START_INDEX} to 
{@code 1}.
+ */
+@Slf4j
+public class KeepByEventTimeStrategy extends KeepByTimeStrategy {
+
+  private final String eventTimeFormat;
+  private final int startIndex;
+  private final boolean deleteHiveDefaultPartition;
+  private final boolean hiveStylePartitioning;
+
+  public KeepByEventTimeStrategy(HoodieTable hoodieTable, String instantTime) {
+    super(hoodieTable, instantTime);
+    this.eventTimeFormat = writeConfig.getPartitionTTLEventTimeFormat();
+    this.startIndex = 
writeConfig.getPartitionTTLEventTimePartitionStartIndex();
+    this.deleteHiveDefaultPartition = 
writeConfig.shouldDeleteHiveDefaultPartitionForEventTimeTTL();
+    // Hive-style partitioning is a table-level property recorded at table 
creation; trust it
+    // rather than guessing per-segment from a stray '=' character in a value.
+    this.hiveStylePartitioning = Boolean.parseBoolean(
+        
hoodieTable.getMetaClient().getTableConfig().getHiveStylePartitioningEnable());
+    if (startIndex < 0) {
+      throw new IllegalArgumentException(
+          "hoodie.partition.ttl.strategy.event.time.partition.start.index must 
be >= 0, got " + startIndex);
+    }
+  }
+
+  @Override
+  protected List<String> getExpiredPartitionsForTimeStrategy(List<String> 
partitionPathsForTTL) {
+    long cutoffMillis = resolveCutoffMillis(instantTime, ttlInMilis);

Review Comment:
   @hudi-agent check again



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/action/ttl/strategy/KeepByEventTimeStrategy.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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.hudi.table.action.ttl.strategy;
+
+import org.apache.hudi.common.table.timeline.HoodieInstantTimeGenerator;
+import org.apache.hudi.common.util.PartitionPathEncodeUtils;
+import org.apache.hudi.table.HoodieTable;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.ParseException;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.TemporalAccessor;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Event-time based partition TTL strategy.
+ * <p>
+ * Unlike {@link KeepByTimeStrategy} (which keys off the partition's last 
commit time) and
+ * {@link KeepByCreationTimeStrategy} (which keys off the partition creation 
commit time), this
+ * strategy derives the partition's reference time from the partition path 
itself. This makes TTL
+ * decoupled from write behaviour: late-arriving data into an old partition 
will not extend its
+ * lifetime, and backfilled historic partitions are still considered old.
+ * <p>
+ * First-version scope of supported partition path shapes:
+ * <ul>
+ *   <li>Day:  {@code 2026-04-24} / {@code dt=2026-04-24} / {@code 20260424} / 
{@code dt=20260424}</li>
+ *   <li>Hour: {@code 2026-04-05/06} / {@code dt=2026-04-05/hh=06} / {@code 
20260405/06} / {@code dt=20260405/hh=06}</li>
+ * </ul>
+ * The time block may appear at any contiguous segment range of the path. 
Examples like
+ * {@code eventType=login/20250405/05} are supported by setting
+ * {@link 
org.apache.hudi.config.HoodieTTLConfig#EVENT_TIME_PARTITION_START_INDEX} to 
{@code 1}.
+ */
+@Slf4j
+public class KeepByEventTimeStrategy extends KeepByTimeStrategy {
+
+  private final String eventTimeFormat;
+  private final int startIndex;
+  private final boolean deleteHiveDefaultPartition;
+  private final boolean hiveStylePartitioning;
+
+  public KeepByEventTimeStrategy(HoodieTable hoodieTable, String instantTime) {
+    super(hoodieTable, instantTime);
+    this.eventTimeFormat = writeConfig.getPartitionTTLEventTimeFormat();
+    this.startIndex = 
writeConfig.getPartitionTTLEventTimePartitionStartIndex();
+    this.deleteHiveDefaultPartition = 
writeConfig.shouldDeleteHiveDefaultPartitionForEventTimeTTL();
+    // Hive-style partitioning is a table-level property recorded at table 
creation; trust it
+    // rather than guessing per-segment from a stray '=' character in a value.
+    this.hiveStylePartitioning = Boolean.parseBoolean(
+        
hoodieTable.getMetaClient().getTableConfig().getHiveStylePartitioningEnable());
+    if (startIndex < 0) {
+      throw new IllegalArgumentException(
+          "hoodie.partition.ttl.strategy.event.time.partition.start.index must 
be >= 0, got " + startIndex);
+    }
+  }
+
+  @Override
+  protected List<String> getExpiredPartitionsForTimeStrategy(List<String> 
partitionPathsForTTL) {
+    long cutoffMillis = resolveCutoffMillis(instantTime, ttlInMilis);
+    DateTimeFormatter formatter = 
DateTimeFormatter.ofPattern(eventTimeFormat).withZone(ZoneOffset.UTC);
+    int segCount = segmentCount(eventTimeFormat);
+    return partitionPathsForTTL.stream().parallel()
+        .filter(path -> isPartitionExpiredByEventTime(
+            path, formatter, startIndex, segCount, cutoffMillis, 
deleteHiveDefaultPartition, hiveStylePartitioning))
+        .collect(Collectors.toList());
+  }
+
+  /**
+   * Number of '/'-separated path segments the configured format occupies.
+   * Example: {@code yyyy-MM-dd/HH} -> 2.
+   */
+  static int segmentCount(String format) {
+    return format.split("/").length;
+  }
+
+  /**
+   * Resolve the "now" reference timestamp from {@code instantTime} so the 
strategy stays
+   * idempotent across retries of the same replace commit.
+   */
+  static long resolveCutoffMillis(String instantTime, long ttlInMillis) {
+    try {
+      return 
HoodieInstantTimeGenerator.parseDateFromInstantTime(instantTime).getTime() - 
ttlInMillis;
+    } catch (ParseException e) {
+      throw new IllegalStateException("Failed to parse instant time " + 
instantTime, e);
+    }
+  }
+
+  /**
+   * Decide whether a partition path is expired.
+   * <p>
+   * Package-private so unit tests can exercise it directly without spinning 
up a HoodieTable.
+   */
+  static boolean isPartitionExpiredByEventTime(String partitionPath,
+                                               DateTimeFormatter formatter,
+                                               int startIndex,
+                                               int segCount,
+                                               long cutoffMillis,
+                                               boolean 
deleteHiveDefaultPartition,
+                                               boolean hiveStylePartitioning) {
+    String[] segments = partitionPath.split("/");

Review Comment:
   @hudi-agent check again



-- 
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]

Reply via email to