Commit 0e8b79d1 authored by Jim Fulton's avatar Jim Fulton

Exposed database storages using the public "storage" attribute.

(The storage is also available as "_storage" for backward
compatibility, mainly for test code.)
parent 0d27b65c
...@@ -73,10 +73,10 @@ This tests tries to provoke this bug by: ...@@ -73,10 +73,10 @@ This tests tries to provoke this bug by:
... _ = lock.acquire() ... _ = lock.acquire()
... try: ... try:
... time.sleep(.1) ... time.sleep(.1)
... assert (db._storage.lastTransaction() ... assert (db.storage.lastTransaction()
... == db._storage._server.lastTransaction()), ( ... == db.storage._server.lastTransaction()), (
... db._storage.lastTransaction(), ... db.storage.lastTransaction(),
... db._storage._server.lastTransactiion()) ... db.storage._server.lastTransactiion())
... conn = db.open() ... conn = db.open()
... for i in range(1000): ... for i in range(1000):
... if conn.root()[i].value != conn2.root()[i].value: ... if conn.root()[i].value != conn2.root()[i].value:
......
...@@ -93,8 +93,8 @@ class Connection(ExportImport, object): ...@@ -93,8 +93,8 @@ class Connection(ExportImport, object):
# Multi-database support # Multi-database support
self.connections = {self._db.database_name: self} self.connections = {self._db.database_name: self}
self._normal_storage = self._storage = db._storage self._normal_storage = self._storage = db.storage
self.new_oid = db._storage.new_oid self.new_oid = db.storage.new_oid
self._savepoint_storage = None self._savepoint_storage = None
# Do we need to join a txn manager? # Do we need to join a txn manager?
......
...@@ -407,7 +407,7 @@ class DB(object): ...@@ -407,7 +407,7 @@ class DB(object):
self._historical_cache_size_bytes = historical_cache_size_bytes self._historical_cache_size_bytes = historical_cache_size_bytes
# Setup storage # Setup storage
self._storage = storage self.storage = storage
self.references = ZODB.serialize.referencesf self.references = ZODB.serialize.referencesf
try: try:
storage.registerDB(self) storage.registerDB(self)
...@@ -455,7 +455,7 @@ class DB(object): ...@@ -455,7 +455,7 @@ class DB(object):
self.history = storage.history self.history = storage.history
def _setupUndoMethods(self): def _setupUndoMethods(self):
storage = self._storage storage = self.storage
try: try:
self.supportsUndo = storage.supportsUndo self.supportsUndo = storage.supportsUndo
except AttributeError: except AttributeError:
...@@ -471,6 +471,10 @@ class DB(object): ...@@ -471,6 +471,10 @@ class DB(object):
raise NotImplementedError raise NotImplementedError
self.undo = undo self.undo = undo
@property
def _storage(self): # Backward compatibility
return self.storage
# This is called by Connection.close(). # This is called by Connection.close().
def _returnToPool(self, connection): def _returnToPool(self, connection):
"""Return a connection to the pool. """Return a connection to the pool.
...@@ -614,7 +618,7 @@ class DB(object): ...@@ -614,7 +618,7 @@ class DB(object):
is closed, so they stop behaving usefully. Perhaps close() is closed, so they stop behaving usefully. Perhaps close()
should also close all the Connections. should also close all the Connections.
""" """
self._storage.close() self.storage.close()
def getCacheSize(self): def getCacheSize(self):
return self._cache_size return self._cache_size
...@@ -623,16 +627,16 @@ class DB(object): ...@@ -623,16 +627,16 @@ class DB(object):
return self._cache_size_bytes return self._cache_size_bytes
def lastTransaction(self): def lastTransaction(self):
return self._storage.lastTransaction() return self.storage.lastTransaction()
def getName(self): def getName(self):
return self._storage.getName() return self.storage.getName()
def getPoolSize(self): def getPoolSize(self):
return self.pool.size return self.pool.size
def getSize(self): def getSize(self):
return self._storage.getSize() return self.storage.getSize()
def getHistoricalCacheSize(self): def getHistoricalCacheSize(self):
return self._historical_cache_size return self._historical_cache_size
...@@ -668,7 +672,7 @@ class DB(object): ...@@ -668,7 +672,7 @@ class DB(object):
self._connectionMap(lambda c: c.invalidateCache()) self._connectionMap(lambda c: c.invalidateCache())
def objectCount(self): def objectCount(self):
return len(self._storage) return len(self.storage)
def open(self, transaction_manager=None, at=None, before=None): def open(self, transaction_manager=None, at=None, before=None):
"""Return a database Connection for use by application code. """Return a database Connection for use by application code.
...@@ -782,7 +786,7 @@ class DB(object): ...@@ -782,7 +786,7 @@ class DB(object):
t = time() t = time()
t -= days * 86400 t -= days * 86400
try: try:
self._storage.pack(t, self.references) self.storage.pack(t, self.references)
except: except:
logger.error("packing", exc_info=True) logger.error("packing", exc_info=True)
raise raise
...@@ -891,9 +895,9 @@ class ResourceManager(object): ...@@ -891,9 +895,9 @@ class ResourceManager(object):
def __init__(self, db): def __init__(self, db):
self._db = db self._db = db
# Delegate the actual 2PC methods to the storage # Delegate the actual 2PC methods to the storage
self.tpc_vote = self._db._storage.tpc_vote self.tpc_vote = self._db.storage.tpc_vote
self.tpc_finish = self._db._storage.tpc_finish self.tpc_finish = self._db.storage.tpc_finish
self.tpc_abort = self._db._storage.tpc_abort self.tpc_abort = self._db.storage.tpc_abort
# Get a number from a simple thread-safe counter, then # Get a number from a simple thread-safe counter, then
# increment it, for the purpose of sorting ResourceManagers by # increment it, for the purpose of sorting ResourceManagers by
...@@ -908,12 +912,12 @@ class ResourceManager(object): ...@@ -908,12 +912,12 @@ class ResourceManager(object):
resource_counter_lock.release() resource_counter_lock.release()
def sortKey(self): def sortKey(self):
return "%s:%016x" % (self._db._storage.sortKey(), self._count) return "%s:%016x" % (self._db.storage.sortKey(), self._count)
def tpc_begin(self, txn, sub=False): def tpc_begin(self, txn, sub=False):
if sub: if sub:
raise ValueError("doesn't support sub-transactions") raise ValueError("doesn't support sub-transactions")
self._db._storage.tpc_begin(txn) self._db.storage.tpc_begin(txn)
# The object registers itself with the txn manager, so the ob # The object registers itself with the txn manager, so the ob
# argument to the methods below is self. # argument to the methods below is self.
...@@ -932,5 +936,5 @@ class TransactionalUndo(ResourceManager): ...@@ -932,5 +936,5 @@ class TransactionalUndo(ResourceManager):
def commit(self, ob, t): def commit(self, ob, t):
# XXX see XXX in ResourceManager # XXX see XXX in ResourceManager
tid, oids = self._db._storage.undo(self._tid, t) tid, oids = self._db.storage.undo(self._tid, t)
self._db.invalidate(tid, dict.fromkeys(oids, 1)) self._db.invalidate(tid, dict.fromkeys(oids, 1))
...@@ -355,6 +355,15 @@ class IDatabase(IStorageDB): ...@@ -355,6 +355,15 @@ class IDatabase(IStorageDB):
entry. entry.
""") """)
storage = Attribute(
"""The object that provides storage for the database
This attribute is useful primarily for tests. Normal
application code should rarely, if ever, have a need to use
this attribute.
""")
def open(transaction_manager=None, serial=''): def open(transaction_manager=None, serial=''):
"""Return an IConnection object for use by application code. """Return an IConnection object for use by application code.
......
...@@ -26,7 +26,7 @@ class ConfigTestBase(ZODB.tests.util.TestCase): ...@@ -26,7 +26,7 @@ class ConfigTestBase(ZODB.tests.util.TestCase):
def _test(self, s): def _test(self, s):
db = self._opendb(s) db = self._opendb(s)
self.storage = db._storage self.storage = db.storage
# Do something with the database to make sure it works # Do something with the database to make sure it works
cn = db.open() cn = db.open()
rt = cn.root() rt = cn.root()
......
...@@ -96,7 +96,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase): ...@@ -96,7 +96,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase):
self.assert_(obj._p_oid is None) self.assert_(obj._p_oid is None)
self.assert_(obj._p_jar is None) self.assert_(obj._p_jar is None)
self.assertRaises(KeyError, self.datamgr.get, oid) self.assertRaises(KeyError, self.datamgr.get, oid)
self.assertEquals(self.db._storage._stored, [oid]) self.assertEquals(self.db.storage._stored, [oid])
def checkCommit(self): def checkCommit(self):
obj = StubObject() obj = StubObject()
...@@ -111,8 +111,8 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase): ...@@ -111,8 +111,8 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase):
# This next assert_ is covered by an assert in tpc_finish. # This next assert_ is covered by an assert in tpc_finish.
##self.assert_(not self.datamgr._added) ##self.assert_(not self.datamgr._added)
self.assertEquals(self.db._storage._stored, [oid]) self.assertEquals(self.db.storage._stored, [oid])
self.assertEquals(self.db._storage._finished, [oid]) self.assertEquals(self.db.storage._finished, [oid])
def checkModifyOnGetstate(self): def checkModifyOnGetstate(self):
member = StubObject() member = StubObject()
...@@ -123,7 +123,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase): ...@@ -123,7 +123,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase):
self.datamgr.tpc_begin(self.transaction) self.datamgr.tpc_begin(self.transaction)
self.datamgr.commit(self.transaction) self.datamgr.commit(self.transaction)
self.datamgr.tpc_finish(self.transaction) self.datamgr.tpc_finish(self.transaction)
storage = self.db._storage storage = self.db.storage
self.assert_(obj._p_oid in storage._stored, "object was not stored") self.assert_(obj._p_oid in storage._stored, "object was not stored")
self.assert_(subobj._p_oid in storage._stored, self.assert_(subobj._p_oid in storage._stored,
"subobject was not stored") "subobject was not stored")
...@@ -352,7 +352,7 @@ class UserMethodTests(unittest.TestCase): ...@@ -352,7 +352,7 @@ class UserMethodTests(unittest.TestCase):
An expedient way to create a read-only storage: An expedient way to create a read-only storage:
>>> db._storage.isReadOnly = lambda: True >>> db.storage.isReadOnly = lambda: True
>>> cn = db.open() >>> cn = db.open()
>>> cn.isReadOnly() >>> cn.isReadOnly()
True True
...@@ -753,7 +753,7 @@ class TestConnectionInterface(unittest.TestCase): ...@@ -753,7 +753,7 @@ class TestConnectionInterface(unittest.TestCase):
class StubDatabase: class StubDatabase:
def __init__(self): def __init__(self):
self._storage = StubStorage() self.storage = StubStorage()
classFactory = None classFactory = None
database_name = 'stubdatabase' database_name = 'stubdatabase'
......
...@@ -135,7 +135,7 @@ True ...@@ -135,7 +135,7 @@ True
We can confirm that we have a non-current revision by asking the We can confirm that we have a non-current revision by asking the
storage. storage.
>>> db._storage.isCurrent(r2["a"]._p_oid, r2["a"]._p_serial) >>> db.storage.isCurrent(r2["a"]._p_oid, r2["a"]._p_serial)
False False
It's possible to modify "a", but we get a conflict error when we It's possible to modify "a", but we get a conflict error when we
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment