Index: build_scheduler/go/db/cache.go |
diff --git a/build_scheduler/go/db/cache.go b/build_scheduler/go/db/cache.go |
deleted file mode 100644 |
index ac3cd2af8103c44d15ac15c562e7c2608de4e223..0000000000000000000000000000000000000000 |
--- a/build_scheduler/go/db/cache.go |
+++ /dev/null |
@@ -1,244 +0,0 @@ |
-package db |
- |
-import ( |
- "fmt" |
- "sync" |
- "time" |
- |
- "github.com/skia-dev/glog" |
-) |
- |
-type TaskCache interface { |
- |
- // GetTask returns the task with the given ID, or an error if no such task exists. |
- GetTask(string) (*Task, error) |
- |
- // GetTaskForCommit retrieves the task with the given name which ran at the |
- // given commit, or nil if no such task exists. |
- GetTaskForCommit(string, string, string) (*Task, error) |
- |
- // GetTasksForCommits retrieves all tasks which included[1] each of the |
- // given commits. Returns a map whose keys are commit hashes and values are |
- // sub-maps whose keys are task spec names and values are tasks. |
- // |
- // 1) Blamelist calculation is outside the scope of the taskCache, but the |
- // implied assumption here is that there is at most one task for each |
- // task spec which has a given commit in its blamelist. The user is |
- // responsible for inserting tasks into the database so that this invariant |
- // is maintained. Generally, a more recent task will "steal" commits from an |
- // earlier task's blamelist, if the blamelists overlap. There are three |
- // cases to consider: |
- // 1. The newer task ran at a newer commit than the older task. Its |
- // blamelist consists of all commits not covered by the previous task, |
- // and therefore does not overlap with the older task's blamelist. |
- // 2. The newer task ran at the same commit as the older task. Its |
- // blamelist is the same as the previous task's blamelist, and |
- // therefore it "steals" all commits from the previous task, whose |
- // blamelist becomes empty. |
- // 3. The newer task ran at a commit which was in the previous task's |
- // blamelist. Its blamelist consists of the commits in the previous |
- // task's blamelist which it also covered. Those commits move out of |
- // the previous task's blamelist and into the newer task's blamelist. |
- GetTasksForCommits(string, []string) (map[string]map[string]*Task, error) |
- |
- // KnownTaskName returns true iff the given task name has been seen before. |
- KnownTaskName(string, string) bool |
- |
- // UnfinishedTasks returns a list of tasks which were not finished at |
- // the time of the last cache update. |
- UnfinishedTasks() ([]*Task, error) |
- |
- // Update loads new tasks from the database. |
- Update() error |
-} |
- |
-type taskCache struct { |
- db DB |
- // map[repo_name][task_spec_name]bool |
- knownTaskNames map[string]map[string]bool |
- mtx sync.RWMutex |
- queryId string |
- tasks map[string]*Task |
- // map[repo_name][commit_hash][task_spec_name]*Task |
- tasksByCommit map[string]map[string]map[string]*Task |
- timePeriod time.Duration |
- unfinished map[string]*Task |
-} |
- |
-// See documentation for TaskCache interface. |
-func (c *taskCache) GetTask(id string) (*Task, error) { |
- c.mtx.RLock() |
- defer c.mtx.RUnlock() |
- |
- if t, ok := c.tasks[id]; ok { |
- return t.Copy(), nil |
- } |
- return nil, fmt.Errorf("No such task!") |
-} |
- |
-// See documentation for TaskCache interface. |
-func (c *taskCache) GetTasksForCommits(repo string, commits []string) (map[string]map[string]*Task, error) { |
- c.mtx.RLock() |
- defer c.mtx.RUnlock() |
- |
- rv := make(map[string]map[string]*Task, len(commits)) |
- commitMap := c.tasksByCommit[repo] |
- for _, commit := range commits { |
- if tasks, ok := commitMap[commit]; ok { |
- rv[commit] = make(map[string]*Task, len(tasks)) |
- for k, v := range tasks { |
- rv[commit][k] = v.Copy() |
- } |
- } else { |
- rv[commit] = map[string]*Task{} |
- } |
- } |
- return rv, nil |
-} |
- |
-// See documentation for TaskCache interface. |
-func (c *taskCache) KnownTaskName(repo, name string) bool { |
- c.mtx.RLock() |
- defer c.mtx.RUnlock() |
- _, ok := c.knownTaskNames[repo][name] |
- return ok |
-} |
- |
-// See documentation for TaskCache interface. |
-func (c *taskCache) GetTaskForCommit(repo, commit, name string) (*Task, error) { |
- c.mtx.RLock() |
- defer c.mtx.RUnlock() |
- |
- commitMap, ok := c.tasksByCommit[repo] |
- if !ok { |
- return nil, nil |
- } |
- if tasks, ok := commitMap[commit]; ok { |
- if t, ok := tasks[name]; ok { |
- return t.Copy(), nil |
- } |
- } |
- return nil, nil |
-} |
- |
-// See documentation for TaskCache interface. |
-func (c *taskCache) UnfinishedTasks() ([]*Task, error) { |
- c.mtx.RLock() |
- defer c.mtx.RUnlock() |
- |
- rv := make([]*Task, 0, len(c.unfinished)) |
- for _, t := range c.unfinished { |
- rv = append(rv, t.Copy()) |
- } |
- return rv, nil |
-} |
- |
-// update inserts the new/updated tasks into the cache. Assumes the caller |
-// holds a lock. |
-func (c *taskCache) update(tasks []*Task) error { |
- for _, t := range tasks { |
- repo := t.Repo |
- commitMap, ok := c.tasksByCommit[repo] |
- if !ok { |
- commitMap = map[string]map[string]*Task{} |
- c.tasksByCommit[repo] = commitMap |
- } |
- |
- // If we already know about this task, the blamelist might, |
- // have changed, so we need to remove it from tasksByCommit |
- // and re-insert where needed. |
- if old, ok := c.tasks[t.Id]; ok { |
- for _, commit := range old.Commits { |
- delete(commitMap[commit], t.Name) |
- } |
- } |
- |
- // Insert the new task into the main map. |
- cpy := t.Copy() |
- c.tasks[t.Id] = cpy |
- |
- // Insert the task into tasksByCommits. |
- for _, commit := range t.Commits { |
- if _, ok := commitMap[commit]; !ok { |
- commitMap[commit] = map[string]*Task{} |
- } |
- commitMap[commit][t.Name] = cpy |
- } |
- |
- // Unfinished tasks. |
- if _, ok := c.unfinished[t.Id]; ok { |
- delete(c.unfinished, t.Id) |
- } |
- if !t.Done() { |
- c.unfinished[t.Id] = cpy |
- } |
- |
- // Known task names. |
- if nameMap, ok := c.knownTaskNames[repo]; ok { |
- nameMap[t.Name] = true |
- } else { |
- c.knownTaskNames[repo] = map[string]bool{t.Name: true} |
- } |
- } |
- return nil |
-} |
- |
-// reset re-initializes c. Assumes the caller holds a lock. |
-func (c *taskCache) reset() error { |
- c.db.StopTrackingModifiedTasks(c.queryId) |
- queryId, err := c.db.StartTrackingModifiedTasks() |
- if err != nil { |
- return err |
- } |
- now := time.Now() |
- start := now.Add(-c.timePeriod) |
- glog.Infof("Reading Tasks from %s to %s.", start, now) |
- tasks, err := c.db.GetTasksFromDateRange(start, now) |
- if err != nil { |
- c.db.StopTrackingModifiedTasks(queryId) |
- return err |
- } |
- c.knownTaskNames = map[string]map[string]bool{} |
- c.queryId = queryId |
- c.tasks = map[string]*Task{} |
- c.tasksByCommit = map[string]map[string]map[string]*Task{} |
- c.unfinished = map[string]*Task{} |
- if err := c.update(tasks); err != nil { |
- return err |
- } |
- return nil |
-} |
- |
-// See documentation for TaskCache interface. |
-func (c *taskCache) Update() error { |
- newTasks, err := c.db.GetModifiedTasks(c.queryId) |
- c.mtx.Lock() |
- defer c.mtx.Unlock() |
- if IsUnknownId(err) { |
- glog.Warningf("Connection to db lost; re-initializing cache from scratch.") |
- if err := c.reset(); err != nil { |
- return err |
- } |
- return nil |
- } else if err != nil { |
- return err |
- } |
- if err := c.update(newTasks); err == nil { |
- return nil |
- } else { |
- return err |
- } |
-} |
- |
-// NewTaskCache returns a local cache which provides more convenient views of |
-// task data than the database can provide. |
-func NewTaskCache(db DB, timePeriod time.Duration) (TaskCache, error) { |
- tc := &taskCache{ |
- db: db, |
- timePeriod: timePeriod, |
- } |
- if err := tc.reset(); err != nil { |
- return nil, err |
- } |
- return tc, nil |
-} |