Skip to content

Commit

Permalink
Make ocs resource info cache interoperable across drivers (#2232)
Browse files Browse the repository at this point in the history
  • Loading branch information
ishank011 authored Feb 7, 2022
1 parent 744304d commit 5261583
Show file tree
Hide file tree
Showing 12 changed files with 360 additions and 37 deletions.
3 changes: 3 additions & 0 deletions changelog/unreleased/ocs-cache-drivers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Enhancement: Make ocs resource info cache interoperable across drivers

https://github.com/cs3org/reva/pull/2232
1 change: 1 addition & 0 deletions cmd/revad/runtime/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
_ "github.com/cs3org/reva/pkg/publicshare/manager/loader"
_ "github.com/cs3org/reva/pkg/rhttp/datatx/manager/loader"
_ "github.com/cs3org/reva/pkg/share/cache/loader"
_ "github.com/cs3org/reva/pkg/share/cache/warmup/loader"
_ "github.com/cs3org/reva/pkg/share/manager/loader"
_ "github.com/cs3org/reva/pkg/storage/favorite/loader"
_ "github.com/cs3org/reva/pkg/storage/fs/loader"
Expand Down
35 changes: 16 additions & 19 deletions internal/http/services/owncloud/ocs/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,22 @@ import (

// Config holds the config options that need to be passed down to all ocs handlers
type Config struct {
Prefix string `mapstructure:"prefix"`
Config data.ConfigData `mapstructure:"config"`
Capabilities data.CapabilitiesData `mapstructure:"capabilities"`
GatewaySvc string `mapstructure:"gatewaysvc"`
StorageregistrySvc string `mapstructure:"storage_registry_svc"`
DefaultUploadProtocol string `mapstructure:"default_upload_protocol"`
UserAgentChunkingMap map[string]string `mapstructure:"user_agent_chunking_map"`
SharePrefix string `mapstructure:"share_prefix"`
HomeNamespace string `mapstructure:"home_namespace"`
AdditionalInfoAttribute string `mapstructure:"additional_info_attribute"`
CacheWarmupDriver string `mapstructure:"cache_warmup_driver"`
CacheWarmupDrivers map[string]map[string]interface{} `mapstructure:"cache_warmup_drivers"`
ResourceInfoCacheSize int `mapstructure:"resource_info_cache_size"`
ResourceInfoCacheTTL int `mapstructure:"resource_info_cache_ttl"`
UserIdentifierCacheTTL int `mapstructure:"user_identifier_cache_ttl"`
Prefix string `mapstructure:"prefix"`
Config data.ConfigData `mapstructure:"config"`
Capabilities data.CapabilitiesData `mapstructure:"capabilities"`
GatewaySvc string `mapstructure:"gatewaysvc"`
StorageregistrySvc string `mapstructure:"storage_registry_svc"`
DefaultUploadProtocol string `mapstructure:"default_upload_protocol"`
UserAgentChunkingMap map[string]string `mapstructure:"user_agent_chunking_map"`
SharePrefix string `mapstructure:"share_prefix"`
HomeNamespace string `mapstructure:"home_namespace"`
AdditionalInfoAttribute string `mapstructure:"additional_info_attribute"`
CacheWarmupDriver string `mapstructure:"cache_warmup_driver"`
CacheWarmupDrivers map[string]map[string]interface{} `mapstructure:"cache_warmup_drivers"`
ResourceInfoCacheDriver string `mapstructure:"resource_info_cache_type"`
ResourceInfoCacheTTL int `mapstructure:"resource_info_cache_ttl"`
ResourceInfoCacheDrivers map[string]map[string]interface{} `mapstructure:"resource_info_caches"`
UserIdentifierCacheTTL int `mapstructure:"user_identifier_cache_ttl"`
}

// Init sets sane defaults
Expand All @@ -64,10 +65,6 @@ func (c *Config) Init() {
c.AdditionalInfoAttribute = "{{.Mail}}"
}

if c.ResourceInfoCacheSize == 0 {
c.ResourceInfoCacheSize = 1000000
}

if c.UserIdentifierCacheTTL == 0 {
c.UserIdentifierCacheTTL = 60
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
"github.com/rs/zerolog/log"

"github.com/ReneKroon/ttlcache/v2"
"github.com/bluele/gcache"
"github.com/cs3org/reva/internal/http/services/owncloud/ocdav"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/config"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
Expand All @@ -52,7 +51,8 @@ import (
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/share"
"github.com/cs3org/reva/pkg/share/cache"
"github.com/cs3org/reva/pkg/share/cache/registry"
cachereg "github.com/cs3org/reva/pkg/share/cache/registry"
warmupreg "github.com/cs3org/reva/pkg/share/cache/warmup/registry"
"github.com/cs3org/reva/pkg/utils"
"github.com/cs3org/reva/pkg/utils/resourceid"
"github.com/pkg/errors"
Expand All @@ -71,7 +71,7 @@ type Handler struct {
homeNamespace string
additionalInfoTemplate *template.Template
userIdentifierCache *ttlcache.Cache
resourceInfoCache gcache.Cache
resourceInfoCache cache.ResourceInfoCache
resourceInfoCacheTTL time.Duration
}

Expand All @@ -83,27 +83,38 @@ type userIdentifiers struct {
}

func getCacheWarmupManager(c *config.Config) (cache.Warmup, error) {
if f, ok := registry.NewFuncs[c.CacheWarmupDriver]; ok {
if f, ok := warmupreg.NewFuncs[c.CacheWarmupDriver]; ok {
return f(c.CacheWarmupDrivers[c.CacheWarmupDriver])
}
return nil, fmt.Errorf("driver not found: %s", c.CacheWarmupDriver)
}

func getCacheManager(c *config.Config) (cache.ResourceInfoCache, error) {
if f, ok := cachereg.NewFuncs[c.ResourceInfoCacheDriver]; ok {
return f(c.ResourceInfoCacheDrivers[c.ResourceInfoCacheDriver])
}
return nil, fmt.Errorf("driver not found: %s", c.ResourceInfoCacheDriver)
}

// Init initializes this and any contained handlers
func (h *Handler) Init(c *config.Config) {
h.gatewayAddr = c.GatewaySvc
h.storageRegistryAddr = c.StorageregistrySvc
h.publicURL = c.Config.Host
h.sharePrefix = c.SharePrefix
h.homeNamespace = c.HomeNamespace
h.resourceInfoCache = gcache.New(c.ResourceInfoCacheSize).LFU().Build()
h.resourceInfoCacheTTL = time.Second * time.Duration(c.ResourceInfoCacheTTL)

h.additionalInfoTemplate, _ = template.New("additionalInfo").Parse(c.AdditionalInfoAttribute)
h.resourceInfoCacheTTL = time.Second * time.Duration(c.ResourceInfoCacheTTL)

h.userIdentifierCache = ttlcache.NewCache()
_ = h.userIdentifierCache.SetTTL(time.Second * time.Duration(c.UserIdentifierCacheTTL))

cache, err := getCacheManager(c)
if err == nil {
h.resourceInfoCache = cache
}

if h.resourceInfoCacheTTL > 0 {
cwm, err := getCacheWarmupManager(c)
if err == nil {
Expand Down Expand Up @@ -1039,11 +1050,16 @@ func (h *Handler) getResourceInfo(ctx context.Context, client gateway.GatewayAPI

var pinfo *provider.ResourceInfo
var status *rpc.Status
if infoIf, err := h.resourceInfoCache.Get(key); h.resourceInfoCacheTTL > 0 && err == nil {
logger.Debug().Msgf("cache hit for resource %+v", key)
pinfo = infoIf.(*provider.ResourceInfo)
status = &rpc.Status{Code: rpc.Code_CODE_OK}
} else {
var err error
var foundInCache bool
if h.resourceInfoCacheTTL > 0 && h.resourceInfoCache != nil {
if pinfo, err = h.resourceInfoCache.Get(key); err == nil {
logger.Debug().Msgf("cache hit for resource %+v", key)
status = &rpc.Status{Code: rpc.Code_CODE_OK}
foundInCache = true
}
}
if !foundInCache {
logger.Debug().Msgf("cache miss for resource %+v, statting", key)
statReq := &provider.StatRequest{
Ref: ref,
Expand Down
10 changes: 10 additions & 0 deletions pkg/share/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,20 @@
package cache

import (
"time"

provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
)

// Warmup is the interface to implement cache warmup strategies.
type Warmup interface {
GetResourceInfos() ([]*provider.ResourceInfo, error)
}

// ResourceInfoCache is the interface to implement caches for resource infos
type ResourceInfoCache interface {
Get(key string) (*provider.ResourceInfo, error)
GetKeys(keys []string) ([]*provider.ResourceInfo, error)
Set(key string, info *provider.ResourceInfo) error
SetWithExpire(key string, info *provider.ResourceInfo, expiration time.Duration) error
}
3 changes: 2 additions & 1 deletion pkg/share/cache/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package loader

import (
// Load share cache drivers.
_ "github.com/cs3org/reva/pkg/share/cache/cbox"
_ "github.com/cs3org/reva/pkg/share/cache/memory"
_ "github.com/cs3org/reva/pkg/share/cache/redis"
// Add your own here
)
83 changes: 83 additions & 0 deletions pkg/share/cache/memory/memory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package memory

import (
"time"

"github.com/bluele/gcache"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/share/cache"
"github.com/cs3org/reva/pkg/share/cache/registry"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)

func init() {
registry.Register("memory", New)
}

type config struct {
CacheSize int `mapstructure:"cache_size"`
}

type manager struct {
cache gcache.Cache
}

// New returns an implementation of a resource info cache that stores the objects in memory
func New(m map[string]interface{}) (cache.ResourceInfoCache, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
return nil, errors.Wrap(err, "error decoding conf")
}
if c.CacheSize == 0 {
c.CacheSize = 1000000
}

return &manager{
cache: gcache.New(c.CacheSize).LFU().Build(),
}, nil
}

func (m *manager) Get(key string) (*provider.ResourceInfo, error) {
infoIf, err := m.cache.Get(key)
if err != nil {
return nil, err
}
return infoIf.(*provider.ResourceInfo), nil
}

func (m *manager) GetKeys(keys []string) ([]*provider.ResourceInfo, error) {
infos := make([]*provider.ResourceInfo, len(keys))
for i, key := range keys {
if infoIf, err := m.cache.Get(key); err == nil {
infos[i] = infoIf.(*provider.ResourceInfo)
}
}
return infos, nil
}

func (m *manager) Set(key string, info *provider.ResourceInfo) error {
return m.cache.Set(key, info)
}

func (m *manager) SetWithExpire(key string, info *provider.ResourceInfo, expiration time.Duration) error {
return m.cache.SetWithExpire(key, info, expiration)
}
Loading

0 comments on commit 5261583

Please sign in to comment.