This is an automated email from the ASF dual-hosted git repository.

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 0ac943c4304 Respect explicit append.uuid.to.segment.name in 
SegmentGenerationAndPushTask (#19820)
0ac943c4304 is described below

commit 0ac943c4304c128b8f8f9b98d38e9416344b0641
Author: Akshay Upadhyay <[email protected]>
AuthorDate: Tue Oct 13 03:08:30 2026 +0530

    Respect explicit append.uuid.to.segment.name in 
SegmentGenerationAndPushTask (#19820)
---
 .../SegmentGenerationAndPushTaskExecutor.java      |   8 +-
 .../SegmentGenerationAndPushTaskGenerator.java     |  11 +-
 .../SegmentGenerationAndPushTaskExecutorTest.java  |  37 +++++
 .../SegmentGenerationAndPushTaskGeneratorTest.java | 151 +++++++++++++++++++++
 4 files changed, 203 insertions(+), 4 deletions(-)

diff --git 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutor.java
 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutor.java
index 5d9825aeb3d..c4dcd5f76b1 100644
--- 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutor.java
+++ 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutor.java
@@ -315,8 +315,12 @@ public class SegmentGenerationAndPushTaskExecutor extends 
BaseTaskExecutor {
       
segmentNameGeneratorSpec.setType(taskConfigs.get(BatchConfigProperties.SEGMENT_NAME_GENERATOR_TYPE));
       
segmentNameGeneratorSpec.setConfigs(IngestionConfigUtils.getConfigMapWithPrefix(taskConfigs,
           BatchConfigProperties.SEGMENT_NAME_GENERATOR_PROP_PREFIX));
-      
segmentNameGeneratorSpec.addConfig(SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME,
-          
taskConfigs.getOrDefault(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
Boolean.toString(false)));
+      // An explicit segmentNameGenerator.configs.append.uuid.to.segment.name 
takes precedence over the top-level key
+      if (!segmentNameGeneratorSpec.getConfigs()
+          
.containsKey(SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME)) {
+        
segmentNameGeneratorSpec.addConfig(SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME,
+            
taskConfigs.getOrDefault(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
Boolean.toString(false)));
+      }
       taskSpec.setSegmentNameGeneratorSpec(segmentNameGeneratorSpec);
       
taskSpec.setCustomProperty(BatchConfigProperties.INPUT_DATA_FILE_URI_KEY, 
inputFileURI.toString());
 
diff --git 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGenerator.java
 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGenerator.java
index b3d9b1f2050..6f1cf20d50a 100644
--- 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGenerator.java
+++ 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/main/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGenerator.java
@@ -286,8 +286,15 @@ public class SegmentGenerationAndPushTaskGenerator extends 
BaseTaskGenerator {
     // overridden, corresponding files become un-ingested, the generator will 
generate new tasks, which generates
     // segments with same names, and override existing segments again... It 
becomes an endless loop
     // We add uuid to segment name to avoid segment collision across multiple 
rounds of task generation to solve the
-    // problem.
-    
singleFileGenerationTaskConfig.put(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME,
 Boolean.toString(true));
+    // problem. Default to true, but respect an explicit value configured in 
the batch config, either under
+    // segmentNameGenerator.configs (takes precedence) or top-level. Note that 
explicitly setting it to false makes
+    // segment names repeat across rounds unless the segment name generator 
produces unique names per input.
+    String appendUuidConfigKey = 
BatchConfigProperties.SEGMENT_NAME_GENERATOR_PROP_PREFIX + "."
+        + BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME;
+    
singleFileGenerationTaskConfig.put(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME,
+        singleFileGenerationTaskConfig.getOrDefault(appendUuidConfigKey,
+            
singleFileGenerationTaskConfig.getOrDefault(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME,
+                Boolean.toString(true))));
     if ((outputDirURI == null) || (pushMode == null)) {
       singleFileGenerationTaskConfig.put(BatchConfigProperties.PUSH_MODE, 
DEFAULT_SEGMENT_PUSH_TYPE.toString());
     } else {
diff --git 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutorTest.java
 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutorTest.java
index b497fc54c85..5a097b07157 100644
--- 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutorTest.java
+++ 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskExecutorTest.java
@@ -86,4 +86,41 @@ public class SegmentGenerationAndPushTaskExecutorTest {
         Map.of("prop.seg.1", "valseg1", "propseg2", "valseg2", 
SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME,
             "true"));
   }
+
+  @Test
+  public void testGenerateTaskSpecAppendUuidPrecedence()
+      throws Exception {
+    // Explicit prefixed config wins over the top-level key
+    assertAppendUuid(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
"true",
+        BatchConfigProperties.SEGMENT_NAME_GENERATOR_PROP_PREFIX + "."
+            + SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME, 
"false"), "false");
+    // Top-level key is still honored when the prefixed config is absent
+    assertAppendUuid(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
"true"), "true");
+    assertAppendUuid(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
"false"), "false");
+    // Unchanged default when neither is set
+    assertAppendUuid(Map.of(), "false");
+  }
+
+  private void assertAppendUuid(Map<String, String> appendUuidConfigs, String 
expected)
+      throws Exception {
+    ClassLoader classLoader = getClass().getClassLoader();
+    URL resourcesLoc = classLoader.getResource(".");
+    assertNotNull(resourcesLoc);
+    URL tableConfigUrl = classLoader.getResource("dummyTable.json");
+    assertNotNull(tableConfigUrl);
+    SegmentGenerationAndPushTaskExecutor executor = new 
SegmentGenerationAndPushTaskExecutor();
+    FieldUtils.writeField(executor, "_eventObserver", new 
DefaultMinionEventObserver(), true);
+    Map<String, String> configMap = new HashMap<>(appendUuidConfigs);
+    configMap.put(BatchConfigProperties.INPUT_DATA_FILE_URI_KEY, resourcesLoc 
+ "dummyTable.json");
+    configMap.put(BatchConfigProperties.RECORD_READER_CLASS, "AReaderClass");
+    configMap.put(BatchConfigProperties.RECORD_READER_CONFIG_CLASS, 
"AReaderConfigClass");
+    configMap.put(BatchConfigProperties.SCHEMA, new 
Schema.SchemaBuilder().build().toSingleLineJsonString());
+    configMap.put(BatchConfigProperties.TABLE_CONFIGS,
+        FileUtils.readFileToString(new File(tableConfigUrl.getFile()), 
StandardCharsets.UTF_8));
+    configMap.put(BatchConfigProperties.SEQUENCE_ID, "42");
+    configMap.put(BatchConfigProperties.SEGMENT_NAME_GENERATOR_TYPE, 
"inputFile");
+    SegmentGenerationTaskSpec spec = executor.generateTaskSpec(configMap, 
Paths.get(resourcesLoc.toURI()).toFile());
+    assertEquals(spec.getSegmentNameGeneratorSpec().getConfigs()
+        .get(SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME), 
expected);
+  }
 }
diff --git 
a/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGeneratorTest.java
 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGeneratorTest.java
new file mode 100644
index 00000000000..156b0f62c7c
--- /dev/null
+++ 
b/pinot-plugins/pinot-minion-tasks/pinot-minion-builtin-tasks/src/test/java/org/apache/pinot/plugin/minion/tasks/segmentgenerationandpush/SegmentGenerationAndPushTaskGeneratorTest.java
@@ -0,0 +1,151 @@
+/**
+ * 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.pinot.plugin.minion.tasks.segmentgenerationandpush;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.commons.lang3.reflect.MethodUtils;
+import org.apache.pinot.controller.helix.core.minion.ClusterInfoAccessor;
+import org.apache.pinot.minion.event.DefaultMinionEventObserver;
+import 
org.apache.pinot.plugin.ingestion.batch.common.SegmentGenerationTaskRunner;
+import org.apache.pinot.spi.data.Schema;
+import org.apache.pinot.spi.ingestion.batch.BatchConfigProperties;
+import org.apache.pinot.spi.ingestion.batch.spec.SegmentGenerationTaskSpec;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+
+/// Tests for [SegmentGenerationAndPushTaskGenerator]
+public class SegmentGenerationAndPushTaskGeneratorTest {
+
+  private static final String TABLE_NAME = "testTable_OFFLINE";
+  private static final URI INPUT_FILE_URI = 
URI.create("file:///tmp/input/data.csv");
+  private static final String APPEND_UUID_CONFIG_KEY =
+      BatchConfigProperties.SEGMENT_NAME_GENERATOR_PROP_PREFIX + "."
+          + BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME;
+
+  private static final String APPEND_UUID_TO_SEGMENT_NAME_KEY = 
SegmentGenerationTaskRunner.APPEND_UUID_TO_SEGMENT_NAME;
+
+  private SegmentGenerationAndPushTaskGenerator _generator;
+
+  @BeforeMethod
+  public void setUp() {
+    ClusterInfoAccessor clusterInfoAccessor = mock(ClusterInfoAccessor.class);
+    
when(clusterInfoAccessor.getVipUrlForLeadController(TABLE_NAME)).thenReturn("http://localhost:9000";);
+    _generator = new SegmentGenerationAndPushTaskGenerator();
+    _generator.init(clusterInfoAccessor);
+  }
+
+  @Test
+  public void testAppendUuidDefaultsToTrueWhenUnset()
+      throws Exception {
+    Map<String, String> taskConfig = 
invokeGetSingleFileGenerationTaskConfig(batchConfigMap(Map.of()));
+    
assertEquals(taskConfig.get(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME), 
"true");
+  }
+
+  @Test
+  public void testAppendUuidRespectsExplicitTopLevelFalse()
+      throws Exception {
+    Map<String, String> taskConfig = invokeGetSingleFileGenerationTaskConfig(
+        
batchConfigMap(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
"false")));
+    
assertEquals(taskConfig.get(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME), 
"false");
+  }
+
+  @Test
+  public void testAppendUuidRespectsExplicitPrefixedFalse()
+      throws Exception {
+    Map<String, String> taskConfig =
+        
invokeGetSingleFileGenerationTaskConfig(batchConfigMap(Map.of(APPEND_UUID_CONFIG_KEY,
 "false")));
+    assertEquals(taskConfig.get(APPEND_UUID_CONFIG_KEY), "false");
+    // Mirrored to the top-level key so that executors which only read the 
top-level key behave the same
+    
assertEquals(taskConfig.get(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME), 
"false");
+  }
+
+  @Test
+  public void testAppendUuidPrefixedTakesPrecedenceOverTopLevel()
+      throws Exception {
+    Map<String, String> taskConfig = invokeGetSingleFileGenerationTaskConfig(
+        
batchConfigMap(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME, 
"true", APPEND_UUID_CONFIG_KEY,
+            "false")));
+    
assertEquals(taskConfig.get(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME), 
"false");
+    assertEquals(taskConfig.get(APPEND_UUID_CONFIG_KEY), "false");
+  }
+
+  @Test
+  public void testGeneratedTaskConfigIsHonoredByExecutor()
+      throws Exception {
+    // Table config -> generator -> executor: the spec consumed by the segment 
generation runner must carry the
+    // configured value
+    assertAppendUuidInExecutorSpec(Map.of(APPEND_UUID_CONFIG_KEY, "false"), 
"false");
+    
assertAppendUuidInExecutorSpec(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME,
 "false"), "false");
+    
assertAppendUuidInExecutorSpec(Map.of(BatchConfigProperties.APPEND_UUID_TO_SEGMENT_NAME,
 "true",
+        APPEND_UUID_CONFIG_KEY, "false"), "false");
+    assertAppendUuidInExecutorSpec(Map.of(), "true");
+  }
+
+  private static Map<String, String> batchConfigMap(Map<String, String> 
extraConfigs) {
+    Map<String, String> batchConfigMap = new HashMap<>(extraConfigs);
+    batchConfigMap.put(BatchConfigProperties.INPUT_DIR_URI, 
"file:///tmp/input");
+    batchConfigMap.put(BatchConfigProperties.INPUT_FORMAT, "csv");
+    batchConfigMap.put(BatchConfigProperties.SEGMENT_NAME_GENERATOR_TYPE, 
"inputFile");
+    return batchConfigMap;
+  }
+
+  private void assertAppendUuidInExecutorSpec(Map<String, String> 
extraBatchConfigs, String expected)
+      throws Exception {
+    // Add the fields the executor normally receives from the controller
+    Map<String, String> taskConfig =
+        new 
HashMap<>(invokeGetSingleFileGenerationTaskConfig(batchConfigMap(extraBatchConfigs)));
+    ClassLoader classLoader = getClass().getClassLoader();
+    URL resourcesLoc = classLoader.getResource(".");
+    assertNotNull(resourcesLoc);
+    URL tableConfigUrl = classLoader.getResource("dummyTable.json");
+    assertNotNull(tableConfigUrl);
+    taskConfig.put(BatchConfigProperties.INPUT_DATA_FILE_URI_KEY, resourcesLoc 
+ "dummyTable.json");
+    taskConfig.put(BatchConfigProperties.RECORD_READER_CLASS, "AReaderClass");
+    taskConfig.put(BatchConfigProperties.RECORD_READER_CONFIG_CLASS, 
"AReaderConfigClass");
+    taskConfig.put(BatchConfigProperties.SCHEMA, new 
Schema.SchemaBuilder().build().toSingleLineJsonString());
+    taskConfig.put(BatchConfigProperties.TABLE_CONFIGS,
+        FileUtils.readFileToString(new File(tableConfigUrl.getFile()), 
StandardCharsets.UTF_8));
+
+    SegmentGenerationAndPushTaskExecutor executor = new 
SegmentGenerationAndPushTaskExecutor();
+    FieldUtils.writeField(executor, "_eventObserver", new 
DefaultMinionEventObserver(), true);
+    SegmentGenerationTaskSpec spec = executor.generateTaskSpec(taskConfig, 
Paths.get(resourcesLoc.toURI()).toFile());
+    
assertEquals(spec.getSegmentNameGeneratorSpec().getConfigs().get(APPEND_UUID_TO_SEGMENT_NAME_KEY),
 expected);
+  }
+
+  @SuppressWarnings("unchecked")
+  private Map<String, String> 
invokeGetSingleFileGenerationTaskConfig(Map<String, String> batchConfigMap)
+      throws Exception {
+    return (Map<String, String>) MethodUtils.invokeMethod(_generator, true, 
"getSingleFileGenerationTaskConfig",
+        TABLE_NAME, 0, batchConfigMap, INPUT_FILE_URI, null);
+  }
+}


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

Reply via email to