@@ -12,6 +12,7 @@ import (
1212 "runtime"
1313 "sort"
1414 "strings"
15+ "sync"
1516 "time"
1617
1718 "github.com/taigrr/colorhash"
@@ -84,7 +85,7 @@ func CreateFileLookupEntry(path, workDirPath string, initial bool) (LookupEntry,
8485 hash , err := GetFileHash (path )
8586
8687 _ , err = CopyToWorkDir (path , workDirPath , hash )
87- l .Target = HashPathFromHashInitial (hash , workDirPath ) + filepath .Ext (path )
88+ l .Target = filepath . Join (hash , filepath .Ext (path ) )
8889 l .Name = path
8990 l .Modified = info .ModTime ()
9091 l .FileSize = info .Size ()
@@ -109,7 +110,9 @@ type lookupWorkerData struct {
109110 initial bool
110111}
111112
112- func initialLookupWorker (lwd chan lookupWorkerData , c chan LookupEntry , errChan chan error , doneChan chan struct {}) {
113+ func initialLookupWorker (lwd <- chan lookupWorkerData , c chan <- LookupEntry , errChan chan <- error , wg * sync.WaitGroup ) {
114+ defer wg .Done ()
115+
113116 for x := range lwd {
114117 le , err := CreateFileLookupEntry (x .subpath , x .output , x .initial )
115118 if err != nil {
@@ -118,7 +121,6 @@ func initialLookupWorker(lwd chan lookupWorkerData, c chan LookupEntry, errChan
118121 }
119122 c <- le
120123 }
121- doneChan <- struct {}{}
122124}
123125
124126func CreateInitialDJAFSManifest (path , output string , filesOnly bool ) (LookupTable , error ) {
@@ -127,16 +129,22 @@ func CreateInitialDJAFSManifest(path, output string, filesOnly bool) (LookupTabl
127129 } else {
128130 output = filepath .Join (output , WorkDir )
129131 }
132+
130133 lt := LookupTable {sorted : false , Entries : EntrySet {}}
131- lookupEntryChan := make (chan LookupEntry , 1 )
132- errChan := make (chan error , 1 )
133- lwdChan := make (chan lookupWorkerData , 1 )
134- doneChan := make (chan struct {}, 1 )
135- threads := runtime .NumCPU ()
136- for i := 0 ; i < threads ; i ++ {
137- go initialLookupWorker (lwdChan , lookupEntryChan , errChan , doneChan )
134+ lookupEntryChan := make (chan LookupEntry , runtime .NumCPU ())
135+ errChan := make (chan error , runtime .NumCPU ())
136+ lwdChan := make (chan lookupWorkerData , runtime .NumCPU ())
137+ var wg sync.WaitGroup
138+
139+ // Start workers
140+ wg .Add (runtime .NumCPU ())
141+ for i := 0 ; i < runtime .NumCPU (); i ++ {
142+ go initialLookupWorker (lwdChan , lookupEntryChan , errChan , & wg )
138143 }
144+
145+ // Start walker
139146 go func () {
147+ defer close (lwdChan )
140148 err := filepath .WalkDir (path , func (subpath string , info os.DirEntry , err error ) error {
141149 if err != nil {
142150 return err
@@ -156,34 +164,44 @@ func CreateInitialDJAFSManifest(path, output string, filesOnly bool) (LookupTabl
156164 if err != nil {
157165 errChan <- err
158166 }
159- close (lwdChan )
160167 }()
161- workLoop:
162- for {
168+
169+ // Process results
170+ go func () {
171+ wg .Wait ()
172+ close (lookupEntryChan )
173+ close (errChan )
174+ }()
175+
176+ var chansClosed bool
177+ for ! chansClosed {
163178 select {
164- case <- doneChan :
165- threads --
166- if threads == 0 {
167- break workLoop
179+ case le , ok := <- lookupEntryChan :
180+ if ! ok {
181+ chansClosed = true
182+ continue
168183 }
169- case le := <- lookupEntryChan :
170184 lt .Entries = append (lt .Entries , le )
171- case errCErr := <- errChan :
185+ case err , ok := <- errChan :
186+ if ! ok {
187+ chansClosed = true
188+ continue
189+ }
172190 switch {
173- case errCErr == nil :
174- case os .IsNotExist (errCErr ):
175- case errors .Is (errCErr , ErrExpectedFile ):
176- case errors .Is (errCErr , ErrUnexpectedSymlink ):
191+ case err == nil :
192+ continue
193+ case errors .Is (err , os .ErrNotExist ):
194+ continue
195+ case errors .Is (err , ErrExpectedFile ):
196+ continue
197+ case errors .Is (err , ErrUnexpectedSymlink ):
198+ continue
177199 default :
178- log .Printf ("error walking path %s: %s" , path , errCErr )
179- return LookupTable {}, errCErr
200+ log .Printf ("error walking path %s: %s" , path , err )
201+ return LookupTable {}, err
180202 }
181203 }
182204 }
183-
184- close (doneChan )
185- close (lookupEntryChan )
186- close (errChan )
187205 sort .Sort (lt .Entries )
188206 return lt , nil
189207}
@@ -311,58 +329,6 @@ func HashPathFromHash(hash string) string {
311329 return fmt .Sprintf ("%d-%05d-%s" , first , second , third )
312330}
313331
314- func HashPathFromHashInitial (hash , workDir string ) string {
315- hInt := colorhash .HashString (hash )
316- hInt = hInt % GlobalModulus
317- first := hInt
318- second := 0
319- third := hash
320-
321- // first, format directory prefix
322- dir := filepath .Join (workDir , fmt .Sprintf ("%05d" , first ))
323- // check to see how many iterables are in that directory
324- des , err := os .ReadDir (dir )
325- // if that directory doesn't exist at all, just return the hash
326- // as there's no need to iterate on a non-existent directory
327- // TODO check for other errors
328- if os .IsNotExist (err ) || err != nil {
329- return fmt .Sprintf ("%05d-%05d-%s" , first , second , third )
330- }
331-
332- // if there are no iterables in that directory, just return the hash
333- if len (des ) == 0 {
334- return fmt .Sprintf ("%05d-%05d-%s" , first , second , third )
335- }
336-
337- // for each of the iterable directories inside of the parent
338- for _ , de := range des {
339- // first make sure it's a directory before any other checks
340- if de .IsDir () {
341- // get the path to the iterable directory
342- iDir := filepath .Join (dir , de .Name ())
343- // get the contents of the iterable directory
344- iDEs , err := os .ReadDir (iDir )
345- // if there's an error, just return the hash
346- if err != nil {
347- return fmt .Sprintf ("%05d-%05d-%s" , first , second , third )
348- }
349- // if there are less than GlobalModulus files in the iterable directory
350- if len (iDEs ) <= GlobalModulus {
351- return fmt .Sprintf ("%05d-%05d-%s" , first , second , third )
352- }
353- // special case: if we've already seen this file, just return the hash
354- maybeFile := filepath .Join (iDir , fmt .Sprintf ("%05d-%05d-%s" , first , second , third ))
355- _ , err = os .Stat (maybeFile )
356- if err != nil {
357- return fmt .Sprintf ("%05d-%05d-%s" , first , second , third )
358- }
359- // otherwise, increment the second counter and try again
360- second ++
361- }
362- }
363- return fmt .Sprintf ("%05d-%05d-%s" , first , second , third )
364- }
365-
366332func WorkspacePrefixFromHashPath (path string ) (string , error ) {
367333 parts := strings .Split (path , "-" )
368334 if len (parts ) < 3 {
0 commit comments