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  }