X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7000c1ebd170001e10807b583a29e9e7e9570b23..0f5b0542513b572959e39400bae42e69aeb1a7b6:/sdk/go/arvados/fs_base.go diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go index bebb74261e..274d207022 100644 --- a/sdk/go/arvados/fs_base.go +++ b/sdk/go/arvados/fs_base.go @@ -234,6 +234,14 @@ type fileinfo struct { mode os.FileMode size int64 modTime time.Time + // If not nil, sys() returns the source data structure, which + // can be a *Collection, *Group, or nil. Currently populated + // only for project dirs and top-level collection dirs. Does + // not stay up to date with upstream changes. + // + // Intended to support keep-web's properties-as-s3-metadata + // feature (https://dev.arvados.org/issues/19088). + sys func() interface{} } // Name implements os.FileInfo. @@ -261,9 +269,12 @@ func (fi fileinfo) Size() int64 { return fi.size } -// Sys implements os.FileInfo. +// Sys implements os.FileInfo. See comment in fileinfo struct. func (fi fileinfo) Sys() interface{} { - return nil + if fi.sys == nil { + return nil + } + return fi.sys() } type nullnode struct{} @@ -409,13 +420,23 @@ func (n *treenode) Sync() error { } func (n *treenode) MemorySize() (size int64) { + // To avoid making other callers wait while we count the + // entire filesystem size, we lock the node only long enough + // to copy the list of children. We accept that the resulting + // size will sometimes be misleading (e.g., we will + // double-count an item that moves from A to B after we check + // A's size but before we check B's size). n.RLock() - defer n.RUnlock() debugPanicIfNotLocked(n, false) + todo := make([]inode, 0, len(n.inodes)) for _, inode := range n.inodes { + todo = append(todo, inode) + } + n.RUnlock() + for _, inode := range todo { size += inode.MemorySize() } - return + return 64 + size } type fileSystem struct { @@ -620,7 +641,15 @@ func (fs *fileSystem) Rename(oldname, newname string) error { } locked := map[sync.Locker]bool{} for i := len(needLock) - 1; i >= 0; i-- { - if n := needLock[i]; !locked[n] { + n := needLock[i] + if fs, ok := n.(interface{ rootnode() inode }); ok { + // Lock the fs's root dir directly, not + // through the fs. Otherwise our "locked" map + // would not reliably prevent double-locking + // the fs's root dir. + n = fs.rootnode() + } + if !locked[n] { n.Lock() defer n.Unlock() locked[n] = true