View | Details | Raw Unified | Return to bug 60623
Collapse All | Expand All

(-)java/org/apache/catalina/core/StartStopHandler.java (+43 lines)
Line 0 Link Here
1
/*
2
 *  Licensed to the Apache Software Foundation (ASF) under one
3
 *  or more contributor license agreements.  See the NOTICE file
4
 *  distributed with this work for additional information
5
 *  regarding copyright ownership.  The ASF licenses this file
6
 *  to you under the Apache License, Version 2.0 (the
7
 *  "License"); you may not use this file except in compliance
8
 *  with the License.  You may obtain a copy of the License at
9
 *
10
 *  http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *  Unless required by applicable law or agreed to in writing,
13
 *  software distributed under the License is distributed on an
14
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 *  KIND, either express or implied.  See the License for the
16
 *  specific language governing permissions and limitations
17
 *  under the License.
18
 */
19
20
package org.apache.catalina.core;
21
22
import org.apache.catalina.Container;
23
import org.apache.catalina.LifecycleException;
24
import org.apache.tomcat.util.res.StringManager;
25
26
abstract class StartStopHandler {
27
    protected static final StringManager sm = StringManager.getManager(Constants.Package);
28
    abstract void start(Container[] children) throws LifecycleException;
29
    abstract void stop(Container[] children) throws LifecycleException;
30
    void stop() {
31
32
    }
33
34
    static StartStopHandler createStartStopHandler(String name, int threadCount) {
35
        if(threadCount == 1) {
36
            return SingleThreadedStartStopHandler.INSTANCE;
37
        }
38
        else {
39
            return new MultiThreadedStartStopHandler(name, threadCount);
40
        }
41
    }
42
43
}
(-)java/org/apache/catalina/core/MultiThreadedStartStopHandler.java (+156 lines)
Line 0 Link Here
1
/*
2
 *  Licensed to the Apache Software Foundation (ASF) under one
3
 *  or more contributor license agreements.  See the NOTICE file
4
 *  distributed with this work for additional information
5
 *  regarding copyright ownership.  The ASF licenses this file
6
 *  to you under the Apache License, Version 2.0 (the
7
 *  "License"); you may not use this file except in compliance
8
 *  with the License.  You may obtain a copy of the License at
9
 *
10
 *  http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *  Unless required by applicable law or agreed to in writing,
13
 *  software distributed under the License is distributed on an
14
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 *  KIND, either express or implied.  See the License for the
16
 *  specific language governing permissions and limitations
17
 *  under the License.
18
 */
19
20
package org.apache.catalina.core;
21
22
import org.apache.catalina.Container;
23
import org.apache.catalina.LifecycleException;
24
import org.apache.juli.logging.Log;
25
import org.apache.juli.logging.LogFactory;
26
27
import java.util.ArrayList;
28
import java.util.List;
29
import java.util.concurrent.*;
30
import java.util.concurrent.atomic.AtomicInteger;
31
32
public class MultiThreadedStartStopHandler extends StartStopHandler {
33
    private final ThreadPoolExecutor startStopExecutor;
34
    private static final Log log = LogFactory.getLog(MultiThreadedStartStopHandler.class);
35
36
    MultiThreadedStartStopHandler(String name, int threadCount) {
37
        int actualThreadCount = getStartStopThreadsInternal(threadCount);
38
        BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
39
        startStopExecutor = new ThreadPoolExecutor(actualThreadCount,actualThreadCount, 10,
40
                TimeUnit.SECONDS,
41
                startStopQueue, new StartStopThreadFactory(name + "-startStop-"));
42
        startStopExecutor.allowCoreThreadTimeOut(true);
43
    }
44
45
    @Override
46
    void start(Container[] children) throws LifecycleException{
47
        List<Future<Void>> results = new ArrayList<>();
48
        for(Container child : children) {
49
            results.add(startStopExecutor.submit(new StartChild(child)));
50
        }
51
        handleFutures(results, "containerBase.threadedStartFailed");
52
    }
53
54
    @Override
55
    void stop(Container[] children) throws LifecycleException{
56
        List<Future<Void>> results = new ArrayList<>();
57
        for(Container child : children) {
58
            results.add(startStopExecutor.submit(new StopChild(child)));
59
        }
60
    }
61
62
    @Override
63
    void stop() {
64
        this.startStopExecutor.shutdownNow();
65
    }
66
67
    private void handleFutures(List<Future<Void>> results, String key) throws LifecycleException {
68
        boolean fail = false;
69
        for (Future<Void> result : results) {
70
            try {
71
                result.get();
72
            } catch (Exception e) {
73
                log.error(sm.getString(key), e);
74
                fail = true;
75
            }
76
        }
77
        if (fail) {
78
            throw new LifecycleException(
79
                    sm.getString(key));
80
        }
81
    }
82
83
    /**
84
     * Handles the special values.
85
     */
86
    private static int getStartStopThreadsInternal(int threadCount) {
87
        int result = threadCount;
88
89
        // Positive values are unchanged
90
        if (result > 0) {
91
            return result;
92
        }
93
94
        // Zero == Runtime.getRuntime().availableProcessors()
95
        // -ve  == Runtime.getRuntime().availableProcessors() + value
96
        // These two are the same
97
        result = Runtime.getRuntime().availableProcessors() + result;
98
        if (result < 1) {
99
            result = 1;
100
        }
101
        return result;
102
    }
103
104
    // ----------------------------- Inner classes used with start/stop Executor
105
106
    private static class StartChild implements Callable<Void> {
107
108
        private Container child;
109
110
        public StartChild(Container child) {
111
            this.child = child;
112
        }
113
114
        @Override
115
        public Void call() throws LifecycleException {
116
            child.start();
117
            return null;
118
        }
119
    }
120
121
    private static class StopChild implements Callable<Void> {
122
123
        private Container child;
124
125
        public StopChild(Container child) {
126
            this.child = child;
127
        }
128
129
        @Override
130
        public Void call() throws LifecycleException {
131
            if (child.getState().isAvailable()) {
132
                child.stop();
133
            }
134
            return null;
135
        }
136
    }
137
138
    private static class StartStopThreadFactory implements ThreadFactory {
139
        private final ThreadGroup group;
140
        private final AtomicInteger threadNumber = new AtomicInteger(1);
141
        private final String namePrefix;
142
143
        public StartStopThreadFactory(String namePrefix) {
144
            SecurityManager s = System.getSecurityManager();
145
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
146
            this.namePrefix = namePrefix;
147
        }
148
149
        @Override
150
        public Thread newThread(Runnable r) {
151
            Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
152
            thread.setDaemon(true);
153
            return thread;
154
        }
155
    }
156
}
(-)java/org/apache/catalina/core/SingleThreadedStartStopHandler.java (+47 lines)
Line 0 Link Here
1
/*
2
 *  Licensed to the Apache Software Foundation (ASF) under one
3
 *  or more contributor license agreements.  See the NOTICE file
4
 *  distributed with this work for additional information
5
 *  regarding copyright ownership.  The ASF licenses this file
6
 *  to you under the Apache License, Version 2.0 (the
7
 *  "License"); you may not use this file except in compliance
8
 *  with the License.  You may obtain a copy of the License at
9
 *
10
 *  http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *  Unless required by applicable law or agreed to in writing,
13
 *  software distributed under the License is distributed on an
14
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 *  KIND, either express or implied.  See the License for the
16
 *  specific language governing permissions and limitations
17
 *  under the License.
18
 */
19
20
package org.apache.catalina.core;
21
22
import org.apache.catalina.Container;
23
import org.apache.catalina.LifecycleException;
24
25
class SingleThreadedStartStopHandler extends StartStopHandler {
26
    static SingleThreadedStartStopHandler INSTANCE = new SingleThreadedStartStopHandler();
27
28
    private SingleThreadedStartStopHandler() {
29
30
    }
31
32
    @Override
33
    void start(Container[] children) throws LifecycleException {
34
        for (Container child : children) {
35
            child.start();
36
        }
37
    }
38
39
    @Override
40
    void stop(Container[] children) throws LifecycleException {
41
        for (Container child : children) {
42
            if (child.getState().isAvailable()) {
43
                child.stop();
44
            }
45
        }
46
    }
47
}
(-)java/org/apache/catalina/core/ContainerBase.java (-77 / +8 lines)
Lines 276-282 Link Here
276
     * children associated with this container.
276
     * children associated with this container.
277
     */
277
     */
278
    private int startStopThreads = 1;
278
    private int startStopThreads = 1;
279
    protected ThreadPoolExecutor startStopExecutor;
279
280
    private StartStopHandler startStopHandler;
280
281
281
282
282
    // ------------------------------------------------------------- Properties
283
    // ------------------------------------------------------------- Properties
Lines 286-323 Link Here
286
        return startStopThreads;
287
        return startStopThreads;
287
    }
288
    }
288
289
289
    /**
290
     * Handles the special values.
291
     */
292
    private int getStartStopThreadsInternal() {
293
        int result = getStartStopThreads();
294
295
        // Positive values are unchanged
296
        if (result > 0) {
297
            return result;
298
        }
299
300
        // Zero == Runtime.getRuntime().availableProcessors()
301
        // -ve  == Runtime.getRuntime().availableProcessors() + value
302
        // These two are the same
303
        result = Runtime.getRuntime().availableProcessors() + result;
304
        if (result < 1) {
305
            result = 1;
306
        }
307
        return result;
308
    }
309
310
    @Override
290
    @Override
311
    public void setStartStopThreads(int startStopThreads) {
291
    public void setStartStopThreads(int startStopThreads) {
312
        this.startStopThreads = startStopThreads;
292
        this.startStopThreads = startStopThreads;
313
293
314
        // Use local copies to ensure thread safety
294
        this.startStopHandler = StartStopHandler.createStartStopHandler(getName(), startStopThreads);
315
        ThreadPoolExecutor executor = startStopExecutor;
316
        if (executor != null) {
317
            int newThreads = getStartStopThreadsInternal();
318
            executor.setMaximumPoolSize(newThreads);
319
            executor.setCorePoolSize(newThreads);
320
        }
321
    }
295
    }
322
296
323
297
Lines 893-905 Link Here
893
867
894
    @Override
868
    @Override
895
    protected void initInternal() throws LifecycleException {
869
    protected void initInternal() throws LifecycleException {
896
        BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
870
        this.startStopHandler = StartStopHandler.createStartStopHandler(getName(), getStartStopThreads());
897
        startStopExecutor = new ThreadPoolExecutor(
898
                getStartStopThreadsInternal(),
899
                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
900
                startStopQueue,
901
                new StartStopThreadFactory(getName() + "-startStop-"));
902
        startStopExecutor.allowCoreThreadTimeOut(true);
903
        super.initInternal();
871
        super.initInternal();
904
    }
872
    }
905
873
Lines 927-952 Link Here
927
        }
895
        }
928
896
929
        // Start our child containers, if any
897
        // Start our child containers, if any
930
        Container children[] = findChildren();
898
        startStopHandler.start(findChildren());
931
        List<Future<Void>> results = new ArrayList<>();
932
        for (int i = 0; i < children.length; i++) {
933
            results.add(startStopExecutor.submit(new StartChild(children[i])));
934
        }
935
936
        boolean fail = false;
937
        for (Future<Void> result : results) {
938
            try {
939
                result.get();
940
            } catch (Exception e) {
941
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
942
                fail = true;
943
            }
944
945
        }
946
        if (fail) {
947
            throw new LifecycleException(
948
                    sm.getString("containerBase.threadedStartFailed"));
949
        }
950
899
951
        // Start the Valves in our pipeline (including the basic), if any
900
        // Start the Valves in our pipeline (including the basic), if any
952
        if (pipeline instanceof Lifecycle)
901
        if (pipeline instanceof Lifecycle)
Lines 983-1007 Link Here
983
        }
932
        }
984
933
985
        // Stop our child containers, if any
934
        // Stop our child containers, if any
986
        Container children[] = findChildren();
935
        startStopHandler.stop(findChildren());
987
        List<Future<Void>> results = new ArrayList<>();
988
        for (int i = 0; i < children.length; i++) {
989
            results.add(startStopExecutor.submit(new StopChild(children[i])));
990
        }
991
992
        boolean fail = false;
993
        for (Future<Void> result : results) {
994
            try {
995
                result.get();
996
            } catch (Exception e) {
997
                log.error(sm.getString("containerBase.threadedStopFailed"), e);
998
                fail = true;
999
            }
1000
        }
1001
        if (fail) {
1002
            throw new LifecycleException(
1003
                    sm.getString("containerBase.threadedStopFailed"));
1004
        }
1005
936
1006
        // Stop our subordinate components, if any
937
        // Stop our subordinate components, if any
1007
        Realm realm = getRealmInternal();
938
        Realm realm = getRealmInternal();
Lines 1042-1049 Link Here
1042
        }
973
        }
1043
974
1044
        // If init fails, this may be null
975
        // If init fails, this may be null
1045
        if (startStopExecutor != null) {
976
        if (startStopHandler != null) {
1046
            startStopExecutor.shutdownNow();
977
            startStopHandler.stop();
1047
        }
978
        }
1048
979
1049
        super.destroyInternal();
980
        super.destroyInternal();

Return to bug 60623