Differences From:
File
tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
part of check-in
[4f1b60dd16]
- Continued work on pass 8. Renamed 'retrograde' to 'Backward Branch', should be easier to understand, and completed the predicate testing if a branch changeset is backward or not.
by
aku on
2007-11-22 03:47:38.
[view]
To:
File
tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
part of check-in
[e50f9ed55e]
- Continued work on pass 8. Completed the handling of backward branches, file level analysis and splitting them. Extended changesets with the necessary methods to the predecessor data and proper per-revision maps.
by
aku on
2007-11-22 04:21:37.
[view]
@@ -122,9 +122,9 @@
# the branch changesets from the state in one go instead of
# having to check each changeset separately. Consider this
# later, get the pass working first.
#
- # NOTE 2: Might we even be able to select the retrograde
+ # NOTE 2: Might we even be able to select the backward branch
# changesets too ?
foreach cset [$graph nodes] {
if {![$cset isbranch]} continue
@@ -136,9 +136,47 @@
proc CheckAndBreakBackwardBranch {graph cset} {
while {[IsABackwardBranch $graph $cset]} {
log write 5 breakacycle "Breaking backward branch changeset <[$cset id]>"
- break
+ # Knowing that the branch is backward we now look at the
+ # individual revisions in the changeset and determine
+ # which of them are responsible for the overlap. This
+ # allows us to split them into two sets, one of
+ # non-overlapping revisions, and of overlapping ones. Each
+ # induces a new changeset, and the second may still be
+ # backward and need further splitting. Hence the looping.
+ #
+ # The border used for the split is the minimal commit
+ # position among the minimal sucessor commit positions for
+ # the revisions in the changeset.
+
+ # Note that individual revisions may not have revision
+ # changesets are predecessors and/or successors, leaving
+ # the limits partially or completely undefined.
+
+ # limits : dict (revision -> list (max predecessor commit, min sucessor commit))
+
+ ComputeLimits $cset limits border
+
+ log write 6 breakacycle "At commit position border $border"
+
+ # Then we sort the file level items based on there they
+ # sit relative to the border into before and after the
+ # border.
+
+ SplitRevisions $limits normalrevisions backwardrevisions
+
+ set replacements [project::rev split $cset $normalrevisions $backwardrevisions]
+ cyclebreaker replace $graph $cset $replacements
+
+ # At last check that the normal frament is indeed not
+ # backward, and iterate over the possibly still backward
+ # second fragment.
+
+ struct::list assign $replacements normal backward
+ if {[IsABackwardBranch $dg $normal]} { trouble internal "The normal fragment is unexpectedly a backward branch" }
+
+ set cset $backward
}
return
}
@@ -183,8 +221,87 @@
}
proc ToPosition {cset} { $cset pos }
proc ValidPosition {pos} { expr {$pos ne ""} }
+
+ proc ComputeLimits {cset lv bv} {
+ upvar 1 $lv thelimits $bv border
+
+ # Initialize the boundaries for all revisions.
+
+ array set limits {}
+ foreach revision [$cset revisions] {
+ set limits($revision) {0 {}}
+ }
+
+ # Compute and store the maximal predecessors per revision
+
+ foreach {revision csets} [$cset predecessormap] {
+ set s [Positions $csets]
+ if {![llength $s]} continue
+ set limits($revision) [lreplace $limits($revision) 0 0 [max $s]]
+ }
+
+ # Compute and store the minimal successors per revision
+
+ foreach {revision csets} [$cset successormap] {
+ set s [Positions $csets]
+ if {![llength $s]} continue
+ set limits($revision) [lreplace $limits($revision) 1 1 [min $s]]
+ }
+
+ # Check that the ordering at the file level is correct. We
+ # cannot have backward ordering per revision, or something is
+ # wrong.
+
+ foreach revision [array names limits] {
+ struct::list assign $limits($revision) maxp mins
+ # Handle min successor position "" as representing infinity
+ if {$mins eq ""} continue
+ if {$maxp < $mins} continue
+
+ trouble internal "Branch revision $revision is backward at file level ($maxp >= $mins)"
+ }
+
+ # Save the limits for the splitter, and compute the border at
+ # which to split as the minimum of all minimal successor
+ # positions.
+
+ set thelimits [array get limits]
+ set border [min [struct::list filter [struct::list map [Values $thelimits] \
+ [myproc MinSuccessorPosition]] \
+ [myproc ValidPosition]]]
+ return
+ }
+
+ proc Values {dict} {
+ set res {}
+ foreach {k v} $dict { lappend res $v }
+ return $res
+ }
+
+ proc MinSuccessorPosition {item} { lindex $item 1 }
+
+ proc SplitRevisions {limits nv bv} {
+ upvar 1 $nv normalrevisions $bv backwardrevisions
+
+ set normalrevisions {}
+ set backwardrevisions {}
+
+ foreach {rev v} $limits {
+ struct::list assign $v maxp mins
+ if {$maxp >= $border} {
+ lappend backwardrevisions $rev
+ } else {
+ lappend normalrevisions $rev
+ }
+ }
+
+ if {![llength $normalrevisions]} { trouble internal "Set of normal revisions is empty" }
+ if {![llength $backwardrevisions]} { trouble internal "Set of backward revisions is empty" }
+ return
+ }
+
# # ## ### ##### ######## #############
proc SaveOrder {cset pos} {