[Zodb-checkins] SVN: ZODB/trunk/src/ZODB/ Added an option to disallow cross-database references.
Jim Fulton
jim at zope.com
Thu Apr 30 07:43:45 EDT 2009
Log message for revision 99602:
Added an option to disallow cross-database references.
Include extra data in InvalidObjectReference exceptions to make
debugging easier.
Changed:
U ZODB/trunk/src/ZODB/component.xml
U ZODB/trunk/src/ZODB/cross-database-references.txt
U ZODB/trunk/src/ZODB/serialize.py
-=-
Modified: ZODB/trunk/src/ZODB/component.xml
===================================================================
--- ZODB/trunk/src/ZODB/component.xml 2009-04-30 11:43:43 UTC (rev 99601)
+++ ZODB/trunk/src/ZODB/component.xml 2009-04-30 11:43:45 UTC (rev 99602)
@@ -113,7 +113,7 @@
Maximum size of the ZEO blob cache, in bytes. If not set, then
the cache size isn't checked and the blob directory will
grow without bound.
-
+
This option is ignored if shared_blob_dir is true.
</description>
</key>
@@ -125,7 +125,6 @@
size. This option is ignored if shared_blob_dir is true.
</description>
</key>
-
<key name="storage" default="1">
<description>
The name of the storage that the client wants to use. If the
@@ -272,12 +271,13 @@
</description>
</key>
<key name="historical-timeout" datatype="time-interval"
- default="5m"/>
+ default="5m">
<description>
The minimum interval that an unused historical connection should be
kept.
</description>
- <key name="database-name" default="unnamed"/>
+ </key>
+ <key name="database-name">
<description>
When multidatabases are in use, this is the name given to this
database in the collection. The name must be unique across all
@@ -288,6 +288,14 @@
their own config files, using the "databases" parameter of a DB
constructor.
</description>
+ </key>
+ <key name="allow-implicit-cross-references" datatype="boolean">
+ <description>
+ If set to false, implicit cross references (the only kind
+ currently possible) are disallowed.
+ </description>
+ </key>
+
</sectiontype>
<sectiontype name="blobstorage" datatype=".BlobStorage"
@@ -301,7 +309,5 @@
</sectiontype>
-
-
</component>
Modified: ZODB/trunk/src/ZODB/cross-database-references.txt
===================================================================
--- ZODB/trunk/src/ZODB/cross-database-references.txt 2009-04-30 11:43:43 UTC (rev 99601)
+++ ZODB/trunk/src/ZODB/cross-database-references.txt 2009-04-30 11:43:45 UTC (rev 99602)
@@ -58,11 +58,13 @@
>>> tm.commit()
>>> p2.p3 = p3
- >>> tm.commit() # doctest: +NORMALIZE_WHITESPACE
+ >>> tm.commit() # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
Traceback (most recent call last):
...
InvalidObjectReference:
- Attempt to store an object from a foreign database connection
+ ('Attempt to store an object from a foreign database connection',
+ <Connection at ...>,
+ <ZODB.tests.testcrossdatabasereferences.MyClass...>)
>>> tm.abort()
@@ -84,11 +86,14 @@
an error is generated if we commit changes when new objects are
reachable from multiple databases:
- >>> tm.commit() # doctest: +NORMALIZE_WHITESPACE
+ >>> tm.commit() # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
Traceback (most recent call last):
...
- InvalidObjectReference: A new object is reachable from multiple
- databases. Won't try to guess which one was correct!
+ InvalidObjectReference:
+ ("A new object is reachable from multiple databases. Won't try to
+ guess which one was correct!",
+ <Connection at ...>,
+ <ZODB.tests.testcrossdatabasereferences.MyClass...>)
>>> tm.abort()
@@ -109,11 +114,14 @@
>>> p1.p5 = p5
>>> s = tm.savepoint()
>>> p2.p5 = p5
- >>> tm.commit() # doctest: +NORMALIZE_WHITESPACE
+ >>> tm.commit() # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
Traceback (most recent call last):
...
- InvalidObjectReference: A new object is reachable from multiple
- databases. Won't try to guess which one was correct!
+ InvalidObjectReference:
+ ("A new object is reachable from multiple databases. Won't try to guess
+ which one was correct!",
+ <Connection at ...>,
+ <ZODB.tests.testcrossdatabasereferences.MyClass...>)
>>> tm.abort()
@@ -133,6 +141,37 @@
This the most explicit and thus the best way, when practical, to avoid
the ambiguity.
+Dissallowing implicit cross-database references
+-----------------------------------------------
+
+The database contructor accepts a xrefs keyword argument that defaults
+to True. If False is passed, the implicit cross database references
+are disallowed. (Note that currently, implicit cross references are
+the only kind of cross references allowed.)
+
+ >>> databases = {}
+ >>> db1 = ZODB.tests.util.DB(databases=databases, database_name='1')
+ >>> db2 = ZODB.tests.util.DB(databases=databases, database_name='2',
+ ... xrefs=False)
+
+In this example, we allow cross-references from db1 to db2, but not
+the other way around.
+
+ >>> c1 = db1.open()
+ >>> c2 = c1.get_connection('2')
+ >>> c1.root.x = c2.root()
+ >>> transaction.commit()
+ >>> c2.root.x = c1.root()
+ >>> transaction.commit() # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ InvalidObjectReference:
+ ("Database '2' doesn't allow implicit cross-database references",
+ <Connection at ...>,
+ {'x': {}})
+
+ >>> transaction.abort()
+
NOTE
----
Modified: ZODB/trunk/src/ZODB/serialize.py
===================================================================
--- ZODB/trunk/src/ZODB/serialize.py 2009-04-30 11:43:43 UTC (rev 99601)
+++ ZODB/trunk/src/ZODB/serialize.py 2009-04-30 11:43:45 UTC (rev 99602)
@@ -186,6 +186,7 @@
>>> from ZODB.tests.util import P
>>> class DummyJar:
+ ... xrefs = True
... def new_oid(self):
... return 42
... def db(self):
@@ -229,11 +230,13 @@
If the jar doesn't match that of the writer, an error is raised:
>>> bob._p_jar = DummyJar()
- >>> writer.persistent_id(bob) # doctest: +NORMALIZE_WHITESPACE
+ >>> writer.persistent_id(bob)
+ ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
Traceback (most recent call last):
...
- InvalidObjectReference: Attempt to store an object from a
- foreign database connection
+ InvalidObjectReference:
+ ('Attempt to store an object from a foreign database connection',
+ <ZODB.serialize.DummyJar instance at ...>, P(bob))
Constructor arguments used by __new__(), as returned by
__getnewargs__(), can affect memory allocation, but may also
@@ -322,8 +325,13 @@
oid = obj._p_oid = self._jar.new_oid()
obj._p_jar = self._jar
self._stack.append(obj)
-
+
elif obj._p_jar is not self._jar:
+ if not self._jar.db().xrefs:
+ raise InvalidObjectReference(
+ "Database %r doesn't allow implicit cross-database "
+ "references" % self._jar.db().database_name,
+ self._jar, obj)
try:
otherdb = obj._p_jar.db()
@@ -334,14 +342,14 @@
if self._jar.db().databases.get(database_name) is not otherdb:
raise InvalidObjectReference(
"Attempt to store an object from a foreign "
- "database connection"
+ "database connection", self._jar, obj,
)
if self._jar.get_connection(database_name) is not obj._p_jar:
raise InvalidObjectReference(
"Attempt to store a reference to an object from "
"a separate connection to the same database or "
- "multidatabase"
+ "multidatabase", self._jar, obj,
)
# OK, we have an object from another database.
@@ -350,9 +358,9 @@
if obj._p_jar._implicitlyAdding(oid):
raise InvalidObjectReference(
"A new object is reachable from multiple databases. "
- "Won't try to guess which one was correct!"
+ "Won't try to guess which one was correct!",
+ self._jar, obj,
)
-
klass = type(obj)
if hasattr(klass, '__getnewargs__'):
More information about the Zodb-checkins
mailing list