001: /**
002: * Objective Database Abstraction Layer (ODAL)
003: * Copyright (c) 2004, The ODAL Development Group
004: * All rights reserved.
005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
006: *
007: * Distributable under LGPL license.
008: * See terms of license at gnu.org.
009: */package com.completex.objective.components.pool.impl;
010:
011: import com.completex.objective.components.log.Log;
012: import com.completex.objective.components.pool.Pool;
013: import com.completex.objective.components.pool.ResourceFactory;
014: import com.completex.objective.components.timer.TimerListener;
015: import com.completex.objective.components.timer.impl.Timer;
016: import com.completex.objective.components.OdalRuntimeException;
017:
018: import java.util.Iterator;
019: import java.util.LinkedList;
020:
021: /**
022: * @author Gennady Krizhevsky
023: */
024: public class ResourceLimitingPool implements Pool, TimerListener {
025:
026: public static final int DEFAULT_MAX_CONNECTIONS = 100;
027: public static final int DEFAULT_STMT_CACHE_SIZE = 50;
028: public static final int DEFAULT_TIMEOUT = 0;
029:
030: private final ResourceFactory resourceFactory;
031: private final int maxSize;
032: private long shrinkTimeInterval = 1000 * 60 * 5;
033: private long timeout = 2 * 60 * 1000;
034: private int shrinkSize = -1;
035: private ShrinkPolicy shrinkPolicy;
036: private long timerCycle = 1000;
037: private Timer timer;
038: private int numberOfBuzy;
039: private int numberOfWaiters;
040: private LinkedList idleResources = new LinkedList();
041: private Log log = Log.NULL_LOGGER;
042:
043: public ResourceLimitingPool(ResourceFactory resourceFactory,
044: int maxSize, Log logger) {
045: this (resourceFactory, maxSize, 0, logger);
046: }
047:
048: public ResourceLimitingPool(ResourceFactory resourceFactory,
049: int maxSize, long shrinkTimeInterval, Log logger) {
050: this (resourceFactory, maxSize, shrinkTimeInterval, 0, logger);
051: }
052:
053: /**
054: * @param resourceFactory
055: * @param maxSize
056: * @param shrinkTimeInterval
057: * @param timeout time to wait until giving up on resource in ms. If 0 is set - will wait indefinitely.
058: * @param logger
059: */
060: public ResourceLimitingPool(ResourceFactory resourceFactory,
061: int maxSize, long shrinkTimeInterval, long timeout,
062: Log logger) {
063: this .resourceFactory = resourceFactory;
064: this .shrinkTimeInterval = shrinkTimeInterval;
065: if (maxSize == 0) {
066: throw new OdalRuntimeException("maxSize == 0");
067: }
068: this .maxSize = maxSize;
069: this .timeout = timeout;
070: this .log = logger;
071: }
072:
073: public void setTimeout(long timeout) {
074: this .timeout = timeout;
075: }
076:
077: public int getMaxSize() {
078: return maxSize;
079: }
080:
081: public void start() {
082: if (shrinkSize >= 0 && shrinkTimeInterval > 0) {
083: if (shrinkPolicy == null) {
084: this .shrinkPolicy = new ShrinkPolicyImpl(shrinkSize,
085: shrinkTimeInterval);
086: ((ShrinkPolicyImpl) shrinkPolicy).setLog(log);
087: }
088: timer = new Timer(this , timerCycle);
089: timer.start();
090: }
091: }
092:
093: public void setLog(Log log) {
094: this .log = log;
095:
096: }
097:
098: public void setShrinkSize(int shrinkSize) {
099: this .shrinkSize = shrinkSize;
100: }
101:
102: public void setShrinkPolicy(ShrinkPolicy shrinkPolicy) {
103: this .shrinkPolicy = shrinkPolicy;
104: }
105:
106: public void setShrinkTimeInterval(long shrinkTimeInterval) {
107: if (shrinkTimeInterval < timerCycle) {
108: throw new IllegalArgumentException("shrinkTimeInterval ["
109: + shrinkTimeInterval
110: + "] is less than timerCycle [" + timerCycle + "]");
111: }
112: this .shrinkTimeInterval = shrinkTimeInterval;
113: }
114:
115: public void timerEvent() {
116: shrinkAsNeeded();
117: }
118:
119: public Object acquireResource() {
120: debug("Enter ResourceLimitingPool::acquireResource");
121: try {
122: synchronized (this ) {
123: Object resource;
124: boolean tried = false;
125: while ((cantAcquireResource() && !tried)) {
126: try {
127: numberOfWaiters++;
128: debug("acquireResource: Waiting for resource : numberOfWaiters "
129: + numberOfWaiters);
130: tried = true;
131: wait(timeout);
132: } catch (InterruptedException e) {
133: log
134: .warn("Interrupted acquireResource because of expired timeout = "
135: + timeout);
136: }
137: }
138: debug("acquireResource: After wait(timeout) : numberOfWaiters "
139: + numberOfWaiters);
140: debug("acquireResource: resource pool " + toString());
141: if (cantAcquireResource()) {
142: // Means that we passed the timeout:
143: throw new OdalRuntimeException(
144: "Could not get resource in "
145: + timeout
146: + " ms while number of resources exceeded the limit: "
147: + maxSize);
148: }
149: if (idleResources.size() != 0) {
150: debug("acquireResource: Before resource = idleResources.removeFirst() ");
151: resource = idleResources.removeFirst();
152: debug("acquireResource: After resource = idleResources.removeFirst() ");
153: } else {
154: debug("acquireResource: Before resource = resourceFactory.createResource() ");
155: resource = resourceFactory.createResource();
156: debug("acquireResource: After resource = resourceFactory.createResource() ");
157: }
158: check();
159: numberOfBuzy++;
160: return resource;
161: }
162: } finally {
163: debug("Exit ResourceLimitingPool::acquireResource");
164: }
165: }
166:
167: private void debug(String message) {
168: if (log != null && log.isDebugEnabled()) {
169: log.debug(message);
170: }
171: }
172:
173: private boolean cantAcquireResource() {
174: long size = size();
175: long idleSize = idleResources.size();
176: return size >= maxSize && idleSize == 0;
177: }
178:
179: public int size() {
180: return numberOfBuzy + idleResources.size();
181: }
182:
183: public void releaseResource(Object resource) {
184: synchronized (this ) {
185: idleResources.addLast(resource);
186: numberOfBuzy--;
187: check();
188: if (numberOfWaiters > 0) {
189: numberOfWaiters--;
190: if (log != null && log.isDebugEnabled()) {
191: log
192: .debug("releaseResource: Notify for resource : numberOfWaiters "
193: + numberOfWaiters);
194: }
195: notify();
196: }
197: }
198: }
199:
200: /**
201: * Do not return bad resource into the pool - just reduce the numberOfBuzy count
202: *
203: * @param resource
204: */
205: public void releaseBadResource(Object resource) {
206: synchronized (this ) {
207: numberOfBuzy--;
208: }
209: }
210:
211: private void shrinkAsNeeded() {
212: // System.err.println("shrinkAsNeeded");
213: if (shrinkPolicy != null) {
214: // System.err.println("shrinkAsNeeded shrinkPolicy != null");
215: synchronized (this ) {
216: if (shrinkPolicy.shouldShrink(idleResources.size())) {
217: // System.err.println("shrinkAsNeeded shrinkPolicy.shouldShrink(idleResources.size())");
218: while (idleResources.size() > shrinkSize) {
219: if (log != null && log.isTraceEnabled()) {
220: log
221: .trace("shrinkAsNeeded idleResources.size() > shrinkSize");
222: }
223: idleResources.removeLast();
224: }
225: }
226: }
227: }
228: }
229:
230: private void check() {
231: if (shrinkPolicy != null) {
232: shrinkPolicy.shouldShrink(idleResources.size());
233: }
234: }
235:
236: public void shutdown() {
237: synchronized (this ) {
238: for (Iterator iterator = idleResources.iterator(); iterator
239: .hasNext();) {
240: resourceFactory.destroyResource(iterator.next());
241: }
242: idleResources = new LinkedList();
243: numberOfBuzy = 0;
244: if (timer != null) {
245: timer.setStop(true);
246: }
247: }
248: }
249:
250: public String toString() {
251: return super .toString() + " : Number Of Buzy : " + numberOfBuzy
252: + "; number of idle: " + idleResources.size()
253: + "; resources limit: " + maxSize;
254: }
255: }
|