001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo;
012:
013: import com.versant.core.common.Debug;
014: import com.versant.core.metric.BaseMetric;
015: import com.versant.core.metric.Metric;
016: import com.versant.core.metric.HasMetrics;
017: import com.versant.core.logging.LogEventStore;
018:
019: import java.util.List;
020:
021: import com.versant.core.common.BindingSupportImpl;
022: import com.versant.core.metric.HasMetrics;
023: import com.versant.core.logging.LogEventStore;
024:
025: /**
026: * This is a pool for PMs. This pool does not have a max limit. It is
027: * thread safe.
028: */
029: public class PMPool implements HasMetrics {
030:
031: private final VersantPMFInternal pmf;
032: private int maxIdle;
033:
034: private VersantPersistenceManagerImp idleHead; // next con to be given out
035: private VersantPersistenceManagerImp idleTail; // last con returned
036: private int idleCount;
037: private int allocatedCount;
038: private int returnedCount;
039:
040: private LogEventStore pes;
041:
042: private BaseMetric metricLocalPMIdle;
043: private BaseMetric metricLocalPMAllocated;
044: private BaseMetric metricLocalPMReturned;
045:
046: public PMPool(VersantPMFInternal pmf, int maxIdle, LogEventStore pes) {
047: this .pmf = pmf;
048: this .maxIdle = maxIdle;
049: this .pes = pes;
050: }
051:
052: /**
053: * Close all connections and shutdown the pool.
054: */
055: public void shutdown() {
056: for (;;) {
057: VersantPersistenceManagerImp pm = removeFromIdleHead();
058: if (pm == null)
059: break;
060: try {
061: pm.destroy();
062: } catch (Exception e) {
063: // ignore
064: }
065: }
066: }
067:
068: public String getStatus() {
069: return "idle " + idleCount + "/" + maxIdle;
070: }
071:
072: /**
073: * Allocate a PM from the pool.
074: */
075: public synchronized VersantPersistenceManagerImp getPM() {
076: VersantPersistenceManagerImp pm;
077: for (;;) {
078: pm = removeFromIdleHead();
079: if (pm == null) {
080: pm = pmf.createVersantPersistenceManagerImp();
081: break;
082: }
083: if (!pm.isActualClosed()) {
084: break;
085: }
086: }
087: pm.setInPool(false);
088: ++allocatedCount;
089: if (pes != null && pes.isFine()) {
090: pes.log(new PmPoolEvent(PmPoolEvent.PM_ALLOC, idleCount,
091: maxIdle));
092: }
093: return pm;
094: }
095:
096: /**
097: * Return a PM to the pool. This is called when the PM is closed.
098: *
099: * @see VersantPersistenceManagerImp#close
100: */
101: public void returnPM(VersantPersistenceManagerImp pm) {
102: if (!pm.isActualClosed()) {
103: if (idleCount >= maxIdle) {
104: pm.destroy();
105: } else {
106: pm.setInPool(true);
107: pm.resetForPooling();
108: addToIdleTail(pm);
109: }
110: ++returnedCount;
111: if (pes != null && pes.isFine()) {
112: pes.log(new PmPoolEvent(PmPoolEvent.PM_RELEASE,
113: idleCount, maxIdle));
114: }
115: }
116: }
117:
118: /**
119: * Add pm to the tail of the idle list. The con has its idle flag set.
120: */
121: private synchronized void addToIdleTail(
122: VersantPersistenceManagerImp pm) {
123: if (Debug.DEBUG) {
124: if (pm.prev != null || pm.next != null) {
125: throw BindingSupportImpl.getInstance().internal(
126: "pm belongs to a list");
127: }
128: }
129: pm.idle = true;
130: if (idleTail == null) {
131: idleHead = idleTail = pm;
132: } else {
133: pm.next = idleTail;
134: idleTail.prev = pm;
135: idleTail = pm;
136: }
137: ++idleCount;
138:
139: if (Debug.DEBUG)
140: checkList(idleTail, idleHead, idleCount);
141: }
142:
143: /**
144: * Check the integrity of the double linked with head and tail.
145: */
146: private void checkList(VersantPersistenceManagerImp tail,
147: VersantPersistenceManagerImp head, int size) {
148: if (tail == null) {
149: testTrue(head == null);
150: return;
151: }
152: if (head == null) {
153: testTrue(tail == null);
154: return;
155: }
156: checkList(tail, size);
157: checkList(head, size);
158: testTrue(tail.prev == null);
159: testTrue(head.next == null);
160: }
161:
162: /**
163: * Check the integrity of the double linked list containing pm.
164: */
165: private void checkList(VersantPersistenceManagerImp pm, int size) {
166: if (pm == null)
167: return;
168: int c = -1;
169: // check links to tail
170: for (VersantPersistenceManagerImp i = pm; i != null; i = i.prev) {
171: if (i.prev != null)
172: testTrue(i.prev.next == i);
173: ++c;
174: }
175: // check links to head
176: for (VersantPersistenceManagerImp i = pm; i != null; i = i.next) {
177: if (i.next != null)
178: testTrue(i.next.prev == i);
179: ++c;
180: }
181: if (size >= 0) {
182: testEquals(size, c);
183: }
184: }
185:
186: private static void testEquals(int a, int b) {
187: if (a != b) {
188: throw BindingSupportImpl.getInstance().internal(
189: "assertion failed: expected " + a + " got " + b);
190: }
191: }
192:
193: private static void testTrue(boolean t) {
194: if (!t) {
195: throw BindingSupportImpl.getInstance().internal(
196: "assertion failed: expected true");
197: }
198: }
199:
200: /**
201: * Return the pm at the head of the idle list removing it from the list.
202: * If there is no idle pm then null is returned. The pm has its idle
203: * flag cleared.
204: */
205: private synchronized VersantPersistenceManagerImp removeFromIdleHead() {
206: VersantPersistenceManagerImp pm = idleHead;
207: if (pm == null)
208: return null;
209: idleHead = pm.prev;
210: pm.prev = null;
211: if (idleHead == null) {
212: idleTail = null;
213: } else {
214: idleHead.next = null;
215: }
216: --idleCount;
217: pm.idle = false;
218: if (Debug.DEBUG)
219: checkList(idleTail, idleHead, idleCount);
220: return pm;
221: }
222:
223: /**
224: * Add our base performance metrics to list. This is only used for the
225: * local PM pool.
226: */
227: public void addMetrics(List list) {
228: String cat = "PM";
229: list.add(metricLocalPMIdle = new BaseMetric("PMIdle",
230: "PM Idle", cat, "Number of idle PMs in pool", 0,
231: Metric.CALC_AVERAGE));
232: list.add(metricLocalPMAllocated = new BaseMetric("PMAlloc",
233: "PM Allocated", cat,
234: "Number of PMs given out by the pool", 3,
235: Metric.CALC_DELTA_PER_SECOND));
236: list.add(metricLocalPMReturned = new BaseMetric("PMReturned",
237: "PM Returned", cat,
238: "Number of PMs returned to the pool", 3,
239: Metric.CALC_DELTA_PER_SECOND));
240: }
241:
242: /**
243: * Get values for our metrics. This is only called for the local PM pool.
244: */
245: public void sampleMetrics(int[][] buf, int pos) {
246: buf[metricLocalPMIdle.getIndex()][pos] = idleCount;
247: buf[metricLocalPMAllocated.getIndex()][pos] = allocatedCount;
248: buf[metricLocalPMReturned.getIndex()][pos] = returnedCount;
249: }
250:
251: }
|