Permalink
Browse files

workspace: Split packages into active, history on backend.

Apply the same type of change to list of packages on backend as was recently done on frontend.
  • Loading branch information...
dmitshur committed Dec 15, 2018
1 parent 4bf622d commit c2ed958aa7634ef0c72d551bf7b1f7f75da495e0
Showing with 39 additions and 40 deletions.
  1. +17 −18 cmd/Go-Package-Store/update.go
  2. +22 −22 workspace/workspace.go
@@ -57,7 +57,7 @@ func (u updateWorker) Start() {
func (u updateWorker) run() {
for ur := range u.updateRequests {
c.pipeline.GoPackageList.Lock()
rp, ok := c.pipeline.GoPackageList.List[ur.Root]
rp, ok := c.pipeline.GoPackageList.ByRoot[ur.Root]
c.pipeline.GoPackageList.Unlock()
if !ok {
ur.ResponseChan <- fmt.Errorf("root %q not found", ur.Root)
@@ -70,16 +70,28 @@ func (u updateWorker) run() {

// Mark repo as updating.
c.pipeline.GoPackageList.Lock()
c.pipeline.GoPackageList.List[ur.Root].UpdateState = workspace.Updating
c.pipeline.GoPackageList.ByRoot[ur.Root].UpdateState = workspace.Updating
c.pipeline.GoPackageList.Unlock()

updateError := u.updater.Update(rp.Repo)

if updateError == nil {
// Move down and mark repo as updated.
c.pipeline.GoPackageList.Lock()
moveDown(c.pipeline.GoPackageList.OrderedList, ur.Root)
c.pipeline.GoPackageList.List[ur.Root].UpdateState = workspace.Updated
for i, rp := range c.pipeline.GoPackageList.Active {
if rp.Repo.Root == ur.Root {
// Remove from active.
copy(c.pipeline.GoPackageList.Active[i:], c.pipeline.GoPackageList.Active[i+1:])
c.pipeline.GoPackageList.Active = c.pipeline.GoPackageList.Active[:len(c.pipeline.GoPackageList.Active)-1]

// Mark repo as updated.
rp.UpdateState = workspace.Updated

// Append to history.
c.pipeline.GoPackageList.History = append(c.pipeline.GoPackageList.History, rp)

break
}
}
c.pipeline.GoPackageList.Unlock()
}

@@ -92,16 +104,3 @@ func (u updateWorker) run() {
// get updated, etc.) haphazardly present both in backend and frontend,
// need to think about that. Probably want to unify workspace.RepoPresentation
// and component.RepoPresentation types, maybe. Try it.
// Also probably want to try separating available updates from completed updates.
// That should simplify some logic, and will make it easier to maintain history
// of updates in the future.

// moveDown moves root down the orderedList towards all other updated.
func moveDown(orderedList []*workspace.RepoPresentation, root string) {
var i int
for ; orderedList[i].Repo.Root != root; i++ { // i is the current package about to be updated.
}
for ; i+1 < len(orderedList) && orderedList[i+1].UpdateState != workspace.Updated; i++ {
orderedList[i], orderedList[i+1] = orderedList[i+1], orderedList[i] // Swap the two.
}
}
@@ -17,12 +17,12 @@ import (
)

// GoPackageList is a list of Go packages.
// It's implemented as a slice and map that are kept in sync, with a mutex.
// It's implemented as two slices and map that are kept in sync, with a mutex.
type GoPackageList struct {
// TODO: Merge the List and OrderedList into a single struct to better communicate that it's a single data structure.
sync.Mutex
OrderedList []*RepoPresentation // OrderedList has the same contents as List, but gives it a stable order.
List map[string]*RepoPresentation // Map key is repoRoot.
Active []*RepoPresentation // Active repo presentations, latest at the end.
History []*RepoPresentation // Historical repo presentations, latest at the end.
ByRoot map[string]*RepoPresentation // Map key is repoRoot.
}

// RepoPresentation represents a repository update presentation.
@@ -106,7 +106,7 @@ func NewPipeline(wd string) *Pipeline {

newObserver: make(chan observerRequest),
observers: make(map[chan *RepoPresentation]struct{}),
GoPackageList: &GoPackageList{List: make(map[string]*RepoPresentation)},
GoPackageList: &GoPackageList{ByRoot: make(map[string]*RepoPresentation)},
}

// It is a lot of work to
@@ -330,9 +330,13 @@ Outer:

// Append repoPresentation to current list.
p.GoPackageList.Lock()
p.GoPackageList.OrderedList = append(p.GoPackageList.OrderedList, repoPresentation)
moveUp(p.GoPackageList.OrderedList, repoPresentation)
p.GoPackageList.List[repoPresentation.Repo.Root] = repoPresentation
switch repoPresentation.UpdateState {
case Available, Updating:
p.GoPackageList.Active = append(p.GoPackageList.Active, repoPresentation)
case Updated:
p.GoPackageList.History = append(p.GoPackageList.History, repoPresentation)
}
p.GoPackageList.ByRoot[repoPresentation.Repo.Root] = repoPresentation
p.GoPackageList.Unlock()

// Send new repoPresentation to all existing observers.
@@ -343,8 +347,11 @@ Outer:
// New observer request.
case req := <-p.newObserver:
p.GoPackageList.Lock()
ch := make(chan *RepoPresentation, len(p.GoPackageList.OrderedList))
for _, repoPresentation := range p.GoPackageList.OrderedList {
ch := make(chan *RepoPresentation, len(p.GoPackageList.Active)+len(p.GoPackageList.History))
for _, repoPresentation := range p.GoPackageList.Active {
ch <- repoPresentation
}
for _, repoPresentation := range p.GoPackageList.History {
ch <- repoPresentation
}
p.GoPackageList.Unlock()
@@ -364,8 +371,11 @@ Outer:
// Respond to new observer requests directly.
for req := range p.newObserver {
p.GoPackageList.Lock()
ch := make(chan *RepoPresentation, len(p.GoPackageList.OrderedList))
for _, repoPresentation := range p.GoPackageList.OrderedList {
ch := make(chan *RepoPresentation, len(p.GoPackageList.Active)+len(p.GoPackageList.History))
for _, repoPresentation := range p.GoPackageList.Active {
ch <- repoPresentation
}
for _, repoPresentation := range p.GoPackageList.History {
ch <- repoPresentation
}
p.GoPackageList.Unlock()
@@ -376,16 +386,6 @@ Outer:
}
}

// moveUp moves last entry up the orderedList above all other updated entries, unless rp is already updated.
func moveUp(orderedList []*RepoPresentation, rp *RepoPresentation) {
if rp.UpdateState == Updated {
return
}
for i := len(orderedList) - 1; i-1 >= 0 && orderedList[i-1].UpdateState == Updated; i-- {
orderedList[i], orderedList[i-1] = orderedList[i-1], orderedList[i] // Swap the two.
}
}

// importPathWorker sends unique repositories to phase 2.
func (p *Pipeline) importPathWorker(wg *sync.WaitGroup) {
defer wg.Done()

0 comments on commit c2ed958

Please sign in to comment.