This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
commit 24672c47c9601653d30549197295175057e3b272 Author: Andy Seaborne <[email protected]> AuthorDate: Tue Feb 17 18:58:25 2026 +0000 GH-3755: Make ExecutionContext immutable --- .../jena/sparql/engine/ExecutionContext.java | 115 ++++++++++----------- .../apache/jena/sparql/function/FunctionEnv.java | 10 +- .../apache/jena/tdb1/solver/OpExecutorTDB1.java | 3 +- .../apache/jena/tdb2/solver/OpExecutorTDB2.java | 3 +- 4 files changed, 64 insertions(+), 67 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/ExecutionContext.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/ExecutionContext.java index 86c9b34e6a..e59305d354 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/ExecutionContext.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/ExecutionContext.java @@ -33,74 +33,40 @@ import org.apache.jena.query.ARQ; import org.apache.jena.query.QueryCancelledException; import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.DatasetGraphFactory; +import org.apache.jena.sparql.engine.iterator.QueryIteratorBase; import org.apache.jena.sparql.engine.main.OpExecutorFactory; import org.apache.jena.sparql.engine.main.QC; import org.apache.jena.sparql.function.FunctionEnv; import org.apache.jena.sparql.util.Context; -public class ExecutionContext implements FunctionEnv +public final class ExecutionContext implements FunctionEnv { private static final boolean TrackAllIterators = false; - private Context context = null; - private DatasetGraph dataset = null; + private final Context context; + private final DatasetGraph dataset; // Iterator tracking private final Collection<QueryIterator> openIterators; // Tracking all iterators leads to a build up of state, - private Collection<QueryIterator> allIterators = null; - private Graph activeGraph = null; - private OpExecutorFactory executor = null; + private final Collection<QueryIterator> allIterators; + private final Graph activeGraph; + private final OpExecutorFactory executor; private final AtomicBoolean cancelSignal; - /** Clone */ - public static ExecutionContext copy(ExecutionContext other) { - return new ExecutionContext(other); - } - - /** @deprecated Use {@link #copy(ExecutionContext)} */ - @Deprecated - public ExecutionContext(ExecutionContext other) { - this.context = other.context; - this.dataset = other.dataset; - this.openIterators = other.openIterators; - this.allIterators = other.allIterators; - this.activeGraph = other.activeGraph; - this.executor = other.executor; - this.cancelSignal = other.cancelSignal; - } - /** Create ExecutionContext from {@link FunctionEnv} */ public static ExecutionContext fromFunctionEnv(FunctionEnv functionEnv) { return new ExecutionContext(functionEnv); } - private ExecutionContext(FunctionEnv other) { - this.context = other.getContext(); - this.dataset = other.getDataset(); - this.openIterators = new ArrayList<>(); - if ( TrackAllIterators ) - this.allIterators = new ArrayList<>(); - else - this.allIterators = null; - this.activeGraph = other.getActiveGraph(); - this.executor = QC.getFactory(context); - this.cancelSignal = Context.getCancelSignal(context); - } - /** Clone and change active graph - shares tracking */ public static ExecutionContext copyChangeActiveGraph(ExecutionContext other, Graph activeGraph) { - return new ExecutionContext(other, activeGraph); + return new ExecutionContext(other, activeGraph, other.executor); } - /** - * Clone and change active graph - shares tracking - * @deprecated Use {@link #copyChangeActiveGraph(ExecutionContext, Graph)}. - */ - @Deprecated - public ExecutionContext(ExecutionContext other, Graph activeGraph) { - this(other); - this.activeGraph = activeGraph; + /** Clone and change OpExecutor - shares tracking */ + public static ExecutionContext copyChangeExecutor(ExecutionContext other, OpExecutorFactory opExecutorFactory) { + return new ExecutionContext(other, other.activeGraph, opExecutorFactory); } /** @@ -144,8 +110,7 @@ public class ExecutionContext implements FunctionEnv * ExecutionContext for normal execution over a dataset. */ public static ExecutionContext create(DatasetGraph dataset, Graph activeGraph, Context context) { - return new ExecutionContext(context, - activeGraph, dataset, + return new ExecutionContext(context, activeGraph, dataset, QC.getFactory(context), Context.getCancelSignal(context)); } @@ -167,12 +132,38 @@ public class ExecutionContext implements FunctionEnv return create(dsg, graph, cxt); } + /** Create from a {@link FunctionEnv} */ + private ExecutionContext(FunctionEnv other) { + this.context = other.getContext(); + this.dataset = other.getDataset(); + this.openIterators = new ArrayList<>(); + this.allIterators = (TrackAllIterators) ? new ArrayList<>() : null; + this.activeGraph = other.getActiveGraph(); + this.executor = QC.getFactory(context); + this.cancelSignal = Context.getCancelSignal(context); + } + + /** + * Clone, changing the active graph and OpExecutorFactory. + */ + private ExecutionContext(ExecutionContext other, Graph activeGraph, OpExecutorFactory opExecutorFactory) { + this.context = other.context; + this.dataset = other.dataset; + this.openIterators = other.openIterators; + this.allIterators = other.allIterators; + this.activeGraph = activeGraph; + this.executor = opExecutorFactory; + this.cancelSignal = other.cancelSignal; + } + + /** + * Make a new ExecutionContext. + */ private ExecutionContext(Context params, Graph activeGraph, DatasetGraph dataset, OpExecutorFactory factory, AtomicBoolean cancelSignal) { this.context = params; this.dataset = dataset; this.openIterators = new ArrayList<>(); - if ( TrackAllIterators ) - this.allIterators = new ArrayList<>(); + this.allIterators = (TrackAllIterators) ? new ArrayList<>() : null; this.activeGraph = activeGraph; this.executor = factory; this.cancelSignal = cancelSignal; @@ -187,7 +178,16 @@ public class ExecutionContext implements FunctionEnv return cancelSignal; } - /** Check the cancel signal and throw {@link QueryCancelledException}} if it is true. */ + + /** + * Check the cancel signal and throw {@link QueryCancelledException}} if it is true. + * + * @deprecated This rarely the right way to handle cancellation. + * Either {@link #getCancelSignal} check the flag, take action and throw + * {@link QueryCancelledException} or let the query iterator machinery + * in {@link QueryIteratorBase} deal with it when no additional action is required. + */ + @Deprecated(forRemoval=true) public void checkCancelSignal() { if ( cancelSignal != null && cancelSignal.get() ) throw new QueryCancelledException(); @@ -217,17 +217,16 @@ public class ExecutionContext implements FunctionEnv return executor; } - /** Setter for the policy for algebra expression evaluation - use with care */ - public void setExecutor(OpExecutorFactory executor) { - this.executor = executor; - } - + /** + * Return the dataset for the query execution. + */ @Override public DatasetGraph getDataset() { return dataset; } - /** Return the active graph (the one matching is against at this point in the query. - * May be null if unknown or not applicable - for example, doing quad store access or - * when sorting + /** + * Return the active graph (the one matching is against at this point in the + * query. May be null if unknown or not applicable - for example, doing quad + * store access or when sorting. */ @Override public Graph getActiveGraph() { return activeGraph; } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionEnv.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionEnv.java index 3420b62037..fd5ade9761 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionEnv.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionEnv.java @@ -26,17 +26,17 @@ import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.util.Context; /** Environment passed to functions */ - public interface FunctionEnv { - /** Return the active graph (the one involved in pattern matching atthis point in the query). - * May be null if unknown or not applicable - for example, doing quad store access or when sorting. + /** + * Return the active graph (the one involved in pattern matching at this point in + * the query execution). May return {@code null} if unknown or not applicable - for example, + * doing quad store access or when sorting. */ public Graph getActiveGraph(); /** - * Return the dataset for the query. - * May be null for "unknown"/"not relevant" + * Return the dataset for the query. May be null for "unknown"/"not relevant" */ public DatasetGraph getDataset(); diff --git a/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java b/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java index a7eff6f9fc..49037551dc 100644 --- a/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java +++ b/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java @@ -247,8 +247,7 @@ public class OpExecutorTDB1 extends OpExecutor // The Op may be a sequence due to TransformFilterPlacement // so we need to do a full execution step, not go straight to the SolverLib. - ExecutionContext ec2 = ExecutionContext.copy(execCxt); - ec2.setExecutor(plainFactory); + ExecutionContext ec2 = ExecutionContext.copyChangeExecutor(execCxt, plainFactory); // Solve without going through this executor again. // There would be issues of nested patterns but this is only a diff --git a/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java b/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java index 23c649d348..ddc1012c08 100644 --- a/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java +++ b/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java @@ -254,8 +254,7 @@ public class OpExecutorTDB2 extends OpExecutor // The Op may be a sequence due to TransformFilterPlacement // so we need to do a full execution step, not go straight to the SolverLib. - ExecutionContext ec2 = ExecutionContext.copy(execCxt); - ec2.setExecutor(plainFactory); + ExecutionContext ec2 = ExecutionContext.copyChangeExecutor(execCxt, plainFactory); // Solve without going through this executor again. // There would be issues of nested patterns but this is only a
