github.com/cs3org/reva/v2@v2.27.7/pkg/storage/cache/stat.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 cache
    20  
    21  import (
    22  	"context"
    23  	"strings"
    24  	"sync"
    25  
    26  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    27  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    28  	"go-micro.dev/v4/store"
    29  	"go.opentelemetry.io/otel"
    30  	"go.opentelemetry.io/otel/attribute"
    31  	semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
    32  	"go.opentelemetry.io/otel/trace"
    33  )
    34  
    35  var tracer trace.Tracer
    36  
    37  func init() {
    38  	tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/cache")
    39  }
    40  
    41  // NewStatCache creates a new StatCache
    42  func NewStatCache(cfg Config) StatCache {
    43  	c := statCache{}
    44  	c.s = getStore(cfg)
    45  	c.database = cfg.Database
    46  	c.table = cfg.Table
    47  	c.ttl = cfg.TTL
    48  	return &c
    49  }
    50  
    51  type statCache struct {
    52  	cacheStore
    53  }
    54  
    55  func (c statCache) RemoveStatContext(ctx context.Context, userID *userpb.UserId, res *provider.ResourceId) {
    56  	_, span := tracer.Start(ctx, "RemoveStatContext")
    57  	defer span.End()
    58  
    59  	span.SetAttributes(semconv.EnduserIDKey.String(userID.GetOpaqueId()))
    60  
    61  	uid := "uid:" + userID.GetOpaqueId()
    62  	sid := ""
    63  	oid := ""
    64  
    65  	if res != nil {
    66  		span.SetAttributes(
    67  			attribute.String("space.id", res.SpaceId),
    68  			attribute.String("node.id", res.OpaqueId),
    69  		)
    70  		sid = "sid:" + res.SpaceId
    71  		oid = "oid:" + res.OpaqueId
    72  	}
    73  
    74  	// TODO currently, invalidating the stat cache is inefficient and should be disabled. Storage providers / drivers can more selectively invalidate stat cache entries.
    75  	// This shotgun invalidation wipes all cache entries for the user, space, and nodeid of a changed resource, which means the stat cache is mostly empty, anyway.
    76  	prefixes := []string{uid, "*" + sid, "*" + oid}
    77  
    78  	wg := sync.WaitGroup{}
    79  	for _, prefix := range prefixes {
    80  		wg.Add(1)
    81  		go func(p string) {
    82  			defer wg.Done()
    83  			keys, _ := c.List(store.ListPrefix(p), store.ListLimit(100))
    84  			for _, key := range keys {
    85  				wg.Add(1)
    86  				go func(k string) {
    87  					defer wg.Done()
    88  					_ = c.Delete(k)
    89  				}(key)
    90  			}
    91  		}(prefix)
    92  	}
    93  
    94  	wg.Wait()
    95  }
    96  
    97  // RemoveStatContext(ctx,  removes a reference from the stat cache
    98  func (c statCache) RemoveStat(userID *userpb.UserId, res *provider.ResourceId) {
    99  	c.RemoveStatContext(context.Background(), userID, res)
   100  }
   101  
   102  // generates a user specific key pointing to ref - used for statcache
   103  // a key looks like: uid:1234-1233!sid:5678-5677!oid:9923-9934!path:/path/to/source
   104  // as you see it adds "uid:"/"sid:"/"oid:" prefixes to the uuids so they can be differentiated
   105  func (c statCache) GetKey(userID *userpb.UserId, ref *provider.Reference, metaDataKeys, fieldMaskPaths []string) string {
   106  	if ref == nil || ref.ResourceId == nil || ref.ResourceId.SpaceId == "" {
   107  		return ""
   108  	}
   109  
   110  	key := strings.Builder{}
   111  	key.WriteString("uid:")
   112  	key.WriteString(userID.GetOpaqueId())
   113  	key.WriteString("!sid:")
   114  	key.WriteString(ref.ResourceId.SpaceId)
   115  	key.WriteString("!oid:")
   116  	key.WriteString(ref.ResourceId.OpaqueId)
   117  	key.WriteString("!path:")
   118  	key.WriteString(ref.Path)
   119  	for _, k := range metaDataKeys {
   120  		key.WriteString("!mdk:")
   121  		key.WriteString(k)
   122  	}
   123  	for _, p := range fieldMaskPaths {
   124  		key.WriteString("!fmp:")
   125  		key.WriteString(p)
   126  	}
   127  
   128  	return key.String()
   129  }