[Zope-Checkins] CVS: Zope/lib/python/DBTab - CHANGES.txt:1.1.2.1 ClassFactories.py:1.1.2.1 DBTab.py:1.1.2.1 Exceptions.py:1.1.2.1 __init__.py:1.1.2.1
Chris McDonough
chrism@zope.com
Mon, 21 Jul 2003 12:35:25 -0400
Update of /cvs-repository/Zope/lib/python/DBTab
In directory cvs.zope.org:/tmp/cvs-serv17213/lib/python/DBTab
Added Files:
Tag: Zope-2_7-branch
CHANGES.txt ClassFactories.py DBTab.py Exceptions.py
__init__.py
Log Message:
Merge changes from HEAD since the release of Zope 2.7a1 into the Zope-2_7-branch in preparation for release of Zope 2.7b1.
=== Added File Zope/lib/python/DBTab/CHANGES.txt ===
HEAD
- Merged into Zope 2.7+. Split into two pieces: the ZODBMountPoint
Product and the DBTab package. Neither custom_zodb.py nor dbtab.conf
is now required (all configuration is performed via zope.conf).
Version 1.2.1
- Began unit tests.
- Fixed a race condition on connection close. The symptom was
spurious "Should not load state when connection closed" errors under
high load.
- DemoStorage configurations can now include a base_type option,
taking advantage of DemoStorage's layering feature.
- The mount status page (visible by selecting "Add DBTab Mount Point")
sometimes indicated there were objects mounted that really were not.
Fixed.
Version 1.2
- Fixed activity monitoring for mounted databases.
- Removed import of AdaptableStorage. Argument converters now work
when you specify the full module of a storage class.
- You can now specify a container_class to generate folderish
objects other than standard folders when mounting a new database.
See dbtab.conf.in.
Version 1.1
- Changed DBTab's mounting strategy so that mounted connections stay
bound to a root connection. This change is designed to:
- eliminate issues with volatile attributes in application code
that cross mount boundaries. Now it's safe to use cross-database
volatile attributes.
- eliminate the global registry of open connections, which seemed
to have a rare race condition (ugh!)
- go faster. :-) The mount point traversal penalty is much lower
now, since the mount point can keep a long-lived reference to the
mounted object.
Version 1.0.2
- Updated to work with the latest BDBStorage and AdaptableStorage.
Version 1.0.1
- Deferred startup until after MainConfiguration has been imported.
Needed for ZRS.
- Added AdaptableStorage and BerkeleyStorage to the list of
easily-configured storage types.
- Fixed bug reported by Robert Boulanger:
If the Storage/Databasename is the same like the mountpath it is
not possible to access the database management screens in the
Control Panel. Instead getting Admin screens for Cache and
Activity you will be redirected to the manage workspace of the
folder.
- Arranged for Zope to properly close open database connections on
clean shutdown.
=== Added File Zope/lib/python/DBTab/ClassFactories.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Available ZODB class factories.
$Id: ClassFactories.py,v 1.1.2.1 2003/07/21 16:35:17 chrism Exp $"""
import OFS.Uninstalled
class_factories = {}
def minimalClassFactory(jar, module, name,
_silly=('__doc__',), _globals={},
):
"""Minimal class factory.
If any class is not found, this class factory will propagate
the exception to the application, unlike the other class factories.
"""
m = __import__(module, _globals, _globals, _silly)
return getattr(m, name)
class_factories['minimal'] = minimalClassFactory
def simpleClassFactory(jar, module, name,
_silly=('__doc__',), _globals={},
):
"""Class factory without ZClass support.
"""
try:
m = __import__(module, _globals, _globals, _silly)
return getattr(m, name)
except:
return OFS.Uninstalled.Broken(jar, None, (module, name))
class_factories['simple'] = simpleClassFactory
def zopeClassFactory(jar, module, name,
_silly=('__doc__',), _globals={},
):
"""Class factory with ZClass support.
"""
try:
if module[:1]=='*':
# ZCLass! Yee ha!
return jar.root()['ZGlobals'][module]
else:
m=__import__(module, _globals, _globals, _silly)
return getattr(m, name)
except:
return OFS.Uninstalled.Broken(jar, None, (module, name))
class_factories['zope'] = zopeClassFactory
def autoClassFactory(jar, module, name):
"""Class factory with ZClasses and support for central class definitions.
"""
# If not the root connection, use the class factory from
# the root database, otherwise use the Zope class factory.
root_conn = getattr(jar, '_root_connection', None)
root_db = getattr(root_conn, '_db', None)
if root_db is not None:
return root_db._classFactory(root_conn, module, name)
else:
return zopeClassFactory(jar, module, name)
class_factories['auto'] = autoClassFactory
=== Added File Zope/lib/python/DBTab/DBTab.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""DBTab and DatabaseFactory classes.
$Id: DBTab.py,v 1.1.2.1 2003/07/21 16:35:17 chrism Exp $
"""
import sys
from thread import allocate_lock
from ZODB.ActivityMonitor import ActivityMonitor
import Globals
from Exceptions import DBTabConfigurationError
class DBTab:
"""A Zope database configuration, similar in purpose to /etc/fstab.
"""
def __init__(self, db_factories, mount_paths):
self._started = 0
self.opened = {} # { name -> Database instance }
self.lock = allocate_lock()
self.db_factories = db_factories # { name -> DatabaseFactory }
self.mount_paths = mount_paths # { virtual path -> name }
def startup(self):
"""Opens the databases set to open_at_startup."""
if self._started:
return
self._started = 1
for name, factory in self.db_factories.items():
if factory.getOpenAtStartup():
self.getDatabase(name=name)
def listMountPaths(self):
"""Returns a sequence of (virtual_mount_path, database_name).
"""
return self.mount_paths.items()
def listDatabaseNames(self):
"""Returns a sequence of names.
"""
return self.db_factories.keys()
def hasDatabase(self, name):
"""Returns true if name is the name of a configured database."""
return self.db_factories.has_key(name)
def _mountPathError(self, mount_path):
if mount_path == '/':
raise DBTabConfigurationError(
"No root database configured")
else:
raise DBTabConfigurationError(
"No database configured for mount point at %s"
% mount_path)
def getDatabase(self, mount_path=None, name=None, is_root=0):
"""Returns an opened database. Requires either mount_path or name.
"""
self.startup()
if name is None:
if mount_path is None:
raise ValueError('Either mount_path or name is required')
name = self.mount_paths.get(mount_path)
if name is None:
self._mountPathError(mount_path)
db = self.opened.get(name)
if db is None:
if not self.db_factories.has_key(name):
raise KeyError('%s is not a configured database' % repr(name))
self.lock.acquire()
try:
# Check again, since the database may have been created
# by another thread before the lock was acquired.
db = self.opened.get(name)
if db is None:
db = self._createDatabase(name, is_root)
finally:
self.lock.release()
return db
def getDatabaseFactory(self, mount_path=None, name=None):
if name is None:
if mount_path is None:
raise ValueError('Either mount_path or name is required')
name = self.mount_paths.get(mount_path)
if name is None:
self._mountPathError(mount_path)
return self.db_factories[name]
def _createDatabase(self, name, is_root):
factory = self.db_factories[name]
db = factory.open()
self.opened[name] = db
if not is_root:
Globals.opened.append(db)
# If it is the root database, Zope will add the database to
# Globals.opened. A database should not be listed twice.
return db
=== Added File Zope/lib/python/DBTab/Exceptions.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""DBTab exception classes.
$Id: Exceptions.py,v 1.1.2.1 2003/07/21 16:35:17 chrism Exp $
"""
class DBTabConfigurationError (Exception):
"""Error in dbtab configuration"""
args = ()
class DBTabOverrideError (Exception):
"""DBTab has taken over some piece of functionality"""
args = ()
=== Added File Zope/lib/python/DBTab/__init__.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""DBTab product.
$Id: __init__.py,v 1.1.2.1 2003/07/21 16:35:17 chrism Exp $
"""
# importing ThreadedAsync has the side effect of patching asyncore so
# that loop callbacks get invoked. You need this to
# mount a ZEO client connection if the main database is not a ZEO client.
# Otherwise ZEO never receives the message telling it to start using the
# main async loop.
import ThreadedAsync