in component/file_cache/file_cache.go [1369:1424]
func (fc *FileCache) GetAttr(options internal.GetAttrOptions) (*internal.ObjAttr, error) {
log.Trace("FileCache::GetAttr : %s", options.Name)
// For get attr, there are three different path situations we have to potentially handle.
// 1. Path in storage but not in local cache
// 2. Path not in storage but in local cache (this could happen if we recently created the file [and are currently writing to it]) (also supports immutable containers)
// 3. Path in storage and in local cache (this could result in dirty properties on the service if we recently wrote to the file)
// To cover case 1, get attributes from storage
var exists bool
attrs, err := fc.NextComponent().GetAttr(options)
if err != nil {
if err == syscall.ENOENT || os.IsNotExist(err) {
log.Debug("FileCache::GetAttr : %s does not exist in storage", options.Name)
exists = false
} else {
log.Err("FileCache::GetAttr : Failed to get attr of %s [%s]", options.Name, err.Error())
return &internal.ObjAttr{}, err
}
} else {
exists = true
}
// To cover cases 2 and 3, grab the attributes from the local cache
localPath := filepath.Join(fc.tmpPath, options.Name)
info, err := os.Lstat(localPath)
// All directory operations are guaranteed to be synced with storage so they cannot be in a case 2 or 3 state.
if (err == nil || os.IsExist(err)) && !info.IsDir() {
if exists { // Case 3 (file in storage and in local cache) so update the relevant attributes
// Return from local cache only if file is not under download or deletion
// If file is under download then taking size or mod time from it will be incorrect.
if !fc.fileLocks.Locked(options.Name) {
log.Debug("FileCache::GetAttr : updating %s from local cache", options.Name)
attrs.Size = info.Size()
attrs.Mtime = info.ModTime()
} else {
log.Debug("FileCache::GetAttr : %s is locked, use storage attributes", options.Name)
}
} else { // Case 2 (file only in local cache) so create a new attributes and add them to the storage attributes
if !strings.Contains(localPath, fc.tmpPath) {
// Here if the path is going out of the temp directory then return ENOENT
exists = false
} else {
log.Debug("FileCache::GetAttr : serving %s attr from local cache", options.Name)
exists = true
attrs = newObjAttr(options.Name, info)
}
}
}
if !exists {
return &internal.ObjAttr{}, syscall.ENOENT
}
return attrs, nil
}