diff --git a/hadoop-hdds/erasurecode/src/main/java/org/apache/ozone/erasurecode/CodecRegistry.java b/hadoop-hdds/erasurecode/src/main/java/org/apache/ozone/erasurecode/CodecRegistry.java index a681e0920eaa..f8234cbadce7 100644 --- a/hadoop-hdds/erasurecode/src/main/java/org/apache/ozone/erasurecode/CodecRegistry.java +++ b/hadoop-hdds/erasurecode/src/main/java/org/apache/ozone/erasurecode/CodecRegistry.java @@ -51,7 +51,8 @@ private CodecRegistry() { coderMap = new HashMap<>(); coderNameMap = new HashMap<>(); final ServiceLoader coderFactories = - ServiceLoader.load(RawErasureCoderFactory.class); + ServiceLoader.load(RawErasureCoderFactory.class, + CodecRegistry.class.getClassLoader()); updateCoders(coderFactories); } diff --git a/hadoop-hdds/erasurecode/src/test/java/org/apache/ozone/erasurecode/TestCodecRegistryTcclIsolation.java b/hadoop-hdds/erasurecode/src/test/java/org/apache/ozone/erasurecode/TestCodecRegistryTcclIsolation.java new file mode 100644 index 000000000000..24e34372f7f8 --- /dev/null +++ b/hadoop-hdds/erasurecode/src/test/java/org/apache/ozone/erasurecode/TestCodecRegistryTcclIsolation.java @@ -0,0 +1,52 @@ +/* + * 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.ozone.erasurecode; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.hadoop.hdds.client.ECReplicationConfig; +import org.apache.ozone.erasurecode.rawcoder.RSRawErasureCoderFactory; +import org.junit.jupiter.api.Test; + +/** + * Tests that CodecRegistry does not depend on the thread context class loader + * (TCCL) for discovering RawErasureCoderFactory providers. + * + *

CodecRegistry is an eagerly-initialized singleton, so this test must run + * in its own JVM (e.g. reuseForks=false) as the first test to touch + * CodecRegistry, otherwise initialization already happened under the normal + * TCCL and the test passes vacuously. + */ +public class TestCodecRegistryTcclIsolation { + + @Test + public void testRegistryLoadsWithoutTccl() { + ClassLoader originalTccl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(new ClassLoader(null) { + }); + String[] rsCoderNames = CodecRegistry.getInstance() + .getCoderNames(ECReplicationConfig.EcCodec.RS.name().toLowerCase()); + assertThat(rsCoderNames).isNotNull(); + assertThat(rsCoderNames).isNotEmpty(); + assertThat(rsCoderNames).contains(RSRawErasureCoderFactory.CODER_NAME); + } finally { + Thread.currentThread().setContextClassLoader(originalTccl); + } + } +}