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 }