github.com/cs3org/reva/v2@v2.27.7/pkg/storage/cache/cache.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 "fmt" 24 "strings" 25 "sync" 26 "time" 27 28 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 29 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 30 "github.com/cs3org/reva/v2/pkg/store" 31 "github.com/shamaton/msgpack/v2" 32 microstore "go-micro.dev/v4/store" 33 ) 34 35 var ( 36 // DefaultStatCache is the memory store. 37 statCaches = make(map[string]StatCache) 38 providerCaches = make(map[string]ProviderCache) 39 createHomeCaches = make(map[string]CreateHomeCache) 40 createPersonalSpaceCaches = make(map[string]CreatePersonalSpaceCache) 41 fileMetadataCaches = make(map[string]FileMetadataCache) 42 mutex sync.Mutex 43 ) 44 45 // Config contains the configuring for a cache 46 type Config struct { 47 Store string `mapstructure:"cache_store"` 48 Nodes []string `mapstructure:"cache_nodes"` 49 Database string `mapstructure:"cache_database"` 50 Table string `mapstructure:"cache_table"` 51 TTL time.Duration `mapstructure:"cache_ttl"` 52 Size int `mapstructure:"cache_size"` 53 DisablePersistence bool `mapstructure:"cache_disable_persistence"` 54 AuthUsername string `mapstructure:"cache_auth_username"` 55 AuthPassword string `mapstructure:"cache_auth_password"` 56 } 57 58 // Cache handles key value operations on caches 59 // It, and the interfaces derived from it, are currently being used 60 // for building caches around go-micro stores, encoding the data 61 // in the messsagepack format. 62 type Cache interface { 63 PullFromCache(key string, dest interface{}) error 64 PushToCache(key string, src interface{}) error 65 List(opts ...microstore.ListOption) ([]string, error) 66 Delete(key string, opts ...microstore.DeleteOption) error 67 Close() error 68 } 69 70 // StatCache handles removing keys from a stat cache 71 type StatCache interface { 72 Cache 73 RemoveStat(userID *userpb.UserId, res *provider.ResourceId) 74 RemoveStatContext(ctx context.Context, userID *userpb.UserId, res *provider.ResourceId) 75 GetKey(userID *userpb.UserId, ref *provider.Reference, metaDataKeys, fieldMaskPaths []string) string 76 } 77 78 // ProviderCache handles removing keys from a storage provider cache 79 type ProviderCache interface { 80 Cache 81 RemoveListStorageProviders(res *provider.ResourceId) 82 GetKey(userID *userpb.UserId, spaceID string) string 83 } 84 85 // CreateHomeCache handles removing keys from a create home cache 86 type CreateHomeCache interface { 87 Cache 88 RemoveCreateHome(res *provider.ResourceId) 89 GetKey(userID *userpb.UserId) string 90 } 91 92 // CreatePersonalSpaceCache handles removing keys from a create home cache 93 type CreatePersonalSpaceCache interface { 94 Cache 95 GetKey(userID *userpb.UserId) string 96 } 97 98 // FileMetadataCache handles file metadata 99 type FileMetadataCache interface { 100 Cache 101 RemoveMetadata(path string) error 102 } 103 104 // GetStatCache will return an existing StatCache for the given store, nodes, database and table 105 // If it does not exist yet it will be created, different TTLs are ignored 106 func GetStatCache(cfg Config) StatCache { 107 mutex.Lock() 108 defer mutex.Unlock() 109 110 key := strings.Join(append(append([]string{cfg.Store}, cfg.Nodes...), cfg.Database, cfg.Table), ":") 111 if statCaches[key] == nil { 112 statCaches[key] = NewStatCache(cfg) 113 } 114 return statCaches[key] 115 } 116 117 // GetProviderCache will return an existing ProviderCache for the given store, nodes, database and table 118 // If it does not exist yet it will be created, different TTLs are ignored 119 func GetProviderCache(cfg Config) ProviderCache { 120 mutex.Lock() 121 defer mutex.Unlock() 122 123 key := strings.Join(append(append([]string{cfg.Store}, cfg.Nodes...), cfg.Database, cfg.Table), ":") 124 if providerCaches[key] == nil { 125 providerCaches[key] = NewProviderCache(cfg) 126 } 127 return providerCaches[key] 128 } 129 130 // GetCreateHomeCache will return an existing CreateHomeCache for the given store, nodes, database and table 131 // If it does not exist yet it will be created, different TTLs are ignored 132 func GetCreateHomeCache(cfg Config) CreateHomeCache { 133 mutex.Lock() 134 defer mutex.Unlock() 135 136 key := strings.Join(append(append([]string{cfg.Store}, cfg.Nodes...), cfg.Database, cfg.Table), ":") 137 if createHomeCaches[key] == nil { 138 createHomeCaches[key] = NewCreateHomeCache(cfg) 139 } 140 return createHomeCaches[key] 141 } 142 143 // GetCreatePersonalSpaceCache will return an existing CreatePersonalSpaceCache for the given store, nodes, database and table 144 // If it does not exist yet it will be created, different TTLs are ignored 145 func GetCreatePersonalSpaceCache(cfg Config) CreatePersonalSpaceCache { 146 mutex.Lock() 147 defer mutex.Unlock() 148 149 key := strings.Join(append(append([]string{cfg.Store}, cfg.Nodes...), cfg.Database, cfg.Table), ":") 150 if createPersonalSpaceCaches[key] == nil { 151 createPersonalSpaceCaches[key] = NewCreatePersonalSpaceCache(cfg) 152 } 153 return createPersonalSpaceCaches[key] 154 } 155 156 // GetFileMetadataCache will return an existing GetFileMetadataCache for the given store, nodes, database and table 157 // If it does not exist yet it will be created, different TTLs are ignored 158 func GetFileMetadataCache(cfg Config) FileMetadataCache { 159 mutex.Lock() 160 defer mutex.Unlock() 161 162 key := strings.Join(append(append([]string{cfg.Store}, cfg.Nodes...), cfg.Database, cfg.Table), ":") 163 if fileMetadataCaches[key] == nil { 164 fileMetadataCaches[key] = NewFileMetadataCache(cfg) 165 } 166 return fileMetadataCaches[key] 167 } 168 169 // CacheStore holds cache store specific configuration 170 type cacheStore struct { 171 s microstore.Store 172 database, table string 173 ttl time.Duration 174 } 175 176 // PullFromCache pulls a value from the configured database and table of the underlying store using the given key 177 func (cache cacheStore) PullFromCache(key string, dest interface{}) error { 178 r, err := cache.s.Read(key, microstore.ReadFrom(cache.database, cache.table), microstore.ReadLimit(1)) 179 if err != nil { 180 return err 181 } 182 if len(r) == 0 { 183 return fmt.Errorf("not found") 184 } 185 186 return msgpack.Unmarshal(r[0].Value, &dest) 187 } 188 189 // PushToCache pushes a key and value to the configured database and table of the underlying store 190 func (cache cacheStore) PushToCache(key string, src interface{}) error { 191 b, err := msgpack.Marshal(src) 192 if err != nil { 193 return err 194 } 195 196 record := µstore.Record{ 197 Key: key, 198 Value: b, 199 Expiry: cache.ttl, 200 } 201 202 return cache.s.Write( 203 record, 204 microstore.WriteTo(cache.database, cache.table), 205 microstore.WriteTTL(cache.ttl), 206 ) 207 } 208 209 // List lists the keys on the configured database and table of the underlying store 210 func (cache cacheStore) List(opts ...microstore.ListOption) ([]string, error) { 211 o := []microstore.ListOption{ 212 microstore.ListFrom(cache.database, cache.table), 213 } 214 o = append(o, opts...) 215 keys, err := cache.s.List(o...) 216 if err != nil { 217 return nil, err 218 } 219 return keys, nil 220 } 221 222 // Delete deletes the given key on the configured database and table of the underlying store 223 func (cache cacheStore) Delete(key string, opts ...microstore.DeleteOption) error { 224 o := []microstore.DeleteOption{ 225 microstore.DeleteFrom(cache.database, cache.table), 226 } 227 o = append(o, opts...) 228 return cache.s.Delete(key, o...) 229 } 230 231 // Close closes the underlying store 232 func (cache cacheStore) Close() error { 233 return cache.s.Close() 234 } 235 236 func getStore(cfg Config) microstore.Store { 237 return store.Create( 238 store.Store(cfg.Store), 239 microstore.Nodes(cfg.Nodes...), 240 microstore.Database(cfg.Database), 241 microstore.Table(cfg.Table), 242 store.TTL(cfg.TTL), 243 store.Size(cfg.Size), 244 store.DisablePersistence(cfg.DisablePersistence), 245 store.Authentication(cfg.AuthUsername, cfg.AuthPassword), 246 ) 247 }