This is an automated email from the ASF dual-hosted git repository. vy pushed a commit to branch api-queue in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 4fd515f7833d4c3e37a728106d34c8e34b5c0fa7 Author: Volkan Yazıcı <[email protected]> AuthorDate: Tue Dec 12 12:45:09 2023 +0100 Move JCTools-based queues in the API to a new module --- {log4j-api => log4j-api-queue-jctools}/pom.xml | 41 +++++++------ .../log4j/api/queue/JCToolsQueueFactory.java | 37 +++++++++++ log4j-api/pom.xml | 11 +--- .../logging/log4j/internal/QueueFactories.java | 71 +++++++++------------- .../logging/log4j/internal/RecyclerFactories.java | 4 +- .../apache/logging/log4j/status/StatusLogger.java | 2 +- pom.xml | 7 +++ 7 files changed, 99 insertions(+), 74 deletions(-) diff --git a/log4j-api/pom.xml b/log4j-api-queue-jctools/pom.xml similarity index 64% copy from log4j-api/pom.xml copy to log4j-api-queue-jctools/pom.xml index 2ea9e66998..18dd10d906 100644 --- a/log4j-api/pom.xml +++ b/log4j-api-queue-jctools/pom.xml @@ -15,44 +15,45 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j</artifactId> <version>${revision}</version> <relativePath>../log4j-parent</relativePath> </parent> - <artifactId>log4j-api</artifactId> - <packaging>jar</packaging> - <name>Apache Log4j API</name> - <description>The Apache Log4j API</description> + + <artifactId>log4j-api-queue-jctools</artifactId> + <name>Apache Log4j API queue provider (JCTools)</name> + <description>Provides JCTools-based queue implementations for the Apache Log4j API.</description> + <properties> - <maven.javadoc.skip>false</maven.javadoc.skip> + + <log4jParentDir>${basedir}/..</log4jParentDir> <!-- ~ OSGi and JPMS options --> - <bnd-module-name>org.apache.logging.log4j</bnd-module-name> - <bnd-extra-package-options> - <!-- No JSR 305 at runtime --> - !javax.annotation.*, - <!-- Optional dependencies --> - org.jctools.*;resolution:=optional - </bnd-extra-package-options> - <bnd-extra-module-options> - <!-- No JSR 305 at runtime --> - jsr305;ignore=true, - <!-- Used in StringBuilders through reflection --> - java.sql;static=true - </bnd-extra-module-options> + <bnd-module-name>org.apache.logging.log4j.api.queue.jctools</bnd-module-name> + <Fragment-Host>org.apache.logging.log4j.core</Fragment-Host> </properties> + <dependencies> + + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + </dependency> + <dependency> <groupId>org.jctools</groupId> <artifactId>jctools-core</artifactId> - <optional>true</optional> </dependency> + </dependencies> + </project> diff --git a/log4j-api-queue-jctools/src/main/java/org/apache/logging/log4j/api/queue/JCToolsQueueFactory.java b/log4j-api-queue-jctools/src/main/java/org/apache/logging/log4j/api/queue/JCToolsQueueFactory.java new file mode 100644 index 0000000000..57a39e31f8 --- /dev/null +++ b/log4j-api-queue-jctools/src/main/java/org/apache/logging/log4j/api/queue/JCToolsQueueFactory.java @@ -0,0 +1,37 @@ +/* + * 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.logging.log4j.api.queue; + +import aQute.bnd.annotation.spi.ServiceProvider; +import java.util.Queue; +import org.apache.logging.log4j.spi.QueueFactory; +import org.jctools.queues.MpmcArrayQueue; + +/** + * A multi-producer-multi-consumer, thread-safe {@link QueueFactory} implementation based on <a href="https://jctools.github.io/JCTools/">JCTools</a>. + */ +@ServiceProvider(QueueFactory.class) +public final class JCToolsQueueFactory implements QueueFactory { + + @Override + public <E> Queue<E> create(final int capacity) { + if (capacity < 1) { + throw new IllegalArgumentException("invalid capacity: " + capacity); + } + return new MpmcArrayQueue<>(capacity); + } +} diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index 2ea9e66998..bb22c40e74 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -36,9 +36,7 @@ <bnd-module-name>org.apache.logging.log4j</bnd-module-name> <bnd-extra-package-options> <!-- No JSR 305 at runtime --> - !javax.annotation.*, - <!-- Optional dependencies --> - org.jctools.*;resolution:=optional + !javax.annotation.* </bnd-extra-package-options> <bnd-extra-module-options> <!-- No JSR 305 at runtime --> @@ -48,11 +46,4 @@ </bnd-extra-module-options> </properties> - <dependencies> - <dependency> - <groupId>org.jctools</groupId> - <artifactId>jctools-core</artifactId> - <optional>true</optional> - </dependency> - </dependencies> </project> diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/QueueFactories.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/QueueFactories.java index 3d0313057b..b0275c4506 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/QueueFactories.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/QueueFactories.java @@ -16,67 +16,56 @@ */ package org.apache.logging.log4j.internal; +import static org.apache.logging.log4j.util.LowLevelLogUtil.log; + +import aQute.bnd.annotation.spi.ServiceConsumer; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.util.List; import java.util.Queue; +import java.util.ServiceLoader; import java.util.concurrent.ArrayBlockingQueue; -import java.util.function.Supplier; import org.apache.logging.log4j.spi.QueueFactory; import org.apache.logging.log4j.util.Cast; import org.apache.logging.log4j.util.InternalApi; import org.apache.logging.log4j.util.LoaderUtil; -import org.jctools.queues.MpmcArrayQueue; +import org.apache.logging.log4j.util.ServiceLoaderUtil; /** - * Provides {@link QueueFactory} instances for different use cases. - * <p> - * Implementations provided by <a href="https://jctools.github.io/JCTools/">JCTools</a> will be preferred, if available at runtime. - * Otherwise, {@link ArrayBlockingQueue} will be used. - * </p> + * Provides the default {@link QueueFactory} instance. * * @since 3.0.0 */ @InternalApi -public enum QueueFactories implements QueueFactory { +@ServiceConsumer(QueueFactory.class) +public final class QueueFactories { /** - * Provides a bounded queue for multi-producer/multi-consumer usage. + * The default {@link QueueFactory} instance. */ - MPMC(() -> MpmcArrayQueue::new); - - private final QueueFactory queueFactory; - - QueueFactories(final Supplier<QueueFactory> queueFactoryProvider) { - this.queueFactory = getOrReplaceQueueFactory(queueFactoryProvider); - } - - private static QueueFactory getOrReplaceQueueFactory(final Supplier<QueueFactory> queueFactoryProvider) { - try { - final QueueFactory queueFactory = queueFactoryProvider.get(); - // Test with a large enough capacity to avoid any `IllegalArgumentExceptions` from trivial queues - queueFactory.create(16); - return queueFactory; - } catch (final LinkageError ignored) { - return ArrayBlockingQueueFactory.INSTANCE; + public static final QueueFactory INSTANCE = findInstance(); + + private static QueueFactory findInstance() { + final ServiceLoader<QueueFactory> serviceLoader = + ServiceLoader.load(QueueFactory.class, QueueFactory.class.getClassLoader()); + final List<QueueFactory> factories = + ServiceLoaderUtil.safeStream(serviceLoader).toList(); + if (factories.isEmpty()) { + return ArrayBlockingQueue::new; + } else { + final int factoryCount = factories.size(); + if (factoryCount > 1) { + log("Log4j was expecting a single `QueueFactory` provider, found:"); + for (int factoryIndex = 0; factoryIndex < factoryCount; factoryIndex++) { + log((factoryIndex + 1) + ". `" + factories.get(factoryIndex) + "`"); + } + log("Log4j will use the first `QueueFactory` provider as the default."); + } + return factories.get(0); } } - @Override - public <E> Queue<E> create(final int capacity) { - return queueFactory.create(capacity); - } - - private static final class ArrayBlockingQueueFactory implements QueueFactory { - - private static final ArrayBlockingQueueFactory INSTANCE = new ArrayBlockingQueueFactory(); - - private ArrayBlockingQueueFactory() {} - - @Override - public <E> Queue<E> create(final int capacity) { - return new ArrayBlockingQueue<>(capacity); - } - } + private QueueFactories() {} /** * Creates a {@link QueueFactory} using the provided supplier. diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/RecyclerFactories.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/RecyclerFactories.java index aea850f199..c7ec83a87a 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/RecyclerFactories.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/RecyclerFactories.java @@ -42,7 +42,7 @@ public final class RecyclerFactories { */ public static final RecyclerFactory INSTANCE = isThreadLocalsEnabled() ? new ThreadLocalRecyclerFactory(CAPACITY) - : new QueueingRecyclerFactory(QueueFactories.MPMC, CAPACITY); + : new QueueingRecyclerFactory(QueueFactories.INSTANCE, CAPACITY); private RecyclerFactories() {} @@ -146,7 +146,7 @@ public final class RecyclerFactories { // Execute the read spec final QueueFactory queueFactory = - supplierPath != null ? QueueFactories.ofSupplier(supplierPath) : QueueFactories.MPMC; + supplierPath != null ? QueueFactories.ofSupplier(supplierPath) : QueueFactories.INSTANCE; return new QueueingRecyclerFactory(queueFactory, capacity); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java index 7f0247ccef..d5134593ef 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java @@ -97,7 +97,7 @@ public final class StatusLogger extends AbstractLogger { this.logger = logger; this.configuration = configuration; this.listenersLevel = configuration.getDefaultLevel().intLevel(); - messages = QueueFactories.MPMC.create(configuration.getMaxEntries()); + messages = QueueFactories.INSTANCE.create(configuration.getMaxEntries()); } /** diff --git a/pom.xml b/pom.xml index 3dcdfa03ce..8862927529 100644 --- a/pom.xml +++ b/pom.xml @@ -234,6 +234,7 @@ Note that modules here must have a corresponding entry in `dependencyManagement > dependencies` block below! --> <module>log4j-1.2-api</module> <module>log4j-api</module> + <module>log4j-api-queue-jctools</module> <module>log4j-api-test</module> <module>log4j-appserver</module> <module>log4j-core</module> @@ -356,6 +357,12 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api-queue-jctools</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api-test</artifactId>
