Author: remm
Date: Thu Nov 8 10:17:43 2018
New Revision: 1846116
URL: http://svn.apache.org/viewvc?rev=1846116&view=rev
Log:
Add a scheduled executor service to the Service, which can be used to process
utility tasks including periodic ones.
Add a simple wrapper to prevent random lifecycle and configuration operations.
Add a bean for it.
Added:
tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
(with props)
Modified:
tomcat/trunk/java/org/apache/catalina/Service.java
tomcat/trunk/java/org/apache/catalina/core/StandardService.java
tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/service.xml
Modified: tomcat/trunk/java/org/apache/catalina/Service.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Service.java?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Service.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Service.java Thu Nov 8 10:17:43 2018
@@ -18,6 +18,8 @@
package org.apache.catalina;
+import java.util.concurrent.ScheduledExecutorService;
+
import org.apache.catalina.connector.Connector;
import org.apache.catalina.mapper.Mapper;
@@ -96,6 +98,20 @@ public interface Service extends Lifecyc
public String getDomain();
+ /**
+ * Get the utility thread count.
+ * @return the thread count
+ */
+ public int getUtilityThreads();
+
+
+ /**
+ * Set the utility thread count.
+ * @param utilityThreads the new thread count
+ */
+ public void setUtilityThreads(int utilityThreads);
+
+
// --------------------------------------------------------- Public Methods
/**
@@ -151,4 +167,10 @@ public interface Service extends Lifecyc
* @return the mapper associated with this Service.
*/
Mapper getMapper();
+
+ /**
+ * @return the utility executor managed by the Service.
+ */
+ ScheduledExecutorService getUtilityExecutor();
+
}
Modified: tomcat/trunk/java/org/apache/catalina/core/StandardService.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardService.java?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardService.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardService.java Thu Nov 8
10:17:43 2018
@@ -20,6 +20,11 @@ package org.apache.catalina.core;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.management.ObjectName;
@@ -85,10 +90,25 @@ public class StandardService extends Lif
private final Object connectorsLock = new Object();
/**
- *
+ * The list of executors held by the service.
*/
protected final ArrayList<Executor> executors = new ArrayList<>();
+ /**
+ * The number of threads available to process utility tasks in this
service.
+ */
+ protected int utilityThreads = 0;
+
+ /**
+ * Utility executor with scheduling capabilities.
+ */
+ private ScheduledThreadPoolExecutor utilityExecutor = null;
+
+ /**
+ * Utility executor wrapper.
+ */
+ private ScheduledExecutorService utilityExecutorWrapper = null;
+
private Engine engine = null;
private ClassLoader parentClassLoader = null;
@@ -202,8 +222,65 @@ public class StandardService extends Lif
}
+ @Override
+ public int getUtilityThreads() {
+ return utilityThreads;
+ }
+
+
+ /**
+ * Handles the special values.
+ */
+ private int getUtilityThreadsInternal() {
+ int result = getUtilityThreads();
+ if (result > 0) {
+ return result;
+ }
+
+ // Zero == Runtime.getRuntime().availableProcessors()
+ // -ve == Runtime.getRuntime().availableProcessors() + value
+ // These two are the same
+ result = (Runtime.getRuntime().availableProcessors() / 2) + result;
+ if (result < 1) {
+ result = 1;
+ }
+ return result;
+ }
+
+ @Override
+ public void setUtilityThreads(int utilityThreads) {
+ if (utilityThreads < getUtilityThreadsInternal()) {
+ return;
+ }
+ int oldUtilityThreads = this.utilityThreads;
+ this.utilityThreads = utilityThreads;
+
+ // Use local copies to ensure thread safety
+ if (oldUtilityThreads != utilityThreads && utilityExecutor != null) {
+ reconfigureUtilityExecutor(getUtilityThreadsInternal());
+ }
+ }
+
+
+ private synchronized void reconfigureUtilityExecutor(int threads) {
+ if (utilityExecutor != null) {
+ utilityExecutor.setMaximumPoolSize(threads);
+ } else {
+ ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
+ new ScheduledThreadPoolExecutor(1, new
UtilityThreadFactory(getName() + "-utility-"));
+ scheduledThreadPoolExecutor.setMaximumPoolSize(threads);
+ scheduledThreadPoolExecutor.setKeepAliveTime(10, TimeUnit.SECONDS);
+ scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
+
scheduledThreadPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ utilityExecutor = scheduledThreadPoolExecutor;
+ utilityExecutorWrapper = new
org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor(utilityExecutor);
+ }
+ }
+
+
// --------------------------------------------------------- Public Methods
+
/**
* Add a new Connector to the set of defined Connectors, and associate it
* with this Service's Container.
@@ -500,6 +577,7 @@ public class StandardService extends Lif
executor.stop();
}
}
+
}
@@ -512,6 +590,9 @@ public class StandardService extends Lif
super.initInternal();
+ reconfigureUtilityExecutor(getUtilityThreadsInternal());
+ register(utilityExecutor, "type=UtilityExecutor");
+
if (engine != null) {
engine.init();
}
@@ -556,6 +637,12 @@ public class StandardService extends Lif
engine.destroy();
}
+ if (utilityExecutor != null) {
+ utilityExecutor.shutdownNow();
+ unregister("type=UtilityExecutor");
+ utilityExecutor = null;
+ }
+
super.destroyInternal();
}
@@ -613,4 +700,29 @@ public class StandardService extends Lif
public final String getObjectNameKeyProperties() {
return "type=Service";
}
+
+ private static class UtilityThreadFactory implements ThreadFactory {
+ private final ThreadGroup group;
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+ private final String namePrefix;
+
+ public UtilityThreadFactory(String namePrefix) {
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
+ this.namePrefix = namePrefix;
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(group, r, namePrefix +
threadNumber.getAndIncrement());
+ thread.setDaemon(true);
+ return thread;
+ }
+ }
+
+ @Override
+ public ScheduledExecutorService getUtilityExecutor() {
+ return utilityExecutorWrapper;
+ }
+
}
Added:
tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java?rev=1846116&view=auto
==============================================================================
---
tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
(added)
+++
tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
Thu Nov 8 10:17:43 2018
@@ -0,0 +1,141 @@
+/*
+ * 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.tomcat.util.threads;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Class which wraps a ScheduledExecutorService, while preventing
+ * lifecycle and configuration operations.
+ */
+public class ScheduledThreadPoolExecutor implements ScheduledExecutorService {
+
+ protected final ScheduledExecutorService executor;
+
+ /**
+ * Builds a wrapper for the given executor.
+ * @param executor the wrapped executor
+ */
+ public ScheduledThreadPoolExecutor(ScheduledExecutorService executor) {
+ this.executor = executor;
+ }
+
+ @Override
+ public void shutdown() {
+ // Do nothing
+ }
+
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return null;
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return executor.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return executor.isTerminated();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return executor.awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ return executor.submit(task);
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ return executor.submit(task, result);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ return executor.submit(task);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>>
tasks)
+ throws InterruptedException {
+ return executor.invokeAll(tasks);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>>
tasks, long timeout,
+ TimeUnit unit) throws InterruptedException {
+ return executor.invokeAll(tasks, timeout, unit);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException, ExecutionException {
+ return executor.invokeAny(tasks);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+ long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return executor.invokeAny(tasks, timeout, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ executor.execute(command);
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay,
+ TimeUnit unit) {
+ return executor.schedule(command, delay, unit);
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay,
+ TimeUnit unit) {
+ return executor.schedule(callable, delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+ long initialDelay, long period, TimeUnit unit) {
+ return executor.scheduleAtFixedRate(command, initialDelay, period,
unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+ long initialDelay, long delay, TimeUnit unit) {
+ return executor.scheduleWithFixedDelay(command, initialDelay, delay,
unit);
+ }
+
+}
Propchange:
tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java
(original)
+++ tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java Thu Nov
8 10:17:43 2018
@@ -72,6 +72,7 @@ public class TestRegistration extends To
"Tomcat:type=Server",
"Tomcat:type=Service",
"Tomcat:type=StringCache",
+ "Tomcat:type=UtilityExecutor",
"Tomcat:type=Valve,name=StandardEngineValve",
};
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Nov 8 10:17:43 2018
@@ -64,6 +64,10 @@
Include German translations for the Manager application in the standard
Tomcat distribution. (markt)
</fix>
+ <add>
+ Add a scheduled executor to the Service, which can be used to
+ process periodic utility tasks. (remm)
+ </add>
</changelog>
</subsection>
</section>
Modified: tomcat/trunk/webapps/docs/config/service.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/service.xml?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/service.xml (original)
+++ tomcat/trunk/webapps/docs/config/service.xml Thu Nov 8 10:17:43 2018
@@ -68,6 +68,17 @@
must be unique.</p>
</attribute>
+ <attribute name="startStopThreads" required="false">
+ <p>The number of threads this <strong>Service</strong> will use for
+ various utility tasks, including recurring ones. The special value
+ of 0 will result in the value of
+ <code>Runtime.getRuntime().availableProcessors()/2</code> being
+ used. Negative values will result in
+ <code>Runtime.getRuntime().availableProcessors()/2 + value</code> being
+ used unless this is less than 1 in which case 1 thread will be used.
+ </p>
+ </attribute>
+
</attributes>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]