From 693f5e9da17af0b4ae6178364e7f8287796ae9d1 Mon Sep 17 00:00:00 2001 From: Dave Marion Date: Fri, 9 Oct 2026 12:03:35 +0000 Subject: [PATCH 1/5] Changed default ContextClassLoaderFactory impl Changed the default implementation to use the system classloader, which is effectively a no-op. Moved the URLContextClassLoaderFactory to a test package for test visibility, updated tests. --- .../core/classloader/ClassLoaderUtil.java | 2 +- .../DefaultContextClassLoaderFactory.java | 30 +++++++++++++++++++ .../test}/URLContextClassLoaderFactory.java | 6 ++-- ... => URLContextClassLoaderFactoryTest.java} | 3 +- .../MiniAccumuloClusterClasspathTest.java | 3 ++ .../ClassLoaderContextCompactionIT.java | 3 ++ .../test/functional/ScannerContextIT.java | 9 ++++++ .../accumulo/test/shell/ShellServerIT.java | 4 ++- 8 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java rename core/src/main/java/org/apache/accumulo/core/{classloader => util/test}/URLContextClassLoaderFactory.java (91%) rename core/src/test/java/org/apache/accumulo/core/classloader/{ContextClassLoaderFactoryTest.java => URLContextClassLoaderFactoryTest.java} (95%) diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java b/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java index e04b772c37c..e9511285b1f 100644 --- a/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java +++ b/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java @@ -46,7 +46,7 @@ public static synchronized void initContextFactory(AccumuloConfiguration conf) { // load the default implementation LOG.info("Using default {}, which is subject to change in a future release", ContextClassLoaderFactory.class.getName()); - FACTORY = new URLContextClassLoaderFactory(); + FACTORY = new DefaultContextClassLoaderFactory(); } else { // load user's selected implementation and provide it with the service environment try { diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java b/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java new file mode 100644 index 00000000000..bd7f307b992 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java @@ -0,0 +1,30 @@ +/* + * 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 + * + * https://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.accumulo.core.classloader; + +import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; + +public class DefaultContextClassLoaderFactory implements ContextClassLoaderFactory { + + @Override + public ClassLoader getClassLoader(String context) throws ContextClassLoaderException { + return ClassLoader.getSystemClassLoader(); + } + +} diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/URLContextClassLoaderFactory.java b/core/src/main/java/org/apache/accumulo/core/util/test/URLContextClassLoaderFactory.java similarity index 91% rename from core/src/main/java/org/apache/accumulo/core/classloader/URLContextClassLoaderFactory.java rename to core/src/main/java/org/apache/accumulo/core/util/test/URLContextClassLoaderFactory.java index 32681e6e5d0..097d76201f4 100644 --- a/core/src/main/java/org/apache/accumulo/core/classloader/URLContextClassLoaderFactory.java +++ b/core/src/main/java/org/apache/accumulo/core/util/test/URLContextClassLoaderFactory.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.accumulo.core.classloader; +package org.apache.accumulo.core.util.test; import java.io.UncheckedIOException; import java.net.MalformedURLException; @@ -34,8 +34,8 @@ import com.github.benmanes.caffeine.cache.Cache; /** - * The default implementation of ContextClassLoaderFactory. This classloader returns a - * URLClassLoader based on the given context value which is a CSV list of URLs. For example, + * A test implementation of ContextClassLoaderFactory. This classloader returns a URLClassLoader + * based on the given context value which is a CSV list of URLs. For example, * file://path/one/jar1.jar,file://path/two/jar2.jar */ public class URLContextClassLoaderFactory implements ContextClassLoaderFactory { diff --git a/core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java b/core/src/test/java/org/apache/accumulo/core/classloader/URLContextClassLoaderFactoryTest.java similarity index 95% rename from core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java rename to core/src/test/java/org/apache/accumulo/core/classloader/URLContextClassLoaderFactoryTest.java index 440d6ca72b4..5789f5854a3 100644 --- a/core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java +++ b/core/src/test/java/org/apache/accumulo/core/classloader/URLContextClassLoaderFactoryTest.java @@ -30,6 +30,7 @@ import org.apache.accumulo.core.conf.ConfigurationCopy; import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory.ContextClassLoaderException; +import org.apache.accumulo.core.util.test.URLContextClassLoaderFactory; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,7 +39,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "paths not set by user input") -public class ContextClassLoaderFactoryTest extends WithTestNames { +public class URLContextClassLoaderFactoryTest extends WithTestNames { @TempDir private static Path tempFolder; diff --git a/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterClasspathTest.java b/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterClasspathTest.java index d12a266cf73..4992976cad0 100644 --- a/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterClasspathTest.java +++ b/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterClasspathTest.java @@ -40,6 +40,7 @@ import org.apache.accumulo.core.data.Mutation; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.util.test.URLContextClassLoaderFactory; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -74,6 +75,8 @@ public static void setupMiniCluster() throws Exception { config.setZooKeeperPort(0); HashMap site = new HashMap<>(); site.put(Property.TSERV_WAL_MAX_SIZE.getKey(), "1G"); + site.put(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY.getKey(), + URLContextClassLoaderFactory.class.getName()); config.setSiteConfig(site); accumulo = new MiniAccumuloCluster(config); accumulo.start(); diff --git a/test/src/main/java/org/apache/accumulo/test/compaction/ClassLoaderContextCompactionIT.java b/test/src/main/java/org/apache/accumulo/test/compaction/ClassLoaderContextCompactionIT.java index 2162b4eb7af..18dfa5fbe3c 100644 --- a/test/src/main/java/org/apache/accumulo/test/compaction/ClassLoaderContextCompactionIT.java +++ b/test/src/main/java/org/apache/accumulo/test/compaction/ClassLoaderContextCompactionIT.java @@ -57,6 +57,7 @@ import org.apache.accumulo.core.metrics.MetricsUtil; import org.apache.accumulo.core.spi.metrics.LoggingMeterRegistryFactory; import org.apache.accumulo.core.util.compaction.ExternalCompactionUtil; +import org.apache.accumulo.core.util.test.URLContextClassLoaderFactory; import org.apache.accumulo.core.util.threads.Threads; import org.apache.accumulo.minicluster.ServerType; import org.apache.accumulo.miniclusterImpl.MiniAccumuloClusterImpl; @@ -101,6 +102,8 @@ public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration coreS cfg.setProperty(Property.COMPACTOR_FAILURE_BACKOFF_INTERVAL, "5s"); cfg.setProperty(Property.COMPACTOR_FAILURE_BACKOFF_RESET, "10m"); cfg.setProperty(Property.COMPACTOR_FAILURE_TERMINATION_THRESHOLD, "3"); + cfg.setProperty(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY, + URLContextClassLoaderFactory.class.getName()); cfg.getClusterServerConfiguration().setNumDefaultCompactors(2); cfg.getClusterServerConfiguration().addCompactorResourceGroup(GROUP1, 1); // Tell the server processes to use a StatsDMeterRegistry and the simple logging registry diff --git a/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java b/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java index 7c7ea5d8490..83bc5121f5b 100644 --- a/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java +++ b/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java @@ -43,8 +43,11 @@ import org.apache.accumulo.core.data.Range; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.util.test.URLContextClassLoaderFactory; import org.apache.accumulo.miniclusterImpl.MiniAccumuloClusterImpl; +import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; import org.apache.accumulo.test.harness.AccumuloClusterHarness; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.junit.jupiter.api.BeforeEach; @@ -64,6 +67,12 @@ protected Duration defaultTimeout() { return Duration.ofMinutes(2); } + @Override + public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration hadoopCoreSite) { + cfg.setProperty(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY, + URLContextClassLoaderFactory.class.getName()); + } + @BeforeEach public void checkCluster() throws Exception { assumeTrue(getClusterType() == ClusterType.MINI); diff --git a/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java b/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java index 4283c8d837d..6fbb243b934 100644 --- a/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java +++ b/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java @@ -91,6 +91,7 @@ import org.apache.accumulo.core.spi.crypto.NoCryptoServiceFactory; import org.apache.accumulo.core.util.format.Formatter; import org.apache.accumulo.core.util.format.FormatterConfig; +import org.apache.accumulo.core.util.test.URLContextClassLoaderFactory; import org.apache.accumulo.minicluster.ServerType; import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; import org.apache.accumulo.test.ImportExportIT; @@ -131,7 +132,8 @@ private static class ShellServerITConfigCallback implements MiniClusterConfigura public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration coreSite) { // Only one tserver to avoid race conditions on ZK propagation (auths and configuration) cfg.getClusterServerConfiguration().setNumDefaultTabletServers(1); - // Set the min span to 0 so we will definitely get all the traces back. See ACCUMULO-4365 + cfg.setProperty(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY, + URLContextClassLoaderFactory.class.getName()); Map siteConf = cfg.getSiteConfig(); cfg.setSiteConfig(siteConf); } From 52b7cdb2b8ccf127d848e3b1188268d097c0f2c1 Mon Sep 17 00:00:00 2001 From: Dave Marion Date: Tue, 13 Oct 2026 11:35:31 +0000 Subject: [PATCH 2/5] Updated based on PR comments --- .../core/classloader/ClassLoaderUtil.java | 6 ++-- .../DefaultContextClassLoaderFactory.java | 30 ------------------- 2 files changed, 3 insertions(+), 33 deletions(-) delete mode 100644 core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java b/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java index e9511285b1f..4190bd578f5 100644 --- a/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java +++ b/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java @@ -44,9 +44,9 @@ public static synchronized void initContextFactory(AccumuloConfiguration conf) { String factoryName = conf.get(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY); if (factoryName == null || factoryName.isEmpty()) { // load the default implementation - LOG.info("Using default {}, which is subject to change in a future release", - ContextClassLoaderFactory.class.getName()); - FACTORY = new DefaultContextClassLoaderFactory(); + LOG.info("{} not set, using System ClassLoader for all contexts", + Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY.getKey()); + FACTORY = context -> ClassLoader.getSystemClassLoader(); } else { // load user's selected implementation and provide it with the service environment try { diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java b/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java deleted file mode 100644 index bd7f307b992..00000000000 --- a/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - * - * https://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.accumulo.core.classloader; - -import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; - -public class DefaultContextClassLoaderFactory implements ContextClassLoaderFactory { - - @Override - public ClassLoader getClassLoader(String context) throws ContextClassLoaderException { - return ClassLoader.getSystemClassLoader(); - } - -} From b3a7cf8f057fea47c5ab58a14f570b4da0dad413 Mon Sep 17 00:00:00 2001 From: Dave Marion Date: Wed, 14 Oct 2026 12:35:18 +0000 Subject: [PATCH 3/5] Fix tests in UpgradeIT and HalfClosedTabletIT --- .../apache/accumulo/test/functional/HalfClosedTabletIT.java | 3 +++ .../main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/src/main/java/org/apache/accumulo/test/functional/HalfClosedTabletIT.java b/test/src/main/java/org/apache/accumulo/test/functional/HalfClosedTabletIT.java index 015dd489c39..9b3f7d7484e 100644 --- a/test/src/main/java/org/apache/accumulo/test/functional/HalfClosedTabletIT.java +++ b/test/src/main/java/org/apache/accumulo/test/functional/HalfClosedTabletIT.java @@ -40,6 +40,7 @@ import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; import org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType; import org.apache.accumulo.core.metadata.schema.TabletsMetadata; +import org.apache.accumulo.core.util.test.URLContextClassLoaderFactory; import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; import org.apache.accumulo.server.ServerContext; import org.apache.accumulo.server.conf.store.TablePropKey; @@ -71,6 +72,8 @@ public static class HalfClosedTabletITConfiguration implements MiniClusterConfig @Override public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration coreSite) { cfg.getClusterServerConfiguration().setNumDefaultTabletServers(1); + cfg.setProperty(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY, + URLContextClassLoaderFactory.class.getName()); } } diff --git a/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java b/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java index 5554d6e2def..a60729cbb3c 100644 --- a/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java +++ b/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java @@ -45,6 +45,7 @@ import org.apache.accumulo.test.util.Wait; import org.apache.hadoop.conf.Configuration; import org.junit.jupiter.api.Test; +import org.opentest4j.AssertionFailedError; public class UpgradeIT extends AccumuloClusterHarness { @@ -124,7 +125,7 @@ public void testServersWontStart() throws Exception { Wait.waitFor(() -> getServerContext().getServerPaths() .getTabletServer(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); - assertThrows(IllegalStateException.class, + assertThrows(AssertionFailedError.class, () -> assertTimeoutPreemptively(Duration.ofMinutes(2), () -> getCluster().start())); // Confirm no servers started From 7d9bd72fbae00853028c1587aa2df9b6ebb635a6 Mon Sep 17 00:00:00 2001 From: Dave Marion Date: Thu, 15 Oct 2026 11:51:29 +0000 Subject: [PATCH 4/5] Fix dependency issue --- .../main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java b/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java index a60729cbb3c..ce18e3f6067 100644 --- a/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java +++ b/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java @@ -45,7 +45,6 @@ import org.apache.accumulo.test.util.Wait; import org.apache.hadoop.conf.Configuration; import org.junit.jupiter.api.Test; -import org.opentest4j.AssertionFailedError; public class UpgradeIT extends AccumuloClusterHarness { @@ -125,7 +124,7 @@ public void testServersWontStart() throws Exception { Wait.waitFor(() -> getServerContext().getServerPaths() .getTabletServer(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); - assertThrows(AssertionFailedError.class, + assertThrows(AssertionError.class, () -> assertTimeoutPreemptively(Duration.ofMinutes(2), () -> getCluster().start())); // Confirm no servers started From db3d4566844128aa055d82b4387ffa3b5d26bd90 Mon Sep 17 00:00:00 2001 From: Dave Marion Date: Wed, 21 Oct 2026 13:41:10 +0000 Subject: [PATCH 5/5] BalanceIT.testBalanceMetadata was failing, this fixed it. --- .../main/java/org/apache/accumulo/manager/BalanceManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/BalanceManager.java b/server/manager/src/main/java/org/apache/accumulo/manager/BalanceManager.java index 9baae8d74dd..7a62a68361b 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/BalanceManager.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/BalanceManager.java @@ -350,6 +350,7 @@ void waitForBalance() { while (unassigned > 0) { log.debug("displayUnassigned():{}", unassigned); UtilWaitThread.sleep(50); + waitForBalance(EnumSet.allOf(Ample.DataLevel.class)); unassigned = getManager().displayUnassigned(); } }