3
Z_ð]“=  ã               @   s*  d dl mZ d dlmZ d dlmZ d dlZd dlZd dlm	Z	 d dl
mZ d dl
mZ d dlmZ d d	lmZ eƒ ZG d
d„ deƒZdd„ ZG dd„ de	ƒZG dd„ deƒZG dd„ deƒZeZG dd„ deƒZx*ejD ] Zefdd„Zeeeeeƒƒ qÚW e`[[G dd„ deƒZG dd„ deƒZ dS )é    )Úprint_function)Údeque)ÚcontextmanagerN)ÚPool)Útimeout)Úhubs)ÚTimer)ÚGreenThreadc               @   s   e Zd ZdS )ÚConnectTimeoutN)Ú__name__Ú
__module__Ú__qualname__© r   r   ú4/tmp/pip-build-yz_zf6az/eventlet/eventlet/db_pool.pyr
      s   r
   c             C   s   | j ƒ  d S )N)Úrollback)Úconnr   r   r   Úcleanup_rollback   s    r   c                   s�   e Zd Zdddddef‡ fdd„	Zdd	„ Zd
d„ Zdd„ Zdd„ Zddd„Z	‡ fdd„Z
ef‡ fdd„	Zeefdd„ƒZdd„ Zdd„ Z‡  ZS )ÚBaseConnectionPoolr   é   é
   é   é   c       
         sR   |st ‚|| _|| _|	| _|| _|| _|| _d| _|| _t	t
| ƒj||dd� dS )a  
        Constructs a pool with at least *min_size* connections and at most
        *max_size* connections.  Uses *db_module* to construct new connections.

        The *max_idle* parameter determines how long pooled connections can
        remain idle, in seconds.  After *max_idle* seconds have elapsed
        without the connection being used, the pool closes the connection.

        *max_age* is how long any particular connection is allowed to live.
        Connections that have been open for longer than *max_age* seconds are
        closed, regardless of idle time.  If *max_age* is 0, all connections are
        closed on return to the pool, reducing it to a concurrency limiter.

        *connect_timeout* is the duration in seconds that the pool will wait
        before timing out on connect() to the database.  If triggered, the
        timeout will raise a ConnectTimeout from get().

        The remainder of the arguments are used as parameters to the
        *db_module*'s connection constructor.
        NT)Úmin_sizeÚmax_sizeZorder_as_stack)ÚAssertionErrorÚ
_db_moduleÚ_argsÚ_kwargsÚmax_idleÚmax_ageÚconnect_timeoutÚ_expiration_timerÚcleanupÚsuperr   Ú__init__)
ÚselfÚ	db_moduler   r   r   r   r    r"   ÚargsÚkwargs)Ú	__class__r   r   r$      s    zBaseConnectionPool.__init__c             C   sæ   | j dks| jdkrdS | jdk	r6t| jddƒ r6dS yZtjƒ }| j|ƒ | jd d | | j }tdd„ | jD ƒƒ}|| | j  }t||ƒ}W n tt	fk
r®   d| _dS X |dkrât
|ttjƒ jƒj| jg i ƒ| _| jjƒ  dS )	a  Sets up a timer that will call _expire_old_connections when the
        oldest connection currently in the free pool is ready to expire.  This
        is the earliest possible time that a connection could expire, thus, the
        timer will be running as infrequently as possible without missing a
        possible expiration.

        If this function is called when a timer is already scheduled, it does
        nothing.

        If max_age or max_idle is 0, _schedule_expiration likewise does nothing.
        r   NÚcalledFé   c             S   s   g | ]}|d  ‘qS )r+   r   )Ú.0Útr   r   r   ú
<listcomp>^   s    z;BaseConnectionPool._schedule_expiration.<locals>.<listcomp>éÿÿÿÿ)r   r   r!   ÚgetattrÚtimeÚ_expire_old_connectionsÚ
free_itemsÚminÚ
IndexErrorÚ
ValueErrorr   r	   r   Zget_hubZgreenletÚswitchÚ_schedule_expirationÚschedule)r%   ÚnowZ
idle_delayZoldestZ	age_delayZ
next_delayr   r   r   r8   B   s&    

z'BaseConnectionPool._schedule_expirationc                s„   t ˆjƒ}‡ ‡fdd„ˆjD ƒ}‡ ‡fdd„ˆjD ƒ}ˆjjƒ  ˆjj|ƒ ˆ j|t ˆjƒ 8  _x|D ]}ˆj|dd� qjW dS )a  Iterates through the open connections contained in the pool, closing
        ones that have remained idle for longer than max_idle seconds, or have
        been in existence for longer than max_age seconds.

        *now* is the current time, as returned by time.time().
        c                s$   g | ]\}}}ˆj ˆ ||ƒr|‘qS r   )Ú_is_expired)r,   Ú	last_usedÚ
created_atr   )r:   r%   r   r   r.   v   s   z>BaseConnectionPool._expire_old_connections.<locals>.<listcomp>c                s*   g | ]"\}}}ˆj ˆ ||ƒs|||f‘qS r   )r;   )r,   r<   r=   r   )r:   r%   r   r   r.   {   s   T)ÚquietN)Úlenr3   ÚclearÚextendÚcurrent_sizeÚ_safe_close)r%   r:   Zoriginal_countZexpiredZnew_freer   r   )r:   r%   r   r2   m   s    




z*BaseConnectionPool._expire_old_connectionsc             C   s8   | j dks0| jdks0|| | j ks0|| | jkr4dS dS )z@Returns true and closes the connection if it's expired.
        r   TF)r   r   )r%   r:   r<   r=   r   r   r   r;   ˆ   s
    zBaseConnectionPool._is_expiredc             C   s:   d}y|r|j }|jƒ  nd}W n tk
r4   Y nX |S )a$  If the connection was wrapped by a subclass of
        BaseConnectionWrapper and is still functional (as determined
        by the __nonzero__, or __bool__ in python3, method), returns
        the unwrapped connection.  If anything goes wrong with this
        process, returns None.
        N)Ú_baseÚ_destroyÚAttributeError)r%   r   Úbaser   r   r   Ú_unwrap_connection‘   s    
z%BaseConnectionPool._unwrap_connectionFc             C   sP   y|j ƒ  W n> tk
r    Y n, tk
rJ   |sFtdtjƒ d  ƒ Y nX dS )zVCloses the (already unwrapped) connection, squelching any
        exceptions.
        zConnection.close raised: %sr+   N)ÚcloserF   Ú	ExceptionÚprintÚsysÚexc_info)r%   r   r>   r   r   r   rC   £   s    zBaseConnectionPool._safe_closec                sz   t t| ƒjƒ }|d krHy| jƒ }W n$ tk
rF   |  jd8  _‚ Y nX t|tƒr^|\}}}ntjƒ }t	|| ƒ}||_
|S )Nr+   )r#   r   ÚgetÚcreaterJ   rB   Ú
isinstanceÚtupler1   ÚPooledConnectionWrapperÚ_db_pool_created_at)r%   r   Z
_last_usedr=   Úwrapped)r)   r   r   rN   ¯   s    

zBaseConnectionPool.getc                s  t |ddƒ}tjƒ }| j|ƒ}| j|||ƒr@| j|dd� d }nn|d k	r®|tkrV| j}y|rd||ƒ W nF tk
rœ } ztd||f ƒ d }W Y d d }~X n   d }‚ Y nX |d k	rÎt	t
| ƒj|||fƒ n,| jƒ dkrìt	t
| ƒjd ƒ n|  jd8  _| jƒ  d S )NrS   r   F)r>   zWARNING: cleanup %s raised: %sr+   )r0   r1   rH   r;   rC   Ú_MISSINGr"   rJ   rK   r#   r   ÚputZwaitingrB   r8   )r%   r   r"   r=   r:   Úe)r)   r   r   rV   Í   s0    
zBaseConnectionPool.putc             c   s(   | j ƒ }z
|V  W d | j||d� X d S )N)r"   )rN   rV   )r%   r"   r   r   r   r   Úitemó   s    
zBaseConnectionPool.itemc             C   sd   | j r| j jƒ  | jtƒ  }| _x>|D ]6}t|tƒr<|d n|}| j|dd� |  jd8  _q&W dS )zuClose all connections that this pool still holds a reference to,
        and removes all references to them.
        é   T)r>   r+   N)r!   Úcancelr3   r   rP   rQ   rC   rB   )r%   r3   rX   r   r   r   r   r@   û   s    

zBaseConnectionPool.clearc             C   s   | j ƒ  d S )N)r@   )r%   r   r   r   Ú__del__  s    zBaseConnectionPool.__del__)F)r   r   r   r   r$   r8   r2   r;   rH   rC   rN   rU   rV   r   rX   r@   r[   Ú__classcell__r   r   )r)   r   r      s   #+	
&r   c               @   s$   e Zd ZdZdd„ Zedd„ ƒZdS )ÚTpooledConnectionPoolzZA pool which gives out :class:`~eventlet.tpool.Proxy`-based database
    connections.
    c             C   s*   t j ƒ }||| j| j| jf| jž| jŽfS )N)r1   Úconnectr   r    r   r   )r%   r:   r   r   r   rO     s    zTpooledConnectionPool.createc          
   O   sL   t j|tƒ ƒ}z.ddlm} |j|jf|ž|Ž}|j|dd�S |jƒ  X d S )Nr   )ÚtpoolÚcursor)Zautowrap_names)r`   )	r   ÚTimeoutr
   Úeventletr_   Úexecuter^   ZProxyrZ   )Úclsr&   r    r'   Úkwr-   r_   r   r   r   r   r^     s    zTpooledConnectionPool.connectN)r   r   r   Ú__doc__rO   Úclassmethodr^   r   r   r   r   r]     s   r]   c               @   s$   e Zd ZdZdd„ Zedd„ ƒZdS )ÚRawConnectionPoolz7A pool which gives out plain database connections.
    c             C   s*   t j ƒ }||| j| j| jf| jž| jŽfS )N)r1   r^   r   r    r   r   )r%   r:   r   r   r   rO   %  s    zRawConnectionPool.createc          
   O   s*   t j|tƒ ƒ}z|j||ŽS |jƒ  X d S )N)r   ra   r
   r^   rZ   )rd   r&   r    r'   re   r-   r   r   r   r^   *  s    zRawConnectionPool.connectN)r   r   r   rf   rO   rg   r^   r   r   r   r   rh   !  s   rh   c                @   s0   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd*Zd)S )+ÚGenericConnectionWrapperc             C   s
   || _ d S )N)rD   )r%   Úbaseconnr   r   r   r$   8  s    z!GenericConnectionWrapper.__init__c             C   s
   | j jƒ S )N)rD   Ú	__enter__)r%   r   r   r   rk   A  s    z"GenericConnectionWrapper.__enter__c             C   s   | j j|||ƒS )N)rD   Ú__exit__)r%   ÚexcÚvalueÚtbr   r   r   rl   D  s    z!GenericConnectionWrapper.__exit__c             C   s
   | j jƒ S )N)rD   Ú__repr__)r%   r   r   r   rp   G  s    z!GenericConnectionWrapper.__repr__Úaffected_rowsÚ
autocommitÚbeginÚchange_userÚcharacter_set_namerI   Úcommitr`   Údump_debug_infoÚerrnoÚerrorÚerrorhandlerÚ	insert_idÚliteralÚpingÚqueryr   Ú	select_dbÚserver_capabilitiesÚset_character_setÚset_isolation_levelÚset_server_optionÚset_sql_modeÚshow_warningsÚshutdownÚsqlstateÚstatÚstore_resultÚstring_literalÚ	thread_idÚ
use_resultÚwarning_countN) rq   rr   rs   rt   ru   rI   rv   r`   rw   rx   ry   rz   r{   r|   r}   r~   r   r   r€   r�   r‚   rƒ   r„   r…   r†   r‡   rˆ   r‰   rŠ   r‹   rŒ   r�   )r   r   r   r$   rk   rl   rp   Ú_proxy_funcsr   r   r   r   ri   7  sH   	                               ri   c                s&   ‡ fdd„}ˆ |_ ˆ |_dˆ  |_|S )Nc                s   t | jˆ ƒ||ŽS )N)r0   rD   )r%   r'   r(   )Ú
_proxy_funr   r   Ú_proxy_methodo  s    z_wrapper.<locals>._proxy_methodzGenericConnectionWrapper.)Ú	func_namer   r   )r�   r�   r   )r�   r   Ú_wrappern  s
    
r’   c                   sD   e Zd ZdZ‡ fdd„Zdd„ ZeZdd„ Zdd	„ Zd
d„ Z	‡  Z
S )rR   zçA connection wrapper where:
    - the close method returns the connection to the pool instead of closing it directly
    - ``bool(conn)`` returns a reasonable value
    - returns itself to the pool if it gets garbage collected
    c                s   t t| ƒj|ƒ || _d S )N)r#   rR   r$   Ú_pool)r%   rj   Úpool)r)   r   r   r$   ‚  s    z PooledConnectionWrapper.__init__c             C   s   t | dƒot| jƒS )NrD   )ÚhasattrÚboolrD   )r%   r   r   r   Ú__nonzero__†  s    z#PooledConnectionWrapper.__nonzero__c             C   s(   d | _ y| `W n tk
r"   Y nX d S )N)r“   rD   rF   )r%   r   r   r   rE   ‹  s
    z PooledConnectionWrapper._destroyc             C   s"   | r| j r| j j| ƒ | jƒ  dS )z–Return the connection to the pool, and remove the
        reference to it so that you can't use it again through this
        wrapper object.
        N)r“   rV   rE   )r%   r   r   r   rI   ’  s    
zPooledConnectionWrapper.closec             C   s   d S )Nr   )r%   r   r   r   r[   ›  s    zPooledConnectionWrapper.__del__)r   r   r   rf   r$   r—   Ú__bool__rE   rI   r[   r\   r   r   )r)   r   rR   {  s   	rR   c               @   s*   e Zd ZdZd	dd„Zdd„ Zdd„ ZdS )
ÚDatabaseConnectorzr
    This is an object which will maintain a collection of database
    connection pools on a per-host basis.
    Nc             O   s@   |st ‚|| _| jdkrt| _|| _|| _|| _|| _i | _dS )z±constructor
        *module*
            Database module to use.
        *credentials*
            Mapping of hostname to connect arguments (e.g. username and password)
        N)r   Ú_conn_pool_classÚConnectionPoolÚ_moduler   r   Ú_credentialsÚ
_databases)r%   ÚmoduleÚcredentialsZ	conn_poolr'   r(   r   r   r   r$   §  s    
zDatabaseConnector.__init__c             C   s&   || j kr| j | S | j jdd ƒS d S )NÚdefault)r�   rN   )r%   Úhostr   r   r   Úcredentials_forº  s    

z!DatabaseConnector.credentials_forc             C   sf   ||f}|| j kr\| jjƒ }||d< ||d< |j| j|ƒƒ | j| jf| jž|Ž}|| j |< | j | S )z@Returns a ConnectionPool to the target host and schema.
        Údbr¢   )rž   r   ÚcopyÚupdater£   rš   rœ   r   )r%   r¢   ZdbnameÚkeyZ
new_kwargsZdbpoolr   r   r   rN   À  s    


zDatabaseConnector.get)N)r   r   r   rf   r$   r£   rN   r   r   r   r   r™   ¡  s   
r™   )!Ú
__future__r   Úcollectionsr   Ú
contextlibr   rL   r1   Zeventlet.poolsr   rb   r   r   Zeventlet.hubs.timerr   Zeventlet.greenthreadr	   ÚobjectrU   rJ   r
   r   r   r]   rh   r›   ri   rŽ   r�   r’   ÚsetattrrR   r™   r   r   r   r   Ú<module>   s4    s5&