| /*=============================================================================# |
| # Copyright (c) 2009, 2021 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.rj.servi; |
| |
| import org.apache.commons.pool2.PooledObject; |
| import org.apache.commons.pool2.PooledObjectState; |
| import org.apache.commons.pool2.impl.DefaultEvictionPolicy; |
| import org.apache.commons.pool2.impl.EvictionConfig; |
| import org.apache.commons.pool2.impl.EvictionPolicy; |
| import org.apache.commons.pool2.impl.GenericObjectPool; |
| import org.apache.commons.pool2.impl.GenericObjectPoolConfig; |
| |
| import org.eclipse.statet.jcommons.collections.ImList; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| |
| import org.eclipse.statet.rj.RjInvalidConfigurationException; |
| import org.eclipse.statet.rj.servi.pool.PoolConfig; |
| |
| |
| @NonNullByDefault |
| public class APool2 extends GenericObjectPool<APool2NodeHandler> { |
| |
| |
| public static final String CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_PROPERTY_KEY= "org.eclipse.statet.rj.servi.pool.client.AllocationRenewPeriod.millis"; //$NON-NLS-1$ |
| |
| public static final int CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_DEFAULT_VALUE= 600_000; // 10 min |
| private static final int CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_MIN_VALUE= 5_000; |
| |
| |
| private static final byte CLOSING= 2; |
| private static final byte CLOSING_FINALLY= 3; |
| private static final byte CLOSED= 4; |
| |
| |
| private static final EvictionPolicy<APool2NodeHandler> EVICTION_POLICY= new DefaultEvictionPolicy<>() { |
| |
| @Override |
| public boolean evict(final EvictionConfig config, |
| final PooledObject<APool2NodeHandler> underTest, final int idleCount) { |
| return (super.evict(config, underTest, idleCount) |
| || underTest.getObject().isEvictRequested(0) ); |
| } |
| |
| }; |
| |
| |
| private static GenericObjectPoolConfig<APool2NodeHandler> createAConfig(final PoolConfig config) { |
| final GenericObjectPoolConfig<APool2NodeHandler> aConfig= new GenericObjectPoolConfig<>(); |
| |
| aConfig.setLifo(true); |
| aConfig.setTestOnReturn(true); |
| aConfig.setTestWhileIdle(false); |
| aConfig.setTestOnBorrow(false); |
| aConfig.setBlockWhenExhausted(true); |
| aConfig.setMaxTotal(config.getMaxTotalCount()); |
| aConfig.setMaxWaitMillis(config.getMaxWaitTime()); |
| aConfig.setMinIdle(config.getMinIdleCount()); |
| aConfig.setMaxIdle(config.getMaxIdleCount()); |
| aConfig.setMinEvictableIdleTimeMillis(0); |
| aConfig.setSoftMinEvictableIdleTimeMillis(config.getMinIdleTime()); |
| aConfig.setTimeBetweenEvictionRunsMillis(5000); |
| aConfig.setNumTestsPerEvictionRun(-4); |
| aConfig.setEvictorShutdownTimeoutMillis(0); |
| |
| return aConfig; |
| } |
| |
| |
| private final String id; |
| |
| private final APool2NodeFactory factory; |
| |
| private int clientAllocationRenewPeriodMillis; |
| |
| private volatile byte state; |
| private boolean evicting; |
| private final Object stateLock= new Object(); |
| |
| |
| public APool2(final String id, final APool2NodeFactory factory, final PoolConfig config) |
| throws RjInvalidConfigurationException { |
| super(factory, createAConfig(config)); |
| this.id= id; |
| this.clientAllocationRenewPeriodMillis= getClientAllocationRenewPeriodMillisDefaultValue(); |
| |
| factory.setPool(this); |
| this.factory= factory; |
| } |
| |
| |
| public String getId() { |
| return this.id; |
| } |
| |
| |
| public void setConfig(final PoolConfig config) { |
| setConfig(createAConfig(config)); |
| } |
| |
| @Override |
| public int getMaxIdle() { |
| if (this.state != 0) { |
| return 0; |
| } |
| return super.getMaxIdle(); |
| } |
| |
| protected int getClientAllocationRenewPeriodMillisDefaultValue() throws RjInvalidConfigurationException { |
| try { |
| int millis= CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_DEFAULT_VALUE; |
| final String s= System.getProperty(CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_PROPERTY_KEY); |
| if (s != null) { |
| millis= Integer.parseInt(s); |
| } |
| if (millis != -1 && millis < CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_MIN_VALUE) { |
| throw new IllegalArgumentException(String.format("%1$s < %2$s", |
| this.clientAllocationRenewPeriodMillis, CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_MIN_VALUE )); |
| } |
| return millis; |
| } |
| catch (final Exception e) { |
| throw new RjInvalidConfigurationException("AllocationRenewPeriod.millis: " + e.getMessage()); |
| } |
| } |
| |
| public int getClientAllocationRenewPeriodMillis() { |
| return this.clientAllocationRenewPeriodMillis; |
| } |
| |
| |
| public APool2NodeHandler borrowObject(final String client) throws Exception { |
| if (this.state != 0) { |
| throw new IllegalStateException("Pool not open"); |
| } |
| |
| this.factory.registerArgs(client); |
| try { |
| return super.borrowObject(); |
| } |
| finally { |
| this.factory.clearArgs(); |
| } |
| } |
| |
| |
| |
| public boolean isOpen() { |
| return (this.state == 0); |
| } |
| |
| @Override |
| public void close() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public void close(final long evictionTimeout) { |
| synchronized (this.stateLock) { |
| if (this.state > CLOSING) { |
| return; |
| } |
| this.state= CLOSING; |
| } |
| final long evictNanos= APool2NodeHandler.evictNanos(evictionTimeout); |
| final boolean evictDirect= (evictionTimeout == 0); |
| |
| try { |
| Thread.sleep(10); |
| } |
| catch (final InterruptedException e) {} |
| |
| clear(); |
| |
| final ImList<APool2NodeHandler> objects= this.factory.getAllObjects(); |
| for (final APool2NodeHandler poolObj : objects) { |
| poolObj.doEvict(evictNanos, evictDirect); |
| } |
| |
| if (this.state > CLOSING) { |
| return; |
| } |
| setNumTestsPerEvictionRun(512); |
| setTimeBetweenEvictionRunsMillis(500); |
| } |
| |
| protected void closeFinally() { |
| super.close(); |
| |
| synchronized (this.stateLock) { |
| this.state= CLOSED; |
| } |
| } |
| |
| @Override |
| public void evict() throws Exception { |
| synchronized (this.stateLock) { |
| if (this.state > CLOSING || this.evicting) { |
| return; |
| } |
| this.evicting= true; |
| } |
| try { |
| int evicted; |
| do { |
| evicted= 0; |
| final long nanos= APool2NodeHandler.safeNanos(System.nanoTime()); |
| |
| final ImList<APool2NodeHandler> objects= this.factory.getAllObjects(); |
| for (final APool2NodeHandler poolObj : objects) { |
| poolObj.checkClientLost(nanos); |
| if (poolObj.isEvictRequested(nanos) |
| && poolObj.getPooledObject().getState() != PooledObjectState.INVALID) { |
| try { |
| invalidateObject(poolObj); |
| evicted++; |
| } |
| catch (final Exception e) {} |
| } |
| } |
| } |
| while (evicted > 0); |
| |
| super.evict(); |
| |
| synchronized (this.stateLock) { |
| if (this.state != CLOSING || this.factory.getNumAll() > 0) { |
| return; |
| } |
| this.state= CLOSING_FINALLY; |
| } |
| closeFinally(); |
| } |
| finally { |
| this.evicting= false; |
| } |
| } |
| |
| @Override |
| public EvictionPolicy<APool2NodeHandler> getEvictionPolicy() { |
| return EVICTION_POLICY; |
| } |
| |
| } |