Artifact bd713af4f16bcf0ba5deb402563768beaa2101ef
File tools/cvs2fossil/lib/c2f_patopsort.tcl part of check-in [00bf8c198e] - The performance was still not satisfying, even with faster recomputing of successors. Doing it multiple times (Building the graph in each breaker and sort passes) eats time. Caching in memory blows the memory. Chosen solution: Cache this information in the database.Created a new pass 'CsetDeps' which is run between 'InitCsets' and 'BreakRevCsetCycles' (i.e. changeset creation and first breaker pass). It computes the changeset dependencies from the file-level dependencies once and saves the result in the state, in the new table 'cssuccessor'. Now the breaker and sort passes can get the information quickly, with virtually no effort. The dependencies are recomputed incrementally when a changeset is split by one of the breaker passes, for its fragments and its predecessors.
The loop check is now trivial, and integrated into the successor computation, with the heavy lifting for the detailed analysis and reporting moved down into the type-dependent SQL queries. The relevant new method is 'loops'. Now that the loop check is incremental the pass based checks have been removed from the integrity module, and the option '--loopcheck' has been eliminated. For paranoia the graph setup and modification code got its loop check reinstated as an assert, redusing the changeset report code.
Renumbered the breaker and sort passes. A number of places, like graph setup and traversal, loading of changesets, etc. got feedback indicators to show their progress.
The selection of revision and symbol changesets for the associated breaker passes was a bit on the slow side. We now keep changeset lists sorted by type (during loading or general construction) and access them directly.
by aku on 2007-12-02 20:04:40.
## -*- tcl -*- # # ## ### ##### ######## ############# ##################### ## Copyright (c) 2007 Andreas Kupries. # # This software is licensed as described in the file LICENSE, which # you should have received as part of this distribution. # # This software consists of voluntary contributions made by many # individuals. For exact contribution history, see the revision # history and logs, available at http://fossil-scm.hwaci.com/fossil # # ## ### ##### ######## ############# ##################### ## Pass XI. This pass goes over all changesets and sorts them ## topologically. It assumes that there are no cycles which could ## impede it, any remaining having been broken by the previous two ## passes, and aborts if that condition doesn't hold. # # ## ### ##### ######## ############# ##################### ## Requirements package require Tcl 8.4 ; # Required runtime. package require snit ; # OO system. package require struct::list ; # Higher order list operations. package require vc::tools::log ; # User feedback. package require vc::fossil::import::cvs::cyclebreaker ; # Breaking dependency cycles. package require vc::fossil::import::cvs::state ; # State storage. package require vc::fossil::import::cvs::project::rev ; # Project level changesets # # ## ### ##### ######## ############# ##################### ## Register the pass with the management vc::fossil::import::cvs::pass define \ AllTopologicalSort \ {Topologically Sort All ChangeSets} \ ::vc::fossil::import::cvs::pass::atopsort # # ## ### ##### ######## ############# ##################### ## snit::type ::vc::fossil::import::cvs::pass::atopsort { # # ## ### ##### ######## ############# ## Public API typemethod setup {} { # Define the names and structure of the persistent state of # this pass. state reading revision state reading changeset state reading csorder state writing cstimestamp { -- Commit order of all changesets based on their -- dependencies, plus a monotonically increasing -- timestamp. cid INTEGER NOT NULL REFERENCES changeset, pos INTEGER NOT NULL, date INTEGER NOT NULL, UNIQUE (cid), UNIQUE (pos), UNIQUE (date) } return } typemethod load {} { # Pass manager interface. Executed to load data computed by # this pass into memory when this pass is skipped instead of # executed. return } typemethod run {} { # Pass manager interface. Executed to perform the # functionality of the pass. set len [string length [project::rev num]] set myatfmt %${len}s incr len 12 set mycsfmt %${len}s cyclebreaker savecmd [myproc SaveTimestamps] state transaction { LoadSymbolChangesets cyclebreaker run tsort-all [myproc Changesets] } return } typemethod discard {} { # Pass manager interface. Executed for all passes after the # run passes, to remove all data of this pass from the state, # as being out of date. state discard cstimestamp return } # # ## ### ##### ######## ############# ## Internal methods proc Changesets {} { project::rev all } proc LoadSymbolChangesets {} { set mysymchangesets [struct::list filter [project::rev all] [myproc IsBySymbol]] return } proc IsBySymbol {cset} { $cset bysymbol } proc SaveTimestamps {graph at cset} { set cid [$cset id] set date [GetTime [lindex [$graph node get $cset timerange] 1] \ [struct::set contain $mysymchangesets $cset] \ message] log write 4 atopsort "Changeset @ [format $myatfmt $at]: [format $mycsfmt [$cset str]]$message" state run { INSERT INTO cstimestamp (cid, pos, date) VALUES ($cid, $at, $date) } return } proc GetTime {stamp expectchange mv} { ::variable mylasttimestamp upvar 1 $mv message set message "" if {$stamp > $mymaxtimestamp} { # A timestamp in the future is believed to be bogus and # shifted backwars in time to prevent it from forcing # other timestamps to be pushed even further in the # future. # From cvs2svn: Note that this is not nearly a complete # solution to the bogus timestamp problem. A timestamp in # the future still affects the ordering of changesets, and # a changeset having such a timestamp will not be # committed until all changesets with earlier timestamps # have been committed, even if other changesets with even # earlier timestamps depend on this one. incr mylasttimestamp if {!$expectchange} { set message " Timestamp [clock format $stamp] is in the future; shifted back to [clock format $mylasttimestamp] ([expr {$mylasttimestamp - $stamp}])" } } elseif {$stamp < ($mylasttimestamp)+1} { incr mylasttimestamp if {!$expectchange} { set message " Timestamp [clock format $stamp] adjusted to [clock format $mylasttimestamp] (+[expr {$mylasttimestamp - $stamp}])" } } else { set mylasttimestamp $stamp } return $mylasttimestamp } typevariable myatfmt ; # Format for log output to gain better alignment of the various columns. typevariable mycsfmt ; # Ditto for the changesets. typevariable mysymchangesets {} ; # Set of the symbol changesets. typevariable mylasttimestamp 0 ; # Last delivered timestamp. typevariable mymaxtimestamp typeconstructor { # The maximum timestamp considered as reasonable is # "now + 1 day". set mymaxtimestamp [clock seconds] incr mymaxtimestamp 86400 ; # 24h * 60min * 60sec return } # # ## ### ##### ######## ############# ## Configuration pragma -hasinstances no ; # singleton pragma -hastypeinfo no ; # no introspection pragma -hastypedestroy no ; # immortal # # ## ### ##### ######## ############# } namespace eval ::vc::fossil::import::cvs::pass { namespace export atopsort namespace eval atopsort { namespace import ::vc::fossil::import::cvs::cyclebreaker namespace import ::vc::fossil::import::cvs::state namespace eval project { namespace import ::vc::fossil::import::cvs::project::rev } namespace import ::vc::tools::log log register atopsort } } # # ## ### ##### ######## ############# ##################### ## Ready package provide vc::fossil::import::cvs::pass::atopsort 1.0 return