|
19 | 19 | import java.util.concurrent.TimeUnit; |
20 | 20 | import java.util.logging.Logger; |
21 | 21 | import org.geotools.util.logging.Logging; |
| 22 | +import org.geowebcache.config.ServerConfiguration; |
22 | 23 | import org.springframework.beans.factory.DisposableBean; |
23 | 24 | import org.springframework.scheduling.concurrent.CustomizableThreadFactory; |
| 25 | +import org.springframework.util.StringUtils; |
24 | 26 |
|
25 | 27 | public class SeederThreadPoolExecutor extends ThreadPoolExecutor implements DisposableBean { |
26 | 28 |
|
27 | 29 | private static final Logger log = Logging.getLogger(SeederThreadPoolExecutor.class.getName()); |
28 | 30 |
|
29 | 31 | private static final ThreadFactory tf = new CustomizableThreadFactory("GWC Seeder Thread-"); |
30 | 32 |
|
31 | | - public SeederThreadPoolExecutor(int corePoolSize, int maxPoolSize) { |
32 | | - super(corePoolSize, maxPoolSize, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), tf); |
| 33 | + protected static final int DEFAULT_CORE_POOL_SIZE = 16; |
| 34 | + |
| 35 | + protected static final int DEFAULT_MAX_POOL_SIZE = 32; |
| 36 | + |
| 37 | + /** |
| 38 | + * Environment variable / system property name for configuring the core pool size. Looked up from Java system |
| 39 | + * properties first, then from OS environment variables. If neither is set or the value is not a valid positive |
| 40 | + * integer, the configuration value (or hardcoded default) is used. |
| 41 | + */ |
| 42 | + public static final String GWC_SEEDER_CORE_POOL_SIZE = "GWC_SEEDER_CORE_POOL_SIZE"; |
| 43 | + |
| 44 | + /** |
| 45 | + * Environment variable / system property name for configuring the maximum pool size. Looked up from Java system |
| 46 | + * properties first, then from OS environment variables. If neither is set or the value is not a valid positive |
| 47 | + * integer, the configuration value (or hardcoded default) is used. |
| 48 | + */ |
| 49 | + public static final String GWC_SEEDER_MAX_POOL_SIZE = "GWC_SEEDER_MAX_POOL_SIZE"; |
| 50 | + |
| 51 | + /** |
| 52 | + * Creates the seeder thread pool, reading pool sizes from the given {@link ServerConfiguration}. The configuration |
| 53 | + * values can be overridden by system properties or environment variables. |
| 54 | + * |
| 55 | + * <p>Precedence: environment variable / system property → ServerConfiguration → hardcoded default (16/32). |
| 56 | + * |
| 57 | + * @param config the server configuration providing pool size settings from geowebcache.xml |
| 58 | + */ |
| 59 | + public SeederThreadPoolExecutor(ServerConfiguration config) { |
| 60 | + this(configuredCorePoolSize(config), configuredMaxPoolSize(config)); |
| 61 | + } |
| 62 | + |
| 63 | + /** |
| 64 | + * Internal constructor that resolves env var overrides and validates sizes. Subclasses (e.g. GeoServer's |
| 65 | + * SeederThreadLocalTransferExecutor) use this to pass in pool sizes read from their own configuration. |
| 66 | + */ |
| 67 | + protected SeederThreadPoolExecutor(int defaultCore, int defaultMax) { |
| 68 | + this(resolvedSizes(defaultCore, defaultMax)); |
| 69 | + } |
| 70 | + |
| 71 | + private SeederThreadPoolExecutor(int[] sizes) { |
| 72 | + super(sizes[0], sizes[1], 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), tf); |
| 73 | + log.info("Seeder thread pool initialized with corePoolSize=" |
| 74 | + + getCorePoolSize() |
| 75 | + + ", maxPoolSize=" |
| 76 | + + getMaximumPoolSize()); |
| 77 | + } |
| 78 | + |
| 79 | + private static int configuredCorePoolSize(ServerConfiguration config) { |
| 80 | + if (config != null) { |
| 81 | + Integer value = config.getSeederCorePoolSize(); |
| 82 | + if (value != null && value > 0) { |
| 83 | + return value; |
| 84 | + } |
| 85 | + } |
| 86 | + return DEFAULT_CORE_POOL_SIZE; |
| 87 | + } |
| 88 | + |
| 89 | + private static int configuredMaxPoolSize(ServerConfiguration config) { |
| 90 | + if (config != null) { |
| 91 | + Integer value = config.getSeederMaxPoolSize(); |
| 92 | + if (value != null && value > 0) { |
| 93 | + return value; |
| 94 | + } |
| 95 | + } |
| 96 | + return DEFAULT_MAX_POOL_SIZE; |
| 97 | + } |
| 98 | + |
| 99 | + /** Resolves both pool sizes applying env var overrides and the core <= max constraint. Returns [core, max]. */ |
| 100 | + private static int[] resolvedSizes(int defaultCore, int defaultMax) { |
| 101 | + int core = resolvePoolSize(GWC_SEEDER_CORE_POOL_SIZE, defaultCore); |
| 102 | + int max = resolvePoolSize(GWC_SEEDER_MAX_POOL_SIZE, defaultMax); |
| 103 | + if (core > max) { |
| 104 | + log.warning("Configured corePoolSize (" |
| 105 | + + core |
| 106 | + + ") is greater than maxPoolSize (" |
| 107 | + + max |
| 108 | + + "), adjusting maxPoolSize to match corePoolSize"); |
| 109 | + max = core; |
| 110 | + } |
| 111 | + return new int[] {core, max}; |
| 112 | + } |
| 113 | + |
| 114 | + /** |
| 115 | + * Resolves a pool size configuration value by looking up the given property name first as a Java system property, |
| 116 | + * then as an OS environment variable. Falls back to the provided default if neither is set or the value is not a |
| 117 | + * valid positive integer. |
| 118 | + * |
| 119 | + * @param propertyName the system property / environment variable name to look up |
| 120 | + * @param defaultValue the fallback value if the property is not set or invalid |
| 121 | + * @return the resolved pool size |
| 122 | + */ |
| 123 | + static int resolvePoolSize(String propertyName, int defaultValue) { |
| 124 | + String value = System.getProperty(propertyName); |
| 125 | + if (!StringUtils.hasText(value)) { |
| 126 | + value = System.getenv(propertyName); |
| 127 | + } |
| 128 | + if (StringUtils.hasText(value)) { |
| 129 | + try { |
| 130 | + int parsed = Integer.parseInt(value.trim()); |
| 131 | + if (parsed > 0) { |
| 132 | + log.info("Using configured value for " + propertyName + "=" + parsed); |
| 133 | + return parsed; |
| 134 | + } else { |
| 135 | + log.warning("Invalid value for " |
| 136 | + + propertyName |
| 137 | + + "=" |
| 138 | + + value |
| 139 | + + " (must be a positive integer), using default " |
| 140 | + + defaultValue); |
| 141 | + } |
| 142 | + } catch (NumberFormatException e) { |
| 143 | + log.warning("Invalid value for " |
| 144 | + + propertyName |
| 145 | + + "=" |
| 146 | + + value |
| 147 | + + " (not a valid integer), using default " |
| 148 | + + defaultValue); |
| 149 | + } |
| 150 | + } |
| 151 | + return defaultValue; |
33 | 152 | } |
34 | 153 |
|
35 | 154 | /** |
|
0 commit comments