On 11/29/2011 02:33 PM, Hyrum K Wright wrote:
> Ev2 doesn't bother with a depth-first tree traversal, the sender just
> invokes paths in whatever order it sees fit. There are a few obvious
> restrictions, such as directories need to exist before their children
> can be processed, for example, but it's much looser than the delta
> editor. Also, the APIs are a bit more streamlined, in that it's not
> legal to set the properties on a node multiple times in the same
> drive, for instance.
>
> To handle the conversion from the delta editor to Ev2, we create an
> editor which receives all the calls from the sender, queues them up,
> and then drives an Ev2 editor in the receiver. Likewise, a similar
> shim exists which receives Ev2 calls, queues them up and then drives a
> delta editor in the proper order. It's all terribly inefficient due
> to the fact that the entire drive is stored in memory prior to being
> translated and replayed to the target editor (whether Ev2 or the delta
> editor), but it's also meant as a temporary measure.
>
> However, svn_delta_path_driver() looks like it interacts with the
> editor while the thing is being driven. It counts on all the prior
> calls actually reaching the target editor before the callback is
> invoked, which means it will have an adverse reaction to something
> which queues up the calls and then replays them, since none of the
> preceding calls will have succeeded by the time its callback is
> invoked.
Of course svn_delta_path_driver() interacts with the editor while it's being
driven -- it's helping to drive it!
Look, what this interface does is pretty straightforward. It examines a
list of interesting paths provided it. Interesting paths are paths which
are added, deleted, or modified. It sorts them into depth-first order, and
drives the provided editor in such a way that all those paths are reached as
part of the editor drive. As each one is reached, it calls its callback
function to say, "Hey, we're at the point of the editor drive where you can
do whatever it is to path FOO that you needed done, so do it and then return
when you're finished." And then it continues along, opening and closing
directories until it reaches the next interesting path, continuing until
every interesting path has been reached as part of the drive and all
intermediate directories have been closed.
For example, say I have a list of paths and the actions I want to do to them:
'trunk/mu': delete it
'trunk/A/D/G/florp': add it as a directory
'trunk/A/B/E/alpha': set the property 'foo' to 'bar' on it
I can tell that the longest common ancestor of these paths is 'trunk', so I
anchor the editor which is supposed to absorb these changes (maybe its an RA
commit editor) there, convert my list of paths to be relative to that
location, then pass the list and the editor to svn_delta_path_driver().
svn_delta_path_driver (SDPD) sorts my relative paths by depth:
'mu'
'A/B/E/alpha'
'A/D/G/florp'
and then starts driving the editor to handle intermediate directories
between and around my interesting paths. In my scenario, it doesn't get far
before it reaches one of my interesting paths:
SDPD: db1 = open_root('')
Now, it's at the point where it can act on 'mu', but it doesn't know what
needs to happen to 'mu'. So it calls the path driver callback (PDCB) I
provided to allow that sucker to do the real work on 'mu', providing 'mu's
parent directory baton to the callback. My callback function knows that I
wanted to delete 'mu' (I had that information stuffed into its baton), so it
does so by calling the delete_entry() function on the same editor that
svn_path_delta_driver() is using.
PDCB: delete_entry(db1, 'mu')
Then it returns.
SDPD continues, driving the editor to the next interesting path
('A/B/E/alpha'), which requires a few more open-dir's:
SDPD: db2 = open_directory(db1, 'A')
SDPD: db3 = open_directory(db2, 'A/B')
SDPD: db4 = open_directory(db3, 'A/B/E')
Having arrived at the next interesting path, it calls my callback to do the
interesting work, and the callback fills in some more of the missing editor
calls:
PDCB: fb = open_file(db4, 'A/B/E/alpha')
PDCB: change_file_prop(fb, 'foo', 'bar')
PDCB: close_file(fb)
Back in SDPD again, we drive to the next destination, which requires moving
up a directory and back down again into another subtree:
SDPD: close_directory(db4)
SDPD: db4 = open_directory(db3, 'A/D/G')
Then it calls the callback again for 'A/D/G/florp', which does:
PDCB: db5 = add_directory(db4, 'A/D/G/florp')
This time the callback does something a little different, though -- because
it opened or added a directory, it returns the dir baton for that directory
so that SDPD can use it to address immediate children (if any) of this
directory. In my example, there are none, so when program control returns
to SDPD, it just closes my new directory as part of its wrap-up of open
directories back to the root.
SDPD: close_directory(db5)
SDPD: close_directory(db4)
SDPD: close_directory(db3)
SDPD: close_directory(db2)
SDPD: close_directory(db1)
And the edit drive is complete save for the close_edit() called from outside
the svn_delta_path_driver() call tree.
> Now, after having written all then, I wonder if there would be a way
> to set up a system whereby the delta_path_driver callback was invoked
> during the replay of the queued items, rather than the initial calls
> to them. It would involve a bit more shim code, but this may be the
> better solution. Hmmm.....
Any consumer of the svn_delta_path_driver() will need to be using Ev1 --
that's what's supported by the API. If their particular editor is a shim to
an Ev2 under the hood, that's fine -- the caller need never be aware of that
any more than they would be if they were manually driving the editor. And
it sounds as if we don't need to rev svn_delta_path_driver() for an Ev2
flavor because Ev2 solves the primary problem that SDPD exists to solve:
the depth-first requirement of editor drives.
--
C. Michael Pilato <cmpilato_at_collab.net>
CollabNet <> www.collab.net <> Distributed Development On Demand
Received on 2011-11-29 22:03:47 CET