AuthZ Service: Use singleflight group to fetch and build the folder tree (#98299)

* AuthZ Service: Use singleflight group to fetch and build the folder tree

* Change the sfgroup key

* Future proof
eleijonmarck/lbac-for-datasources/integration-tests
Gabriel MABILLE 7 months ago committed by GitHub
parent 24bf337c56
commit 55f8be62a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 68
      pkg/services/authz/rbac/service.go
  2. 2
      pkg/services/authz/rbac/service_test.go

@ -8,6 +8,7 @@ import (
authzv1 "github.com/grafana/authlib/authz/proto/v1"
"github.com/grafana/authlib/claims"
"golang.org/x/sync/singleflight"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/apiserver/pkg/endpoints/request"
@ -49,6 +50,9 @@ type Service struct {
teamCache *localcache.CacheService
basicRoleCache *localcache.CacheService
folderCache *localcache.CacheService
// Deduplication of concurrent requests
sf *singleflight.Group
}
func NewService(sql legacysql.LegacyDatabaseProvider, identityStore legacy.LegacyIdentityStore, logger log.Logger, tracer tracing.Tracer) *Service {
@ -63,6 +67,7 @@ func NewService(sql legacysql.LegacyDatabaseProvider, identityStore legacy.Legac
teamCache: localcache.New(shortCacheTTL, shortCleanupInterval),
basicRoleCache: localcache.New(longCacheTTL, longCleanupInterval),
folderCache: localcache.New(shortCacheTTL, shortCleanupInterval),
sf: new(singleflight.Group),
}
}
@ -339,38 +344,45 @@ func (s *Service) buildFolderTree(ctx context.Context, ns claims.NamespaceInfo)
return cached.(map[string]FolderNode), nil
}
folders, err := s.store.GetFolders(ctx, ns)
if err != nil {
return nil, fmt.Errorf("could not get folders: %w", err)
}
res, err, _ := s.sf.Do(ns.Value+"_buildFolderTree", func() (interface{}, error) {
folders, err := s.store.GetFolders(ctx, ns)
if err != nil {
return nil, fmt.Errorf("could not get folders: %w", err)
}
folderMap := make(map[string]FolderNode, len(folders))
for _, folder := range folders {
if node, has := folderMap[folder.UID]; !has {
folderMap[folder.UID] = FolderNode{
uid: folder.UID,
parentUID: folder.ParentUID,
folderMap := make(map[string]FolderNode, len(folders))
for _, folder := range folders {
if node, has := folderMap[folder.UID]; !has {
folderMap[folder.UID] = FolderNode{
uid: folder.UID,
parentUID: folder.ParentUID,
}
} else {
node.parentUID = folder.ParentUID
folderMap[folder.UID] = node
}
} else {
node.parentUID = folder.ParentUID
folderMap[folder.UID] = node
}
// Register that the parent has this child node
if folder.ParentUID == nil {
continue
}
if parent, has := folderMap[*folder.ParentUID]; has {
parent.childrenUIDs = append(parent.childrenUIDs, folder.UID)
folderMap[*folder.ParentUID] = parent
} else {
folderMap[*folder.ParentUID] = FolderNode{
uid: *folder.ParentUID,
childrenUIDs: []string{folder.UID},
// Register that the parent has this child node
if folder.ParentUID == nil {
continue
}
if parent, has := folderMap[*folder.ParentUID]; has {
parent.childrenUIDs = append(parent.childrenUIDs, folder.UID)
folderMap[*folder.ParentUID] = parent
} else {
folderMap[*folder.ParentUID] = FolderNode{
uid: *folder.ParentUID,
childrenUIDs: []string{folder.UID},
}
}
}
}
s.folderCache.Set(key, folderMap, 0)
s.folderCache.Set(key, folderMap, 0)
return folderMap, nil
})
if err != nil {
return nil, err
}
return folderMap, nil
return res.(map[string]FolderNode), nil
}

@ -8,6 +8,7 @@ import (
"github.com/grafana/authlib/claims"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sync/singleflight"
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
@ -438,6 +439,7 @@ func TestService_buildFolderTree(t *testing.T) {
store: store,
folderCache: cacheService,
logger: log.New("test"),
sf: new(singleflight.Group),
}
tree, err := s.buildFolderTree(ctx, ns)

Loading…
Cancel
Save