View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.pool2;
19  
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import org.apache.commons.pool2.impl.DefaultPooledObject;
24  
25  /**
26   * Object factory with configurable latencies for object lifecycle methods.
27   * This factory will also track and enforce maxActive, maxActivePerKey contracts.
28   * If the factory's maxActive / maxActivePerKey are set to match those of the
29   * pool, makeObject will throw IllegalStateException if the number of makes - destroys
30   * (per key) exceeds the configured max.
31   *
32   * @param <K> The type of keys managed by this factory.
33   */
34  public class WaiterFactory<K> implements PooledObjectFactory<Waiter>, KeyedPooledObjectFactory<K, Waiter> {
35  
36      /** Integer value 0. */
37      private static final Integer ZERO = Integer.valueOf(0);
38  
39      /** Integer value 1. */
40      private static final Integer ONE = Integer.valueOf(1);
41  
42      /** Latency of activateObject */
43      private final long activateLatency;
44  
45      /** Latency of destroyObject */
46      private final long destroyLatency;
47  
48      /** Latency of makeObject */
49      private final long makeLatency;
50  
51      /** Latency of passivateObject */
52      private final long passivateLatency;
53  
54      /** Latency of validateObject */
55      private final long validateLatency;
56  
57      /** Latency of doWait for Waiter instances created by this factory */
58      private final long waiterLatency;
59  
60      /** Probability that passivation will invalidate Waiter instances */
61      private final double passivateInvalidationProbability;
62  
63      /** Count of (makes - destroys) since last reset */
64      private long activeCount;
65  
66      /** Count of (makes - destroys) per key since last reset */
67      private final Map<K, Integer> activeCounts = new HashMap<>();
68  
69      /** Maximum of (makes - destroys) - if exceeded IllegalStateException */
70      private final long maxActive;  // GKOP 1.x calls this maxTotal
71  
72      /** Maximum of (makes - destroys) per key */
73      private final long maxActivePerKey;  // GKOP 1.x calls this maxActive
74  
75      public WaiterFactory(final long activateLatency, final long destroyLatency, final long makeLatency, final long passivateLatency, final long validateLatency,
76              final long waiterLatency) {
77          this(activateLatency, destroyLatency, makeLatency, passivateLatency, validateLatency, waiterLatency, Long.MAX_VALUE, Long.MAX_VALUE, 0);
78      }
79  
80      public WaiterFactory(final long activateLatency, final long destroyLatency, final long makeLatency, final long passivateLatency, final long validateLatency,
81              final long waiterLatency, final long maxActive) {
82          this(activateLatency, destroyLatency, makeLatency, passivateLatency, validateLatency, waiterLatency, maxActive, Long.MAX_VALUE, 0);
83      }
84  
85      public WaiterFactory(final long activateLatency, final long destroyLatency, final long makeLatency, final long passivateLatency, final long validateLatency,
86              final long waiterLatency, final long maxActive, final long maxActivePerKey, final double passivateInvalidationProbability) {
87          this.activateLatency = activateLatency;
88          this.destroyLatency = destroyLatency;
89          this.makeLatency = makeLatency;
90          this.passivateLatency = passivateLatency;
91          this.validateLatency = validateLatency;
92          this.waiterLatency = waiterLatency;
93          this.maxActive = maxActive;
94          this.maxActivePerKey = maxActivePerKey;
95          this.passivateInvalidationProbability = passivateInvalidationProbability;
96      }
97  
98      @Override
99      public void activateObject(final K key, final PooledObject<Waiter> obj) {
100         activateObject(obj);
101     }
102 
103     @Override
104     public void activateObject(final PooledObject<Waiter> obj) {
105         doWait(activateLatency);
106         obj.getObject().setActive(true);
107     }
108 
109     @Override
110     public void destroyObject(final K key, final PooledObject<Waiter> obj) {
111         destroyObject(obj);
112         synchronized (this) {
113             activeCounts.computeIfPresent(key, (k, v) -> Integer.valueOf(v.intValue() - 1));
114         }
115     }
116 
117     @Override
118     public void destroyObject(final PooledObject<Waiter> obj) {
119         doWait(destroyLatency);
120         obj.getObject().setValid(false);
121         obj.getObject().setActive(false);
122         // Decrement *after* destroy
123         synchronized (this) {
124             activeCount--;
125         }
126     }
127 
128     protected void doWait(final long latency) {
129         if (latency == 0) {
130             return;
131         }
132         Waiter.sleepQuietly(latency);
133     }
134 
135     /**
136      * @return the maxActive
137      */
138     public synchronized long getMaxActive() {
139         return maxActive;
140     }
141 
142     @Override
143     public PooledObject<Waiter> makeObject() {
144         // Increment and test *before* make
145         synchronized (this) {
146             if (activeCount >= maxActive) {
147                 throw new IllegalStateException("Too many active instances: " +
148                 activeCount + " in circulation with maxActive = " + maxActive);
149             }
150             activeCount++;
151         }
152         doWait(makeLatency);
153         return new DefaultPooledObject<>(new Waiter(false, true, waiterLatency));
154     }
155 
156     @Override
157     public PooledObject<Waiter> makeObject(final K key) {
158         synchronized (this) {
159             activeCounts.merge(key, ONE, (v1, v2) -> {
160                 if (v1.intValue() >= maxActivePerKey) {
161                     throw new IllegalStateException("Too many active instances for key = " + key + ": " + v1.intValue()
162                             + " in circulation with maxActivePerKey = " + maxActivePerKey);
163                 }
164                 return Integer.valueOf(v1.intValue() + 1);
165             });
166         }
167         return makeObject();
168     }
169 
170     @Override
171     public void passivateObject(final K key, final PooledObject<Waiter> obj) {
172         passivateObject(obj);
173     }
174 
175     @Override
176     public void passivateObject(final PooledObject<Waiter> obj) {
177         obj.getObject().setActive(false);
178         doWait(passivateLatency);
179         if (Math.random() < passivateInvalidationProbability) {
180             obj.getObject().setValid(false);
181         }
182     }
183 
184     public synchronized void reset() {
185         activeCount = 0;
186         if (activeCounts.isEmpty()) {
187             return;
188         }
189         activeCounts.keySet().forEach(key -> activeCounts.put(key, ZERO));
190     }
191 
192     @Override
193     public boolean validateObject(final K key, final PooledObject<Waiter> obj) {
194         return validateObject(obj);
195     }
196 
197     @Override
198     public boolean validateObject(final PooledObject<Waiter> obj) {
199         doWait(validateLatency);
200         return obj.getObject().isValid();
201     }
202 
203 }