- Q:
- For what sorts of applications is Durus best suited?
- A:
- Durus aggressively caches data and does not do locking. As a result
it performs very well for applications do mostly reading and only a
little writing.
- Q:
- Why did was Durus developed when ZODB and ZEO already existed?
- A:
The initial motivation mostly that we wanted to use new-style
classes instead of ExtensionClasses. Durus does not have as many
features as ZODB (multi-threaded access, multiple storage backends,
asynchronous IO, versions, undo, conflict resolution). That all
adds up to making the code much simpler.
Recent releases of ZODB now use new-style classes too. So, if you
need extra features or multi-threading then ZODB is still the way to
go. We like Durus because it does what we need and it is simple
enough that we can understand it in its entirety.
The programming interface is nearly the same as ZODB (Durus is
heavily influenced by the ZODB design). Speed is pretty similar
although Durus may be a little faster.
- Q:
- How would you handle an application which has frequent concurrent
writes to the same object? Durus is generating lots of write
conflicts.
- A:
- If your application does a lot of writing then Durus may not be the
appropriate database. That said, there are some ways to mitigate
write conflicts. Try to avoid designs that require frequent writes
to the same objects. Also, try to keep transactions short (i.e.
the time between abort()/commit() and commit()).
- Q:
- I made a change in one client but it is not visible in another
client.
- A:
- You need to call commit() or abort() in the second client in
order to see the new data. This behavior is necessary to provide
data consistency. Between transaction boundaries clients must see a
consistent view of the data. This necessarily means that they may
be seeing out-of-date data.
- Q:
- When does a write conflict occur?
- A:
- If a client makes changes based on out-of-date data and tries to commit
then a ConflictError exception will be raised. This occurs when
some other client has committed a change during the first client's
transaction (i.e. between commit()/abort() and commit()).
- Q:
- When does a read conflict occur?
- A:
The exact conditions under which a ReadConflictError is raised
are complicated so the source code is probably the best reference.
In essence, a read conflict occurs when a client tries to load data
from the storage server that is inconsistent with data that it has
previously loaded. For example, a client loads object A, a second
client modifies object A and object B. If the first client tries to
load object B it will get a read conflict error. The state of
object A, already in loaded, is not consistent with the state of B.
Multi-version concurrency control (MVCC) can avoid read conflicts.
When MVCC is used, an older version of the object's state is
returned to the client (a version consistent with the other objects
that the client loaded). Durus does not implement MVCC. Recent
versions of the Zope Object Database (ZODB) do.
- Q:
- My client has received a ConflictError or ReadConflictError.
What must it do to recover?
- A:
- The client must call abort() and restart the transaction. Note
that it must not keep partial results in local variables, for
example, since the data it was using before the conflict was out of
date.
- Q:
- I've made changes to my object model. How do I update an existing
database?
- A:
- We have found that a separate database update script works well.
Using __getstate__ and __setstate__ is not recommended.
- Q:
- I need to find all objects of a certain class in order to update
their attributes.
- A:
- If you can't easily find them by following the object graph then you
can use the gen_oid_class() function from the storage
module. Note that this is expensive since it iterates over every
record in the database. We use it only for making data model
changes.
- Q:
- I want to rename a class. How do I update the database?
- A:
- First, make sure the class can be accessed via the old name (e.g.
OldClass = NewClass). In your update DB script, set the
_p_changed flag on all instances of the class and then call
commit(). You can now remove the old name.
- Q:
- I want to rename a module. How do I update the database?
- A:
This is basically the same as changing a class name. A useful trick
is to assign to sys.modules directly. For example, in your update
DB script you could do something like:
import newmodule
sys.modules["oldmodule"] = newmodule
- Q:
- How do I backup a database? Do I need to shutdown the storage
server first?
- A:
- It is safe to just copy the file. Data is only appended to the file
and the FileStorage class can detect if the last transaction has
been truncated. There is no need to shutdown the storage server
first.