new filterRanges query and Cluster.filterRanges field

This commit is contained in:
Lou Knauer 2021-05-06 08:36:24 +02:00
parent 5c0ada7ec9
commit b6df8e88b9
5 changed files with 734 additions and 293 deletions

View File

@ -59,6 +59,10 @@ models:
fields: fields:
tags: tags:
resolver: true resolver: true
Cluster:
fields:
filterRanges:
resolver: true
JobTag: JobTag:
model: "github.com/ClusterCockpit/cc-jobarchive/graph/model.JobTag" model: "github.com/ClusterCockpit/cc-jobarchive/graph/model.JobTag"
Timestamp: Timestamp:

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,10 @@ import (
"time" "time"
) )
type AddJobInput struct { type FilterRanges struct {
JobID string `json:"jobId"` Duration *IntRangeOutput `json:"duration"`
UserID string `json:"userId"` NumNodes *IntRangeOutput `json:"numNodes"`
ProjectID string `json:"projectId"` StartTime *TimeRangeOutput `json:"startTime"`
ClusterID string `json:"clusterId"`
StartTime time.Time `json:"startTime"`
Duration int `json:"duration"`
NumNodes int `json:"numNodes"`
} }
type FloatRange struct { type FloatRange struct {
@ -34,6 +30,11 @@ type IntRange struct {
To int `json:"to"` To int `json:"to"`
} }
type IntRangeOutput struct {
From int `json:"from"`
To int `json:"to"`
}
type JobFilter struct { type JobFilter struct {
Tags []string `json:"tags"` Tags []string `json:"tags"`
JobID *StringInput `json:"jobId"` JobID *StringInput `json:"jobId"`
@ -110,19 +111,6 @@ type PageRequest struct {
Page *int `json:"page"` Page *int `json:"page"`
} }
type StartJobInput struct {
JobID string `json:"jobId"`
UserID string `json:"userId"`
ProjectID string `json:"projectId"`
ClusterID string `json:"clusterId"`
StartTime time.Time `json:"startTime"`
NumNodes int `json:"numNodes"`
}
type StopJobInput struct {
StopTime time.Time `json:"stopTime"`
}
type StringInput struct { type StringInput struct {
Eq *string `json:"eq"` Eq *string `json:"eq"`
Contains *string `json:"contains"` Contains *string `json:"contains"`
@ -135,6 +123,11 @@ type TimeRange struct {
To time.Time `json:"to"` To time.Time `json:"to"`
} }
type TimeRangeOutput struct {
From time.Time `json:"from"`
To time.Time `json:"to"`
}
type JobMetricScope string type JobMetricScope string
const ( const (

View File

@ -357,34 +357,9 @@ func (r *queryResolver) JobMetrics(
} }
func (r *queryResolver) Tags( func (r *queryResolver) Tags(
ctx context.Context, jobId *string) ([]*model.JobTag, error) { ctx context.Context) ([]*model.JobTag, error) {
if jobId == nil { rows, err := r.DB.Queryx("SELECT * FROM tag")
rows, err := r.DB.Queryx("SELECT * FROM tag")
if err != nil {
return nil, err
}
tags := []*model.JobTag{}
for rows.Next() {
var tag model.JobTag
err = rows.StructScan(&tag)
if err != nil {
return nil, err
}
tags = append(tags, &tag)
}
return tags, nil
}
/* TODO: Use cluster id? */
query := `
SELECT tag.id, tag.tag_name, tag.tag_type FROM tag
JOIN jobtag ON tag.id = jobtag.tag_id
JOIN job ON job.id = jobtag.job_id
WHERE job.job_id = $1
`
rows, err := r.DB.Queryx(query, jobId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -398,10 +373,42 @@ func (r *queryResolver) Tags(
} }
tags = append(tags, &tag) tags = append(tags, &tag)
} }
return tags, nil return tags, nil
} }
func (r *queryResolver) FilterRanges(
ctx context.Context) (*model.FilterRanges, error) {
rows, err := r.DB.Query(`
SELECT MIN(duration), MAX(duration),
MIN(num_nodes), MAX(num_nodes),
MIN(start_time), MAX(start_time) FROM job
`)
defer rows.Close()
if err != nil {
return nil, err
}
if !rows.Next() {
panic("expected exactly one row")
}
duration := &model.IntRangeOutput{};
numNodes := &model.IntRangeOutput{};
var startTimeMin, startTimeMax int64
err = rows.Scan(&duration.From, &duration.To,
&numNodes.From, &numNodes.To,
&startTimeMin, &startTimeMax)
if err != nil {
return nil, err
}
startTime := &model.TimeRangeOutput {
time.Unix(startTimeMin, 0), time.Unix(startTimeMax, 0) }
return &model.FilterRanges{ duration, numNodes, startTime }, nil
}
func (r *jobResolver) Tags(ctx context.Context, job *model.Job) ([]*model.JobTag, error) { func (r *jobResolver) Tags(ctx context.Context, job *model.Job) ([]*model.JobTag, error) {
query := ` query := `
SELECT tag.id, tag.tag_name, tag.tag_type FROM tag SELECT tag.id, tag.tag_name, tag.tag_type FROM tag
@ -426,8 +433,44 @@ func (r *jobResolver) Tags(ctx context.Context, job *model.Job) ([]*model.JobTag
return tags, nil return tags, nil
} }
func (r *Resolver) Job() generated.JobResolver { return &jobResolver{r} } func (r *clusterResolver) FilterRanges(
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } ctx context.Context, cluster *model.Cluster) (*model.FilterRanges, error) {
rows, err := r.DB.Query(`
SELECT MIN(duration), MAX(duration),
MIN(num_nodes), MAX(num_nodes),
MIN(start_time), MAX(start_time)
FROM job WHERE job.cluster_id = $1
`, cluster.ClusterID)
defer rows.Close()
if err != nil {
return nil, err
}
if !rows.Next() {
panic("expected exactly one row")
}
duration := &model.IntRangeOutput{};
numNodes := &model.IntRangeOutput{};
var startTimeMin, startTimeMax int64
err = rows.Scan(&duration.From, &duration.To,
&numNodes.From, &numNodes.To,
&startTimeMin, &startTimeMax)
if err != nil {
return nil, err
}
startTime := &model.TimeRangeOutput {
time.Unix(startTimeMin, 0), time.Unix(startTimeMax, 0) }
return &model.FilterRanges{ duration, numNodes, startTime }, nil
}
func (r *Resolver) Job() generated.JobResolver { return &jobResolver{r} }
func (r *Resolver) Cluster() generated.ClusterResolver { return &clusterResolver{r} }
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
type jobResolver struct{ *Resolver } type jobResolver struct{ *Resolver }
type clusterResolver struct{ *Resolver }
type queryResolver struct{ *Resolver } type queryResolver struct{ *Resolver }

View File

@ -10,11 +10,11 @@ type Job {
numNodes: Int! numNodes: Int!
hasProfile: Boolean! hasProfile: Boolean!
memUsed_max: Float memUsedMax: Float
flopsAny_avg: Float flopsAnyAvg: Float
memBw_avg: Float memBwAvg: Float
netBw_avg: Float netBwAvg: Float
fileBw_avg: Float fileBwAvg: Float
tags: [JobTag!] tags: [JobTag!]
} }
@ -29,6 +29,7 @@ type Cluster {
flopRateSimd: Int! flopRateSimd: Int!
memoryBandwidth: Int! memoryBandwidth: Int!
metricConfig: [MetricConfig!]! metricConfig: [MetricConfig!]!
filterRanges: FilterRanges!
} }
type MetricConfig { type MetricConfig {
@ -80,8 +81,9 @@ type Query {
jobsStatistics(filter: JobFilterList): JobsStatistics! jobsStatistics(filter: JobFilterList): JobsStatistics!
jobMetrics(jobId: String!, clusterId: String, startTime: Time, metrics: [String]): [JobMetricWithName]! jobMetrics(jobId: String!, clusterId: String, startTime: Time, metrics: [String]): [JobMetricWithName]!
# Return all known tags or, if jobId is specified, only tags from this job tags: [JobTag!]!
tags(jobId: String): [JobTag!]!
filterRanges: FilterRanges!
} }
input JobFilterList { input JobFilterList {
@ -100,6 +102,22 @@ input JobFilter {
hasProfile: Boolean hasProfile: Boolean
} }
type IntRangeOutput {
from: Int!
to: Int!
}
type TimeRangeOutput {
from: Time!
to: Time!
}
type FilterRanges {
duration: IntRangeOutput!
numNodes: IntRangeOutput!
startTime: TimeRangeOutput!
}
input OrderByInput { input OrderByInput {
field: String! field: String!
order: SortDirectionEnum = ASC order: SortDirectionEnum = ASC