| /* |
| * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.enterprise.resource.pool.datastructure; |
| |
| import com.sun.enterprise.resource.ResourceHandle; |
| import com.sun.enterprise.resource.allocator.ResourceAllocator; |
| import com.sun.appserv.connectors.internal.api.PoolingException; |
| import com.sun.enterprise.resource.pool.ResourceHandler; |
| import com.sun.enterprise.resource.pool.datastructure.strategy.ResourceSelectionStrategy; |
| |
| import java.util.ArrayList; |
| import java.util.concurrent.Semaphore; |
| |
| /** |
| * List based datastructure that can be used by connection pool <br> |
| * |
| * @author Jagadish Ramu |
| */ |
| public class ListDataStructure implements DataStructure { |
| private final ArrayList<ResourceHandle> free; |
| private final ArrayList<ResourceHandle> resources; |
| //Max Size of the datastructure.Depends mostly on the max-pool-size of |
| // the connection pool. |
| private int maxSize; |
| private final DynamicSemaphore dynSemaphore; |
| |
| private ResourceHandler handler; |
| private ResourceSelectionStrategy strategy; |
| |
| public ListDataStructure(String parameters, int maxSize, ResourceHandler handler, String strategyClass) { |
| resources = new ArrayList<ResourceHandle>((maxSize > 1000) ? 1000 : maxSize); |
| free = new ArrayList<ResourceHandle>((maxSize > 1000) ? 1000 : maxSize); |
| this.handler = handler; |
| initializeStrategy(strategyClass); |
| dynSemaphore = new DynamicSemaphore(); |
| setMaxSize(maxSize); |
| } |
| |
| |
| /** |
| * Set maxSize based on the new max pool size set on the connection pool |
| * during a reconfiguration. |
| * 1. When permits contained within the dynamic semaphore are greater than 0, |
| * maxSize is increased and hence so many permits are released. |
| * 2. When permits contained within the dynamic semaphore are less than 0, |
| * maxSize has reduced to a smaller value. Hence so many permits are reduced |
| * from the semaphore's available limit for the subsequent resource requests |
| * to act based on the new configuration. |
| * @param newMaxSize |
| */ |
| public synchronized void setMaxSize(int newMaxSize) { |
| |
| //Find currently open with the current maxsize |
| int permits = newMaxSize - this.maxSize; |
| |
| if (permits == 0) { |
| //None are open |
| return; |
| } else if (permits > 0) { |
| //Case when no of permits are increased |
| this.dynSemaphore.release(permits); |
| } else { |
| //permits would be a -ve value |
| //Case when no of permits are to be reduced. |
| permits *= -1; |
| this.dynSemaphore.reducePermits(permits); |
| } |
| this.maxSize = newMaxSize; |
| } |
| |
| private void initializeStrategy(String strategyClass) { |
| //TODO |
| } |
| |
| /** |
| * creates a new resource and adds to the datastructure. |
| * |
| * @param allocator ResourceAllocator |
| * @param count Number (units) of resources to create |
| * @return int number of resources added |
| */ |
| public int addResource(ResourceAllocator allocator, int count) throws PoolingException { |
| int numResAdded = 0; |
| for (int i = 0; i < count && resources.size() < maxSize; i++) { |
| boolean lockAcquired = dynSemaphore.tryAcquire(); |
| if(lockAcquired) { |
| try { |
| ResourceHandle handle = handler.createResource(allocator); |
| synchronized (resources) { |
| synchronized (free) { |
| free.add(handle); |
| resources.add(handle); |
| numResAdded++; |
| } |
| } |
| } catch (Exception e) { |
| dynSemaphore.release(); |
| PoolingException pe = new PoolingException(e.getMessage()); |
| pe.initCause(e); |
| throw pe; |
| } |
| } |
| } |
| return numResAdded; |
| } |
| |
| /** |
| * get a resource from the datastructure |
| * |
| * @return ResourceHandle |
| */ |
| public ResourceHandle getResource() { |
| ResourceHandle resource = null; |
| if (strategy != null) { |
| resource = strategy.retrieveResource(); |
| } else { |
| synchronized (free) { |
| if (free.size() > 0){ |
| resource = free.remove(0); |
| } |
| } |
| } |
| return resource; |
| } |
| |
| /** |
| * remove the specified resource from the datastructure |
| * |
| * @param resource ResourceHandle |
| */ |
| public void removeResource(ResourceHandle resource) { |
| boolean removed = false; |
| synchronized (resources) { |
| synchronized (free) { |
| free.remove(resource); |
| removed = resources.remove(resource); |
| } |
| } |
| if(removed) { |
| dynSemaphore.release(); |
| handler.deleteResource(resource); |
| } |
| } |
| |
| /** |
| * returns the resource to the datastructure |
| * |
| * @param resource ResourceHandle |
| */ |
| public void returnResource(ResourceHandle resource) { |
| synchronized (free) { |
| free.add(resource); |
| } |
| } |
| |
| /** |
| * get the count of free resources in the datastructure |
| * |
| * @return int count |
| */ |
| public int getFreeListSize() { |
| return free.size(); |
| } |
| |
| /** |
| * remove & destroy all resources from the datastructure. |
| */ |
| public void removeAll() { |
| synchronized (resources) { |
| synchronized (free) { |
| while (resources.size() > 0) { |
| ResourceHandle handle = resources.remove(0); |
| free.remove(handle); |
| dynSemaphore.release(); |
| handler.deleteResource(handle); |
| } |
| } |
| } |
| free.clear(); |
| resources.clear(); |
| } |
| |
| /** |
| * get total number of resources in the datastructure |
| * |
| * @return int count |
| */ |
| public int getResourcesSize() { |
| return resources.size(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public ArrayList<ResourceHandle> getAllResources() { |
| return this.resources; |
| } |
| |
| /** |
| * Semaphore whose available permits change according to the |
| * changes in max-pool-size via a reconfiguration. |
| */ |
| private static final class DynamicSemaphore extends Semaphore { |
| |
| DynamicSemaphore() { |
| //Default is 0 |
| super(0); |
| } |
| |
| @Override |
| protected void reducePermits(int size) { |
| super.reducePermits(size); |
| } |
| } |
| } |