Skip to content

Commit

Permalink
add named types for all numeric ID columns
Browse files Browse the repository at this point in the history
We already have a lot of `map[int64]Something` and more are coming, so
this was getting quite confusing.
  • Loading branch information
majewsky committed Jan 3, 2024
1 parent 367ba4c commit 09edb6d
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 122 deletions.
6 changes: 3 additions & 3 deletions internal/api/commitment.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ func (p *v1Provider) GetProjectCommitments(w http.ResponseWriter, r *http.Reques
}

//enumerate project services
serviceTypeByID := make(map[int64]string)
serviceTypeByID := make(map[db.ProjectServiceID]string)
query := `SELECT id, type FROM project_services WHERE project_id = $1`
err := sqlext.ForeachRow(p.DB, query, []any{dbProject.ID}, func(rows *sql.Rows) error {
var (
serviceID int64
serviceID db.ProjectServiceID
serviceType string
)
err := rows.Scan(&serviceID, &serviceType)
Expand Down Expand Up @@ -123,7 +123,7 @@ func (p *v1Provider) GetProjectCommitments(w http.ResponseWriter, r *http.Reques
func (p *v1Provider) convertCommitmentToDisplayForm(c db.ProjectCommitment, serviceType string) limesresources.Commitment {
resInfo := p.Cluster.InfoForResource(serviceType, c.ResourceName)
return limesresources.Commitment{
ID: c.ID,
ID: int64(c.ID),
ServiceType: serviceType,
ResourceName: c.ResourceName,
AvailabilityZone: c.AvailabilityZone,
Expand Down
16 changes: 8 additions & 8 deletions internal/collector/capacity_scrape.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@ func (c *Collector) processCapacityScrapeTask(_ context.Context, task capacitySc

//collect mapping of cluster_services type names to IDs
//(these DB entries are maintained for us by checkConsistencyCluster)
serviceIDForType := make(map[string]int64)
serviceTypeForID := make(map[int64]string)
serviceIDForType := make(map[string]db.ClusterServiceID)
serviceTypeForID := make(map[db.ClusterServiceID]string)
err := sqlext.ForeachRow(c.DB, getClusterServicesQuery, nil, func(rows *sql.Rows) error {
var (
serviceID int64
serviceID db.ClusterServiceID
serviceType string
)
err := rows.Scan(&serviceID, &serviceType)
Expand Down Expand Up @@ -207,7 +207,7 @@ func (c *Collector) processCapacityScrapeTask(_ context.Context, task capacitySc
}
}

var wantedResources []db.ResourceRef
var wantedResources []db.ResourceRef[db.ClusterServiceID]
for serviceType, serviceData := range capacityData {
if !c.Cluster.HasService(serviceType) {
logg.Info("discarding capacities reported by %s for unknown service type: %s", capacitor.CapacitorID, serviceType)
Expand All @@ -223,7 +223,7 @@ func (c *Collector) processCapacityScrapeTask(_ context.Context, task capacitySc
logg.Info("discarding capacity reported by %s for unknown resource name: %s/%s", capacitor.CapacitorID, serviceType, resourceName)
continue
}
wantedResources = append(wantedResources, db.ResourceRef{
wantedResources = append(wantedResources, db.ResourceRef[db.ClusterServiceID]{
ServiceID: serviceID,
Name: resourceName,
})
Expand All @@ -232,11 +232,11 @@ func (c *Collector) processCapacityScrapeTask(_ context.Context, task capacitySc
slices.SortFunc(wantedResources, db.CompareResourceRefs) //for deterministic test behavior

//create and delete cluster_resources for this capacitor as needed
setUpdate := db.SetUpdate[db.ClusterResource, db.ResourceRef]{
setUpdate := db.SetUpdate[db.ClusterResource, db.ResourceRef[db.ClusterServiceID]]{
ExistingRecords: dbOwnedResources,
WantedKeys: wantedResources,
KeyForRecord: db.ClusterResource.Ref,
Create: func(ref db.ResourceRef) (db.ClusterResource, error) {
Create: func(ref db.ResourceRef[db.ClusterServiceID]) (db.ClusterResource, error) {
return db.ClusterResource{
ServiceID: ref.ServiceID,
Name: ref.Name,
Expand All @@ -261,7 +261,7 @@ func (c *Collector) processCapacityScrapeTask(_ context.Context, task capacitySc
if err != nil {
return fmt.Errorf("cannot inspect existing cluster AZ resources: %w", err)
}
dbAZResourcesByResourceID := make(map[int64][]db.ClusterAZResource)
dbAZResourcesByResourceID := make(map[db.ClusterResourceID][]db.ClusterAZResource)
for _, azRes := range dbAZResources {
dbAZResourcesByResourceID[azRes.ResourceID] = append(dbAZResourcesByResourceID[azRes.ResourceID], azRes)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/collector/scrape.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func (c *Collector) writeResourceScrapeResult(dbDomain db.Domain, dbProject db.P
if err != nil {
return fmt.Errorf("while reading existing project AZ resources: %w", err)
}
dbAZResourcesByResourceID := make(map[int64][]db.ProjectAZResource, len(resourceUpdateResult.DBResources))
dbAZResourcesByResourceID := make(map[db.ProjectResourceID][]db.ProjectAZResource, len(resourceUpdateResult.DBResources))
for _, azRes := range dbAZResources {
dbAZResourcesByResourceID[azRes.ResourceID] = append(dbAZResourcesByResourceID[azRes.ResourceID], azRes)
}
Expand Down Expand Up @@ -383,7 +383,7 @@ func (c *Collector) writeResourceScrapeResult(dbDomain db.Domain, dbProject db.P
return nil
}

func (c *Collector) writeDummyResources(dbDomain db.Domain, dbProject db.Project, srv db.ProjectServiceRef) error {
func (c *Collector) writeDummyResources(dbDomain db.Domain, dbProject db.Project, srv db.ServiceRef[db.ProjectServiceID]) error {
//Rationale: This is called when we first try to scrape a project service,
//and the scraping fails (most likely due to some internal error in the
//backend service). We used to just not touch the database at this point,
Expand Down
30 changes: 15 additions & 15 deletions internal/datamodel/allocation_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ import (
// - CanConfirmNewCommitment
// - ConfirmPendingCommitments
type clusterAZAllocationStats struct {
Capacity uint64
StatsByProjectServiceID map[int64]projectAZAllocationStats
Capacity uint64
ProjectStats map[db.ProjectServiceID]projectAZAllocationStats
}

func (c clusterAZAllocationStats) FitsAdditionalCommitment(targetProjectServiceID int64, amount uint64) bool {
func (c clusterAZAllocationStats) FitsAdditionalCommitment(serviceID db.ProjectServiceID, amount uint64) bool {
// calculate `sum_over_projects(max(committed, usage))` including the requested commitment
usedCapacity := uint64(0)
for projectServiceID, stats := range c.StatsByProjectServiceID {
if projectServiceID == targetProjectServiceID {
for projectServiceID, stats := range c.ProjectStats {
if projectServiceID == serviceID {
usedCapacity += max(stats.Committed+amount, stats.Usage)
} else {
usedCapacity += max(stats.Committed, stats.Usage)
Expand Down Expand Up @@ -91,7 +91,7 @@ var (
// Shared data collection phase for CanConfirmNewCommitment and ConfirmPendingCommitments.
func collectAZAllocationStats(serviceType, resourceName string, az limes.AvailabilityZone, cluster *core.Cluster, dbi db.Interface, now time.Time) (clusterAZAllocationStats, error) {
result := clusterAZAllocationStats{
StatsByProjectServiceID: make(map[int64]projectAZAllocationStats),
ProjectStats: make(map[db.ProjectServiceID]projectAZAllocationStats),
}

//get raw capacity
Expand All @@ -109,11 +109,11 @@ func collectAZAllocationStats(serviceType, resourceName string, az limes.Availab
//get resource usage
err = sqlext.ForeachRow(dbi, getUsageInAZResourceQuery, queryArgs, func(rows *sql.Rows) error {
var (
projectServiceID int64
stats projectAZAllocationStats
serviceID db.ProjectServiceID
stats projectAZAllocationStats
)
err := rows.Scan(&projectServiceID, &stats.Usage)
result.StatsByProjectServiceID[projectServiceID] = stats
err := rows.Scan(&serviceID, &stats.Usage)
result.ProjectStats[serviceID] = stats
return err
})
if err != nil {
Expand All @@ -124,13 +124,13 @@ func collectAZAllocationStats(serviceType, resourceName string, az limes.Availab
queryArgs = []any{serviceType, resourceName, az, now}
err = sqlext.ForeachRow(dbi, getCommittedInAZResourceQuery, queryArgs, func(rows *sql.Rows) error {
var (
projectServiceID int64
committed uint64
serviceID db.ProjectServiceID
committed uint64
)
err := rows.Scan(&projectServiceID, &committed)
stats := result.StatsByProjectServiceID[projectServiceID]
err := rows.Scan(&serviceID, &committed)
stats := result.ProjectStats[serviceID]
stats.Committed = committed
result.StatsByProjectServiceID[projectServiceID] = stats
result.ProjectStats[serviceID] = stats
return err
})
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/datamodel/apply_backend_quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var (
// This function must be called after each ProjectResourceUpdate.Run(). It is
// not called by Run() because the caller will usually want to commit the DB
// transaction before calling out into the backend.
func ApplyBackendQuota(dbi db.Interface, cluster *core.Cluster, domain core.KeystoneDomain, project db.Project, srv db.ProjectServiceRef) error {
func ApplyBackendQuota(dbi db.Interface, cluster *core.Cluster, domain core.KeystoneDomain, project db.Project, srv db.ServiceRef[db.ProjectServiceID]) error {
plugin := cluster.QuotaPlugins[srv.Type]
if plugin == nil {
return fmt.Errorf("no quota plugin registered for service type %s", srv.Type)
Expand Down
2 changes: 1 addition & 1 deletion internal/datamodel/apply_computed_domain_quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var recomputeDomainQuotaQueryStr = `
// ApplyComputedDomainQuota reevaluates auto-computed domain quotas in the given domain service.
// This is only relevant for resources with non-hierarchical quota distribution, since those resources will have their domain
// quota always set equal to the sum of all respective project quotas.
func ApplyComputedDomainQuota(dbi db.Interface, cluster *core.Cluster, domainID int64, serviceType string) error {
func ApplyComputedDomainQuota(dbi db.Interface, cluster *core.Cluster, domainID db.DomainID, serviceType string) error {
plugin := cluster.QuotaPlugins[serviceType]
if plugin == nil {
return fmt.Errorf("no quota plugin registered for service type %s", serviceType)
Expand Down
10 changes: 5 additions & 5 deletions internal/datamodel/confirm_project_commitments.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func CanConfirmNewCommitment(req limesresources.CommitmentRequest, project db.Pr
if err != nil {
return false, err
}
var serviceID int64
var serviceID db.ProjectServiceID
err = dbi.QueryRow(`SELECT id FROM project_services WHERE project_id = $1 AND type = $2`, project.ID, req.ServiceType).Scan(&serviceID)
if err != nil {
return false, err
Expand All @@ -75,8 +75,8 @@ func ConfirmPendingCommitments(serviceType, resourceName string, az limes.Availa
//load confirmable commitments (we need to load them into a buffer first, since
//lib/pq cannot do UPDATE while a SELECT targeting the same rows is still going)
type confirmableCommitment struct {
ProjectServiceID int64
CommitmentID int64
ProjectServiceID db.ProjectServiceID
CommitmentID db.ProjectCommitmentID
Amount uint64
}
var confirmableCommitments []confirmableCommitment
Expand Down Expand Up @@ -105,8 +105,8 @@ func ConfirmPendingCommitments(serviceType, resourceName string, az limes.Availa
}

//block its allocation from being committed again in this loop
oldStats := stats.StatsByProjectServiceID[c.ProjectServiceID]
stats.StatsByProjectServiceID[c.ProjectServiceID] = projectAZAllocationStats{
oldStats := stats.ProjectStats[c.ProjectServiceID]
stats.ProjectStats[c.ProjectServiceID] = projectAZAllocationStats{
Committed: oldStats.Committed + c.Amount,
Usage: oldStats.Usage,
}
Expand Down
4 changes: 2 additions & 2 deletions internal/datamodel/project_resource_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type ProjectResourceUpdateResult struct {
// caller to update resource data as necessary.
// - Constraints are enforced and other derived fields are recomputed on all
// ProjectResource entries.
func (u ProjectResourceUpdate) Run(dbi db.Interface, cluster *core.Cluster, domain db.Domain, project db.Project, srv db.ProjectServiceRef) (*ProjectResourceUpdateResult, error) {
func (u ProjectResourceUpdate) Run(dbi db.Interface, cluster *core.Cluster, domain db.Domain, project db.Project, srv db.ServiceRef[db.ProjectServiceID]) (*ProjectResourceUpdateResult, error) {
if u.LogError == nil {
u.LogError = logg.Error
}
Expand Down Expand Up @@ -202,7 +202,7 @@ func unwrapOrDefault[T any](value *T, defaultValue T) T {
}

// Ensures that `res` conforms to various constraints and validation rules.
func validateResourceConstraints(domain db.Domain, project db.Project, srv db.ProjectServiceRef, res *db.ProjectResource, resInfo limesresources.ResourceInfo, constraint core.QuotaConstraint) {
func validateResourceConstraints(domain db.Domain, project db.Project, srv db.ServiceRef[db.ProjectServiceID], res *db.ProjectResource, resInfo limesresources.ResourceInfo, constraint core.QuotaConstraint) {
if resInfo.NoQuota {
//ensure that NoQuota resources do not contain any quota values
res.Quota = nil
Expand Down
Loading

0 comments on commit 09edb6d

Please sign in to comment.