Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix public link lookup performance #3866

Merged
merged 4 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/space-registry-path-filtering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Bugfix: Fix public link lookup performance

Fix inefficient path based space lookup for public links

https://github.com/cs3org/reva/pull/3866
5 changes: 5 additions & 0 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ func (s *svc) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSp
// TODO check for allowed filters
filters["mask"] = mask
}
path := utils.ReadPlainFromOpaque(req.Opaque, "path")
if path != "" {
// TODO check for allowed filters
filters["path"] = path
}

for _, f := range req.Filters {
switch f.Type {
Expand Down
42 changes: 37 additions & 5 deletions pkg/storage/registry/spaces/spaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"bytes"
"context"
"encoding/json"
"os"
"path/filepath"
"regexp"
"strconv"
Expand Down Expand Up @@ -534,9 +535,10 @@ func (r *registry) findProvidersForResource(ctx context.Context, id string, find

// findProvidersForAbsolutePathReference takes a path and returns the storage provider with the longest matching path prefix
// FIXME use regex to return the correct provider when multiple are configured
func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, path string, unique, unrestricted bool, _ string) []*registrypb.ProviderInfo {
func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, requestedPath string, unique, unrestricted bool, _ string) []*registrypb.ProviderInfo {
currentUser := ctxpkg.ContextMustGetUser(ctx)

pathSegments := strings.Split(strings.TrimPrefix(requestedPath, string(os.PathSeparator)), string(os.PathSeparator))
deepestMountPath := ""
var deepestMountSpace *providerpb.StorageSpace
var deepestMountPathProvider *registrypb.ProviderInfo
Expand All @@ -549,12 +551,42 @@ func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, pa
var spaces []*providerpb.StorageSpace
var err error

// check if any space in the provider has a valid mountpoint
containsRelatedSpace := false

spaceLoop:
for _, space := range provider.Spaces {
spacePath, _ := space.SpacePath(currentUser, nil)
spacePathSegments := strings.Split(strings.TrimPrefix(spacePath, string(os.PathSeparator)), string(os.PathSeparator))

for i, segment := range spacePathSegments {
if i >= len(pathSegments) {
break
}
if pathSegments[i] != segment {
if segment != "" && !strings.Contains(segment, "{{") {
// Mount path points elsewhere -> irrelevant
continue spaceLoop
}
// Encountered a template which couldn't be filled -> potentially relevant
break
}
}

containsRelatedSpace = true
break
}

if !containsRelatedSpace {
continue
}

// when listing paths also return mountpoints
filters := []*providerpb.ListStorageSpacesRequest_Filter{
{
Type: providerpb.ListStorageSpacesRequest_Filter_TYPE_PATH,
Term: &providerpb.ListStorageSpacesRequest_Filter_Path{
Path: strings.TrimPrefix(path, p.ProviderPath),
Path: strings.TrimPrefix(requestedPath, p.ProviderPath), // FIXME this no longer has an effect as the p.Providerpath is always empty
},
},
{
Expand Down Expand Up @@ -595,14 +627,14 @@ func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, pa

// determine deepest mount point
switch {
case spacePath == path && unique:
case spacePath == requestedPath && unique:
validSpaces = append(validSpaces, space)

deepestMountPath = spacePath
deepestMountSpace = space
deepestMountPathProvider = p

case !unique && isSubpath(spacePath, path):
case !unique && isSubpath(spacePath, requestedPath):
// and add all providers below and exactly matching the path
// requested /foo, mountPath /foo/sub
validSpaces = append(validSpaces, space)
Expand All @@ -612,7 +644,7 @@ func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, pa
deepestMountPathProvider = p
}

case isSubpath(path, spacePath) && len(spacePath) > len(deepestMountPath):
case isSubpath(requestedPath, spacePath) && len(spacePath) > len(deepestMountPath):
// eg. three providers: /foo, /foo/sub, /foo/sub/bar
// requested /foo/sub/mob
deepestMountPath = spacePath
Expand Down