[Zope] [Further investigations] Re: A question about __setstate__ in Shared/DC/ZRDB/Connection.py

Marco Bizzarri marco.bizzarri at gmail.com
Fri Sep 19 05:33:44 EDT 2008


On Fri, Sep 19, 2008 at 9:23 AM, Marco Bizzarri
<marco.bizzarri at gmail.com> wrote:
> Hi all.
>
> I'm working on an application which uses Zope (2.8, at the moment) and
> ZPsycopgDA (toghter with a number of other products).
>
> While writing an acceptance test, I encountered a strange problem: the
> test locks up.
>
> A further investigation shown that there were two connections at the
> database; one of them was not committed, the other one was blocked
> waiting for the other to commit.
>
> I therefore used the pdb in order to stop the execution of the test
> inside the connect method of the ZPsycopgDA.DA. Once I had that
> breakpoint, I was able to get the logs of the two transactions on the
> database, and I had the confirmation that indeed there were two
> different transactions.
>
> So, I wondered what could possibily happen, I mean why during a test
> there could be a second connect to the database.
>
> I issued a "bt" to see the stack of calls leading to the connect, and
> what I could see was that the coonect was called inside the
> __setstate__ method of Shared/DC/ZRDB/Connection.py.
>
> I assume therefore that the ZPsycopgDA object has been "ghostified",
> during the transaction. But this "assumption" is not supported by any
> evidence. In particular, it is not supported by my knowledge of the
> internal behaviour of ZODB on objects during a single transaction.
>
> Can anyone provide suggestion on this topic?
>
> Regards
> Marco
> --
> Marco Bizzarri
> http://notenotturne.blogspot.com/
> http://iliveinpisa.blogspot.com/
>

I did further investigation on the topic, and I think I've pinned the
problem. I don't know the solution, but I can reproduce the problem
with a small sample. Here is the sample:


import os
import sys
import unittest

if __name__ == '__main__':
    execfile(os.path.join(sys.path[0], '../framework.py'))

from Testing import ZopeTestCase

from OFS import Image

from Products.ZPsycopgDA.DA import manage_addZPsycopgConnection
from Products.ZSQLMethods import SQL


class DoubleTransactionTest(ZopeTestCase.ZopeTestCase):

    def _add_big_image(self, value, data):
        Image.manage_addFile(self.app, "f%06s" % value, data , "a title")

    def test_showdouble(self):
        manage_addZPsycopgConnection(self.app, "db_connection", "",
"host=localhost user=postgres dbname=template1")
        self.app._setObject('sql', SQL.SQL("sql", "", "db_connection",
"", "select * from pg_tables"))
        self.app.sql()
        data =  "*" * (1 << 20)
        for x in range(1000):
            self._add_big_image(x, data)
            print "Added %s " % x
        self.app.sql()

if __name__ == '__main__':
    unittest.main()


I'm doing three things here:

- creating a db connection
- making a query to the db (this causes a transaction to begin)
- creating a lot of "big" files (expecially, larger than 2 * 2 ^ 16 *)
- making another query to the db;

Once I create a big file I fall into the following branch inside the
OFS.Image._read_data


        if size <= 2*n:
            seek(0)
            if size < n: return read(size), size
            return Pdata(read(size)), size

        # Make sure we have an _p_jar, even if we are a new object, by
        # doing a sub-transaction commit.
        transaction.savepoint(optimistic=True)

This causes, at the end, to call the ZODB.Connection.savepoint which,
just before returning, calls a cacheGC to be called, which, I'm
afraid, causes the db_connection to be "sent" out of the cache itself,
thus leaving it without the _v_ attributes.

Hope this can help in giving suggestions.

Regards
Marco

-- 
Marco Bizzarri
http://notenotturne.blogspot.com/
http://iliveinpisa.blogspot.com/


More information about the Zope mailing list