[Zope-dev] performance tuning of ZODB

Syver Enstad syver at inout.no
Thu Apr 22 11:57:49 EDT 2004


Toby Dickenson <tdickenson at geminidataloggers.com> writes:

> On Thursday 22 April 2004 11:43, Syver Enstad wrote:
> 
> > cache_deactivate_after sounds interesting. Since I am running ZODB in
> > a web server I don't want the data to timeout and disappear from
> > memory since every object I have should be loaded at all times.
> 
> Thats why ZODB ignores that parameter now ;-)

Good :-)

I have a strange case here with ReadConflictErrors. I don't know if
this is covered already but anyway. I am using ZODB 3.2 so this might
be fixed in 3.3 for all I know.

Just replace the twisted stuff with the standard lib unittest module to
have it work on a computer without twisted installed.

-------------- next part --------------
import pdb
import sys
import time
import threading
import os

from ZODB import DB
from ZODB.PersistentList import PersistentList
from ZODB.FileStorage import FileStorage
from ZODB.POSException import ReadConflictError
from Persistence import Persistent

from twisted.trial import unittest


class Computer(Persistent):
    def __init__(self, oidInteger):
        self._oid = oidInteger
        self._articleStatus = None
        self._endUserPrice = None
        self._location = None
        
    def setArticleStatus(self, anObject):
        self._articleStatus = anObject

    def setEndUserPrice(self, anObject):
        self._endUserPrice = anObject

    def setLocation(self, anObject):
        self._location = anObject


class MockArticleDb(Persistent):
    def __init__(self):
        self._articles = PersistentList()

    def addArticle(self, anArticle):
        self._articles.append(anArticle)

    def articles(self):
        return self._articles



class TestReadConflictError(unittest.TestCase):
    def setUp(self):
        try:
            os.unlink('test.fs')
        except OSError, err:
            pass
        storage = FileStorage(
            'test.fs',
            create=True)
        db = DB(storage, cache_size=100000)
        connection = db.open()
        connection.setLocalTransaction()
        connection.root()['articledb'] = MockArticleDb()
        computer = Computer(1)
        computer.setArticleStatus('For sale')
        computer.setEndUserPrice(10050)
        computer.setLocation('H0101')
        connection.root()['articledb'].addArticle(computer)
        connection.getTransaction().commit()
        connection.close()
        db.close()
        storage.close()

        storage = FileStorage(
            'test.fs',
            create=False)
        self._db = DB(storage, cache_size=100000)
        

    def writeStuff(self, connection):
        begin = time.time()
        connection.sync()
        articleDb = connection.root()['articledb']
        eachBegin = time.time()
        computer = Computer(1)
        computer.setArticleStatus('For sale')
        computer.setEndUserPrice(10050)
        computer.setLocation('H0101')
        articleDb.addArticle(computer)
        connection.getTransaction().commit()
        print 'write list length', len(articleDb.articles())

    def doRead(self, oddRead, connection):
        tryCount = 1
        articleDb = connection.root()['articledb']
        try:
            for article in articleDb.articles():
                pass
        except ReadConflictError, err:
            if True: 
                connection.sync()
            else: # this also works
                connection.close()
                connection = self._db.open()
                connection.setLocalTransaction()
            for article in articleDb.articles():
                pass
            tryCount += 1
        print 'read list length', len(articleDb.articles())
        if oddRead:
            # on first, third, fifth read we get a ReadConflictError
            self.assertEquals(
                2,
                tryCount)
        else:
            # but on second, fourth and so forth we don't
            self.assertEquals(
                1,
                tryCount)                
        
    def testProvokeReadConflictError(self):
        conn2 = self._db.open()
        conn2.setLocalTransaction()
        for each in range(1, 11): # 1000 works also but takes a bit of time
            begin = time.time()
            connection = self._db.open()
            connection.setLocalTransaction()
            self.writeStuff(conn2)
            oddRead = each % 2 != 0
            self.doRead(oddRead, connection)
            connection.close()
        
        
if __name__ == '__main__':
    from twisted.scripts.trial import run
    import sys
    sys.argv.append(sys.argv[0])
    run()


More information about the Zope-Dev mailing list