| 1 | # -*- coding: gb2312 -*-
|
|---|
| 2 | #
|
|---|
| 3 | # author: junzhang.jn@gmail.com
|
|---|
| 4 |
|
|---|
| 5 | import threading,thread
|
|---|
| 6 | import time
|
|---|
| 7 | import sys,traceback
|
|---|
| 8 |
|
|---|
| 9 | class DBPoolWithThread:
|
|---|
| 10 | # @param factory PooledObjectFactory object create factory
|
|---|
| 11 | # @param freetime integer when object's idle time > freetime , check_thread will destory it
|
|---|
| 12 | # @param threadsafety integer like dbapi2.0£¬
|
|---|
| 13 | # 0 = Threads may not share the module.
|
|---|
| 14 | # 1 = Threads may share the module, but not connections.
|
|---|
| 15 | # 2 = Threads may share the module and connections.
|
|---|
| 16 | # 3 = Threads may share the module, connections and cursors.
|
|---|
| 17 | def __init__( self , factory , freetime = 30 , threadsafety = 1 ):
|
|---|
| 18 | self.factory = factory
|
|---|
| 19 | self.threadsafety = threadsafety
|
|---|
| 20 | if threadsafety == 0:
|
|---|
| 21 | raise RuntimeError( 'threadsafety is %d , you cannot use connectionpool for this db driver' % threadsafety )
|
|---|
| 22 | self.idlepool = {} # { threadid: [] , }
|
|---|
| 23 | self.lock = threading.Lock()
|
|---|
| 24 | self.freetime = freetime
|
|---|
| 25 | self.idleTime = {} # { obj: ( threadid , time ) , }
|
|---|
| 26 | self.deleted = False
|
|---|
| 27 | self.exitEvent = threading.Event()
|
|---|
| 28 | self.thread = threading.Thread( target=DBPoolWithThread.check_thread , args = ( self , ) )
|
|---|
| 29 | self.thread.start()
|
|---|
| 30 |
|
|---|
| 31 | def __container_get_obj( self ):
|
|---|
| 32 | try:
|
|---|
| 33 | self.lock.acquire()
|
|---|
| 34 | threadid = thread.get_ident()
|
|---|
| 35 | obj = None
|
|---|
| 36 | try:
|
|---|
| 37 | # 1.1 get object in current thread
|
|---|
| 38 | li = None
|
|---|
| 39 | try:
|
|---|
| 40 | li = self.idlepool[ threadid ]
|
|---|
| 41 | # 1.2 get first object
|
|---|
| 42 | obj = li.pop(0)
|
|---|
| 43 | if len( li ) == 0:
|
|---|
| 44 | del self.idlepool[ threadid ]
|
|---|
| 45 | except KeyError , e:
|
|---|
| 46 | # not find object list in current thread
|
|---|
| 47 | if self.threadsafety == 1:
|
|---|
| 48 | return None
|
|---|
| 49 | except IndexError , e :
|
|---|
| 50 | # this exception should not occured.
|
|---|
| 51 | del self.idlepool[ threadid ]
|
|---|
| 52 |
|
|---|
| 53 | # 1.3 not found object in current thread
|
|---|
| 54 | if obj == None and self.threadsafety > 1:
|
|---|
| 55 | # 2 get object from other thread, threadsafety MUST > 1
|
|---|
| 56 | for key , cons in self.idlepool.items():
|
|---|
| 57 | obj = cons.pop(0)
|
|---|
| 58 | if len( cons ) == 0:
|
|---|
| 59 | del self.idlepool[ key ]
|
|---|
| 60 | break
|
|---|
| 61 | except :
|
|---|
| 62 | pass
|
|---|
| 63 | if obj and self.idleTime.has_key( obj ):
|
|---|
| 64 | del self.idleTime[ obj ] # clear idle timer for return object
|
|---|
| 65 | return obj
|
|---|
| 66 | finally:
|
|---|
| 67 | self.lock.release()
|
|---|
| 68 |
|
|---|
| 69 | def __container_put_obj( self , obj ):
|
|---|
| 70 | try:
|
|---|
| 71 | self.lock.acquire()
|
|---|
| 72 | threadid = thread.get_ident()
|
|---|
| 73 | try:
|
|---|
| 74 | li = self.idlepool[ threadid ]
|
|---|
| 75 | except KeyError , e:
|
|---|
| 76 | li = []
|
|---|
| 77 | self.idlepool[ threadid ] = li
|
|---|
| 78 | li.append( obj )
|
|---|
| 79 | self.idleTime[ obj ] = ( threadid , time.time() )
|
|---|
| 80 | finally:
|
|---|
| 81 | self.lock.release()
|
|---|
| 82 |
|
|---|
| 83 | def borrow_object( self ):
|
|---|
| 84 | i = 0
|
|---|
| 85 | while i < 5:
|
|---|
| 86 | obj = self.__container_get_obj()
|
|---|
| 87 |
|
|---|
| 88 | if not obj :
|
|---|
| 89 | obj = self.factory.create_object()
|
|---|
| 90 | break
|
|---|
| 91 |
|
|---|
| 92 | if self.factory.validate_object( obj ):
|
|---|
| 93 | # object is valid
|
|---|
| 94 | break
|
|---|
| 95 | else:
|
|---|
| 96 | # not valid
|
|---|
| 97 | self.factory.destroy_object( obj )# destroy invalid object
|
|---|
| 98 | obj = None
|
|---|
| 99 | i += 1
|
|---|
| 100 | return obj
|
|---|
| 101 |
|
|---|
| 102 | def return_object( self , obj ):
|
|---|
| 103 | if obj:
|
|---|
| 104 | self.__container_put_obj( obj )
|
|---|
| 105 |
|
|---|
| 106 | def __del__( self ):
|
|---|
| 107 | try:
|
|---|
| 108 | self.lock.acquire()
|
|---|
| 109 | self.exitEvent.set()
|
|---|
| 110 | for key , cons in self.idlepool.items():
|
|---|
| 111 | for obj in cons:
|
|---|
| 112 | self.factory.destroy_object( obj )
|
|---|
| 113 | finally:
|
|---|
| 114 | self.lock.release()
|
|---|
| 115 |
|
|---|
| 116 | def check_thread( this ):
|
|---|
| 117 | while True:
|
|---|
| 118 | this.exitEvent.wait( this.freetime ) # wait interval time
|
|---|
| 119 | if this.exitEvent.isSet():
|
|---|
| 120 | break
|
|---|
| 121 | if this.freetime:
|
|---|
| 122 | this.lock.acquire()
|
|---|
| 123 | try:
|
|---|
| 124 | threadid = thread.get_ident()
|
|---|
| 125 | for k,v in this.idleTime.items():
|
|---|
| 126 | if time.time() - v[1] > this.freetime: # timeout will destroy
|
|---|
| 127 | li = this.idlepool[ v[0] ]
|
|---|
| 128 | li.remove( k )
|
|---|
| 129 | this.factory.destroy_object( k )
|
|---|
| 130 | if len( li ) == 0:
|
|---|
| 131 | del this.idlepool[ v[0] ] # delete list
|
|---|
| 132 | del this.idleTime[ k ]
|
|---|
| 133 | finally:
|
|---|
| 134 | this.lock.release()
|
|---|
| 135 | check_thread = staticmethod( check_thread )
|
|---|
| 136 |
|
|---|
| 137 | # object create factory interface
|
|---|
| 138 | class PooledObjectFactory:
|
|---|
| 139 | def __init__( self ):
|
|---|
| 140 | pass
|
|---|
| 141 |
|
|---|
| 142 | def create_object( self ):
|
|---|
| 143 | raise NotImplementedError()
|
|---|
| 144 |
|
|---|
| 145 | def destroy_object( self , obj ):
|
|---|
| 146 | raise NotImplementedError()
|
|---|
| 147 |
|
|---|
| 148 | def validate_object( self , obj ):
|
|---|
| 149 | raise NotImplementedError()
|
|---|