From: Yuval T. <yu...@il...> - 2003-10-26 18:31:49
|
Hello everyone - I've been testing the module extensively in the past few days using the following code: import DB2,sys,random for x in range(5000): conn = DB2.Connect('uvrerch','db2rerch','db2rerch') curs = conn.cursor() id = random.randint(0, 500) curs.execute("SELECT * FROM MYTABLE WHERE ID=%d" % id) Here are some comments: 1. In line 414 - default autocommit mode was changed to "no auto commit" - this change causes the select query to consume plenty of memory. Of course, if I add a conn.commit() after the execute statement (or call conn.autocommit(1) after creating the connection object), the memory is stable. Is this the kind of behaviour that we want? I mean "commit" is meant to be called only after inserts, no ? 2. In the dealloc functions (for both cursor, and connection objects) we call PyMem_DEL after we initialized those objects with PyObject_NEW. According to the python api, objects should be deleted using PyObject_DEL. 3. In DB2_connection_object_cursor (line 666 :-), there's a commented out call to Py_INCREF(self) right after the assignment of cursor->conn = self. If we want to make sure that the connection object stays alive while the cursor is alive, we must call incref ( and decref upon destruction ). 4. We clear the cursor data prior to fetching instead of after fetching - this can cause leaks. After we converted the data to pyobjects, we need to clear the data. So, to fix this (potential) problem I did the following: A. I changed the name of DB2_cursor_object_fetchone to DB2_cursor_object_do_fetch, and created the following new wrapper function: static PyObject * DB2_cursor_object_fetchone(DB2CursorObject *self, PyObject *args) { PyObject *pRet = DB2_cursor_object_do_fetch(self, args); DB2_cursor_object_clear_data(self); return pRet; } B. In fetchall and fetchmany, I changed the calls from fetchone to do_fetch, and added a calls to DB2_cursor_object_clear_data(self); at the end of the loops. That's what I got till now. I have those code changes - and I'm currently testing them. They're looking good. If you want me to commit those changes to the CVS, then drop me a note. -- Yuval Turgeman Content Technology, Aduva LTD. |
From: Yuval T. <yu...@il...> - 2003-10-26 19:04:34
|
Yuval Turgeman wrote: > 4. We clear the cursor data prior to fetching instead of after > fetching - this can cause leaks. After we converted the data to > pyobjects, we need to clear the data. So, to fix this (potential) > problem I did the following: > A. I changed the name of DB2_cursor_object_fetchone to > DB2_cursor_object_do_fetch, and created the following new wrapper > function: > > static PyObject * > DB2_cursor_object_fetchone(DB2CursorObject *self, PyObject *args) > { > PyObject *pRet = DB2_cursor_object_do_fetch(self, args); > DB2_cursor_object_clear_data(self); > return pRet; > } > > B. In fetchall and fetchmany, I changed the calls from fetchone to > do_fetch, and added a calls to DB2_cursor_object_clear_data(self); at > the end of the loops. Disregard this specific issue - I just saw that in DB2.py, we call several times to self._cs.fetchone() and never call to the C functions. Why is that by the way? Anyway, this makes the fetching issue irrelevant (and the suggested fix above doesn't work as well) -- Yuval Turgeman Content Technology, Aduva LTD. |
From: <yu...@ad...> - 2003-10-27 10:10:38
|
Quoting ??? <yo...@li...>: > Hi~ > > Python DB2 module owes a lot to Yuval. > I think he should have write access to PyDB2 CVS in sf.net. Cool - thanks! > You mean the line number 414 in _db2_module.c? > I didn't know about the memory consumption in case of no autocommit. > But "No" auto commit is the default mode the most people expect. > They don't want they INSERT or UPDATE operation committed > immediately. But this affects the SELECT queries as well - I mean if you don't call commit after your SELECT statements, the module keeps consuming memory without bounds. I dont know about other ppl, but as a user of this module it seems silly that i have to commit after SELECT. For now, I just set autocommit(1) after creation and it solves the problem. > I didn't find the clean way to avoid cyclic reference situation. > In case of db.close(), users expect cursors from that ``db'' also close, > I think. How about your idea? I didn't think of that - but for this case, I think I read somewhere that there's an object type that is allowed to have cyclic ref. in it. --- Python C API --- TYPE* PyObject_GC_New( TYPE, PyTypeObject *type) Analogous to PyObject_New() but for container objects with the Py_TPFLAGS_HAVE_GC flag set. --------------------- And GC can handle the situation you mentioned (I think... :-) ) Another solution would be to remove the db.close method... ;-) Btw, regarding the fetching functions - why don't we use the DB2_cursor_object_fetchall and fetchmany functions ? In DB2.py there's a loop in fetchall and fetchmany that calls self.fetchone(). Is there a special reason for not using the C functions ? Thanks, Yuval. ------------------------------------------------- This mail sent through IMP: http://horde.org/imp/ |
From: <po...@or...> - 2003-10-27 13:14:45
|
yu...@ad... writes: > Quoting ??? <yo...@li...>: > > > Python DB2 module owes a lot to Yuval. > > I think he should have write access to PyDB2 CVS in sf.net. > > Cool - thanks! Done. I also gave him release privileges, in case he wanted to help put together a file release with a new version of the package. -- Patrick K. O'Brien Orbtech http://www.orbtech.com/web/pobrien ----------------------------------------------- "Your source for Python programming expertise." ----------------------------------------------- |