store: fix duplicate paths

A deployment with multiple times the same path would appear repeated in
`LookupDeploymentByPath`.

This change indexes paths as a map rather than a list, thus avoiding the
issue altogether.

Fixes #276

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2021-04-05 14:28:59 -07:00
parent 1ae0ce65e9
commit 5a6a8c0ff6

View File

@ -26,12 +26,17 @@ type Store struct {
l sync.RWMutex l sync.RWMutex
// ID -> Deployment
deployments map[string]*DeploymentState deployments map[string]*DeploymentState
// Various indices for fast lookups // Name -> Deployment
deploymentsByName map[string]*DeploymentState deploymentsByName map[string]*DeploymentState
deploymentsByPath map[string][]*DeploymentState
pathsByDeploymentID map[string][]string // Path -> (ID->Deployment)
deploymentsByPath map[string]map[string]*DeploymentState
// ID -> (Path->{})
pathsByDeploymentID map[string]map[string]struct{}
} }
func NewStore(root string) (*Store, error) { func NewStore(root string) (*Store, error) {
@ -39,8 +44,8 @@ func NewStore(root string) (*Store, error) {
root: root, root: root,
deployments: make(map[string]*DeploymentState), deployments: make(map[string]*DeploymentState),
deploymentsByName: make(map[string]*DeploymentState), deploymentsByName: make(map[string]*DeploymentState),
deploymentsByPath: make(map[string][]*DeploymentState), deploymentsByPath: make(map[string]map[string]*DeploymentState),
pathsByDeploymentID: make(map[string][]string), pathsByDeploymentID: make(map[string]map[string]struct{}),
} }
return store, store.loadAll() return store, store.loadAll()
} }
@ -120,8 +125,15 @@ func (s *Store) indexDeployment(r *DeploymentState) {
if i.Type != InputTypeDir { if i.Type != InputTypeDir {
return return
} }
s.deploymentsByPath[i.Dir.Path] = append(s.deploymentsByPath[i.Dir.Path], r) if s.deploymentsByPath[i.Dir.Path] == nil {
s.pathsByDeploymentID[r.ID] = append(s.pathsByDeploymentID[r.ID], i.Dir.Path) s.deploymentsByPath[i.Dir.Path] = make(map[string]*DeploymentState)
}
s.deploymentsByPath[i.Dir.Path][r.ID] = r
if s.pathsByDeploymentID[r.ID] == nil {
s.pathsByDeploymentID[r.ID] = make(map[string]struct{})
}
s.pathsByDeploymentID[r.ID][i.Dir.Path] = struct{}{}
} }
mapPath(r.PlanSource) mapPath(r.PlanSource)
@ -138,16 +150,8 @@ func (s *Store) deindexDeployment(id string) {
delete(s.deployments, r.ID) delete(s.deployments, r.ID)
delete(s.deploymentsByName, r.Name) delete(s.deploymentsByName, r.Name)
for _, p := range s.pathsByDeploymentID[r.ID] { for p := range s.pathsByDeploymentID[r.ID] {
// Remove this deployments from the path->deployment mapping delete(s.deploymentsByPath[p], r.ID)
deployments := []*DeploymentState{}
for _, d := range s.deploymentsByPath[p] {
if d.ID == r.ID {
continue
}
deployments = append(deployments, d)
}
s.deploymentsByPath[p] = deployments
} }
delete(s.pathsByDeploymentID, r.ID) delete(s.pathsByDeploymentID, r.ID)
} }
@ -217,11 +221,18 @@ func (s *Store) LookupDeploymentByPath(ctx context.Context, path string) ([]*Dep
s.l.RLock() s.l.RLock()
defer s.l.RUnlock() defer s.l.RUnlock()
st, ok := s.deploymentsByPath[path] res := []*DeploymentState{}
deployments, ok := s.deploymentsByPath[path]
if !ok { if !ok {
return []*DeploymentState{}, nil return res, nil
} }
return st, nil
for _, d := range deployments {
res = append(res, d)
}
return res, nil
} }
func (s *Store) ListDeployments(ctx context.Context) ([]*DeploymentState, error) { func (s *Store) ListDeployments(ctx context.Context) ([]*DeploymentState, error) {