[Zope-dev] PANIC(300) ZODB storage error--shouldn't happen

Ross Boylan RossBoylan@stanfordalumni.org
Mon, 17 Jan 2000 14:25:23 -0800


Here's the traceback for Error: release unlocked lock

Traceback (innermost last):
  File V:\src\ZopeRoot\lib\python\ZPublisher\Publish.py, line 214, in
publish_module
  File V:\src\ZopeRoot\lib\python\ZPublisher\Publish.py, line 179, in publish
  File V:\src\ZopeRoot\lib\python\Zope\__init__.py, line 202, in
zpublisher_exception_hook
    (Object: RoleManager)
  File V:\src\ZopeRoot\lib\python\ZPublisher\Publish.py, line 169, in publish
  File V:\src\ZopeRoot\lib\python\ZODB\Transaction.py, line 275, in commit
  File V:\src\ZopeRoot\lib\python\ZODB\Connection.py, line 467, in tpc_finish
  File V:\src\ZopeRoot\lib\python\ZODB\BaseStorage.py, line 202, in tpc_finish
    (Object: V:\src\ZopeRoot/var/Data.fs)

The traceback appears in the browser, while the error message below appears
on the console.  After this, the application is unresponsive.

The only reason I got a new connection was that I didn't know how to get
the old one (or if it was safe to reuse it).  Is there a canonical way to
get Zope's connection?  I tried again using Zope.app()._p_jar.  (I had
thought Zope.app() returned an application wrapper, and gave up when it
didn't).  This produces the connection, but leads to the same error.

Other points:
After this failure, the key of the object I am trying to insert appears in
my OrgUserDirectory, and the value is of the right type (OrgUser).  But the
value has nothing  in it.  The standard Zope users do seem to be created
(see below).

I am able to create the error immediately by executing
get_transaction.commit() in the debugger after my code finishes its normal
execution.

I tried del root['OrgUser'] in hopes that a new one would work better. It
didn't.

Some files are hanging around var/, even after a regular shutdown, which
look a bit odd.  Here's a listing:
 Directory of V:\src\ZopeRoot\var

01/17/00  02:15p               144,466 Data.fs
01/17/00  02:18p                 1,971 Data.fs.index
01/17/00  02:18p                     3 Data.fs.lock
01/17/00  02:16p                     0 Data.fs.tmp
12/04/99  12:30p        <DIR>          gadfly
01/17/00  02:16p                     3 pcgi.pid
01/17/00  02:17p               374,745 Z2.log
01/17/00  02:16p                     3 Z2.pid
              10 File(s)        521,191 bytes

Here's the code I'm running, with some junk stripped out.  The product
creates OrgUserFolder.  Some dtml then sends that object addOrgUser.  This
creates  a regular zope user and then an OrgUserDirectory and an OrgUser,
and puts the latter in the former.
---------------------------------- __init__.py
-----------------------------------------------------------------
import OrgUser

def initialize(context):
    try:
	context.registerClass(
            OrgUser.OrgUserFolder,
            constructors=(OrgUser.manage_addUserFolder, )
            )
[except clause omited]

---------------------------------
OrgUser.py-------------------------------------------------------------------
import Globals
from Globals import HTMLFile, MessageDialog
import Persistence
from AccessControl.User import UserFolder
import Zope	# for app for database

manage_addUserForm = HTMLFile('addUser', globals())


class OrgUser(Persistence.Persistent):
	"""Add additional information on the user"""
	meta_type ='Org User'
	id	= 'Organizational_User'
	title	= 'Organizational User'


	def __init__(self, user, email):
		self.user = user
		self.email = email
		getOrgUserDirectory().addUser(self)

	def getUserName(self):
		return self.user.getUserName()

def addOrgUser(name, password, confirm, email, namespace, REQUEST=None ) :
	"To be called from dtml.  Use _ for namespace"
[code omitted--I couldn't figure out how to call it, and it seems not to be
active]
	
# class method for OrgUserDirectory
_my_Dir = None

def getOrgUserDirectory():
	"Return the root directory for OrgUsers"
	global _my_Dir
	if not _my_Dir :
		import pdb
		pdb.set_trace()
		conn = Zope.app()._p_jar
		root = conn.root()
		_my_Dir = root.get("OrgUser", None)
		if _my_Dir :
			print "Found directory"
		else:
			print "Creating directory"
			root["OrgUser"] = OrgUserDirectory()
			_my_Dir = root["OrgUser"]
	return _my_Dir
	

class OrgUserDirectory(Persistence.PersistentMapping):

	def __init__(self) :
		print "Creating OrgUserDirectory"
		Persistence.PersistentMapping.__init__(self)


	def addUser(self, orgUser):
		"Add indicated user to database"
		name = orgUser.getUserName()
		if self.has_key(name) :
			raise "You can not add an existing user"
		self[name] = orgUser
		

class OrgUserFolder(UserFolder):
    """Base class for UserFolder-like objects"""
    meta_type='Org User Folder'
    title    ='Organizational User Folder'
    manage_userInfo=HTMLFile('editUser',globals())
    def addOrgUser(acl, name, password, confirm, email, REQUEST=None ) :
	"To be called from dtml. "
	print "passing bound addOrgUser"
	roles = []   # to be decided
	domains =  []
	result = acl._addUser(name, password, confirm, roles, domains)
	#I think that if we don't pass request, it returns None if all well
	if result :
		return result  # probably not right since management
	user = acl.getUser(name)
	orgUser = OrgUser(user, email)
	return "I think we're done"
	
def manage_addUserFolder(self,dtself=None,REQUEST=None,**ignored):
    """ """
    f=OrgUserFolder()
    self=self.this()
    try:    self._setObject('acl_users', f)
    except: return MessageDialog(
                   title  ='Item Exists',
                   message='This object already contains a User Folder',
                   action ='%s/manage_main' % REQUEST['URL1'])
    self.__allow_groups__=f
    
    if REQUEST: return self.manage_main(self,REQUEST,update_menu=1)



At 08:58 AM 1/17/00 -0500, Jim Fulton wrote:
>Ross Boylan wrote:
>> 
>> Can anyone suggest how to avoid the following?  Feel free to consider this
>> a bug report, if it is a bug.
>> 
>> 2000-01-16T04:38:30 PANIC(300) ZODB A storage error occurred in the last
>> phase o
>> f a two-phase commit.  This shouldn't happen. The application may be in a
>> hosed
>> state, so we will not allow transactions to commit from here on
>
>Was some sort of traceback displayed to go with this?
>The only time I've seen this is when running out of space.
>
>> This happens after some seemingly successful database activity.  I believe
>> the error is triggered by the commit before returning to the browser.  I
>> suspect I have opened a connection in a way that conflicts with the
>> existing one.
>> 
>> I say, in some code which a form calls,
>>                 conn = Globals.DB.open()
>>                 root = conn.root()
>>                 _my_Dir = root.get("OrgUser", None)
>>                 if _my_Dir :
>>                         print "Found directory"
>>                 else:
>>                         print "Creating directory"
>>                         root["OrgUser"] = OrgUserDirectory()  #subclass
of PersistentMapping
>>                         _my_Dir = root["OrgUser"]
>> I then add an object to _my_dir, using dictionary protocols.
>
>This is incomplete. I see nothing so far to indicate a problem, 
>but I don't see what else you've done.  Why do you open a new connection?
>If you just want to get the root object, you can get the root object for the
>connection of some existing persistent object with:
>
>  anExistingPersistentObject._p_jar.root()
>
>The attribute '_p_jar' is the database connection for a persistent object.
>
>If you open a new connection, you need to make sure you close it.
>
>> The zope session is started with -D.  running Zope 2.1.1 on win32.
>> 
>> It may also be relevant that my function returns a plain string to the
>> browser.
>
>Nah.
>
>Jim
>
>--
>Jim Fulton           mailto:jim@digicool.com   Python Powered!        
>Technical Director   (888) 344-4332            http://www.python.org  
>Digital Creations    http://www.digicool.com   http://www.zope.org    
>
>Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email
>address may not be added to any commercial mail list with out my
>permission.  Violation of my privacy with advertising or SPAM will
>result in a suit for a MINIMUM of $500 damages/incident, $1500 for
>repeats.
>