From 59dd9ef58a0502cbe3d427631f1d9bb8197f8807 Mon Sep 17 00:00:00 2001 From: Darren Ranalli Date: Fri, 14 May 2010 00:25:39 +0000 Subject: [PATCH] added to prevent garbage leaks --- direct/src/directutil/DirectMySQLdb.py | 10 ++ .../src/directutil/DirectMySQLdbConnection.py | 120 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100755 direct/src/directutil/DirectMySQLdb.py create mode 100755 direct/src/directutil/DirectMySQLdbConnection.py diff --git a/direct/src/directutil/DirectMySQLdb.py b/direct/src/directutil/DirectMySQLdb.py new file mode 100755 index 0000000000..1fb4ae5020 --- /dev/null +++ b/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 diff --git a/direct/src/directutil/DirectMySQLdbConnection.py b/direct/src/directutil/DirectMySQLdbConnection.py new file mode 100755 index 0000000000..ee89d47414 --- /dev/null +++ b/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