github.com/cyverse/go-irodsclient@v0.13.2/fs/cache.go (about) 1 package fs 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/cyverse/go-irodsclient/irods/types" 9 "github.com/cyverse/go-irodsclient/irods/util" 10 gocache "github.com/patrickmn/go-cache" 11 ) 12 13 // MetadataCacheTimeoutSetting defines cache timeout for path 14 type MetadataCacheTimeoutSetting struct { 15 Path string 16 Timeout time.Duration 17 Inherit bool 18 } 19 20 // FileSystemCache manages filesystem caches 21 type FileSystemCache struct { 22 cacheTimeout time.Duration 23 cleanupTimeout time.Duration 24 cacheTimeoutPaths []MetadataCacheTimeoutSetting 25 cacheTimeoutPathMap map[string]MetadataCacheTimeoutSetting 26 invalidateParentEntryCacheImmediately bool 27 entryCache *gocache.Cache 28 negativeEntryCache *gocache.Cache 29 dirCache *gocache.Cache 30 metadataCache *gocache.Cache 31 groupUsersCache *gocache.Cache 32 userGroupsCache *gocache.Cache 33 groupsCache *gocache.Cache 34 usersCache *gocache.Cache 35 aclCache *gocache.Cache 36 } 37 38 // NewFileSystemCache creates a new FileSystemCache 39 func NewFileSystemCache(cacheTimeout time.Duration, cleanup time.Duration, cacheTimeoutSettings []MetadataCacheTimeoutSetting, invalidateParentEntryCacheImmediately bool) *FileSystemCache { 40 entryCache := gocache.New(cacheTimeout, cleanup) 41 negativeEntryCache := gocache.New(cacheTimeout, cleanup) 42 dirCache := gocache.New(cacheTimeout, cleanup) 43 metadataCache := gocache.New(cacheTimeout, cleanup) 44 groupUsersCache := gocache.New(cacheTimeout, cleanup) 45 userGroupsCache := gocache.New(cacheTimeout, cleanup) 46 groupsCache := gocache.New(cacheTimeout, cleanup) 47 usersCache := gocache.New(cacheTimeout, cleanup) 48 aclCache := gocache.New(cacheTimeout, cleanup) 49 50 if cacheTimeoutSettings == nil { 51 cacheTimeoutSettings = []MetadataCacheTimeoutSetting{} 52 } 53 54 // build a map for quick search 55 cacheTimeoutSettingMap := map[string]MetadataCacheTimeoutSetting{} 56 for _, timeoutSetting := range cacheTimeoutSettings { 57 cacheTimeoutSettingMap[timeoutSetting.Path] = timeoutSetting 58 } 59 60 return &FileSystemCache{ 61 cacheTimeout: cacheTimeout, 62 cleanupTimeout: cleanup, 63 cacheTimeoutPaths: cacheTimeoutSettings, 64 cacheTimeoutPathMap: cacheTimeoutSettingMap, 65 invalidateParentEntryCacheImmediately: invalidateParentEntryCacheImmediately, 66 entryCache: entryCache, 67 negativeEntryCache: negativeEntryCache, 68 dirCache: dirCache, 69 metadataCache: metadataCache, 70 groupUsersCache: groupUsersCache, 71 userGroupsCache: userGroupsCache, 72 groupsCache: groupsCache, 73 usersCache: usersCache, 74 aclCache: aclCache, 75 } 76 } 77 78 func (cache *FileSystemCache) getCacheTTLForPath(path string) time.Duration { 79 if len(cache.cacheTimeoutPathMap) == 0 { 80 // no data 81 return 0 82 } 83 84 // check map first 85 if timeoutSetting, ok := cache.cacheTimeoutPathMap[path]; ok { 86 // exact match 87 return timeoutSetting.Timeout 88 } 89 90 // check inherit 91 parentPaths := util.GetParentIRODSDirs(path) 92 for i := len(parentPaths) - 1; i >= 0; i-- { 93 parentPath := parentPaths[i] 94 95 if timeoutSetting, ok := cache.cacheTimeoutPathMap[parentPath]; ok { 96 // parent match 97 if timeoutSetting.Inherit { 98 // inherit 99 return timeoutSetting.Timeout 100 } 101 } 102 } 103 104 // use default 105 return 0 106 } 107 108 // AddEntryCache adds an entry cache 109 func (cache *FileSystemCache) AddEntryCache(entry *Entry) { 110 ttl := cache.getCacheTTLForPath(entry.Path) 111 cache.entryCache.Set(entry.Path, entry, ttl) 112 } 113 114 // RemoveEntryCache removes an entry cache 115 func (cache *FileSystemCache) RemoveEntryCache(path string) { 116 cache.entryCache.Delete(path) 117 } 118 119 // RemoveParentDirCache removes an entry cache for the parent path of the given path 120 func (cache *FileSystemCache) RemoveParentDirCache(path string) { 121 if cache.invalidateParentEntryCacheImmediately { 122 parentPath := util.GetIRODSPathDirname(path) 123 cache.entryCache.Delete(parentPath) 124 } 125 } 126 127 // GetEntryCache retrieves an entry cache 128 func (cache *FileSystemCache) GetEntryCache(path string) *Entry { 129 if entry, exist := cache.entryCache.Get(path); exist { 130 if fsentry, ok := entry.(*Entry); ok { 131 return fsentry 132 } 133 } 134 return nil 135 } 136 137 // ClearEntryCache clears all entry caches 138 func (cache *FileSystemCache) ClearEntryCache() { 139 cache.entryCache.Flush() 140 } 141 142 // AddNegativeEntryCache adds a negative entry cache 143 func (cache *FileSystemCache) AddNegativeEntryCache(path string) { 144 ttl := cache.getCacheTTLForPath(path) 145 cache.negativeEntryCache.Set(path, true, ttl) 146 } 147 148 // RemoveNegativeEntryCache removes a negative entry cache 149 func (cache *FileSystemCache) RemoveNegativeEntryCache(path string) { 150 cache.negativeEntryCache.Delete(path) 151 } 152 153 // RemoveAllNegativeEntryCacheForPath removes all negative entry caches 154 func (cache *FileSystemCache) RemoveAllNegativeEntryCacheForPath(path string) { 155 prefix := fmt.Sprintf("%s/", path) 156 deleteKey := []string{} 157 for k := range cache.negativeEntryCache.Items() { 158 if k == path || strings.HasPrefix(k, prefix) { 159 deleteKey = append(deleteKey, k) 160 } 161 } 162 163 for _, k := range deleteKey { 164 cache.negativeEntryCache.Delete(k) 165 } 166 } 167 168 // HasNegativeEntryCache checks the existence of a negative entry cache 169 func (cache *FileSystemCache) HasNegativeEntryCache(path string) bool { 170 if exist, existOk := cache.negativeEntryCache.Get(path); existOk { 171 if bexist, ok := exist.(bool); ok { 172 return bexist 173 } 174 } 175 return false 176 } 177 178 // ClearNegativeEntryCache clears all negative entry caches 179 func (cache *FileSystemCache) ClearNegativeEntryCache() { 180 cache.negativeEntryCache.Flush() 181 } 182 183 // AddDirCache adds a dir cache 184 func (cache *FileSystemCache) AddDirCache(path string, entries []string) { 185 ttl := cache.getCacheTTLForPath(path) 186 cache.dirCache.Set(path, entries, ttl) 187 } 188 189 // RemoveDirCache removes a dir cache 190 func (cache *FileSystemCache) RemoveDirCache(path string) { 191 cache.dirCache.Delete(path) 192 } 193 194 // GetDirCache retrives a dir cache 195 func (cache *FileSystemCache) GetDirCache(path string) []string { 196 data, exist := cache.dirCache.Get(path) 197 if exist { 198 if entries, ok := data.([]string); ok { 199 return entries 200 } 201 } 202 return nil 203 } 204 205 // ClearDirCache clears all dir caches 206 func (cache *FileSystemCache) ClearDirCache() { 207 cache.dirCache.Flush() 208 } 209 210 // AddMetadataCache adds a metadata cache 211 func (cache *FileSystemCache) AddMetadataCache(path string, metas []*types.IRODSMeta) { 212 ttl := cache.getCacheTTLForPath(path) 213 cache.metadataCache.Set(path, metas, ttl) 214 } 215 216 // RemoveMetadataCache removes a metadata cache 217 func (cache *FileSystemCache) RemoveMetadataCache(path string) { 218 cache.metadataCache.Delete(path) 219 } 220 221 // GetMetadataCache retrieves a metadata cache 222 func (cache *FileSystemCache) GetMetadataCache(path string) []*types.IRODSMeta { 223 data, exist := cache.metadataCache.Get(path) 224 if exist { 225 if metas, ok := data.([]*types.IRODSMeta); ok { 226 return metas 227 } 228 } 229 return nil 230 } 231 232 // ClearMetadataCache clears all metadata caches 233 func (cache *FileSystemCache) ClearMetadataCache() { 234 cache.metadataCache.Flush() 235 } 236 237 // AddGroupUsersCache adds a group user (users in a group) cache 238 func (cache *FileSystemCache) AddGroupUsersCache(group string, users []*types.IRODSUser) { 239 cache.groupUsersCache.Set(group, users, 0) 240 } 241 242 // RemoveGroupUsersCache removes a group user (users in a group) cache 243 func (cache *FileSystemCache) RemoveGroupUsersCache(group string) { 244 cache.groupUsersCache.Delete(group) 245 } 246 247 // GetGroupUsersCache retrives a group user (users in a group) cache 248 func (cache *FileSystemCache) GetGroupUsersCache(group string) []*types.IRODSUser { 249 users, exist := cache.groupUsersCache.Get(group) 250 if exist { 251 if irodsUsers, ok := users.([]*types.IRODSUser); ok { 252 return irodsUsers 253 } 254 } 255 return nil 256 } 257 258 // AddUserGroupsCache adds a user's groups (groups that a user belongs to) cache 259 func (cache *FileSystemCache) AddUserGroupsCache(user string, groups []*types.IRODSUser) { 260 cache.userGroupsCache.Set(user, groups, 0) 261 } 262 263 // RemoveUserGroupsCache removes a user's groups (groups that a user belongs to) cache 264 func (cache *FileSystemCache) RemoveUserGroupsCache(user string) { 265 cache.userGroupsCache.Delete(user) 266 } 267 268 // GetUserGroupsCache retrives a user's groups (groups that a user belongs to) cache 269 func (cache *FileSystemCache) GetUserGroupsCache(user string) []*types.IRODSUser { 270 groups, exist := cache.userGroupsCache.Get(user) 271 if exist { 272 if irodsGroups, ok := groups.([]*types.IRODSUser); ok { 273 return irodsGroups 274 } 275 } 276 return nil 277 } 278 279 // AddGroupsCache adds a groups cache (cache of a list of all groups) 280 func (cache *FileSystemCache) AddGroupsCache(groups []*types.IRODSUser) { 281 cache.groupsCache.Set("groups", groups, 0) 282 } 283 284 // RemoveGroupsCache removes a groups cache (cache of a list of all groups) 285 func (cache *FileSystemCache) RemoveGroupsCache() { 286 cache.groupsCache.Delete("groups") 287 } 288 289 // GetGroupsCache retrives a groups cache (cache of a list of all groups) 290 func (cache *FileSystemCache) GetGroupsCache() []*types.IRODSUser { 291 groups, exist := cache.groupsCache.Get("groups") 292 if exist { 293 if irodsGroups, ok := groups.([]*types.IRODSUser); ok { 294 return irodsGroups 295 } 296 } 297 return nil 298 } 299 300 // AddUsersCache adds a users cache (cache of a list of all users) 301 func (cache *FileSystemCache) AddUsersCache(users []*types.IRODSUser) { 302 cache.usersCache.Set("users", users, 0) 303 } 304 305 // RemoveUsersCache removes a users cache (cache of a list of all users) 306 func (cache *FileSystemCache) RemoveUsersCache() { 307 cache.usersCache.Delete("users") 308 } 309 310 // GetUsersCache retrives a users cache (cache of a list of all users) 311 func (cache *FileSystemCache) GetUsersCache() []*types.IRODSUser { 312 users, exist := cache.usersCache.Get("users") 313 if exist { 314 if irodsUsers, ok := users.([]*types.IRODSUser); ok { 315 return irodsUsers 316 } 317 } 318 return nil 319 } 320 321 // AddACLsCache adds a ACLs cache 322 func (cache *FileSystemCache) AddACLsCache(path string, accesses []*types.IRODSAccess) { 323 ttl := cache.getCacheTTLForPath(path) 324 cache.aclCache.Set(path, accesses, ttl) 325 } 326 327 // AddACLsCacheMulti adds multiple ACLs caches 328 func (cache *FileSystemCache) AddACLsCacheMulti(accesses []*types.IRODSAccess) { 329 m := map[string][]*types.IRODSAccess{} 330 331 for _, access := range accesses { 332 if existingAccesses, ok := m[access.Path]; ok { 333 // has it, add 334 existingAccesses = append(existingAccesses, access) 335 m[access.Path] = existingAccesses 336 } else { 337 // create it 338 m[access.Path] = []*types.IRODSAccess{access} 339 } 340 } 341 342 for path, access := range m { 343 ttl := cache.getCacheTTLForPath(path) 344 cache.aclCache.Set(path, access, ttl) 345 } 346 } 347 348 // RemoveACLsCache removes a ACLs cache 349 func (cache *FileSystemCache) RemoveACLsCache(path string) { 350 cache.aclCache.Delete(path) 351 } 352 353 // GetACLsCache retrives a ACLs cache 354 func (cache *FileSystemCache) GetACLsCache(path string) []*types.IRODSAccess { 355 data, exist := cache.aclCache.Get(path) 356 if exist { 357 if entries, ok := data.([]*types.IRODSAccess); ok { 358 return entries 359 } 360 } 361 return nil 362 } 363 364 // ClearACLsCache clears all ACLs caches 365 func (cache *FileSystemCache) ClearACLsCache() { 366 cache.aclCache.Flush() 367 }