npm模块generic-pool源码分析

来源:互联网 发布:wpf 流程图 软件 编辑:程序博客网 时间:2024/04/29 14:42

About generic-pool

github地址:https://github.com/coopernurse/node-pool
description:
Generic resource pool. Can be used to reuse or throttle expensive resources such as database connections.
由此可以看出,该模块是一般的资源池,用来重复使用昂贵的资源,比如数据库连接等。

使用这个模块

Step 1:创建资源池

<code class="hljs sql has-numbering">//Step 1 - <span class="hljs-operator"><span class="hljs-keyword">Create</span> pool <span class="hljs-keyword">using</span> a factory object// <span class="hljs-keyword">Create</span> a MySQL <span class="hljs-keyword">connection</span> pool <span class="hljs-keyword">with</span>,创建Mysql连接// a <span class="hljs-aggregate">max</span> <span class="hljs-keyword">of</span> <span class="hljs-number">10</span> connections, a <span class="hljs-aggregate">min</span> <span class="hljs-keyword">of</span> <span class="hljs-number">2</span>, <span class="hljs-keyword">and</span> a <span class="hljs-number">30</span> <span class="hljs-keyword">second</span> <span class="hljs-aggregate">max</span> idle <span class="hljs-keyword">time</span>var Pool = require(<span class="hljs-string">'generic-pool'</span>).Pool;</span>var mysql = require('mysql'); // v2.10.xvar pool = new Pool({    name     : 'mysql',    <span class="hljs-operator"><span class="hljs-keyword">create</span>   : function(callback) {        //创建连接        var c = mysql.createConnection({                <span class="hljs-keyword">user</span>: <span class="hljs-string">'scott'</span>,                password: <span class="hljs-string">'tiger'</span>,                <span class="hljs-keyword">database</span>:<span class="hljs-string">'mydb'</span>        })        // parameter <span class="hljs-keyword">order</span>: err, resource        callback(<span class="hljs-keyword">null</span>, c);</span>    },    //销毁连接    destroy  : function(client) { client.<span class="hljs-operator"><span class="hljs-keyword">end</span>();</span> },    //最大并发数    max      : 10,    // optional. if you <span class="hljs-operator"><span class="hljs-keyword">set</span> this, make sure <span class="hljs-keyword">to</span> drain() (see step <span class="hljs-number">3</span>),如果设置了并发数,记得在不使用时执行drain()方法,(英文意思为排干,流尽)    //最小并发数    <span class="hljs-aggregate">min</span>      : <span class="hljs-number">2</span>,    // specifies how long a resource can stay idle <span class="hljs-keyword">in</span> pool <span class="hljs-keyword">before</span> being removed,idle:资源超时时间    idleTimeoutMillis : <span class="hljs-number">30000</span>,     // <span class="hljs-keyword">if</span> <span class="hljs-keyword">true</span>, logs via console.log - can also be a function     //是否打印日志,log可以为一个函数,执行函数log    log : <span class="hljs-keyword">true</span> });</span>Step 3 - Drain pool during shutdown (optional)If you are shutting down a long-lived process, you may notice that node fails to exit for 30 seconds or so. This is a side effect of the idleTimeoutMillis behavior <span class="hljs-comment">-- the pool has a setTimeout() call registered that is in the event loop queue, so node won't terminate until all resources have timed out, and the pool stops trying to manage them.</span>This behavior will be more problematic when you <span class="hljs-operator"><span class="hljs-keyword">set</span> factory.<span class="hljs-aggregate">min</span> > <span class="hljs-number">0</span>, <span class="hljs-keyword">as</span> the pool will never become empty, <span class="hljs-keyword">and</span> the setTimeout calls will never <span class="hljs-keyword">end</span>.<span class="hljs-keyword">In</span> these cases, use the pool.drain() function. This sets the pool <span class="hljs-keyword">into</span> a <span class="hljs-string">"draining"</span> state which will gracefully wait until <span class="hljs-keyword">all</span> idle resources have timed out. <span class="hljs-keyword">For</span> example, you can <span class="hljs-keyword">call</span>:// <span class="hljs-keyword">Only</span> <span class="hljs-keyword">call</span> this once <span class="hljs-keyword">in</span> your application -- <span class="hljs-keyword">at</span> the point you want// <span class="hljs-keyword">to</span> shutdown <span class="hljs-keyword">and</span> stop <span class="hljs-keyword">using</span> this pool.pool.drain(function() {    pool.destroyAllNow();</span>});</code>

Step 2:使用资源池(acquire,release)

<code class="hljs javascript has-numbering"><span class="hljs-comment">//Step 2 - Use pool in your code to acquire/release resources</span><span class="hljs-comment">// acquire connection - callback function is called</span><span class="hljs-comment">// once a resource becomes available</span>pool.acquire(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(err, client)</span> {</span>    <span class="hljs-keyword">if</span> (err) {        <span class="hljs-comment">// handle error - this is generally the err from your</span>        <span class="hljs-comment">// factory.create function</span>    }    <span class="hljs-keyword">else</span> {        client.query(<span class="hljs-string">"select * from foo"</span>, [], <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span>            <span class="hljs-comment">// return object back to pool,将资源对象返回给资源池</span>            pool.release(client);        });    }});</code>

Step 3:把资源池的水排干,可选

在一个已经运行了很长的进程中,如果你想把资源池关闭了,你可能会发现,有节点会在30s后才执行关闭动作。这个是由设置的idleTimeoutMillis 引发的副作用:资源池存在一个setTimeout()调用,该调用被添加到事件循环队列中,所以该节点不能被关闭,直到所有的资源都超时,此时,资源池将不会对这些资源进行管理。

这样的行为,当设置最小并发数大于0的时候,这样如果关闭的话,将会导致该资源池永远都不能为空,而存在于事件循环队列的setTimeout()调用将永远得不到执行。

如上面的情况,应该使用pool.drain()函数,这个函数会将资源池里的所有资源都清除干净,在任何你想关闭或者停止使用资源池的地方调用它,并且这个函数只能被执行一次 如:

<code class="hljs javascript has-numbering">pool.drain(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span>    pool.destroyAllNow();});</code>

Pool

<code class="hljs php has-numbering">git <span class="hljs-keyword">clone</span> https:<span class="hljs-comment">//github.com/coopernurse/node-pool.git</span></code>

发现主要的代码就位于lib文件夹中的generic-pool.js,打开代码,发现只有580行,这更激起我阅读该模块的兴趣了。。
源码的第580行导出了Pool,故先看Pool类

<code class="hljs fix has-numbering"><span class="hljs-attribute">exports.Pool </span>=<span class="hljs-string"> Pool</span></code>

Pool构造函数

<code class="hljs coffeescript has-numbering">/** * Generate an Object pool <span class="hljs-reserved">with</span> a specified `<span class="javascript">factory</span>`. * * <span class="hljs-property">@class</span> * <span class="hljs-property">@param</span> {Object} factory *   用来生成和删除实例 * <span class="hljs-property">@param</span> {String} factory.name *   工厂的名字,主要用来写log用 * <span class="hljs-property">@param</span> {Function} factory.create *   生成实例所必须的方法,生成后执行回调,将以回调参数的形式返回给调用资源池者。 * <span class="hljs-property">@param</span> {Function} factory.destroy *  温柔滴关闭正在运行的资源。 * <span class="hljs-property">@param</span> {Function} factory.validate * 在acquire中返回前判断资源是否有效,默认为有效 * <span class="hljs-property">@param</span> {Function} factory.validateAsync * 同步调用 * <span class="hljs-property">@param</span> {Number} factory.max *   最大并发数,默认为<span class="hljs-number">1.</span> * <span class="hljs-property">@param</span> {Number} factory.min *   最小并发数,默认为<span class="hljs-number">0</span> *  一旦资源池被创建或者资源被回收的时候,需要检查资源池的资源是否小于并发数,以下,如果小于并发数以下,应该创建新的资源并将其加入到资源池中。 * <span class="hljs-property">@param</span> {Number} factory.idleTimeoutMillis *   超时时间,单位为毫秒,超时回收 * <span class="hljs-property">@param</span> {Number} factory.reapIntervalMillis *   检查空闲资源的频率 (<span class="hljs-reserved">default</span> <span class="hljs-number">1000</span>), * <span class="hljs-property">@param</span> {Boolean|Function} factory.log *  <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span> <span class="hljs-keyword">or</span> <span class="hljs-reserved">function</span> 如果为<span class="hljs-literal">true</span>,log,info,verbose,信息会被传送到<span class="hljs-built_in">console</span>.log(<span class="hljs-string">""</span>)中,如果为<span class="hljs-reserved">function</span>,则需要两个参数 * log string * log level (<span class="hljs-string">'verbose'</span>, <span class="hljs-string">'info'</span>, <span class="hljs-string">'warn'</span>, <span class="hljs-string">'error'</span>) * <span class="hljs-property">@param</span> {Number} factory.priorityRange *  int  <span class="hljs-number">1</span> to x  ,如果没有资源可使用,将根据工厂的优先级,依次从工厂队列中寻求资源。默认工厂优先级为<span class="hljs-number">1</span> * <span class="hljs-property">@param</span> {RefreshIdle} factory.refreshIdle * 默认为<span class="hljs-literal">true</span> ,默认情况先选择空闲资源被销毁后重新创建,时间即为超时时间。 * <span class="hljs-property">@param</span> {Bool} [factory.returnToHead=<span class="hljs-literal">false</span>] * 默认为<span class="hljs-literal">false</span>,如果为真,那么每次资源 * 返回到available对象数组的头部那么下一次获取的资源就为该数组的的第一个资源,这样就将资源队列变成了资源栈了 **/<span class="hljs-reserved">function</span> Pool (factory) {    <span class="hljs-keyword">if</span> (!(<span class="hljs-keyword">this</span> <span class="hljs-keyword">instanceof</span> Pool)) {        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Pool(factory)    }    <span class="hljs-keyword">if</span> (factory.validate && factory.validateAsync) {        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error(<span class="hljs-string">'Only one of validate or validateAsync may be specified'</span>)    }    <span class="hljs-regexp">//</span> defaults,默认设置    factory.idleTimeoutMillis = factory.idleTimeoutMillis || <span class="hljs-number">30000</span>    factory.returnToHead = factory.returnToHead || <span class="hljs-literal">false</span>    factory.refreshIdle = (<span class="hljs-string">'refreshIdle'</span> <span class="hljs-keyword">in</span> factory) ? factory.refreshIdle : <span class="hljs-literal">true</span>    factory.reapInterval = factory.reapIntervalMillis || <span class="hljs-number">1000</span>    factory.priorityRange = factory.priorityRange || <span class="hljs-number">1</span>    factory.validate = factory.validate || <span class="hljs-reserved">function</span> () { <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> }    factory.max = parseInt(factory.max, <span class="hljs-number">10</span>)    factory.min = parseInt(factory.min, <span class="hljs-number">10</span>)    factory.max = Math.max(isNaN(factory.max) ? <span class="hljs-number">1</span> : factory.max, <span class="hljs-number">1</span>)    factory.min = Math.min(isNaN(factory.min) ? <span class="hljs-number">0</span> : factory.min, factory.max - <span class="hljs-number">1</span>)    <span class="hljs-keyword">this</span>._factory = factory    <span class="hljs-keyword">this</span>._inUseObjects = []<span class="hljs-regexp">/*正在使用的资源*/</span>    <span class="hljs-keyword">this</span>._draining = <span class="hljs-literal">false</span>    <span class="hljs-keyword">this</span>._waitingClients = <span class="hljs-keyword">new</span> PriorityQueue(factory.priorityRange) <span class="hljs-regexp">/*优先级队列*/</span>    <span class="hljs-keyword">this</span>._availableObjects = [] <span class="hljs-regexp">/*可用的资源*/</span>    <span class="hljs-keyword">this</span>._count = <span class="hljs-number">0</span> /*引用计数*/    <span class="hljs-keyword">this</span>._removeIdleTimer = <span class="hljs-literal">null</span>    <span class="hljs-keyword">this</span>._removeIdleScheduled = <span class="hljs-literal">false</span>    <span class="hljs-regexp">//</span> create initial resources (<span class="hljs-keyword">if</span> factory.min > <span class="hljs-number">0</span>)    <span class="hljs-keyword">this</span>._ensureMinimum()<span class="hljs-regexp">/*此处即为保证资源池中存在最少并发数资源*/</span>}</code>

上述代码的最后一句写明,该方法是用来保证资源池中存在最少并发数资源,那么来看下这个方法是如何实现的。这个也是个人学习源码的一点经验。

Pool.prototype._ensureMinimum 保证最小并发数

私有方法
实现代码就几行

<code class="hljs javascript has-numbering">Pool.prototype._ensureMinimum = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_ensureMinimum</span> <span class="hljs-params">()</span> {</span>    <span class="hljs-keyword">var</span> i, diff    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>._draining && (<span class="hljs-keyword">this</span>._count < <span class="hljs-keyword">this</span>._factory.min)) {        diff = <span class="hljs-keyword">this</span>._factory.min - <span class="hljs-keyword">this</span>._count        <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i < diff; i++) {            <span class="hljs-keyword">this</span>._createResource()        }    }}</code>

* ___* 上述代码中,如果没有将资源池排干或者当前资源计数小于最小并发数,那么将根据差值的个数构造相应多的资源。
那么来看下如何创建资源的:

Pool.prototype._createResource 创建资源

私有方法
先不看这个函数的具体实现,首先根据已经得到的知识,可以得到,至少创建一个资源,引用数加1,往_inUseObjects中push一个资源,还有就是打印日志等。

<code class="hljs javascript has-numbering">Pool.prototype._createResource = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_createResource</span> <span class="hljs-params">()</span> {</span>    <span class="hljs-keyword">this</span>._count += <span class="hljs-number">1</span>    <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'createResource() - creating obj - count='</span> + <span class="hljs-keyword">this</span>._count + <span class="hljs-string">' min='</span> + <span class="hljs-keyword">this</span>._factory.min + <span class="hljs-string">' max='</span> + <span class="hljs-keyword">this</span>._factory.max, <span class="hljs-string">'verbose'</span>)    <span class="hljs-keyword">var</span> self = <span class="hljs-keyword">this</span>    <span class="hljs-keyword">this</span>._factory.create(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span>        <span class="hljs-keyword">var</span> err, obj         <span class="hljs-comment">//从优先级队列中弹出一个Clinet客户应用</span>        <span class="hljs-keyword">var</span> clientCb = self._waitingClients.dequeue()        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">arguments</span>.length > <span class="hljs-number">1</span>) {            err = <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>]            obj = <span class="hljs-built_in">arguments</span>[<span class="hljs-number">1</span>]        } <span class="hljs-keyword">else</span> {            err = (<span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) ? <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] : <span class="hljs-literal">null</span>            obj = (<span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) ? <span class="hljs-literal">null</span> : <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>]        }        <span class="hljs-keyword">if</span> (err) {            self._count -= <span class="hljs-number">1</span> <span class="hljs-comment">//错误则-1 </span>            <span class="hljs-keyword">if</span> (self._count < <span class="hljs-number">0</span>) self._count = <span class="hljs-number">0</span>            <span class="hljs-keyword">if</span> (clientCb) {                clientCb(err, obj)            }            process.nextTick(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span>                self._dispense() <span class="hljs-comment">//下次循环事件中_dispense()很关键</span>            })        } <span class="hljs-keyword">else</span> {            self._inUseObjects.push(obj) <span class="hljs-comment">//push一个资源</span>            <span class="hljs-keyword">if</span> (clientCb) {                clientCb(err, obj)            } <span class="hljs-keyword">else</span> {                self.release(obj)<span class="hljs-comment">//错则释放</span>            }        }    })}</code>

Pool.prototype._dispense 工作

私有方法
这个方法用来:获取一个client使其工作,并且清理资源池里的空闲资源

  1. 如果有要连接的client正在等待,则将client后进先出(LIFO),并执行回调函数。
  2. 如果没有client等待,则尝试构造一个client,不超过最大连接数
  3. 如果构造的client超过了最大值,则将这个client加入等待队列中
<code class="hljs javascript has-numbering">Pool.prototype._dispense = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dispense</span> <span class="hljs-params">()</span> {</span>......    <span class="hljs-keyword">var</span> waitingCount = <span class="hljs-keyword">this</span>._waitingClients.size()    <span class="hljs-keyword">if</span> (waitingCount > <span class="hljs-number">0</span>) {        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._factory.validateAsync) {            doWhileAsync(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span>                <span class="hljs-keyword">return</span> self._availableObjects.length > <span class="hljs-number">0</span>            }, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(next)</span> {</span>                objWithTimeout = self._availableObjects[<span class="hljs-number">0</span>]                self._factory.validateAsync(objWithTimeout.obj, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(valid)</span> {</span>                    <span class="hljs-keyword">if</span> (!valid) {                        self.destroy(objWithTimeout.obj)                        next()                    } <span class="hljs-keyword">else</span> {                        self._availableObjects.shift()<span class="hljs-comment">//移出</span>                        self._inUseObjects.push(objWithTimeout.obj)                        clientCb = self._waitingClients.dequeue()                         clientCb(err, objWithTimeout.obj)<span class="hljs-comment">//回调</span>                    }                })            }, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span>                <span class="hljs-keyword">if</span> (self._count < self._factory.max) {                    self._createResource()                }            })            <span class="hljs-keyword">return</span>        }        <span class="hljs-keyword">while</span> (<span class="hljs-keyword">this</span>._availableObjects.length > <span class="hljs-number">0</span>) {            <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'dispense() - reusing obj'</span>, <span class="hljs-string">'verbose'</span>)            objWithTimeout = <span class="hljs-keyword">this</span>._availableObjects[<span class="hljs-number">0</span>]            <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>._factory.validate(objWithTimeout.obj)) {                <span class="hljs-keyword">this</span>.destroy(objWithTimeout.obj)                <span class="hljs-keyword">continue</span>            }            <span class="hljs-keyword">this</span>._availableObjects.shift()            <span class="hljs-keyword">this</span>._inUseObjects.push(objWithTimeout.obj)            clientCb = <span class="hljs-keyword">this</span>._waitingClients.dequeue()            <span class="hljs-keyword">return</span> clientCb(err, objWithTimeout.obj)        }        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._count < <span class="hljs-keyword">this</span>._factory.max) {            <span class="hljs-keyword">this</span>._createResource()        }    }}</code>

上述代码可能不好理解,因为用到一个函数doWhileAsync

<code class="hljs lua has-numbering"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doWhileAsync</span> <span class="hljs-params">(conditionFn, iterateFn, callbackFn)</span></span> {    var <span class="hljs-built_in">next</span> = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span></span> {        <span class="hljs-keyword">if</span> (conditionFn()) {            iterateFn(<span class="hljs-built_in">next</span>)        } <span class="hljs-keyword">else</span> {            callbackFn()        }    }    <span class="hljs-built_in">next</span>()}</code>

所以根据上述的方法,可以得到_dispense中,如果self._availableObjects.length大于0,那么执行第二个函数,该函数从availableObjects中获取一个资源,并将其放入inUseObjects中,然后从client等待队列中选取一个进行回调,并进行递归调用。直到没有可用资源,最后执行第三个函数,就是继续创造资源。

Pool.prototype.acquire从资源池中获取资源

<code class="hljs javascript has-numbering">Pool.prototype.acquire = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">acquire</span> <span class="hljs-params">(callback, priority)</span> {</span>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._draining) {        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'pool is draining and cannot accept work'</span>)    }    <span class="hljs-comment">////回调函数和优先级入队列,在变量clientCb中执行回调</span>    <span class="hljs-keyword">this</span>._waitingClients.enqueue(callback, priority)    <span class="hljs-keyword">this</span>._dispense()<span class="hljs-comment">//回调就在此处执行,使client执行。</span>    <span class="hljs-keyword">return</span> (<span class="hljs-keyword">this</span>._count < <span class="hljs-keyword">this</span>._factory.max)}</code>

Pool.prototype.release将资源返回到资源池中

<code class="hljs javascript has-numbering">Pool.prototype.release = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">release</span> <span class="hljs-params">(obj)</span> {</span>    <span class="hljs-comment">//如果在可用资源对象中已经存在了这样的obj,那么说明资源已经被回收,而这个release被调用了多次。那么不处理,只打印日志</span>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._availableObjects.some(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(objWithTimeout)</span> {</span> <span class="hljs-keyword">return</span> (objWithTimeout.obj === obj) })) {        <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'release called twice for the same resource: '</span> + (<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>().stack), <span class="hljs-string">'error'</span>)        <span class="hljs-keyword">return</span>    }    <span class="hljs-comment">//判断要释放的资源是否在in use对象数组中,如果存在则remove</span>    <span class="hljs-keyword">var</span> index = <span class="hljs-keyword">this</span>._inUseObjects.indexOf(obj)    <span class="hljs-keyword">if</span> (index < <span class="hljs-number">0</span>) {        <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'attempt to release an invalid resource: '</span> + (<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>().stack), <span class="hljs-string">'error'</span>)        <span class="hljs-keyword">return</span>    }    <span class="hljs-comment">// this._log("return to pool")</span>    <span class="hljs-keyword">this</span>._inUseObjects.splice(index, <span class="hljs-number">1</span>)<span class="hljs-comment">//在正在使用的对象数组中删除</span>    <span class="hljs-keyword">var</span> objWithTimeout = { obj: obj, timeout: (<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime() + <span class="hljs-keyword">this</span>._factory.idleTimeoutMillis) }    <span class="hljs-comment">//是否返回到available对象数组的头部</span>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._factory.returnToHead) {    <span class="hljs-comment">//从0开始,不删除项目(0),在头中添加objWithTimeoutd对象</span>        <span class="hljs-keyword">this</span>._availableObjects.splice(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, objWithTimeout)    } <span class="hljs-keyword">else</span> {        <span class="hljs-keyword">this</span>._availableObjects.push(objWithTimeout)<span class="hljs-comment">//尾部添加</span>    }    <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'timeout: '</span> + objWithTimeout.timeout, <span class="hljs-string">'verbose'</span>)    <span class="hljs-keyword">this</span>._dispense() <span class="hljs-comment">//clean up idles items</span>    <span class="hljs-keyword">this</span>._scheduleRemoveIdle()<span class="hljs-comment">//移出多余的idle资源,因为资源返回了,故可能需要,将idle资源回收。</span>}</code>
<code class="hljs cs has-numbering"><span class="hljs-keyword">this</span>._scheduleRemoveIdle()</code>

此方法不是重点,但是通过查看源码可以得知,如果设置是this._factory.reapInterval idle资源回收频率,那么模块将在Timeout时间内执行._removeIdle()函数,该函数的执行就是先获取需要remove的资源,放入到数组toRemove中,然后逐一调用this.destroy(toRemove[i]);注意remove的资源个数应为当前引用个数-最小并发数。

Pool.prototype.drain

<code class="hljs scala has-numbering"><span class="hljs-javadoc">/** * 不允许任何新请求,和已请求分离 * * <span class="hljs-javadoctag">@param</span> {Function} callback *   可选,如果所有的操作做完,所有的clients断开连接则执行回调函数 */</span>Pool.prototype.drain = function drain (callback) { ...    <span class="hljs-keyword">this</span>._draining = <span class="hljs-keyword">true</span>    <span class="hljs-keyword">var</span> check = function () {        <span class="hljs-keyword">if</span> (self._waitingClients.size() > <span class="hljs-number">0</span>) {            <span class="hljs-comment">// wait until all client requests have been satisfied.</span>            setTimeout(check, <span class="hljs-number">100</span>)        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (self._availableObjects.length !== self._count) {            <span class="hljs-comment">// wait until all objects have been released.</span>            setTimeout(check, <span class="hljs-number">100</span>)        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (callback) {            callback()        }    }    check()}</code>

上述代码,就是一直在检查一直在检查,检查好了,执行回调操作

<code class="hljs javascript has-numbering">pool.drain(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span>    pool.destroyAllNow();});</code>

最后来看一下:

Pool.prototype.destroyAllNow 清空所有连接

<code class="hljs javascript has-numbering">Pool.prototype.destroyAllNow = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">destroyAllNow</span> <span class="hljs-params">(callback)</span> {</span>    <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'force destroying all objects'</span>, <span class="hljs-string">'info'</span>)    <span class="hljs-keyword">var</span> willDie = <span class="hljs-keyword">this</span>._availableObjects    <span class="hljs-keyword">this</span>._availableObjects = [] <span class="hljs-comment">//清空</span>    <span class="hljs-keyword">var</span> obj = willDie.shift()    <span class="hljs-keyword">while</span> (obj !== <span class="hljs-literal">null</span> && obj !== <span class="hljs-literal">undefined</span>) {        <span class="hljs-keyword">this</span>.destroy(obj.obj)        obj = willDie.shift()    }    <span class="hljs-keyword">this</span>._removeIdleScheduled = <span class="hljs-literal">false</span>    clearTimeout(<span class="hljs-keyword">this</span>._removeIdleTimer)    <span class="hljs-keyword">if</span> (callback) {        callback()    }}</code>

有了前面代码的详细解释,这里的代码就能一看就懂了。

总结

  1. 内部使用了优先级队列,看了源码,只是几个简单的入队和出队等方法,故没有详细阐述,若有兴趣,可以查看源码学习之
  2. 若有错误,请一定要指出,相互学习。
0 0