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

abstractdog pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tez.git


The following commit(s) were added to refs/heads/master by this push:
     new cba56893f TEZ-4723: TestMapProcessor is flaky (#504) (Laszlo Bodor 
reviewed by Ayush Saxena)
cba56893f is described below

commit cba56893fe4b759c08a1cd9ce7d1434b6818795f
Author: Bodor Laszlo <[email protected]>
AuthorDate: Mon Jun 8 15:12:42 2026 +0200

    TEZ-4723: TestMapProcessor is flaky (#504) (Laszlo Bodor reviewed by Ayush 
Saxena)
---
 .../org/apache/tez/common/TezSharedExecutor.java   |   7 +-
 .../mapreduce/processor/map/TestMapProcessor.java  | 150 +++++++++++++--------
 2 files changed, 97 insertions(+), 60 deletions(-)

diff --git 
a/tez-common/src/main/java/org/apache/tez/common/TezSharedExecutor.java 
b/tez-common/src/main/java/org/apache/tez/common/TezSharedExecutor.java
index 011a3b382..19f7ddcd4 100644
--- a/tez-common/src/main/java/org/apache/tez/common/TezSharedExecutor.java
+++ b/tez-common/src/main/java/org/apache/tez/common/TezSharedExecutor.java
@@ -47,7 +47,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
  */
 @Private
 @Unstable
-public class TezSharedExecutor implements TezExecutors {
+public class TezSharedExecutor implements TezExecutors, AutoCloseable {
 
   // The shared executor service which will be used to execute all the tasks.
   private final ThreadPoolExecutor service;
@@ -96,6 +96,11 @@ public class TezSharedExecutor implements TezExecutors {
     poller.interrupt();
   }
 
+  @Override
+  public void close() {
+    this.shutdownNow();
+  }
+
   @Override
   protected void finalize() {
     this.shutdown();
diff --git 
a/tez-mapreduce/src/test/java/org/apache/tez/mapreduce/processor/map/TestMapProcessor.java
 
b/tez-mapreduce/src/test/java/org/apache/tez/mapreduce/processor/map/TestMapProcessor.java
index 556968de6..1958d3c9f 100644
--- 
a/tez-mapreduce/src/test/java/org/apache/tez/mapreduce/processor/map/TestMapProcessor.java
+++ 
b/tez-mapreduce/src/test/java/org/apache/tez/mapreduce/processor/map/TestMapProcessor.java
@@ -22,6 +22,7 @@ package org.apache.tez.mapreduce.processor.map;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -34,7 +35,12 @@ import org.apache.hadoop.io.DataInputBuffer;
 import org.apache.hadoop.io.LongWritable;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.mapred.JobConf;
+import org.apache.hadoop.mapred.MapReduceBase;
+import org.apache.hadoop.mapred.Mapper;
+import org.apache.hadoop.mapred.OutputCollector;
+import org.apache.hadoop.mapred.Reporter;
 import org.apache.hadoop.mapreduce.MRConfig;
+import org.apache.hadoop.test.GenericTestUtils;
 import org.apache.tez.common.MRFrameworkConfigs;
 import org.apache.tez.common.TezRuntimeFrameworkConfigs;
 import org.apache.tez.common.TezSharedExecutor;
@@ -62,7 +68,6 @@ import 
org.apache.tez.runtime.library.common.task.local.output.TezTaskOutputFile
 import org.apache.tez.runtime.library.output.OrderedPartitionedKVOutput;
 
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
@@ -76,7 +81,7 @@ public class TestMapProcessor {
   private static JobConf defaultConf = new JobConf();
   private static FileSystem localFs = null;
   private static Path workDir = null;
-  static float progressUpdate = 0.0f;
+  private static CountDownLatch progressLatch;
   static {
     try {
       defaultConf.set("fs.defaultFS", "file:///");
@@ -152,49 +157,74 @@ public class TestMapProcessor {
         OutputDescriptor.create(OrderedPartitionedKVOutput.class.getName())
             .setUserPayload(TezUtils.createUserPayloadFromConf(jobConf)), 1);
 
-    TezSharedExecutor sharedExecutor = new TezSharedExecutor(jobConf);
-    LogicalIOProcessorRuntimeTask task = MapUtils.createLogicalTask(localFs, 
workDir, jobConf, 0,
-        new Path(workDir, "map0"), new TestUmbilical(), dagName, vertexName,
-        Collections.singletonList(mapInputSpec), 
Collections.singletonList(mapOutputSpec),
-        sharedExecutor);
+    try (TezSharedExecutor sharedExecutor = new TezSharedExecutor(jobConf)) {
+      LogicalIOProcessorRuntimeTask task = MapUtils.createLogicalTask(localFs, 
workDir, jobConf, 0,
+          new Path(workDir, "map0"), new TestUmbilical(), dagName, vertexName,
+          Collections.singletonList(mapInputSpec), 
Collections.singletonList(mapOutputSpec),
+          sharedExecutor);
 
-    task.initialize();
-    task.run();
-    task.close();
-    sharedExecutor.shutdownNow();
+      task.initialize();
+      task.run();
+      task.close();
 
-    OutputContext outputContext = task.getOutputContexts().iterator().next();
-    TezTaskOutput mapOutputs = new TezTaskOutputFiles(
-        jobConf, outputContext.getUniqueIdentifier(),
-        outputContext.getDagIdentifier());
+      OutputContext outputContext = task.getOutputContexts().iterator().next();
+      TezTaskOutput mapOutputs = new TezTaskOutputFiles(
+          jobConf, outputContext.getUniqueIdentifier(),
+          outputContext.getDagIdentifier());
 
 
-    // TODO NEWTEZ FIXME OutputCommitter verification
+      // TODO NEWTEZ FIXME OutputCommitter verification
 //    MRTask mrTask = (MRTask)t.getProcessor();
 //    Assert.assertEquals(TezNullOutputCommitter.class.getName(), mrTask
 //        .getCommitter().getClass().getName());
 //    t.close();
 
-    Path mapOutputFile = getMapOutputFile(jobConf, outputContext);
-    LOG.info("mapOutputFile = " + mapOutputFile);
-    IFile.Reader reader =
-        new IFile.Reader(localFs, mapOutputFile, null, null, null, false, 0, 
-1);
-    LongWritable key = new LongWritable();
-    Text value = new Text();
-    DataInputBuffer keyBuf = new DataInputBuffer();
-    DataInputBuffer valueBuf = new DataInputBuffer();
-    long prev = Long.MIN_VALUE;
-    while (reader.nextRawKey(keyBuf)) {
-      reader.nextRawValue(valueBuf);
-      key.readFields(keyBuf);
-      value.readFields(valueBuf);
-      if (prev != Long.MIN_VALUE) {
-        assert(prev <= key.get());
-        prev = key.get();
+      Path mapOutputFile = getMapOutputFile(jobConf, outputContext);
+      LOG.info("mapOutputFile = " + mapOutputFile);
+      IFile.Reader reader =
+          new IFile.Reader(localFs, mapOutputFile, null, null, null, false, 0, 
-1);
+      LongWritable key = new LongWritable();
+      Text value = new Text();
+      DataInputBuffer keyBuf = new DataInputBuffer();
+      DataInputBuffer valueBuf = new DataInputBuffer();
+      long prev = Long.MIN_VALUE;
+      while (reader.nextRawKey(keyBuf)) {
+        reader.nextRawValue(valueBuf);
+        key.readFields(keyBuf);
+        value.readFields(valueBuf);
+        if (prev != Long.MIN_VALUE) {
+          assert(prev <= key.get());
+          prev = key.get();
+        }
+        LOG.info("key = " + key.get() + "; value = " + value);
+      }
+      reader.close();
+    }
+  }
+
+  /**
+   * A mapper that waits on a latch after the first record, giving the
+   * ProgressHelper time to report intermediate progress. The latch is
+   * released by the test once progress has been captured.
+   */
+  public static class LatchMapper extends MapReduceBase
+      implements Mapper<LongWritable, Text, LongWritable, Text> {
+    private boolean waited = false;
+
+    @Override
+    public void map(LongWritable key, Text value,
+        OutputCollector<LongWritable, Text> output, Reporter reporter)
+        throws IOException {
+      output.collect(key, value);
+      if (!waited) {
+        waited = true;
+        try {
+          progressLatch.await();
+        } catch (InterruptedException e) {
+          Thread.currentThread().interrupt();
+        }
       }
-      LOG.info("key = " + key.get() + "; value = " + value);
     }
-    reader.close();
   }
 
   @Test(timeout = 30000)
@@ -204,6 +234,9 @@ public class TestMapProcessor {
     JobConf jobConf = new JobConf(defaultConf);
     setUpJobConf(jobConf);
 
+    jobConf.setMapperClass(LatchMapper.class);
+    progressLatch = new CountDownLatch(1);
+
     MRHelpers.translateMRConfToTez(jobConf);
     jobConf.setInt(MRJobConfig.APPLICATION_ATTEMPT_ID, 0);
 
@@ -215,7 +248,7 @@ public class TestMapProcessor {
     Path mapInput = new Path(workDir, "map0");
 
 
-    MapUtils.generateInputSplit(localFs, workDir, jobConf, mapInput, 100000);
+    MapUtils.generateInputSplit(localFs, workDir, jobConf, mapInput, 100);
 
     InputSpec mapInputSpec = new InputSpec("NullSrcVertex",
         InputDescriptor.create(MRInputLegacy.class.getName())
@@ -229,30 +262,29 @@ public class TestMapProcessor {
         OutputDescriptor.create(OrderedPartitionedKVOutput.class.getName())
             .setUserPayload(TezUtils.createUserPayloadFromConf(jobConf)), 1);
 
-    TezSharedExecutor sharedExecutor = new TezSharedExecutor(jobConf);
-    final LogicalIOProcessorRuntimeTask task = MapUtils.createLogicalTask
-        (localFs, workDir, jobConf, 0,
-            new Path(workDir, "map0"), new TestUmbilical(), dagName, 
vertexName,
-            Collections.singletonList(mapInputSpec),
-            Collections.singletonList(mapOutputSpec), sharedExecutor);
-
-    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
-    Thread monitorProgress = new Thread(new Runnable() {
-      @Override
-      public void run() {
+    try (TezSharedExecutor sharedExecutor = new TezSharedExecutor(jobConf);
+         ScheduledExecutorService scheduler = 
Executors.newScheduledThreadPool(1)) {
+
+      final LogicalIOProcessorRuntimeTask task = MapUtils.createLogicalTask(
+          localFs, workDir, jobConf, 0,
+              new Path(workDir, "map0"), new TestUmbilical(), dagName, 
vertexName,
+              Collections.singletonList(mapInputSpec),
+              Collections.singletonList(mapOutputSpec), sharedExecutor);
+
+      scheduler.scheduleAtFixedRate(() -> {
         float prog = task.getProgress();
-        if(prog > 0.0f && prog < 1.0f)
-          progressUpdate = prog;
-      }
-    });
-
-    task.initialize();
-    scheduler.scheduleAtFixedRate(monitorProgress, 0, 1,
-        TimeUnit.MILLISECONDS);
-    task.run();
-    Assert.assertTrue("Progress Updates should be captured!",
-        progressUpdate > 0.0f && progressUpdate < 1.0f);
-    task.close();
-    sharedExecutor.shutdownNow();
+        if (prog > 0.0f && prog < 1.0f) {
+          progressLatch.countDown();
+        }
+      }, 0, 1, TimeUnit.MILLISECONDS);
+
+      task.initialize();
+      task.run();
+
+      GenericTestUtils.waitFor(() -> progressLatch.getCount() == 0, 10, 5000,
+          "Progress update between 0.0 and 1.0 was never captured");
+
+      task.close();
+    }
   }
 }

Reply via email to