dashboard_version.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package sqlstore
  2. import (
  3. "fmt"
  4. "math"
  5. "sort"
  6. "strconv"
  7. "strings"
  8. "github.com/grafana/grafana/pkg/bus"
  9. m "github.com/grafana/grafana/pkg/models"
  10. "github.com/grafana/grafana/pkg/setting"
  11. )
  12. func init() {
  13. bus.AddHandler("sql", GetDashboardVersion)
  14. bus.AddHandler("sql", GetDashboardVersions)
  15. bus.AddHandler("sql", DeleteExpiredVersions)
  16. }
  17. // GetDashboardVersion gets the dashboard version for the given dashboard ID and version number.
  18. func GetDashboardVersion(query *m.GetDashboardVersionQuery) error {
  19. version := m.DashboardVersion{}
  20. has, err := x.Where("dashboard_version.dashboard_id=? AND dashboard_version.version=? AND dashboard.org_id=?", query.DashboardId, query.Version, query.OrgId).
  21. Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`).
  22. Get(&version)
  23. if err != nil {
  24. return err
  25. }
  26. if !has {
  27. return m.ErrDashboardVersionNotFound
  28. }
  29. version.Data.Set("id", version.DashboardId)
  30. query.Result = &version
  31. return nil
  32. }
  33. // GetDashboardVersions gets all dashboard versions for the given dashboard ID.
  34. func GetDashboardVersions(query *m.GetDashboardVersionsQuery) error {
  35. err := x.Table("dashboard_version").
  36. Select(`dashboard_version.id,
  37. dashboard_version.dashboard_id,
  38. dashboard_version.parent_version,
  39. dashboard_version.restored_from,
  40. dashboard_version.version,
  41. dashboard_version.created,
  42. dashboard_version.created_by as created_by_id,
  43. dashboard_version.message,
  44. dashboard_version.data,`+
  45. dialect.Quote("user")+`.login as created_by`).
  46. Join("LEFT", "user", `dashboard_version.created_by = `+dialect.Quote("user")+`.id`).
  47. Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`).
  48. Where("dashboard_version.dashboard_id=? AND dashboard.org_id=?", query.DashboardId, query.OrgId).
  49. OrderBy("dashboard_version.version DESC").
  50. Limit(query.Limit, query.Start).
  51. Find(&query.Result)
  52. if err != nil {
  53. return err
  54. }
  55. if len(query.Result) < 1 {
  56. return m.ErrNoVersionsForDashboardId
  57. }
  58. return nil
  59. }
  60. func DeleteExpiredVersions(cmd *m.DeleteExpiredVersionsCommand) error {
  61. return inTransaction(func(sess *DBSession) error {
  62. var expiredCount int64 = 0
  63. var versions []DashboardVersionExp
  64. // Don't clean up if user set versions_to_keep to 2147483647 (MaxInt32)
  65. if versionsToKeep := setting.DashboardVersionsToKeep; versionsToKeep < math.MaxInt32 {
  66. // Get dashboard ids to clean up
  67. affectedDashboardsQuery := fmt.Sprintf(`SELECT dashboard_id FROM dashboard_version
  68. GROUP BY dashboard_id HAVING COUNT(dashboard_version.id)>%d`, versionsToKeep)
  69. err := x.Table("dashboard_version").
  70. Select("dashboard_version.id, dashboard_version.version, dashboard_version.dashboard_id").
  71. Where(fmt.Sprintf("dashboard_id IN (%s)", affectedDashboardsQuery)).
  72. Find(&versions)
  73. if err != nil {
  74. return err
  75. }
  76. // Keep last versionsToKeep versions and delete other
  77. versionIdsToDelete := getVersionIDsToDelete(versions, versionsToKeep)
  78. versionIdsToDeleteStr := getVersionIDsToDeleteStr(versionIdsToDelete)
  79. deleteExpiredSql := fmt.Sprintf("DELETE FROM dashboard_version WHERE id IN (%v)", strings.Join(versionIdsToDeleteStr, ", "))
  80. expiredResponse, err := x.Exec(deleteExpiredSql)
  81. if err != nil {
  82. return err
  83. }
  84. expiredCount, _ = expiredResponse.RowsAffected()
  85. }
  86. sqlog.Debug("Deleted old/expired dashboard versions", "expired", expiredCount)
  87. return nil
  88. })
  89. }
  90. // Short version of DashboardVersion for getting expired versions
  91. type DashboardVersionExp struct {
  92. Id int64 `json:"id"`
  93. DashboardId int64 `json:"dashboardId"`
  94. Version int `json:"version"`
  95. }
  96. // Implement sort.Interface for []DashboardVersionExp (sort by Version field)
  97. type ByVersion []DashboardVersionExp
  98. func (v ByVersion) Len() int {
  99. return len(v)
  100. }
  101. func (v ByVersion) Swap(i, j int) {
  102. v[i], v[j] = v[j], v[i]
  103. }
  104. func (v ByVersion) Less(i, j int) bool {
  105. return v[i].Version < v[j].Version
  106. }
  107. func getVersionIDsToDelete(versions []DashboardVersionExp, versionsToKeep int) []int64 {
  108. dashboards := make(map[int64][]DashboardVersionExp)
  109. for _, v := range versions {
  110. elem, present := dashboards[v.DashboardId]
  111. if present {
  112. dashboards[v.DashboardId] = append(elem, v)
  113. } else {
  114. dashboards[v.DashboardId] = []DashboardVersionExp{v}
  115. }
  116. }
  117. versionIds := make([]int64, 0)
  118. for dashboard_id, versions := range dashboards {
  119. sort.Sort(sort.Reverse(ByVersion(versions)))
  120. dashboards[dashboard_id] = versions[versionsToKeep:]
  121. for _, ver := range dashboards[dashboard_id] {
  122. versionIds = append(versionIds, ver.Id)
  123. }
  124. }
  125. return versionIds
  126. }
  127. func getVersionIDsToDeleteStr(versionIds []int64) []string {
  128. var versionIdsToDeleteStr []string
  129. for _, versionId := range versionIds {
  130. versionIdsToDeleteStr = append(versionIdsToDeleteStr, strconv.FormatInt(versionId, 10))
  131. }
  132. return versionIdsToDeleteStr
  133. }