mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Folders: Reduce DB queries when counting and deleting resources under folders (#81153)
* Add folder store method for fetching all folder descendants * Modify GetDescendantCounts() to fetch folder descendants at once * Reduce DB calls when counting library panels under dashboard * Reduce DB calls when counting dashboards under folder * Reduce DB calls during folder delete * Modify folder registry to count/delete entities under multiple folders * Reduce DB calls when counting * Reduce DB calls when deleting
This commit is contained in:
committed by
GitHub
parent
0139ac205d
commit
89d3b55bec
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
@@ -188,25 +190,41 @@ func importLibraryPanelsRecursively(c context.Context, service libraryelements.S
|
||||
|
||||
// CountInFolder is a handler for retrieving the number of library panels contained
|
||||
// within a given folder and for a specific organisation.
|
||||
func (lps LibraryPanelService) CountInFolder(ctx context.Context, orgID int64, folderUID string, u identity.Requester) (int64, error) {
|
||||
func (lps LibraryPanelService) CountInFolders(ctx context.Context, orgID int64, folderUIDs []string, u identity.Requester) (int64, error) {
|
||||
if len(folderUIDs) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
var count int64
|
||||
return count, lps.SQLStore.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
folder, err := lps.FolderService.Get(ctx, &folder.GetFolderQuery{UID: &folderUID, OrgID: orgID, SignedInUser: u})
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryPanels).Inc()
|
||||
// the sequential IDs for the respective entries of dashboard and folder tables are different,
|
||||
// so we need to get the folder ID from the dashboard table
|
||||
// TODO: In the future, we should consider adding a folder UID column to the library_element table
|
||||
// and use that instead of the folder ID.
|
||||
s := fmt.Sprintf(`SELECT COUNT(*) FROM library_element
|
||||
WHERE org_id = ? AND folder_id IN (SELECT id FROM dashboard WHERE org_id = ? AND uid IN (%s)) AND kind = ?`, strings.Repeat("?,", len(folderUIDs)-1)+"?")
|
||||
args := make([]interface{}, 0, len(folderUIDs)+2)
|
||||
args = append(args, orgID, orgID)
|
||||
for _, folderUID := range folderUIDs {
|
||||
args = append(args, folderUID)
|
||||
}
|
||||
args = append(args, int64(model.PanelElement))
|
||||
_, err := sess.SQL(s, args...).Get(&count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryPanels).Inc()
|
||||
// nolint:staticcheck
|
||||
q := sess.Table("library_element").Where("org_id = ?", u.GetOrgID()).
|
||||
Where("folder_id = ?", folder.ID).Where("kind = ?", int64(model.PanelElement))
|
||||
count, err = q.Count()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteInFolder deletes the library panels contained in a given folder.
|
||||
func (lps LibraryPanelService) DeleteInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) error {
|
||||
return lps.LibraryElementService.DeleteLibraryElementsInFolder(ctx, user, folderUID)
|
||||
func (lps LibraryPanelService) DeleteInFolders(ctx context.Context, orgID int64, folderUIDs []string, user identity.Requester) error {
|
||||
for _, folderUID := range folderUIDs {
|
||||
if err := lps.LibraryElementService.DeleteLibraryElementsInFolder(ctx, user, folderUID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kind returns the name of the library panel type of entity.
|
||||
|
||||
@@ -326,14 +326,14 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) {
|
||||
|
||||
scenarioWithLibraryPanel(t, "It should return the correct count of library panels in a folder",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
count, err := sc.lps.CountInFolder(context.Background(), sc.user.OrgID, sc.folder.UID, sc.user)
|
||||
count, err := sc.lps.CountInFolders(context.Background(), sc.user.OrgID, []string{sc.folder.UID}, sc.user)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), count)
|
||||
})
|
||||
|
||||
scenarioWithLibraryPanel(t, "It should delete library panels in a folder",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
err := sc.lps.DeleteInFolder(context.Background(), sc.user.OrgID, sc.folder.UID, sc.user)
|
||||
err := sc.lps.DeleteInFolders(context.Background(), sc.user.OrgID, []string{sc.folder.UID}, sc.user)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sc.elementService.GetElement(sc.ctx, sc.user,
|
||||
|
||||
Reference in New Issue
Block a user