|
|
|
@ -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,6 +344,7 @@ func (s *Service) buildFolderTree(ctx context.Context, ns claims.NamespaceInfo) |
|
|
|
|
return cached.(map[string]FolderNode), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
@ -371,6 +377,12 @@ func (s *Service) buildFolderTree(ctx context.Context, ns claims.NamespaceInfo) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s.folderCache.Set(key, folderMap, 0) |
|
|
|
|
|
|
|
|
|
return folderMap, nil |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return res.(map[string]FolderNode), nil |
|
|
|
|
} |
|
|
|
|