1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

fix(perf): speed up summary retrieval of all time interval (resolve #336)

This commit is contained in:
Ferdinand Mütsch 2022-03-17 11:08:40 +01:00
parent d1bd7b96b8
commit b763c4acc6
4 changed files with 113 additions and 12 deletions

View File

@ -0,0 +1,56 @@
package migrations
import (
"github.com/emvi/logbuch"
"github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"gorm.io/gorm"
)
func init() {
const name = "20220317-align_num_heartbeats"
f := migrationFunc{
name: name,
f: func(db *gorm.DB, cfg *config.Config) error {
if hasRun(name, db) {
return nil
}
logbuch.Info("this may take a while!")
// find all summaries whose num_heartbeats is zero even though they have items
var faultyIds []uint
if err := db.Model(&models.Summary{}).
Distinct("summaries.id").
Joins("INNER JOIN summary_items ON summaries.num_heartbeats = 0 AND summaries.id = summary_items.summary_id").
Scan(&faultyIds).Error; err != nil {
return err
}
// update their heartbeats counter
result := db.
Table("summaries AS s1").
Where("s1.id IN ?", faultyIds).
Update(
"num_heartbeats",
db.
Model(&models.Heartbeat{}).
Select("COUNT(*)").
Where("user_id = ?", gorm.Expr("s1.user_id")).
Where("time BETWEEN ? AND ?", gorm.Expr("s1.from_time"), gorm.Expr("s1.to_time")),
)
if err := result.Error; err != nil {
return err
}
logbuch.Info("corrected heartbeats counter of %d summaries", result.RowsAffected)
setHasRun(name, db)
return nil
},
}
registerPostMigration(f)
}

View File

@ -101,7 +101,23 @@ func (s *Summary) MappedItems() map[uint8]*SummaryItems {
} }
func (s *Summary) ItemsByType(summaryType uint8) *SummaryItems { func (s *Summary) ItemsByType(summaryType uint8) *SummaryItems {
return s.MappedItems()[summaryType] switch summaryType {
case SummaryProject:
return &s.Projects
case SummaryLanguage:
return &s.Languages
case SummaryEditor:
return &s.Editors
case SummaryOS:
return &s.OperatingSystems
case SummaryMachine:
return &s.Machines
case SummaryLabel:
return &s.Labels
case SummaryBranch:
return &s.Branches
}
return nil
} }
func (s *Summary) KeepOnly(types map[uint8]bool) *Summary { func (s *Summary) KeepOnly(types map[uint8]bool) *Summary {

View File

@ -18,15 +18,15 @@ func (r *SummaryRepository) GetAll() ([]*models.Summary, error) {
var summaries []*models.Summary var summaries []*models.Summary
if err := r.db. if err := r.db.
Order("from_time asc"). Order("from_time asc").
Preload("Projects", "type = ?", models.SummaryProject).
Preload("Languages", "type = ?", models.SummaryLanguage).
Preload("Editors", "type = ?", models.SummaryEditor).
Preload("OperatingSystems", "type = ?", models.SummaryOS).
Preload("Machines", "type = ?", models.SummaryMachine).
// branch summaries are currently not persisted, as only relevant in combination with project filter // branch summaries are currently not persisted, as only relevant in combination with project filter
Find(&summaries).Error; err != nil { Find(&summaries).Error; err != nil {
return nil, err return nil, err
} }
if err := r.populateItems(summaries); err != nil {
return nil, err
}
return summaries, nil return summaries, nil
} }
@ -44,15 +44,15 @@ func (r *SummaryRepository) GetByUserWithin(user *models.User, from, to time.Tim
Where("from_time >= ?", from.Local()). Where("from_time >= ?", from.Local()).
Where("to_time <= ?", to.Local()). Where("to_time <= ?", to.Local()).
Order("from_time asc"). Order("from_time asc").
Preload("Projects", "type = ?", models.SummaryProject).
Preload("Languages", "type = ?", models.SummaryLanguage).
Preload("Editors", "type = ?", models.SummaryEditor).
Preload("OperatingSystems", "type = ?", models.SummaryOS).
Preload("Machines", "type = ?", models.SummaryMachine).
// branch summaries are currently not persisted, as only relevant in combination with project filter // branch summaries are currently not persisted, as only relevant in combination with project filter
Find(&summaries).Error; err != nil { Find(&summaries).Error; err != nil {
return nil, err return nil, err
} }
if err := r.populateItems(summaries); err != nil {
return nil, err
}
return summaries, nil return summaries, nil
} }
@ -74,3 +74,32 @@ func (r *SummaryRepository) DeleteByUser(userId string) error {
} }
return nil return nil
} }
// inplace
func (r *SummaryRepository) populateItems(summaries []*models.Summary) error {
summaryMap := map[uint]*models.Summary{}
summaryIds := make([]uint, len(summaries))
for i, s := range summaries {
if s.NumHeartbeats == 0 {
continue
}
summaryMap[s.ID] = s
summaryIds[i] = s.ID
}
var items []*models.SummaryItem
if err := r.db.
Model(&models.SummaryItem{}).
Where("summary_id in ?", summaryIds).
Find(&items).Error; err != nil {
return err
}
for _, item := range items {
l := summaryMap[item.SummaryID].ItemsByType(item.Type)
*l = append(*l, item)
}
return nil
}

View File

@ -1 +1 @@
2.2.6 2.2.7