diff --git a/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java b/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java index 35f94b26982..a116ca2681c 100644 --- a/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java +++ b/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java @@ -347,10 +347,10 @@ public void run() { * Trigger break/continue/switch to next thread Loop depending on consumer implementation * @param sampler Sampler Base sampler * @param threadContext - * @param consumer Consumer that will process the tree of elements up to root node + * @param consumer Consumer that will process the parent controllers list */ private void triggerLoopLogicalActionOnParentControllers(Sampler sampler, JMeterContext threadContext, - Consumer consumer) { + Consumer> consumer) { TransactionSampler transactionSampler = null; if (sampler instanceof TransactionSampler transSampler) { transactionSampler = transSampler; @@ -362,11 +362,10 @@ private void triggerLoopLogicalActionOnParentControllers(Sampler sampler, JMeter "Got null subSampler calling findRealSampler for:" + (sampler != null ? sampler.getName() : "null") + ", sampler:" + sampler); } - // Find parent controllers of current sampler - FindTestElementsUpToRootTraverser pathToRootTraverser = new FindTestElementsUpToRootTraverser(realSampler); - testTree.traverse(pathToRootTraverser); + // Reuse controller path already computed by TestCompiler + List controllers = compiler.getControllersForSampler(realSampler); - consumer.accept(pathToRootTraverser); + consumer.accept(controllers); // bug 52968 // When using Start Next Loop option combined to TransactionController. @@ -381,11 +380,10 @@ private void triggerLoopLogicalActionOnParentControllers(Sampler sampler, JMeter /** * Executes a continue of current loop, equivalent of "continue" in algorithm. * As a consequence it ends the first loop it finds on the path to root - * @param pathToRootTraverser {@link FindTestElementsUpToRootTraverser} + * @param controllers parent controllers from nearest to root */ - private static void continueOnCurrentLoop(FindTestElementsUpToRootTraverser pathToRootTraverser) { - List controllersToReinit = pathToRootTraverser.getControllersToRoot(); - for (Controller parentController : controllersToReinit) { + private static void continueOnCurrentLoop(List controllers) { + for (Controller parentController : controllers) { if (parentController instanceof AbstractThreadGroup tg) { tg.startNextLoop(); } else if (parentController instanceof IteratingController iterController) { @@ -400,11 +398,10 @@ private static void continueOnCurrentLoop(FindTestElementsUpToRootTraverser path /** * Executes a break of current loop, equivalent of "break" in algorithm. * As a consequence it ends the first loop it finds on the path to root - * @param pathToRootTraverser {@link FindTestElementsUpToRootTraverser} + * @param controllers parent controllers from nearest to root */ - private static void breakOnCurrentLoop(FindTestElementsUpToRootTraverser pathToRootTraverser) { - List controllersToReinit = pathToRootTraverser.getControllersToRoot(); - for (Controller parentController : controllersToReinit) { + private static void breakOnCurrentLoop(List controllers) { + for (Controller parentController : controllers) { if (parentController instanceof AbstractThreadGroup tg) { tg.breakThreadLoop(); } else if (parentController instanceof IteratingController iterController) { @@ -419,11 +416,10 @@ private static void breakOnCurrentLoop(FindTestElementsUpToRootTraverser pathToR /** * Executes a restart of Thread loop, equivalent of "continue" in algorithm but on Thread Loop. * As a consequence it ends all loop on the path to root - * @param pathToRootTraverser {@link FindTestElementsUpToRootTraverser} + * @param controllers parent controllers from nearest to root */ - private static void continueOnThreadLoop(FindTestElementsUpToRootTraverser pathToRootTraverser) { - List controllersToReinit = pathToRootTraverser.getControllersToRoot(); - for (Controller parentController : controllersToReinit) { + private static void continueOnThreadLoop(List controllers) { + for (Controller parentController : controllers) { if (parentController instanceof AbstractThreadGroup tg) { tg.startNextLoop(); } else { diff --git a/src/core/src/main/java/org/apache/jmeter/threads/SamplePackage.java b/src/core/src/main/java/org/apache/jmeter/threads/SamplePackage.java index 7265b5b7fbd..deb0b3e2f49 100644 --- a/src/core/src/main/java/org/apache/jmeter/threads/SamplePackage.java +++ b/src/core/src/main/java/org/apache/jmeter/threads/SamplePackage.java @@ -226,4 +226,13 @@ public List getConfigs() { return configs; } + /** + * Returns the parent controllers from nearest to root. + * + * @return List of {@link Controller} + */ + public List getControllers() { + return controllers; + } + } diff --git a/src/core/src/main/java/org/apache/jmeter/threads/TestCompiler.java b/src/core/src/main/java/org/apache/jmeter/threads/TestCompiler.java index 14b537a0e19..a3ca25517a8 100644 --- a/src/core/src/main/java/org/apache/jmeter/threads/TestCompiler.java +++ b/src/core/src/main/java/org/apache/jmeter/threads/TestCompiler.java @@ -114,6 +114,19 @@ public SamplePackage configureTransactionSampler(TransactionSampler transactionS return pack; } + /** + * Returns the parent controllers for the given sampler without + * triggering configuration side effects. + * + * @param sampler the {@link Sampler} to look up + * @return parent controllers from nearest to root, or an empty list + * if the sampler has not been compiled + */ + public List getControllersForSampler(Sampler sampler) { + SamplePackage pack = samplerConfigMap.get(sampler); + return pack != null ? pack.getControllers() : List.of(); + } + /** * Reset pack to its initial state * @param pack the {@link SamplePackage} to reset