Skip to content

Commit 374d671

Browse files
ishank011root
authored and
root
committed
Enhance storage registry with virtual views and regular expressions. (cs3org#1570)
1 parent 8a74120 commit 374d671

File tree

8 files changed

+212
-123
lines changed

8 files changed

+212
-123
lines changed

Diff for: changelog/unreleased/storage-registry-refactor.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Enhancement: Enhance storage registry with virtual views and regular expressions
2+
3+
Add the functionality to the storage registry service to handle user requests
4+
for references which can span across multiple storage providers, particularly
5+
useful for cases where directories are sharded across providers or virtual views
6+
are expected.
7+
8+
https://github.com/cs3org/cs3apis/pull/116
9+
https://github.com/cs3org/reva/pull/1570

Diff for: go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/cheggaaa/pb v1.0.29
1414
github.com/coreos/go-oidc v2.2.1+incompatible
1515
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e
16-
github.com/cs3org/go-cs3apis v0.0.0-20210316113645-e4a74cb8761c
16+
github.com/cs3org/go-cs3apis v0.0.0-20210322124405-872bbbf14d0b
1717
github.com/dgrijalva/jwt-go v3.2.0+incompatible
1818
github.com/eventials/go-tus v0.0.0-20200718001131-45c7ec8f5d59
1919
github.com/ffurano/grpc-proto v0.0.0-20210312134900-65801a1ca184

Diff for: go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
142142
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
143143
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8=
144144
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
145-
github.com/cs3org/go-cs3apis v0.0.0-20210316113645-e4a74cb8761c h1:2vcWjiaFkJMhMZHeTbkkXWwhhAOTAIKpul8yjAo95UU=
146-
github.com/cs3org/go-cs3apis v0.0.0-20210316113645-e4a74cb8761c/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
145+
github.com/cs3org/go-cs3apis v0.0.0-20210322124405-872bbbf14d0b h1:80DK9Yufaj1YJ0fPb6x1WZfijHWA+CMstq3MEZs/8To=
146+
github.com/cs3org/go-cs3apis v0.0.0-20210322124405-872bbbf14d0b/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
147147
github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA=
148148
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
149149
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=

Diff for: internal/grpc/services/gateway/storageprovider.go

+168-42
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"net/url"
2525
"path"
2626
"strings"
27+
"sync"
2728
"time"
2829

2930
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -35,10 +36,9 @@ import (
3536
"github.com/cs3org/reva/pkg/rgrpc/status"
3637
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
3738
"github.com/cs3org/reva/pkg/storage/utils/etag"
38-
"github.com/cs3org/reva/pkg/storage/utils/templates"
39-
"github.com/cs3org/reva/pkg/user"
4039
"github.com/cs3org/reva/pkg/utils"
4140
"github.com/dgrijalva/jwt-go"
41+
"github.com/google/uuid"
4242
"github.com/pkg/errors"
4343
)
4444

@@ -193,6 +193,7 @@ func (s *svc) getHome(_ context.Context) string {
193193
// TODO(labkode): issue #601, /home will be hardcoded.
194194
return "/home"
195195
}
196+
196197
func (s *svc) InitiateFileDownload(ctx context.Context, req *provider.InitiateFileDownloadRequest) (*gateway.InitiateFileDownloadResponse, error) {
197198
log := appctx.GetLogger(ctx)
198199
p, st := s.getPath(ctx, req.Ref)
@@ -366,6 +367,7 @@ func (s *svc) InitiateFileDownload(ctx context.Context, req *provider.InitiateFi
366367
}
367368

368369
func (s *svc) initiateFileDownload(ctx context.Context, req *provider.InitiateFileDownloadRequest) (*gateway.InitiateFileDownloadResponse, error) {
370+
// TODO(ishank011): enable downloading references spread across storage providers, eg. /eos
369371
c, err := s.find(ctx, req.Ref)
370372
if err != nil {
371373
return &gateway.InitiateFileDownloadResponse{
@@ -857,6 +859,7 @@ func (s *svc) Delete(ctx context.Context, req *provider.DeleteRequest) (*provide
857859
}
858860

859861
func (s *svc) delete(ctx context.Context, req *provider.DeleteRequest) (*provider.DeleteResponse, error) {
862+
// TODO(ishank011): enable deleting references spread across storage providers, eg. /eos
860863
c, err := s.find(ctx, req.Ref)
861864
if err != nil {
862865
return &provider.DeleteResponse{
@@ -974,19 +977,20 @@ func (s *svc) Move(ctx context.Context, req *provider.MoveRequest) (*provider.Mo
974977
}
975978

976979
func (s *svc) move(ctx context.Context, req *provider.MoveRequest) (*provider.MoveResponse, error) {
977-
srcP, err := s.findProvider(ctx, req.Source)
980+
srcList, err := s.findProviders(ctx, req.Source)
978981
if err != nil {
979982
return &provider.MoveResponse{
980983
Status: status.NewStatusFromErrType(ctx, "move src="+req.Source.String(), err),
981984
}, nil
982985
}
983986

984-
dstP, err := s.findProvider(ctx, req.Destination)
987+
dstList, err := s.findProviders(ctx, req.Destination)
985988
if err != nil {
986989
return &provider.MoveResponse{
987990
Status: status.NewStatusFromErrType(ctx, "move dst="+req.Destination.String(), err),
988991
}, nil
989992
}
993+
srcP, dstP := srcList[0], dstList[0]
990994

991995
// if providers are not the same we do not implement cross storage copy yet.
992996
if srcP.Address != dstP.Address {
@@ -1007,6 +1011,7 @@ func (s *svc) move(ctx context.Context, req *provider.MoveRequest) (*provider.Mo
10071011
}
10081012

10091013
func (s *svc) SetArbitraryMetadata(ctx context.Context, req *provider.SetArbitraryMetadataRequest) (*provider.SetArbitraryMetadataResponse, error) {
1014+
// TODO(ishank011): enable for references spread across storage providers, eg. /eos
10101015
c, err := s.find(ctx, req.Ref)
10111016
if err != nil {
10121017
return &provider.SetArbitraryMetadataResponse{
@@ -1023,6 +1028,7 @@ func (s *svc) SetArbitraryMetadata(ctx context.Context, req *provider.SetArbitra
10231028
}
10241029

10251030
func (s *svc) UnsetArbitraryMetadata(ctx context.Context, req *provider.UnsetArbitraryMetadataRequest) (*provider.UnsetArbitraryMetadataResponse, error) {
1031+
// TODO(ishank011): enable for references spread across storage providers, eg. /eos
10261032
c, err := s.find(ctx, req.Ref)
10271033
if err != nil {
10281034
return &provider.UnsetArbitraryMetadataResponse{
@@ -1142,14 +1148,89 @@ func (s *svc) statSharesFolder(ctx context.Context) (*provider.StatResponse, err
11421148
}
11431149

11441150
func (s *svc) stat(ctx context.Context, req *provider.StatRequest) (*provider.StatResponse, error) {
1145-
c, err := s.find(ctx, req.Ref)
1151+
providers, err := s.findProviders(ctx, req.Ref)
11461152
if err != nil {
11471153
return &provider.StatResponse{
1148-
Status: status.NewStatusFromErrType(ctx, "stat ref="+req.Ref.String(), err),
1154+
Status: status.NewStatusFromErrType(ctx, "stat ref: "+req.Ref.String(), err),
11491155
}, nil
11501156
}
11511157

1152-
return c.Stat(ctx, req)
1158+
resPath := req.Ref.GetPath()
1159+
if len(providers) == 1 && (resPath == "" || strings.HasPrefix(resPath, providers[0].ProviderPath)) {
1160+
c, err := s.getStorageProviderClient(ctx, providers[0])
1161+
if err != nil {
1162+
return &provider.StatResponse{
1163+
Status: status.NewInternal(ctx, err, "error connecting to storage provider="+providers[0].Address),
1164+
}, nil
1165+
}
1166+
return c.Stat(ctx, req)
1167+
}
1168+
1169+
infoFromProviders := make([]*provider.ResourceInfo, len(providers))
1170+
errors := make([]error, len(providers))
1171+
var wg sync.WaitGroup
1172+
1173+
for i, p := range providers {
1174+
wg.Add(1)
1175+
go s.statOnProvider(ctx, req, infoFromProviders[i], p, &errors[i], &wg)
1176+
}
1177+
wg.Wait()
1178+
1179+
var totalSize uint64
1180+
for i := range providers {
1181+
if errors[i] != nil {
1182+
return &provider.StatResponse{
1183+
Status: status.NewStatusFromErrType(ctx, "stat ref: "+req.Ref.String(), errors[i]),
1184+
}, nil
1185+
}
1186+
if infoFromProviders[i] != nil {
1187+
totalSize += infoFromProviders[i].Size
1188+
}
1189+
}
1190+
1191+
// TODO(ishank011): aggregrate other properties for references spread across storage providers, eg. /eos
1192+
return &provider.StatResponse{
1193+
Status: status.NewOK(ctx),
1194+
Info: &provider.ResourceInfo{
1195+
Id: &provider.ResourceId{
1196+
StorageId: "/",
1197+
OpaqueId: uuid.New().String(),
1198+
},
1199+
Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER,
1200+
Path: resPath,
1201+
Size: totalSize,
1202+
},
1203+
}, nil
1204+
}
1205+
1206+
func (s *svc) statOnProvider(ctx context.Context, req *provider.StatRequest, res *provider.ResourceInfo, p *registry.ProviderInfo, e *error, wg *sync.WaitGroup) {
1207+
defer wg.Done()
1208+
c, err := s.getStorageProviderClient(ctx, p)
1209+
if err != nil {
1210+
*e = errors.Wrap(err, "error connecting to storage provider="+p.Address)
1211+
return
1212+
}
1213+
1214+
resPath := path.Clean(req.Ref.GetPath())
1215+
newPath := req.Ref.GetPath()
1216+
if resPath != "" && !strings.HasPrefix(resPath, p.ProviderPath) {
1217+
newPath = p.ProviderPath
1218+
}
1219+
r, err := c.Stat(ctx, &provider.StatRequest{
1220+
Ref: &provider.Reference{
1221+
Spec: &provider.Reference_Path{
1222+
Path: newPath,
1223+
},
1224+
},
1225+
})
1226+
if err != nil {
1227+
*e = errors.Wrap(err, "gateway: error calling ListContainer")
1228+
return
1229+
}
1230+
if res == nil {
1231+
res = &provider.ResourceInfo{}
1232+
}
1233+
*res = *r.Info
11531234
}
11541235

11551236
func (s *svc) Stat(ctx context.Context, req *provider.StatRequest) (*provider.StatResponse, error) {
@@ -1454,19 +1535,88 @@ func (s *svc) listSharesFolder(ctx context.Context) (*provider.ListContainerResp
14541535
}
14551536

14561537
func (s *svc) listContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
1457-
c, err := s.find(ctx, req.Ref)
1538+
providers, err := s.findProviders(ctx, req.Ref)
14581539
if err != nil {
14591540
return &provider.ListContainerResponse{
1460-
Status: status.NewStatusFromErrType(ctx, "listContainer ref="+req.Ref.String(), err),
1541+
Status: status.NewStatusFromErrType(ctx, "listContainer ref: "+req.Ref.String(), err),
14611542
}, nil
14621543
}
14631544

1464-
res, err := c.ListContainer(ctx, req)
1545+
resPath := path.Clean(req.Ref.GetPath())
1546+
infoFromProviders := make([][]*provider.ResourceInfo, len(providers))
1547+
errors := make([]error, len(providers))
1548+
var wg sync.WaitGroup
1549+
1550+
for i, p := range providers {
1551+
wg.Add(1)
1552+
go s.listContainerOnProvider(ctx, req, &infoFromProviders[i], p, &errors[i], &wg)
1553+
}
1554+
wg.Wait()
1555+
1556+
infos := []*provider.ResourceInfo{}
1557+
indirects := make(map[string][]*provider.ResourceInfo)
1558+
for i := range providers {
1559+
if errors[i] != nil {
1560+
return &provider.ListContainerResponse{
1561+
Status: status.NewStatusFromErrType(ctx, "listContainer ref: "+req.Ref.String(), errors[i]),
1562+
}, nil
1563+
}
1564+
for _, inf := range infoFromProviders[i] {
1565+
if parent := path.Dir(inf.Path); resPath != "" && resPath != parent {
1566+
parts := strings.Split(strings.TrimPrefix(inf.Path, resPath), "/")
1567+
p := path.Join(resPath, parts[1])
1568+
indirects[p] = append(indirects[p], inf)
1569+
} else {
1570+
infos = append(infos, inf)
1571+
}
1572+
}
1573+
}
1574+
1575+
for k, v := range indirects {
1576+
inf := &provider.ResourceInfo{
1577+
Id: &provider.ResourceId{
1578+
StorageId: "/",
1579+
OpaqueId: uuid.New().String(),
1580+
},
1581+
Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER,
1582+
Etag: etag.GenerateEtagFromResources(nil, v),
1583+
Path: k,
1584+
Size: 0,
1585+
}
1586+
infos = append(infos, inf)
1587+
}
1588+
1589+
return &provider.ListContainerResponse{
1590+
Status: status.NewOK(ctx),
1591+
Infos: infos,
1592+
}, nil
1593+
}
1594+
1595+
func (s *svc) listContainerOnProvider(ctx context.Context, req *provider.ListContainerRequest, res *[]*provider.ResourceInfo, p *registry.ProviderInfo, e *error, wg *sync.WaitGroup) {
1596+
defer wg.Done()
1597+
c, err := s.getStorageProviderClient(ctx, p)
14651598
if err != nil {
1466-
return nil, errors.Wrap(err, "gateway: error calling ListContainer")
1599+
*e = errors.Wrap(err, "error connecting to storage provider="+p.Address)
1600+
return
14671601
}
14681602

1469-
return res, nil
1603+
resPath := path.Clean(req.Ref.GetPath())
1604+
newPath := req.Ref.GetPath()
1605+
if resPath != "" && !strings.HasPrefix(resPath, p.ProviderPath) {
1606+
newPath = p.ProviderPath
1607+
}
1608+
r, err := c.ListContainer(ctx, &provider.ListContainerRequest{
1609+
Ref: &provider.Reference{
1610+
Spec: &provider.Reference_Path{
1611+
Path: newPath,
1612+
},
1613+
},
1614+
})
1615+
if err != nil {
1616+
*e = errors.Wrap(err, "gateway: error calling ListContainer")
1617+
return
1618+
}
1619+
*res = r.Infos
14701620
}
14711621

14721622
func (s *svc) ListContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
@@ -1888,11 +2038,11 @@ func (s *svc) findByPath(ctx context.Context, path string) (provider.ProviderAPI
18882038
}
18892039

18902040
func (s *svc) find(ctx context.Context, ref *provider.Reference) (provider.ProviderAPIClient, error) {
1891-
p, err := s.findProvider(ctx, ref)
2041+
p, err := s.findProviders(ctx, ref)
18922042
if err != nil {
18932043
return nil, err
18942044
}
1895-
return s.getStorageProviderClient(ctx, p)
2045+
return s.getStorageProviderClient(ctx, p[0])
18962046
}
18972047

18982048
func (s *svc) getStorageProviderClient(_ context.Context, p *registry.ProviderInfo) (provider.ProviderAPIClient, error) {
@@ -1905,37 +2055,13 @@ func (s *svc) getStorageProviderClient(_ context.Context, p *registry.ProviderIn
19052055
return c, nil
19062056
}
19072057

1908-
func (s *svc) findProvider(ctx context.Context, ref *provider.Reference) (*registry.ProviderInfo, error) {
1909-
home := s.getHome(ctx)
1910-
if strings.HasPrefix(ref.GetPath(), home) && s.c.HomeMapping != "" {
1911-
if u, ok := user.ContextGetUser(ctx); ok {
1912-
layout := templates.WithUser(u, s.c.HomeMapping)
1913-
newRef := &provider.Reference{
1914-
Spec: &provider.Reference_Path{
1915-
Path: path.Join(layout, strings.TrimPrefix(ref.GetPath(), home)),
1916-
},
1917-
}
1918-
res, err := s.getStorageProvider(ctx, newRef)
1919-
if err != nil {
1920-
// if we get a NotFound error, default to the original reference
1921-
if _, ok := err.(errtypes.IsNotFound); !ok {
1922-
return nil, err
1923-
}
1924-
} else {
1925-
return res, nil
1926-
}
1927-
}
1928-
}
1929-
return s.getStorageProvider(ctx, ref)
1930-
}
1931-
1932-
func (s *svc) getStorageProvider(ctx context.Context, ref *provider.Reference) (*registry.ProviderInfo, error) {
2058+
func (s *svc) findProviders(ctx context.Context, ref *provider.Reference) ([]*registry.ProviderInfo, error) {
19332059
c, err := pool.GetStorageRegistryClient(s.c.StorageRegistryEndpoint)
19342060
if err != nil {
19352061
return nil, errors.Wrap(err, "gateway: error getting storage registry client")
19362062
}
19372063

1938-
res, err := c.GetStorageProvider(ctx, &registry.GetStorageProviderRequest{
2064+
res, err := c.GetStorageProviders(ctx, &registry.GetStorageProvidersRequest{
19392065
Ref: ref,
19402066
})
19412067

@@ -1958,11 +2084,11 @@ func (s *svc) getStorageProvider(ctx context.Context, ref *provider.Reference) (
19582084
}
19592085
}
19602086

1961-
if res.Provider == nil {
2087+
if res.Providers == nil {
19622088
return nil, errors.New("gateway: provider is nil")
19632089
}
19642090

1965-
return res.Provider, nil
2091+
return res.Providers, nil
19662092
}
19672093

19682094
type etagWithTS struct {

0 commit comments

Comments
 (0)