Edgewall Software

Ticket #8443: t8443-deactivate-r9234.patch

File t8443-deactivate-r9234.patch, 2.7 KB (added by cboos, 2 years ago)

db pool: try harder to rollback unused db connections

  • trac/db/pool.py

    # HG changeset patch
    # Parent f4eede049f46ec816d9c272161a16005e75b68eb
    db pool: try harder to `rollback` unused db connections, which is especially important for the PostgreSQL backend where failing to do so can leave `idle in transaction` connections behind.
    
    Should fix #8443.
    
    
    diff --git a/trac/db/pool.py b/trac/db/pool.py
    a b class ConnectionPoolBackend(object): 
    132132    def _return_cnx(self, cnx, key, tid): 
    133133        self._available.acquire() 
    134134        try: 
    135             assert (tid, key) in self._active 
    136             cnx, num = self._active[(tid, key)] 
    137             if num == 1: 
    138                 del self._active[(tid, key)] 
    139                 self._available.notify()  
    140                 if cnx.poolable and try_rollback(cnx): 
    141                     self._pool.append(cnx) 
    142                     self._pool_key.append(key) 
    143                     self._pool_time.append(time.time()) 
    144             else: 
    145                 self._active[(tid, key)] = (cnx, num - 1) 
     135            tk = (tid, key) 
     136            if tk in self._active: 
     137                cnx, num = self._active[tk] 
     138                if num == 1: 
     139                    self._deactivate(tk) 
     140                else: 
     141                    self._active[(tid, key)] = (cnx, num - 1) 
     142             # else, might be gone already due to `shutdown(tid)` 
    146143        finally: 
    147144            self._available.release() 
    148145 
     146    def _deactivate(self, tid_key): 
     147        """Remove (tid, key) entry from the `_active` connections 
     148        and from there put the `cnx` in the pool if it is poolable. 
     149         
     150        Note: _available lock must be held. 
     151        """ 
     152        cnx, num = self._active.pop(tid_key) 
     153        if try_rollback(cnx) and cnx.poolable: 
     154            self._pool.append(cnx) 
     155            self._pool_key.append(tid_key[1]) 
     156            self._pool_time.append(time.time()) 
     157        self._available.notify() 
     158 
    149159    def shutdown(self, tid=None): 
    150160        """Close pooled connections not used in a while""" 
    151161        delay = 120 
    class ConnectionPoolBackend(object): 
    154164        when = time.time() - delay 
    155165        self._available.acquire() 
    156166        try: 
     167            # forceful clean-up of active connections for this thread (#8443) 
     168            for tk in [tk for tk in self._active.keys() if tk[0] == tid]: 
     169                self._deactivate(tk) 
     170            # claim unused connections 
    157171            while self._pool_time and self._pool_time[0] <= when: 
    158172                self._pool.pop(0) 
    159173                self._pool_key.pop(0) 
    160174                self._pool_time.pop(0) 
     175                self._available.notify() 
    161176        finally: 
    162177            self._available.release() 
    163178