After some further discussion on IRC, and some thought...
I think this may be more of a representational problem, and might not
be a "true" fourth tree. Especially because supporting the revert
scenario actually implies N trees. Bert tried to describe this a while
back, but I didn't understand his description (too many "A" nodes).
Consider the following:
$ svn cp A X # copies A/Y/Z/file
$ svn cp B X/Y # copies B/Z/file
$ svn cp C X/Y/Z # copies C/file
$ svn cp file X/Y/Z/file
We have four operation roots, and four layers of "file". Reverting
each op-root will reveal the previous layer.
In 1.6, we probably had just one layer, but if we're going to solve
this, then let's do it right.
I propose that we create a new table called NODE_DATA which is keyed
by <wc_id, local_relpath, op_depth>. The first two are the usual, and
op_depth is the "operation depth". In the above example, we have four
WORKING_NODE rows, each establishing an operation root, with
local_relpath values of [X, X/Y, X/Y/Z, X/Y/Z/file]. In the NODE_DATA
table, we have the following four rows:
<1, X/Y/Z/file, 1> # from the X op-root
<1, X/Y/Z/file, 2> # from the X/Y op-root
<1, X/Y/Z/file, 3> # from the X/Y/Z op-root
<1, X/Y/Z/file, 4> # from the X/Y/Z/file op-root
Essentially, op_depth = oproot_relpath.count('/') + 1
We can record BASE node data as op_depth == 0.
Looking up the data for "file" is a query like this:
SELECT * from NODE_DATA
WHERE wc_id = ?1 AND local_relpath = ?2
ORDER BY op_depth DESC
That provides the "current" file data.
Some of the common columns between BASE_NODE and WORKING_NODE move to
this new NODE_DATA table. I think they are:
kind, [checksum], changed_*, properties
Those columns, plus the key, may be about it. I don't know that this
table needs a presence column, as the "visible" state is determined by
the BASE and WORKING trees. This is why I suggest that maybe we're
looking more at how to represent (in the database) the WORKING tree,
than truly adding a new "tree".
On Wed, Apr 7, 2010 at 16:15, Greg Stein <gstein_at_gmail.com> wrote:
> On Wed, Apr 7, 2010 at 04:52, Philip Martin <philip.martin_at_wandisco.com> wrote:
>> Greg Stein <gstein_at_gmail.com> writes:
>>> I believe that we have the following operations:
>>> add: plain old add
>>> add-within-copy/move: add within a subtree
>> Those two are much the same. It makes little difference whether it's
>> a plain add, an add within an add or an add within a copy/move.
> Well... we couldn't distinguish these two cases before. With a few
> additional presence values, we can.
>>> replace: delete-base + add
>>> replace-within-copy/move: delete-child + add
>> There is also
>> replace: base node not-present + add
>> the old deleted=true state. This is explicitly excluded from being a
>> replace in svn_wc__internal_is_replaced but that may be a bug (it
>> causes revert to erroneously remove the not-present base node).
> It is excluded from being svn_wc_schedule_replace. I'd prefer to
> ignore that fact.
>>> delete-base: deleting a base node
>>> delete-child: deleting a child of an add/copy/move
>>> copy(-within): same as add•
>>> moved-here(-within): same as add*
>>> moved-away(-within): same as delete*
>>> I'm thinking that we add the following presence values (for
>>> "added": same as "normal" today. clarifies what this really means. we
>>> map this to status_added, so why not use this for the presence
>>> anyways? no need to "minimize/conserve" the set of presence values.
>>> "replaced": indicates an added/copied-here/moved-here node that
>>> replaces a child of a copied-here/moved-here subtree.
>>> "deleted": same as "not-present" today. clarifies what this really means.
>>> "inherit": applied to children of copied-here/moved-here and
>>> deleted/base-deleted nodes. implies that no commit operations are
>>> required for these nodes.
>> Being able to distinguish add and replace is not enough for full 1.6
>> compatibility. When a node replaces a copied child it overwrites the
>> child's data, things like checksum and properties. This data is not
>> derived or inherited from the copied parent, so it cannot be restored
>> after being overwriten. In 1.6 it is possible to revert the replace
>> and restore to the copied child.
> Urgh. Yeah. I've only ever looked at that scenario as "no partial
> reverts (yet). revert the whole thing". In that case, meaning the
> whole copy. But that's not right, if the user is reverting
> SOME/SUBDIR/PATH. Only the change(s) to the child should be reverted.
>> Another problem is a copy of a mixed revision tree that includes base
>> nodes that are not-present. In 1.6 we represent these as "fake"
>> schedule deletes in the copy, so that they are explicitly deleted when
>> the copy is committed. This works but has problems, the main one
>> being that if one tries to revert the delete the full node information
>> is not available (because the not-present source doesn't have it).
>> Perhaps we should have a distinct presence for this type of node?
>> There are similar questions about absent and excluded nodes.
> Okay. In this case, reverting the delete should result in an excluded
> node. That's the best we can do. "svn update --depth=infinity
> NOTPRESENT" can restore the file.
> Note that we *could* revert a replaced-child into an excluded node,
> too. That would be a feature loss compared to 1.6, however.
> It seems like we need one more tree, to hold "inherit" data. If you do
> a further operation on an operation-root (something in WORKING_NODE),
> then it will alter that node and all inherited nodes. But if you
> perform an operation on an inherited node, then you're establishing a
> new operation-root in WORKING_NODE. The inherited data can still
> remain elsewhere, but WORKING_NODE now refers to a new operation-root.
> Reverting that operation would bring back the inherited node.
> Thus, WORKING_NODE would become *just* explicit operations. ie. the
> stuff we send during a commit.
> Hmm. Almost...
> A delete operation could mark the root in WORKING_NODE (we'd probably
> want a new name for this!), and then drop a bunch of markers in
> WORKING_NODE to occlude any children present in the inherited tree and
> the BASE tree. Those markers couldn't be individually reverted
> however, and they don't represent data to send during commit. We
> *could* alter a presence-like flag in the inherited tree instead, yet
> leave all the data intact for a revert. Or place markers in the
> inherited tree to occlude the BASE nodes.
Received on 2010-04-07 23:25:54 CEST