npm模块generic-pool源码分析

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.x

var 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. 若有错误,请一定要指出,相互学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值