I've been looking at a delete bug: delete can remove a directory NODES
row and leave rows for children, thus creating an invalid metadata
state. The code is structured as
svn_wc_delete4(path):
various checks on path
for each child of path:
various checks on child
svn_wc_delete4(child)
svn_wc__db_temp_op_delete(path)
notify
cleanup
The recursion happens in svn_wc_delete4 while svn_wc__db_temp_op_delete
is where the database is modifed (non-recursively). I can fix the bug
by modify the checks in svn_wc_delete4 but I think this is the wrong way
to do it. I wrote svn_wc__db_temp_op_delete and the _temp_ part is
simply because I didn't really know how it should work.
Our metadata API should be responsible for maintaining the implied
database invariants. Thus the svn_wc__db_op_delete needs to do the
checks to ensure that children don't become orphans. It either needs to
reject such a change, or it needs to be recursive and remove the
children.
Making the checks in svn_wc__db_op_delete also solves a race. At
present the checks made by svn_wc_delete4 are only protected by a
wclock, putting them in svn_wc__db_op_delete means they can go inside
the same SQLite transaction that modifies the database.
Once svn_wc__db_op_delete is making the checks there is very little
point in svn_wc_delete4 making the same checks, and a good performance
reason for only making the checks once. It's probably more efficient to
move the recursion into svn_wc__db_op_delete as well and doing so also
solves the problem that currently op_depth needs to be rewritten as each
parent gets deleted.
That all seems to be good until we come to notification and workqueues.
svn_wc__db_op_delete can't really do notification as it would be making
callbacks from within an SQLite transaction. So svn_wc_delete4 must
continue to notify, and as it can't reliably identify which paths were
deleted svn_wc__db_op_delete must return a list of affected paths.
Delete doesn't currently use a workqueue. It could, and perhaps it
should, although I'm not sure it's strictly necessary. If it were to
use a workqueue then the function that modifies the metadata,
svn_wc__db_op_delete, should install any wq items (one per path or one
per tree).
So the delete code ends up looking like
svn_wc_delete4(path):
deleted = svn_wc__db_op_delete(path)
for name in deleted:
notify(name)
run workqueue
cleanup
Does that sound sensible?
Finally, while this mail refers to delete there are similar problems in
other functions: revert, copy, etc.
--
Philip
Received on 2010-10-25 22:22:00 CEST