github.com/cs3org/reva/v2@v2.27.7/internal/grpc/services/gateway/storageprovidercache.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package gateway
    20  
    21  import (
    22  	"context"
    23  
    24  	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
    25  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    26  	registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
    27  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    28  	sdk "github.com/cs3org/reva/v2/pkg/sdk/common"
    29  	"github.com/cs3org/reva/v2/pkg/storage/cache"
    30  	"github.com/cs3org/reva/v2/pkg/utils"
    31  	"github.com/pkg/errors"
    32  	"google.golang.org/grpc"
    33  )
    34  
    35  /*
    36     Cached Registry
    37  */
    38  
    39  type cachedRegistryClient struct {
    40  	c     registry.RegistryAPIClient
    41  	cache cache.ProviderCache
    42  }
    43  
    44  func (c *cachedRegistryClient) ListStorageProviders(ctx context.Context, in *registry.ListStorageProvidersRequest, opts ...grpc.CallOption) (*registry.ListStorageProvidersResponse, error) {
    45  
    46  	spaceID := sdk.DecodeOpaqueMap(in.Opaque)["space_id"]
    47  
    48  	u, ok := ctxpkg.ContextGetUser(ctx)
    49  	if !ok {
    50  		return nil, errors.New("user not found in context")
    51  	}
    52  
    53  	key := c.cache.GetKey(u.GetId(), spaceID)
    54  	if key != "" {
    55  		s := &registry.ListStorageProvidersResponse{}
    56  		if err := c.cache.PullFromCache(key, s); err == nil {
    57  			return s, nil
    58  		}
    59  	}
    60  
    61  	resp, err := c.c.ListStorageProviders(ctx, in, opts...)
    62  	switch {
    63  	case err != nil:
    64  		return nil, err
    65  	case resp.Status.Code != rpc.Code_CODE_OK:
    66  		return resp, nil
    67  	case spaceID == "":
    68  		return resp, nil
    69  	case spaceID == utils.ShareStorageSpaceID: // TODO do we need to compare providerid and spaceid separately?
    70  		return resp, nil
    71  	default:
    72  		return resp, c.cache.PushToCache(key, resp)
    73  	}
    74  }
    75  
    76  // not cached
    77  
    78  func (c *cachedRegistryClient) GetStorageProviders(ctx context.Context, in *registry.GetStorageProvidersRequest, opts ...grpc.CallOption) (*registry.GetStorageProvidersResponse, error) {
    79  	return c.c.GetStorageProviders(ctx, in, opts...)
    80  }
    81  
    82  func (c *cachedRegistryClient) GetHome(ctx context.Context, in *registry.GetHomeRequest, opts ...grpc.CallOption) (*registry.GetHomeResponse, error) {
    83  	return c.c.GetHome(ctx, in, opts...)
    84  }
    85  
    86  /*
    87     Cached Spaces Provider
    88  */
    89  
    90  type cachedSpacesAPIClient struct {
    91  	c                        provider.SpacesAPIClient
    92  	createPersonalSpaceCache cache.CreatePersonalSpaceCache
    93  }
    94  
    95  // CreateStorageSpace creates a storage space
    96  func (c *cachedSpacesAPIClient) CreateStorageSpace(ctx context.Context, in *provider.CreateStorageSpaceRequest, opts ...grpc.CallOption) (*provider.CreateStorageSpaceResponse, error) {
    97  	if in.Type == "personal" {
    98  		u, ok := ctxpkg.ContextGetUser(ctx)
    99  		if !ok {
   100  			return nil, errors.New("user not found in context")
   101  		}
   102  
   103  		key := c.createPersonalSpaceCache.GetKey(u.GetId())
   104  		if key != "" {
   105  			s := &provider.CreateStorageSpaceResponse{}
   106  			if err := c.createPersonalSpaceCache.PullFromCache(key, s); err == nil {
   107  				return s, nil
   108  			}
   109  		}
   110  		resp, err := c.c.CreateStorageSpace(ctx, in, opts...)
   111  		switch {
   112  		case err != nil:
   113  			return nil, err
   114  		case resp.Status.Code != rpc.Code_CODE_OK && resp.Status.Code != rpc.Code_CODE_ALREADY_EXISTS:
   115  			return resp, nil
   116  		case key == "":
   117  			return resp, nil
   118  		default:
   119  			return resp, c.createPersonalSpaceCache.PushToCache(key, resp)
   120  		}
   121  	}
   122  	return c.c.CreateStorageSpace(ctx, in, opts...)
   123  }
   124  
   125  func (c *cachedSpacesAPIClient) ListStorageSpaces(ctx context.Context, in *provider.ListStorageSpacesRequest, opts ...grpc.CallOption) (*provider.ListStorageSpacesResponse, error) {
   126  	return c.c.ListStorageSpaces(ctx, in, opts...)
   127  }
   128  func (c *cachedSpacesAPIClient) UpdateStorageSpace(ctx context.Context, in *provider.UpdateStorageSpaceRequest, opts ...grpc.CallOption) (*provider.UpdateStorageSpaceResponse, error) {
   129  	return c.c.UpdateStorageSpace(ctx, in, opts...)
   130  }
   131  func (c *cachedSpacesAPIClient) DeleteStorageSpace(ctx context.Context, in *provider.DeleteStorageSpaceRequest, opts ...grpc.CallOption) (*provider.DeleteStorageSpaceResponse, error) {
   132  	return c.c.DeleteStorageSpace(ctx, in, opts...)
   133  }
   134  
   135  /*
   136     Cached Storage Provider
   137  */
   138  
   139  type cachedAPIClient struct {
   140  	c                        provider.ProviderAPIClient
   141  	createPersonalSpaceCache cache.CreatePersonalSpaceCache
   142  }
   143  
   144  // CreateHome caches calls to CreateHome locally - anyways they only need to be called once per user
   145  func (c *cachedAPIClient) CreateHome(ctx context.Context, in *provider.CreateHomeRequest, opts ...grpc.CallOption) (*provider.CreateHomeResponse, error) {
   146  	u, ok := ctxpkg.ContextGetUser(ctx)
   147  	if !ok {
   148  		return nil, errors.New("user not found in context")
   149  	}
   150  
   151  	key := c.createPersonalSpaceCache.GetKey(u.GetId())
   152  	if key != "" {
   153  		s := &provider.CreateHomeResponse{}
   154  		if err := c.createPersonalSpaceCache.PullFromCache(key, s); err == nil {
   155  			return s, nil
   156  		}
   157  	}
   158  	resp, err := c.c.CreateHome(ctx, in, opts...)
   159  	switch {
   160  	case err != nil:
   161  		return nil, err
   162  	case resp.Status.Code != rpc.Code_CODE_OK && resp.Status.Code != rpc.Code_CODE_ALREADY_EXISTS:
   163  		return resp, nil
   164  	case key == "":
   165  		return resp, nil
   166  	default:
   167  		return resp, c.createPersonalSpaceCache.PushToCache(key, resp)
   168  	}
   169  }
   170  
   171  // methods below here are not cached, they just call the client directly
   172  
   173  // Stat returns the Resoure info for a given resource
   174  func (c *cachedAPIClient) Stat(ctx context.Context, in *provider.StatRequest, opts ...grpc.CallOption) (*provider.StatResponse, error) {
   175  	return c.c.Stat(ctx, in, opts...)
   176  }
   177  func (c *cachedAPIClient) AddGrant(ctx context.Context, in *provider.AddGrantRequest, opts ...grpc.CallOption) (*provider.AddGrantResponse, error) {
   178  	return c.c.AddGrant(ctx, in, opts...)
   179  }
   180  func (c *cachedAPIClient) CreateContainer(ctx context.Context, in *provider.CreateContainerRequest, opts ...grpc.CallOption) (*provider.CreateContainerResponse, error) {
   181  	return c.c.CreateContainer(ctx, in, opts...)
   182  }
   183  func (c *cachedAPIClient) Delete(ctx context.Context, in *provider.DeleteRequest, opts ...grpc.CallOption) (*provider.DeleteResponse, error) {
   184  	return c.c.Delete(ctx, in, opts...)
   185  }
   186  func (c *cachedAPIClient) DenyGrant(ctx context.Context, in *provider.DenyGrantRequest, opts ...grpc.CallOption) (*provider.DenyGrantResponse, error) {
   187  	return c.c.DenyGrant(ctx, in, opts...)
   188  }
   189  func (c *cachedAPIClient) GetPath(ctx context.Context, in *provider.GetPathRequest, opts ...grpc.CallOption) (*provider.GetPathResponse, error) {
   190  	return c.c.GetPath(ctx, in, opts...)
   191  }
   192  func (c *cachedAPIClient) GetQuota(ctx context.Context, in *provider.GetQuotaRequest, opts ...grpc.CallOption) (*provider.GetQuotaResponse, error) {
   193  	return c.c.GetQuota(ctx, in, opts...)
   194  }
   195  func (c *cachedAPIClient) InitiateFileDownload(ctx context.Context, in *provider.InitiateFileDownloadRequest, opts ...grpc.CallOption) (*provider.InitiateFileDownloadResponse, error) {
   196  	return c.c.InitiateFileDownload(ctx, in, opts...)
   197  }
   198  func (c *cachedAPIClient) InitiateFileUpload(ctx context.Context, in *provider.InitiateFileUploadRequest, opts ...grpc.CallOption) (*provider.InitiateFileUploadResponse, error) {
   199  	return c.c.InitiateFileUpload(ctx, in, opts...)
   200  }
   201  func (c *cachedAPIClient) ListGrants(ctx context.Context, in *provider.ListGrantsRequest, opts ...grpc.CallOption) (*provider.ListGrantsResponse, error) {
   202  	return c.c.ListGrants(ctx, in, opts...)
   203  }
   204  func (c *cachedAPIClient) ListContainerStream(ctx context.Context, in *provider.ListContainerStreamRequest, opts ...grpc.CallOption) (provider.ProviderAPI_ListContainerStreamClient, error) {
   205  	return c.c.ListContainerStream(ctx, in, opts...)
   206  }
   207  func (c *cachedAPIClient) ListContainer(ctx context.Context, in *provider.ListContainerRequest, opts ...grpc.CallOption) (*provider.ListContainerResponse, error) {
   208  	return c.c.ListContainer(ctx, in, opts...)
   209  }
   210  func (c *cachedAPIClient) ListFileVersions(ctx context.Context, in *provider.ListFileVersionsRequest, opts ...grpc.CallOption) (*provider.ListFileVersionsResponse, error) {
   211  	return c.c.ListFileVersions(ctx, in, opts...)
   212  }
   213  func (c *cachedAPIClient) ListRecycleStream(ctx context.Context, in *provider.ListRecycleStreamRequest, opts ...grpc.CallOption) (provider.ProviderAPI_ListRecycleStreamClient, error) {
   214  	return c.c.ListRecycleStream(ctx, in, opts...)
   215  }
   216  func (c *cachedAPIClient) ListRecycle(ctx context.Context, in *provider.ListRecycleRequest, opts ...grpc.CallOption) (*provider.ListRecycleResponse, error) {
   217  	return c.c.ListRecycle(ctx, in, opts...)
   218  }
   219  func (c *cachedAPIClient) Move(ctx context.Context, in *provider.MoveRequest, opts ...grpc.CallOption) (*provider.MoveResponse, error) {
   220  	return c.c.Move(ctx, in, opts...)
   221  }
   222  func (c *cachedAPIClient) RemoveGrant(ctx context.Context, in *provider.RemoveGrantRequest, opts ...grpc.CallOption) (*provider.RemoveGrantResponse, error) {
   223  	return c.c.RemoveGrant(ctx, in, opts...)
   224  }
   225  func (c *cachedAPIClient) PurgeRecycle(ctx context.Context, in *provider.PurgeRecycleRequest, opts ...grpc.CallOption) (*provider.PurgeRecycleResponse, error) {
   226  	return c.c.PurgeRecycle(ctx, in, opts...)
   227  }
   228  func (c *cachedAPIClient) RestoreFileVersion(ctx context.Context, in *provider.RestoreFileVersionRequest, opts ...grpc.CallOption) (*provider.RestoreFileVersionResponse, error) {
   229  	return c.c.RestoreFileVersion(ctx, in, opts...)
   230  }
   231  func (c *cachedAPIClient) RestoreRecycleItem(ctx context.Context, in *provider.RestoreRecycleItemRequest, opts ...grpc.CallOption) (*provider.RestoreRecycleItemResponse, error) {
   232  	return c.c.RestoreRecycleItem(ctx, in, opts...)
   233  }
   234  func (c *cachedAPIClient) UpdateGrant(ctx context.Context, in *provider.UpdateGrantRequest, opts ...grpc.CallOption) (*provider.UpdateGrantResponse, error) {
   235  	return c.c.UpdateGrant(ctx, in, opts...)
   236  }
   237  func (c *cachedAPIClient) CreateSymlink(ctx context.Context, in *provider.CreateSymlinkRequest, opts ...grpc.CallOption) (*provider.CreateSymlinkResponse, error) {
   238  	return c.c.CreateSymlink(ctx, in, opts...)
   239  }
   240  func (c *cachedAPIClient) CreateReference(ctx context.Context, in *provider.CreateReferenceRequest, opts ...grpc.CallOption) (*provider.CreateReferenceResponse, error) {
   241  	return c.c.CreateReference(ctx, in, opts...)
   242  }
   243  func (c *cachedAPIClient) SetArbitraryMetadata(ctx context.Context, in *provider.SetArbitraryMetadataRequest, opts ...grpc.CallOption) (*provider.SetArbitraryMetadataResponse, error) {
   244  	return c.c.SetArbitraryMetadata(ctx, in, opts...)
   245  }
   246  func (c *cachedAPIClient) UnsetArbitraryMetadata(ctx context.Context, in *provider.UnsetArbitraryMetadataRequest, opts ...grpc.CallOption) (*provider.UnsetArbitraryMetadataResponse, error) {
   247  	return c.c.UnsetArbitraryMetadata(ctx, in, opts...)
   248  }
   249  func (c *cachedAPIClient) SetLock(ctx context.Context, in *provider.SetLockRequest, opts ...grpc.CallOption) (*provider.SetLockResponse, error) {
   250  	return c.c.SetLock(ctx, in, opts...)
   251  }
   252  func (c *cachedAPIClient) GetLock(ctx context.Context, in *provider.GetLockRequest, opts ...grpc.CallOption) (*provider.GetLockResponse, error) {
   253  	return c.c.GetLock(ctx, in, opts...)
   254  }
   255  func (c *cachedAPIClient) RefreshLock(ctx context.Context, in *provider.RefreshLockRequest, opts ...grpc.CallOption) (*provider.RefreshLockResponse, error) {
   256  	return c.c.RefreshLock(ctx, in, opts...)
   257  }
   258  func (c *cachedAPIClient) Unlock(ctx context.Context, in *provider.UnlockRequest, opts ...grpc.CallOption) (*provider.UnlockResponse, error) {
   259  	return c.c.Unlock(ctx, in, opts...)
   260  }
   261  func (c *cachedAPIClient) GetHome(ctx context.Context, in *provider.GetHomeRequest, opts ...grpc.CallOption) (*provider.GetHomeResponse, error) {
   262  	return c.c.GetHome(ctx, in, opts...)
   263  }
   264  func (c *cachedAPIClient) TouchFile(ctx context.Context, in *provider.TouchFileRequest, opts ...grpc.CallOption) (*provider.TouchFileResponse, error) {
   265  	return c.c.TouchFile(ctx, in, opts...)
   266  }