Skip to content

Commit

Permalink
feat: parallelism to speed up conflict search
Browse files Browse the repository at this point in the history
  • Loading branch information
letFunny committed Nov 7, 2024
1 parent 7eb8428 commit d958de5
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 21 deletions.
87 changes: 67 additions & 20 deletions internal/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"path"
"path/filepath"
"regexp"
"runtime"
"slices"
"strings"
"sync"

"golang.org/x/crypto/openpgp/packet"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -197,34 +199,60 @@ func (r *Release) validate() error {
}
}

// Check for glob and generate conflicts.
// Check for generate and glob conflicts.
maxInflight := runtime.NumCPU()
sem := NewSemaphore(maxInflight)
canceled := make(chan struct{})
var err error
var errOnce sync.Once
for oldPath, old := range globs {
oldInfo := old.Contents[oldPath]
for newPath, new := range paths {
if oldPath == newPath {
// Identical paths have been filtered earlier. This must be the
// exact same entry.
continue
}
newInfo := new.Contents[newPath]
if oldInfo.Kind == GlobPath && (newInfo.Kind == GlobPath || newInfo.Kind == CopyPath) {
if new.Package == old.Package {
select {
case <-canceled:
// Stop processing on the first failure.
break
default:
}

sem.Down()
go func(oldPath string, old *Slice) {
defer sem.Up()
oldInfo := old.Contents[oldPath]
for newPath, new := range paths {
if oldPath == newPath {
// Identical paths have been filtered earlier. This must be the
// exact same entry.
continue
}
}
if strdist.GlobPath(newPath, oldPath) {
if (old.Package > new.Package) || (old.Package == new.Package && old.Name > new.Name) ||
(old.Package == new.Package && old.Name == new.Name && oldPath > newPath) {
old, new = new, old
oldPath, newPath = newPath, oldPath
newInfo := new.Contents[newPath]
if oldInfo.Kind == GlobPath && (newInfo.Kind == GlobPath || newInfo.Kind == CopyPath) {
if new.Package == old.Package {
continue
}
}
if strdist.GlobPath(newPath, oldPath) {
if (old.Package > new.Package) || (old.Package == new.Package && old.Name > new.Name) ||
(old.Package == new.Package && old.Name == new.Name && oldPath > newPath) {
old, new = new, old
oldPath, newPath = newPath, oldPath
}
errOnce.Do(func() {
err = fmt.Errorf("slices %s and %s conflict on %s and %s", old, new, oldPath, newPath)
close(canceled)
})
}
return fmt.Errorf("slices %s and %s conflict on %s and %s", old, new, oldPath, newPath)
}
}
}(oldPath, old)
}
// Wait for all goroutines to finish.
for i := 0; i < maxInflight; i++ {
sem.Down()
}
if err != nil {
return err
}

// Check for cycles.
_, err := order(r.Packages, keys)
_, err = order(r.Packages, keys)
if err != nil {
return err
}
Expand Down Expand Up @@ -917,3 +945,22 @@ func packageToYAML(p *Package) (*yamlPackage, error) {
}
return pkg, nil
}

type Semaphore struct {
c chan struct{}
}

func NewSemaphore(n int) *Semaphore {
sem := &Semaphore{
c: make(chan struct{}, n),
}
return sem
}

func (sem *Semaphore) Up() {
<-sem.c
}

func (sem *Semaphore) Down() {
sem.c <- struct{}{}
}
2 changes: 1 addition & 1 deletion internal/setup/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ var setupTests = []setupTest{{
/file/foob*r:
`,
},
relerror: `slices mypkg1_myslice and mypkg2_myslice conflict on /file/f\*obar and /file/foob\*r`,
relerror: `slices mypkg1_myslice and mypkg2_myslice conflict on (/file/f\*obar and /file/foob\*r)|(/file/foob\*r and /file/f\*obar)`,
}, {
summary: "Conflicting globs and plain copies",
input: map[string]string{
Expand Down

0 comments on commit d958de5

Please sign in to comment.