Browse Source

added to prevent garbage leaks

Darren Ranalli 15 years ago
parent
commit
59dd9ef58a

+ 10 - 0
direct/src/directutil/DirectMySQLdb.py

@@ -0,0 +1,10 @@
+from MySQLdb import *
+
+### DCR: from MySQLdb __init__.py
+def Connect(*args, **kwargs):
+    """Factory function for connections.Connection."""
+    ### DCR: use DirectMySQLdbConnection to prevent memory leaks
+    from direct.directutil.DirectMySQLdbConnection import DirectMySQLdbConnection
+    return DirectMySQLdbConnection(*args, **kwargs)
+
+connect = Connection = Connect

+ 120 - 0
direct/src/directutil/DirectMySQLdbConnection.py

@@ -0,0 +1,120 @@
+import MySQLdb
+from MySQLdb.connections import *
+
+class DirectMySQLdbConnection(Connection):
+    ### DCR: from MySQLdb connections.py Connection.__init__
+    def __init__(self, *args, **kwargs):
+        ### DCR: fixed up relative imports
+        from MySQLdb.constants import CLIENT, FIELD_TYPE
+        from MySQLdb.converters import conversions
+        from weakref import proxy, WeakValueDictionary
+        
+        import types
+
+        kwargs2 = kwargs.copy()
+        
+        if kwargs.has_key('conv'):
+            conv = kwargs['conv']
+        else:
+            conv = conversions
+
+        kwargs2['conv'] = dict([ (k, v) for k, v in conv.items()
+                                 if type(k) is int ])
+    
+        self.cursorclass = kwargs2.pop('cursorclass', self.default_cursor)
+        charset = kwargs2.pop('charset', '')
+
+        if charset:
+            use_unicode = True
+        else:
+            use_unicode = False
+            
+        use_unicode = kwargs2.pop('use_unicode', use_unicode)
+        sql_mode = kwargs2.pop('sql_mode', '')
+
+        client_flag = kwargs.get('client_flag', 0)
+        ### DCR: fixed up module reference
+        client_version = tuple([ int(n) for n in MySQLdb.connections._mysql.get_client_info().split('.')[:2] ])
+        if client_version >= (4, 1):
+            client_flag |= CLIENT.MULTI_STATEMENTS
+        if client_version >= (5, 0):
+            client_flag |= CLIENT.MULTI_RESULTS
+            
+        kwargs2['client_flag'] = client_flag
+
+        ### DCR: skip over the Connection __init__
+        #super(Connection, self).__init__(*args, **kwargs2)
+        MySQLdb._mysql.connection.__init__(self, *args, **kwargs2)
+
+        self.encoders = dict([ (k, v) for k, v in conv.items()
+                               if type(k) is not int ])
+        
+        self._server_version = tuple([ int(n) for n in self.get_server_info().split('.')[:2] ])
+
+        db = proxy(self)
+        ### DCR: these functions create memory leaks with gc.DEBUG_SAVEALL turned on
+        """
+        def _get_string_literal():
+            def string_literal(obj, dummy=None):
+                return db.string_literal(obj)
+            return string_literal
+
+        def _get_unicode_literal():
+            def unicode_literal(u, dummy=None):
+                return db.literal(u.encode(unicode_literal.charset))
+            return unicode_literal
+
+        def _get_string_decoder():
+            def string_decoder(s):
+                return s.decode(string_decoder.charset)
+            return string_decoder
+        """
+
+        ### DCR: use methods rather than inline-defined functions to prevent memory leaks
+        string_literal = self._get_string_literal(db)
+        self.unicode_literal = unicode_literal = self._get_unicode_literal(db)
+        self.string_decoder = string_decoder = self._get_string_decoder()
+        if not charset:
+            charset = self.character_set_name()
+        self.set_character_set(charset)
+
+        if sql_mode:
+            self.set_sql_mode(sql_mode)
+
+        if use_unicode:
+            self.converter[FIELD_TYPE.STRING].insert(-1, (None, string_decoder))
+            self.converter[FIELD_TYPE.VAR_STRING].insert(-1, (None, string_decoder))
+            self.converter[FIELD_TYPE.BLOB].insert(-1, (None, string_decoder))
+
+        self.encoders[types.StringType] = string_literal
+        self.encoders[types.UnicodeType] = unicode_literal
+        self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
+        if self._transactional:
+            # PEP-249 requires autocommit to be initially off
+            self.autocommit(False)
+        self.messages = []
+
+    ### DCR: make inline-defined functions into member methods to avoid garbage
+    def _string_literal(self, db, obj, dummy=None):
+        return db.string_literal(obj)
+    def _get_string_literal(self, db):
+        return Functor(self._string_literal, db)
+
+    def _unicode_literal(self, db, u, dummy=None):
+        return db.literal(u.encode(unicode_literal.charset))
+    def _get_unicode_literal(self, db):
+        return Functor(self._unicode_literal, db)
+
+    def _string_decoder(self, s):
+        return s.decode(string_decoder.charset)
+    def _get_string_decoder(self):
+        # make it into a Functor since MySQLdb.connections.Connection wants to set
+        # attributes on its string_decoder
+        return Functor(self._string_decoder)
+
+    def close(self):
+        Connection.close(self)
+        # break garbage cycles
+        self.unicode_literal = None
+        self.string_decoder = None
+        self.encoders = None