Check-in [adf168e23e]
Not logged in
Overview

SHA1 Hash:adf168e23e3d3812bb7c49d385a1bfd797e23a36
Date: 2007-10-24 08:01:01
User: aku
Comment:Extended handling of id's for files so that we have them for backreferences from symbols and revisions. Completed persistence of revisions and symbols at file-level and fixed small problem with left-over links to branches.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified tools/cvs2fossil/lib/c2f_file.tcl from [f06eb21d1d] to [bd5c5d46d2].

@@ -19,10 +19,11 @@
 package require Tcl 8.4                             ; # Required runtime.
 package require snit                                ; # OO system.
 package require struct::set                         ; # Set operations.
 package require vc::fossil::import::cvs::file::rev  ; # CVS per file revisions.
 package require vc::fossil::import::cvs::file::sym  ; # CVS per file symbols.
+package require vc::fossil::import::cvs::state      ; # State storage.
 package require vc::tools::trouble                  ; # Error reporting.
 package require vc::tools::log                      ; # User feedback
 package require vc::tools::misc                     ; # Text formatting
 
 # # ## ### ##### ######## ############# #####################
@@ -30,19 +31,27 @@
 
 snit::type ::vc::fossil::import::cvs::file {
     # # ## ### ##### ######## #############
     ## Public API
 
-    constructor {path usrpath executable project} {
+    constructor {id path usrpath executable project} {
+	set myid         $id
 	set mypath       $path
 	set myusrpath    $usrpath
 	set myexecutable $executable
 	set myproject    $project
 	set mytrunk      [$myproject trunk]
 	return
     }
 
+    method setid {id} {
+	if {$myid ne ""} { trouble internal "File '$mypath' already has an id, '$myid'" }
+	set myid $id
+	return
+    }
+
+    method id      {} { return $myid }
     method path    {} { return $mypath }
     method usrpath {} { return $myusrpath }
     method project {} { return $myproject }
 
     delegate method commitmessageof to myproject
@@ -64,10 +73,30 @@
 
     # # ## ### ##### ######## #############
     ## Persistence (pass II)
 
     method persist {} {
+	# First collect the reachable revisions and symbols, then
+	# assign id's to all. They are sorted so that we will have ids
+	# which sort in order of creation. Then we can save them. This
+	# is done bottom up. Revisions, then symbols. __NOTE__ This
+	# works only because sqlite is not checking foreign key
+	# references during insert. This allows to have dangling
+	# references which are fixed later. The longest dangling
+	# references are for the project level symbols, these we do
+	# not save here, but at the end of the pass. What we need are
+	# the ids, hence the two phases.
+
+	struct::list assign [$self Active] revisions symbols
+	foreach rev $revisions { $rev defid }
+	foreach sym $symbols   { $sym defid }
+
+	state transaction {
+	    foreach rev $revisions { $rev persist }
+	    foreach sym $symbols   { $sym persist }
+	}
+	return
     }
 
     method drop {} {
 	foreach {_ rev}    [array get myrev]      { $rev destroy }
 	foreach {_ branch} [array get mybranches] { $branch destroy }
@@ -220,10 +249,11 @@
     }
 
     # # ## ### ##### ######## #############
     ## State
 
+    variable myid              {} ; # File id in the persistent state.
     variable mypath            {} ; # Path of the file's rcs archive.
     variable myusrpath         {} ; # Path of the file as seen by users.
     variable myexecutable      0  ; # Boolean flag 'file executable'.
     variable myproject         {} ; # Reference to the project object
 				    # the file belongs to.
@@ -308,18 +338,18 @@
 	if {[info exists mybranches($branchnr)]} {
 	    log write 1 file "In '$mypath': Branch '$branchnr' named '[$mybranches($branchnr) name]'"
 	    log write 1 file "Cannot have second name '$name', ignoring it"
 	    return
 	}
-	set branch [sym %AUTO% branch $branchnr [$myproject getsymbol $name]]
+	set branch [sym %AUTO% branch $branchnr [$myproject getsymbol $name] $self]
 	$branch setposition [incr mybranchcnt]
 	set mybranches($branchnr) $branch
 	return $branch
     }
 
     method AddTag {name revnr} {
-	set tag [sym %AUTO% tag $revnr [$myproject getsymbol $name]]
+	set tag [sym %AUTO% tag $revnr [$myproject getsymbol $name] $self]
 	lappend mytags($revnr) $tag
 	return $tag
     }
 
     method RecordBasicDependencies {revnr next} {
@@ -378,11 +408,11 @@
 		# If revisions were committed on the branch we store a
 		# reference to the branch there, and further declare
 		# the first child's parent to be branch's parent, and
 		# list this child in the parent revision.
 
-		if {[$branch haschild]} {
+		if {[$branch haschildrev]} {
 		    set childrevnr [$branch childrevnr]
 		    set child $myrev($childrevnr)
 		    $branch setchild $child
 
 		    $child setparentbranch $branch
@@ -670,10 +700,11 @@
 	    set vendor [$first parentbranch]
 	    if {$vendor eq ""} { trouble internal "First NTDB revision has no branch" }
 	    if {[$vendor parent] eq $rev11} {
 		$rev11 removebranch        $vendor
 		$rev11 removechildonbranch $first
+		$vendor cutchild
 		$first cutfromparentbranch
 		lappend myroots $first
 	    }
 
 	    # Change the type of first (typically from Change to Add):
@@ -726,11 +757,11 @@
 		set child [$root child]
 		$child cutfromparent
 		lappend myroots $child
 	    }
 
-	    # Remove the branches spawned by the revision to be
+	    # Cut out the branches spawned by the revision to be
 	    # deleted. If the branch has revisions they should already
 	    # use operation 'add', no need to change that. The first
 	    # revision on each branch becomes a new and disconnected
 	    # root.
 
@@ -737,10 +768,11 @@
 	    foreach branch [$root branches] {
 		if {![$branch haschild]} continue
 		set first [$branch child]
 		$first cutfromparentbranch
 		$first cutfromparent
+		$branch cutchild
 		lappend myroots $first
 	    }
 	    $root removeallbranches
 
 	    # Tagging a dead revision doesn't do anything, so remove
@@ -779,11 +811,13 @@
 	    set child  [$root child]
 
 	    ldelete myroots $root
 	    lappend myroots $child
 
+	    $branch cutchild
 	    $child  cutfromparent
+
 	    $parent removebranch        $branch
 	    $parent removechildonbranch $root
 	}
 	return
     }
@@ -971,10 +1005,29 @@
 	}
 
         return
     }
 
+    method Active {} {
+	set revisions {}
+	set symbols   {}
+
+	foreach root [$self LinesOfDevelopment] {
+	    if {[$root hasparentbranch]} { lappend symbols [$root parentbranch] }
+	    while {$root ne ""} {
+		lappend revisions $root
+		foreach tag    [$root tags]     { lappend symbols $tag    }
+		foreach branch [$root branches] { lappend symbols $branch }
+		set lod [$root lod]
+		if {![$lod istrunk]} { lappend symbols $lod }
+		set root [$root child]
+	    }
+	}
+
+	return [list [lsort -unique -dict $revisions] [lsort -unique -dict $symbols]]
+    }
+
     # # ## ### ##### ######## #############
     ## Configuration
 
     pragma -hastypeinfo    no  ; # no type introspection
     pragma -hasinfo        no  ; # no object introspection
@@ -990,13 +1043,14 @@
 	# namespace import ::vc::fossil::import::cvs::file::rev
 	# namespace import ::vc::fossil::import::cvs::file::sym
 	namespace import ::vc::tools::misc::*
 	namespace import ::vc::tools::trouble
 	namespace import ::vc::tools::log
+	namespace import ::vc::fossil::import::cvs::state
     }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file 1.0
 return

Modified tools/cvs2fossil/lib/c2f_frev.tcl from [2e41dc7df6] to [8b070e3579].

@@ -16,10 +16,11 @@
 ## Requirements
 
 package require Tcl 8.4                             ; # Required runtime.
 package require snit                                ; # OO system.
 package require vc::tools::misc                     ; # Text formatting
+package require vc::fossil::import::cvs::state      ; # State storage.
 
 # # ## ### ##### ######## ############# #####################
 ##
 
 snit::type ::vc::fossil::import::cvs::file::rev {
@@ -32,10 +33,17 @@
 	set myorigdate $date
 	set mystate    $state
 	set myfile     $thefile
 	return
     }
+
+    method defid {} {
+	set myid [incr myidcounter]
+	return
+    }
+
+    method id {} { return $myid }
 
     # Basic pieces ________________________
 
     method hasmeta {} { return [expr {$mymetaid ne ""}] }
     method hastext {} {
@@ -332,16 +340,64 @@
 	# Chop the last segment off
 	return [join [lrange [split $branchnr .] 0 end-1] .]
     }
 
     # # ## ### ##### ######## #############
+
+    method persist {} {
+	set fid [$myfile id]
+	set op  $myopcode($myoperation)
+	set idb $myisondefaultbranch
+
+	struct::list assign $mytext cs cl
+	set cl [expr {$cl - $cs}]
+
+	lappend map @L@ [expr { [$mylod istrunk]        ? "NULL" : [$mylod          id] }]
+	lappend map @P@ [expr { ($myparent       eq "") ? "NULL" : [$myparent       id] }]
+	lappend map @C@ [expr { ($mychild        eq "") ? "NULL" : [$mychild        id] }]
+	lappend map @DP [expr { ($mydbparent     eq "") ? "NULL" : [$mydbparent     id] }]
+	lappend map @DC [expr { ($mydbchild      eq "") ? "NULL" : [$mydbchild      id] }]
+	lappend map @BP [expr { ($myparentbranch eq "") ? "NULL" : [$myparentbranch id] }]
+
+	set cmd {
+	    INSERT INTO revision ( rid,   fid, lod,  rev,      date,    state,    mid,       cs,  cl, op,   isdefault, parent, child, dbparent, dbchild, bparent)
+	    VALUES               ($myid, $fid, @L@, $myrevnr, $mydate, $mystate, $mymetaid, $cs, $cl, $op, $idb,       @P@,    @C@,   @DP,      @DC,     @BP);
+	}
+
+	state transaction {
+	    state run [string map $map $cmd]
+	}
+	return
+    }
+
+    # # ## ### ##### ######## #############
     ## State
+
+    # Persistent: myid                - revision.rid
+    #             myfile              - revision.fid
+    #             mylod               - revision.lod
+    #             myrevnr             - revision.rev
+    #             mydate              - revision.date
+    #             mystate             - revision.state
+    #             mymetaid            - revision.mid
+    #             mytext              - revision.{cs,cl}
+    #             myparent            - revision.parent
+    #             mychild             - revision.child
+    #             myparentbranch      - revision.bparent
+    #             myoperation         - revision.op
+    #             myisondefaultbranch - revision.isdefault
+    #             mydbparent          - revision.dbparent
+    #             mydbchild           - revision.dbchild
+
 
     typevariable mybranchpattern {^((?:\d+\.\d+\.)+)(?:0\.)?(\d+)$}
     # First a nonzero even number of digit groups with trailing dot
     # CVS then sticks an extra 0 in here; RCS does not.
     # And the last digit group.
+
+    typevariable myidcounter 0 ; # Counter for revision ids.
+    variable myid           {} ; # Revision id.
 
     variable myrevnr     {} ; # Revision number of the revision.
     variable mydate      {} ; # Timestamp of the revision, seconds since epoch
     variable myorigdate  {} ; # Original unmodified timestamp.
     variable mystate     {} ; # State of the revision.
@@ -424,10 +480,16 @@
 	{0 0} change
 	{0 1} delete
 	{1 0} add
 	{1 1} nothing
     }
+    typevariable myopcode -array {
+	change   2
+	delete  -1
+	add      1
+	nothing  0
+    }
 
     # # ## ### ##### ######## #############
     ## Internal methods
 
     # # ## ### ##### ######## #############
@@ -442,13 +504,14 @@
 
 namespace eval ::vc::fossil::import::cvs::file {
     namespace export rev
     namespace eval rev {
 	namespace import ::vc::tools::misc::*
+	namespace import ::vc::fossil::import::cvs::state
     }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file::rev 1.0
 return

Modified tools/cvs2fossil/lib/c2f_fsym.tcl from [0f3cff0586] to [0342b00fc2].

@@ -17,19 +17,21 @@
 
 package require Tcl 8.4                             ; # Required runtime.
 package require snit                                ; # OO system.
 package require vc::tools::trouble                  ; # Error reporting.
 package require vc::fossil::import::cvs::file::rev  ; # CVS per file revisions.
+package require vc::fossil::import::cvs::state      ; # State storage.
 
 # # ## ### ##### ######## ############# #####################
 ##
 
 snit::type ::vc::fossil::import::cvs::file::sym {
     # # ## ### ##### ######## #############
     ## Public API
 
-    constructor {symtype nr symbol} {
+    constructor {symtype nr symbol file} {
+	set myfile   $file
 	set mytype   $symtype
 	set mynr     $nr
 	set mysymbol $symbol
 
 	switch -exact -- $mytype {
@@ -37,10 +39,17 @@
 	    tag     { }
 	    default { trouble internal "Bad symbol type '$mytype'" }
 	}
 	return
     }
+
+    method defid {} {
+	set myid [incr myidcounter]
+	return
+    }
+
+    method fid {} { return $myid }
 
     # Symbol acessor methods.
 
     delegate method name to mysymbol
     delegate method id   to mysymbol
@@ -56,15 +65,17 @@
     }
 
     method setposition {n}   { set mybranchposition $n ; return }
     method setparent   {rev} { set mybranchparent $rev ; return }
     method setchild    {rev} { set mybranchchild  $rev ; return }
+    method cutchild    {}    { set mybranchchild  ""   ; return }
 
     method branchnr    {} { return $mynr }
     method parentrevnr {} { return $mybranchparentrevnr }
     method childrevnr  {} { return $mybranchchildrevnr }
-    method haschild    {} { return [expr {$mybranchchildrevnr ne ""}] }
+    method haschildrev {} { return [expr {$mybranchchildrevnr ne ""}] }
+    method haschild    {} { return [expr {$mybranchchild ne ""}] }
     method parent      {} { return $mybranchparent }
     method child       {} { return $mybranchchild }
     method position    {} { return $mybranchposition }
 
 
@@ -99,14 +110,73 @@
 	}
 	return
     }
 
     # # ## ### ##### ######## #############
+
+    method persist {} {
+	# Save the information we need after the collection pass.
+
+	# NOTE: mybranchposition is currently not saved. This can
+	# likely be figured out later from the id itself. If yes, we
+	# can also get rid of 'sortbranches' (cvs::file) and the
+	# associated information.
+
+	set fid [$myfile   id]
+	set sid [$mysymbol id]
+
+	lappend map @L@ [expr { [$mylod istrunk] ? "NULL" : [$mylod id] }]
+
+	switch -exact -- $mytype {
+	    tag {
+		set rid [$mytagrev id]
+		set cmd {
+		    INSERT INTO tag ( tid,   fid, lod,  sid,  rev)
+		    VALUES          ($myid, $fid, @L@, $sid, $rid);
+		}
+	    }
+	    branch {
+		lappend map @F@ [expr { ($mybranchchild eq "") ? "NULL" : [$mybranchchild id] }]
+
+		set rid [$mybranchparent id]
+		set cmd {
+		    INSERT INTO branch ( bid,   fid, lod,  sid,  root, first, bra )
+		    VALUES             ($myid, $fid, @L@, $sid, $rid,  @F@, $mynr);
+		}
+	    }
+	}
+
+	state transaction {
+	    state run [string map $map $cmd]
+	}
+	return
+    }
+
+    # # ## ### ##### ######## #############
     ## State
+
+    # Persistent:
+    #        Tag: myid           - tag.tid
+    #             myfile         - tag.fid
+    #             mylod          - tag.lod
+    #             mysymbol       - tag.sid
+    #             mytagrev       - tag.rev
+    #
+    #     Branch: myid           - branch.bid
+    #		  myfile         - branch.fid
+    #		  mylod          - branch.lod
+    #             mysymbol       - branch.sid
+    #             mybranchparent - branch.root
+    #             mybranchchild  - branch.first
+    #             mynr           - branch.bra
+
+    typevariable myidcounter 0 ; # Counter for symbol ids.
+    variable myid           {} ; # Symbol id.
 
     ## Basic, all symbols _________________
 
+    variable myfile   {} ; # Reference to the file the symbol is in.
     variable mytype   {} ; # Symbol type, 'tag', or 'branch'.
     variable mynr     {} ; # Revision number of a 'tag', branch number
 			   # of a 'branch'.
     variable mysymbol {} ; # Reference to the symbol object of this
 			   # symbol at the project level.
@@ -162,14 +232,15 @@
 
 namespace eval ::vc::fossil::import::cvs::file {
     namespace export sym
     namespace eval sym {
 	namespace import ::vc::fossil::import::cvs::file::rev
+	namespace import ::vc::fossil::import::cvs::state
 	namespace import ::vc::tools::trouble
     }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file::sym 1.0
 return

Modified tools/cvs2fossil/lib/c2f_pcollrev.tcl from [38ef86c838] to [a41e2628dd].

@@ -56,57 +56,64 @@
 	# revisions and symbols. The latter can be further separated
 	# into tags and branches. At project level the per-file
 	# symbols information is merged.
 
 	# File level ...
-	#	Event, Revision, Symbol, Branch, Tag
+	#	Revisions, Branches, Tags
 	#
-	#	Tag    <- Symbol <- Event
-	#	Branch <- Symbol <- Event
-	#	Revision <- Event
-	#
-	#	Head revision, Principal branch, Comment
-
-	state writing rcs {
-	    fid       INTEGER  NOT NULL  REFERENCES file,    -- RCS inherit from FILE
-	    head      INTEGER  NOT NULL  REFERENCES revision,
-	    principal INTEGER  NOT NULL  REFERENCES branch,
-	    comment   TEXT     NOT NULL
-	}
-
-	state writing item {
-	    iid  INTEGER  NOT NULL  PRIMARY KEY AUTOINCREMENT,
-	    type INTEGER  NOT NULL,                 -- enum { tag = 1, branch, revision }
-	    fid  INTEGER  NOT NULL  REFERENCES file  -- File the item belongs to
-	}
+	# Pseudo class hierarchy
+	#	Tag      <- Symbol <- Event
+	#	Branch   <- Symbol <- Event
+	#	Revision           <- Event
 
 	state writing revision {
-	    iid   INTEGER  NOT NULL  REFERENCES item,   -- REVISION inherit from ITEM
-	    lod   INTEGER  NOT NULL  REFERENCES symbol, -- Line of development
+	    rid  INTEGER  NOT NULL  PRIMARY KEY AUTOINCREMENT,
+	    fid  INTEGER  NOT NULL  REFERENCES file,   -- File the item belongs to
+	    lod  INTEGER            REFERENCES symbol, -- Line of development (NULL => Trunk)
 
 	    -- The tags and branches belonging to a revision can be
 	    -- determined by selecting on the backreferences in the
 	    -- tag and branch tables.
 
-	    rev   TEXT     NOT NULL,                     -- revision number
-	    date  INTEGER  NOT NULL,                     -- date of entry, seconds since epoch
-	    state TEXT     NOT NULL,                     -- state of revision
-	    mid   INTEGER  NOT NULL REFERENCES meta,     -- meta data (author, commit message)
-	    next  INTEGER  NOT NULL REFERENCES revision, -- next in chain of revisions.
-	    cs    INTEGER  NOT NULL, -- Revision content as offset and length
-	    cl    INTEGER  NOT NULL  -- into the archive file.
+	    rev   TEXT     NOT NULL,                 -- revision number
+	    date  INTEGER  NOT NULL,                 -- date of entry, seconds since epoch
+	    state TEXT     NOT NULL,                 -- state of revision
+	    mid   INTEGER  NOT NULL REFERENCES meta, -- meta data (author, commit message)
+	    cs    INTEGER  NOT NULL,                 -- Revision content as offset and
+	    cl    INTEGER  NOT NULL,                 -- length into the archive file.
+
+	    -- Derived information, and links
+	    -- Basic: Parent/Child
+	    -- NTDB:  DefaultParent/DefaultChild
+	    -- Branches: Branch parent revision
+
+	    op        INTEGER NOT NULL,
+	    isdefault INTEGER NOT NULL,
+	    parent    INTEGER        REFERENCES revision,
+	    child     INTEGER        REFERENCES revision,
+	    dbparent  INTEGER        REFERENCES revision,
+	    dbchild   INTEGER        REFERENCES revision,
+	    bparent   INTEGER        REFERENCES symbol
 	}
 
 	state writing tag {
-	    iid INTEGER  NOT NULL  REFERENCES item,     -- TAG inherit from ITEM
-	    sid INTEGER  NOT NULL  REFERENCES symbol,   -- Symbol capturing the tag
-	    rev INTEGER  NOT NULL  REFERENCES revision -- The revision being tagged.
+	    tid  INTEGER  NOT NULL  PRIMARY KEY AUTOINCREMENT,
+	    fid  INTEGER  NOT NULL  REFERENCES file,     -- File the item belongs to
+	    lod  INTEGER            REFERENCES symbol,   -- Line of development (NULL => Trunk)
+
+	    sid  INTEGER  NOT NULL  REFERENCES symbol,   -- Symbol capturing the tag
+
+	    rev  INTEGER  NOT NULL  REFERENCES revision  -- The revision being tagged.
 	}
 
 	state writing branch {
-	    iid   INTEGER  NOT NULL  REFERENCES item,     -- BRANCH inherit from ITEM
+	    bid   INTEGER  NOT NULL  PRIMARY KEY AUTOINCREMENT,
+	    fid   INTEGER  NOT NULL  REFERENCES file,     -- File the item belongs to
+	    lod   INTEGER            REFERENCES symbol,   -- Line of development (NULL => Trunk)
+
 	    sid   INTEGER  NOT NULL  REFERENCES symbol,   -- Symbol capturing the branch
+
 	    root  INTEGER  NOT NULL  REFERENCES revision, -- Revision the branch sprouts from
 	    first INTEGER            REFERENCES revision, -- First revision committed to the branch
 	    bra   TEXT     NOT NULL                       -- branch number
 	}
 
@@ -207,21 +214,23 @@
 			trouble fatal "$path is not a valid RCS archive ($msg)"
 		    } else {
 			global errorInfo
 			trouble internal $errorInfo
 		    }
+		} else {
+		    # We persist the core of the data collected about
+		    # each file immediately after it has been parsed
+		    # and wrangled into shape, and then drop it from
+		    # memory. This is done to keep the amount of
+		    # required memory within sensible limits. Without
+		    # doing it this way we would easily gobble up 1G
+		    # of RAM or more with all the objects (revisions
+		    # and file-level symbols).
+
+		    $file persist
 		}
 
-		# We persist the core of the data collected about each
-		# file immediately after it has been parsed and
-		# wrangled into shape, and then drop it from
-		# memory. This is done to keep the memory requirements
-		# within limits, i.e. without doing it this way it is
-		# easy to blow 1G of RAM with all the objects
-		# (revisions and file-level symbols).
-
-		$file persist
 		$file drop
 	    }
 	}
 
 	repository printrevstatistics
@@ -234,12 +243,10 @@
     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 rcs
-	state discard item
 	state discard revision
 	state discard tag
 	state discard branch
 	state discard symbol
 	state discard blocker

Modified tools/cvs2fossil/lib/c2f_project.tcl from [69ed821c29] to [cfcc67163f].

@@ -45,12 +45,12 @@
 	return $mybase
     }
 
     method setid {id} { set myid $id ; return }
 
-    method addfile {rcs usr executable} {
-	set myfiles($rcs) [list $usr $executable]
+    method addfile {rcs usr executable {fid {}}} {
+	set myfiles($rcs) [list $usr $executable $fid]
 	return
     }
 
     method filenames {} {
 	return [lsort -dict [array names myfiles]]
@@ -77,10 +77,12 @@
 	return $mysymbols($name)
     }
 
     # pass I persistence
     method persist {} {
+	TheFiles ; # Force id assignment.
+
 	state transaction {
 	    # Project data first. Required so that we have its id
 	    # ready for the files.
 
 	    state run {
@@ -90,28 +92,32 @@
 	    set myid [state id]
 
 	    # Then all files, with proper backreference to their
 	    # project.
 
-	    foreach {rcs item} [array get myfiles] {
-		struct::list assign $item usr executable
+	    foreach rcs [lsort -dict [array names myfiles]] {
+		struct::list assign $myfiles($rcs) usr executable _fid_
 		state run {
 		    INSERT INTO file (fid,  pid,   name, visible, exec)
 		    VALUES           (NULL, $myid, $rcs, $usr,    $executable);
 		}
+		$myfmap($rcs) setid [state id]
 	    }
 	}
 	return
     }
 
     # pass II persistence
     method persistrev {} {
+	# Note: The per file information (incl. revisions and symbols)
+	# has already been saved and dropped, immediately after
+	# processing it, to keep out use of memory under control. Now
+	# we just have to save the remaining project level parts to
+	# fix the left-over dangling references.
+
 	state transaction {
 	    # TODO: per project persistence (symbols, meta data)
-	    foreach f [TheFiles] {
-		$f persist
-	    }
 	}
 	return
     }
 
     # # ## ### ##### ######## #############
@@ -122,31 +128,34 @@
     variable mytrunk          {} ; # Reference to the main line of
 				   # development for the project.
     variable myfiles   -array {} ; # Maps the rcs archive paths to
 				   # their user-visible files.
     variable myfobj           {} ; # File objects for the rcs archives
+    variable myfmap    -array {} ; # Map rcs archive to their object.
     variable myrepository     {} ; # Repository the prject belongs to.
     variable mysymbols -array {} ; # Map symbol names to project-level
 				   # symbol objects.
 
     # # ## ### ##### ######## #############
     ## Internal methods
 
     proc TheFiles {} {
-	upvar 1 myfiles myfiles myfobj myfobj self self
+	upvar 1 myfiles myfiles myfobj myfobj self self myfmap myfmap
 	if {![llength $myfobj]} {
 	    set myfobj [EmptyFiles myfiles]
 	}
 	return $myfobj
     }
 
     proc EmptyFiles {fv} {
-	upvar 1 $fv myfiles self self
+	upvar 1 $fv myfiles self self myfmap myfmap
 	set res {}
 	foreach rcs [lsort -dict [array names myfiles]] {
-	    struct::list assign $myfiles($rcs) f executable
-	    lappend res [file %AUTO% $rcs $f $executable $self]
+	    struct::list assign $myfiles($rcs) f executable fid
+	    set file [file %AUTO% $fid $rcs $f $executable $self]
+	    lappend res $file
+	    set myfmap($rcs) $file
 	}
 	return $res
     }
 
     # # ## ### ##### ######## #############

Modified tools/cvs2fossil/lib/c2f_repository.tcl from [2bc22e9971] to [e30942cde8].

@@ -150,11 +150,11 @@
 		$pr($pid) setid $pid
 	    }
 	    foreach   {fid  pid  name  visible  exec} [state run {
 		SELECT fid, pid, name, visible, exec FROM file ;
 	    }] {
-		$pr($pid) addfile $name $visible $exec
+		$pr($pid) addfile $name $visible $exec $fid
 	    }
 	}
 	return
     }