blob: f51d4c7e5634a269019189c1a6937d05a9fe8ff3 [file] [log] [blame]
// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package scheduler
import (
"infra/qscheduler/qslib/protos/metrics"
"infra/qscheduler/qslib/tutils"
"sort"
)
// Snapshot represents the scheduler state at a specified timestamp.
type Snapshot struct {
Accounts []*metrics.Account
Tasks []*metrics.Task
Workers []*metrics.Worker
}
func (s *state) snapshot(poolID string) *Snapshot {
return &Snapshot{
s.accountSnapshot(poolID),
s.taskSnapshot(poolID),
s.workerSnapshot(poolID),
}
}
func (s *state) accountSnapshot(PoolID string) []*metrics.Account {
accounts := make([]*metrics.Account, 0, len(s.balances))
for aid, bal := range s.balances {
bCopy := bal
accounts = append(accounts, &metrics.Account{
Id: &metrics.Account_ID{Name: string(aid)},
Pool: &metrics.Pool{Id: PoolID},
Balance: bCopy[:],
SnapshotTime: tutils.TimestampProto(s.lastUpdateTime),
})
}
return sortAccountByID(accounts)
}
func (s *state) taskSnapshot(PoolID string) []*metrics.Task {
tasks := make([]*metrics.Task, 0, len(s.queuedRequests)+len(s.workers))
for _, rq := range s.queuedRequests {
tasks = append(tasks, &metrics.Task{
Id: &metrics.Task_ID{Name: string(rq.ID)},
Pool: &metrics.Pool{Id: string(PoolID)},
AccountId: &metrics.Account_ID{Name: string(rq.AccountID)},
WorkerId: &metrics.Worker_ID{Name: ""},
BaseLabels: sortLabels(rq.BaseLabels),
ProvisionableLabels: sortLabels(rq.ProvisionableLabels),
SnapshotTime: tutils.TimestampProto(s.lastUpdateTime),
})
}
for _, w := range s.workers {
if !w.IsIdle() {
rq := w.runningTask.request
tasks = append(tasks, &metrics.Task{
Id: &metrics.Task_ID{Name: string(rq.ID)},
Pool: &metrics.Pool{Id: string(PoolID)},
AccountId: &metrics.Account_ID{Name: string(rq.AccountID)},
WorkerId: &metrics.Worker_ID{Name: string(w.ID)},
BaseLabels: sortLabels(rq.BaseLabels),
ProvisionableLabels: sortLabels(rq.ProvisionableLabels),
SnapshotTime: tutils.TimestampProto(s.lastUpdateTime),
})
}
}
return sortTaskByID(tasks)
}
func (s *state) workerSnapshot(PoolID string) []*metrics.Worker {
workers := make([]*metrics.Worker, 0, len(s.workers))
for _, w := range s.workers {
taskID := ""
if !w.IsIdle() {
taskID = string(w.runningTask.request.ID)
}
workers = append(workers, &metrics.Worker{
Id: &metrics.Worker_ID{Name: string(w.ID)},
Pool: &metrics.Pool{Id: string(PoolID)},
TaskId: &metrics.Task_ID{Name: taskID},
Labels: sortLabels(w.Labels.ToSlice()),
SnapshotTime: tutils.TimestampProto(s.lastUpdateTime),
})
}
return sortWorkerByID(workers)
}
func sortAccountByID(accounts []*metrics.Account) []*metrics.Account {
sort.Slice(accounts, func(i, j int) bool {
return accounts[i].GetId().GetName() < accounts[j].GetId().GetName()
})
return accounts
}
func sortTaskByID(tasks []*metrics.Task) []*metrics.Task {
sort.Slice(tasks, func(i, j int) bool {
return tasks[i].GetId().GetName() < tasks[j].GetId().GetName()
})
return tasks
}
func sortWorkerByID(workers []*metrics.Worker) []*metrics.Worker {
sort.Slice(workers, func(i, j int) bool {
return workers[i].GetId().GetName() < workers[j].GetId().GetName()
})
return workers
}
// A wrapper to sort labels.
func sortLabels(labels []string) []string {
sort.Strings(labels)
return labels
}