1717 * limitations under the License.
1818 */
1919
20+ import { newError } from "../error" ;
21+ import { promiseOrTimeout } from "./util" ;
22+
2023class Pool {
2124 /**
2225 * @param create an allocation function that creates a new resource. It's given
@@ -30,12 +33,15 @@ class Pool {
3033 * @param maxIdle the max number of resources that are allowed idle in the pool at
3134 * any time. If this threshold is exceeded, resources will be evicted.
3235 */
33- constructor ( create , destroy = ( ( ) => true ) , validate = ( ( ) => true ) , maxIdle = 50 ) {
36+ constructor ( create , destroy = ( ( ) => true ) , validate = ( ( ) => true ) , config = { } ) {
3437 this . _create = create ;
3538 this . _destroy = destroy ;
3639 this . _validate = validate ;
37- this . _maxIdle = maxIdle ;
40+ this . _maxIdleSize = config . maxIdleSize ;
41+ this . _maxSize = config . maxSize ;
42+ this . _acquisitionTimeout = config . acquisitionTimeout ;
3843 this . _pools = { } ;
44+ this . _acquireRequests = { } ;
3945 this . _activeResourceCounts = { } ;
4046 this . _release = this . _release . bind ( this ) ;
4147 }
@@ -46,26 +52,35 @@ class Pool {
4652 * @return {object } resource that is ready to use.
4753 */
4854 acquire ( key ) {
49- let pool = this . _pools [ key ] ;
50- if ( ! pool ) {
51- pool = [ ] ;
52- this . _pools [ key ] = pool ;
55+ const resource = this . _acquire ( key ) ;
56+
57+ if ( resource ) {
58+ resourceAcquired ( key , this . _activeResourceCounts ) ;
59+
60+ return Promise . resolve ( resource ) ;
5361 }
54- while ( pool . length ) {
55- const resource = pool . pop ( ) ;
5662
57- if ( this . _validate ( resource ) ) {
58- // idle resource is valid and can be acquired
59- resourceAcquired ( key , this . _activeResourceCounts ) ;
60- return resource ;
61- } else {
62- this . _destroy ( resource ) ;
63- }
63+ // We're out of resources and will try to acquire later on when an existing resource is released.
64+ const allRequests = this . _acquireRequests ;
65+ const requests = allRequests [ key ] ;
66+ if ( ! requests ) {
67+ allRequests [ key ] = [ ] ;
6468 }
6569
66- // there exist no idle valid resources, create a new one for acquisition
67- resourceAcquired ( key , this . _activeResourceCounts ) ;
68- return this . _create ( key , this . _release ) ;
70+ let request ;
71+
72+ return promiseOrTimeout (
73+ this . _acquisitionTimeout ,
74+ new Promise (
75+ ( resolve , reject ) => {
76+ request = new PendingRequest ( resolve ) ;
77+
78+ allRequests [ key ] . push ( request ) ;
79+ }
80+ ) , ( ) => {
81+ allRequests [ key ] = allRequests [ key ] . filter ( item => item !== request ) ;
82+ }
83+ ) ;
6984 }
7085
7186 /**
@@ -106,12 +121,37 @@ class Pool {
106121 return this . _activeResourceCounts [ key ] || 0 ;
107122 }
108123
124+ _acquire ( key ) {
125+ let pool = this . _pools [ key ] ;
126+ if ( ! pool ) {
127+ pool = [ ] ;
128+ this . _pools [ key ] = pool ;
129+ }
130+ while ( pool . length ) {
131+ const resource = pool . pop ( ) ;
132+
133+ if ( this . _validate ( resource ) ) {
134+ // idle resource is valid and can be acquired
135+ return resource ;
136+ } else {
137+ this . _destroy ( resource ) ;
138+ }
139+ }
140+
141+ if ( this . _maxSize && this . activeResourceCount ( key ) >= this . _maxSize ) {
142+ return null ;
143+ }
144+
145+ // there exist no idle valid resources, create a new one for acquisition
146+ return this . _create ( key , this . _release ) ;
147+ }
148+
109149 _release ( key , resource ) {
110150 const pool = this . _pools [ key ] ;
111151
112152 if ( pool ) {
113153 // there exist idle connections for the given key
114- if ( pool . length >= this . _maxIdle || ! this . _validate ( resource ) ) {
154+ if ( pool . length >= this . _maxIdleSize || ! this . _validate ( resource ) ) {
115155 this . _destroy ( resource ) ;
116156 } else {
117157 pool . push ( resource ) ;
@@ -121,6 +161,23 @@ class Pool {
121161 this . _destroy ( resource ) ;
122162 }
123163
164+ // check if there are any pending requests
165+ const requests = this . _acquireRequests [ key ] ;
166+ if ( requests ) {
167+ var pending = requests . shift ( ) ;
168+
169+ if ( pending ) {
170+ var resource = this . _acquire ( key ) ;
171+ if ( resource ) {
172+ pending . resolve ( resource ) ;
173+
174+ return ;
175+ }
176+ } else {
177+ delete this . _acquireRequests [ key ] ;
178+ }
179+ }
180+
124181 resourceReleased ( key , this . _activeResourceCounts ) ;
125182 }
126183}
@@ -143,11 +200,24 @@ function resourceAcquired(key, activeResourceCounts) {
143200function resourceReleased ( key , activeResourceCounts ) {
144201 const currentCount = activeResourceCounts [ key ] || 0 ;
145202 const nextCount = currentCount - 1 ;
203+
146204 if ( nextCount > 0 ) {
147205 activeResourceCounts [ key ] = nextCount ;
148206 } else {
149207 delete activeResourceCounts [ key ] ;
150208 }
151209}
152210
211+ class PendingRequest {
212+
213+ constructor ( resolve ) {
214+ this . _resolve = resolve ;
215+ }
216+
217+ resolve ( resource ) {
218+ this . _resolve ( resource ) ;
219+ }
220+
221+ }
222+
153223export default Pool
0 commit comments