X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/16f704326f44fd1e5e5e60b936c9b5895d6a6ff8..c502c5a50aae825683ee4cff629c6839a4209501:/sdk/go/arvados/fs_site.go?ds=sidebyside diff --git a/sdk/go/arvados/fs_site.go b/sdk/go/arvados/fs_site.go index 82114e2ea9..0a561f667a 100644 --- a/sdk/go/arvados/fs_site.go +++ b/sdk/go/arvados/fs_site.go @@ -16,14 +16,18 @@ type CustomFileSystem interface { MountByID(mount string) MountProject(mount, uuid string) MountUsers(mount string) + ForwardSlashNameSubstitution(string) } type customFileSystem struct { fileSystem root *vdirnode + thr *throttle staleThreshold time.Time staleLock sync.Mutex + + forwardSlashNameSubstitution string } func (c *Client) CustomFileSystem(kc keepClient) CustomFileSystem { @@ -33,9 +37,10 @@ func (c *Client) CustomFileSystem(kc keepClient) CustomFileSystem { fileSystem: fileSystem{ fsBackend: keepBackend{apiClient: c, keepClient: kc}, root: root, + thr: newThrottle(concurrentWriters), }, } - root.inode = &treenode{ + root.treenode = treenode{ fs: fs, parent: root, fileinfo: fileinfo{ @@ -49,9 +54,11 @@ func (c *Client) CustomFileSystem(kc keepClient) CustomFileSystem { } func (fs *customFileSystem) MountByID(mount string) { - fs.root.inode.Child(mount, func(inode) (inode, error) { + fs.root.treenode.Lock() + defer fs.root.treenode.Unlock() + fs.root.treenode.Child(mount, func(inode) (inode, error) { return &vdirnode{ - inode: &treenode{ + treenode: treenode{ fs: fs, parent: fs.root, inodes: make(map[string]inode), @@ -67,18 +74,22 @@ func (fs *customFileSystem) MountByID(mount string) { } func (fs *customFileSystem) MountProject(mount, uuid string) { - fs.root.inode.Child(mount, func(inode) (inode, error) { - return fs.newProjectNode(fs.root, mount, uuid), nil + fs.root.treenode.Lock() + defer fs.root.treenode.Unlock() + fs.root.treenode.Child(mount, func(inode) (inode, error) { + return fs.newProjectNode(fs.root, mount, uuid, nil), nil }) } func (fs *customFileSystem) MountUsers(mount string) { - fs.root.inode.Child(mount, func(inode) (inode, error) { + fs.root.treenode.Lock() + defer fs.root.treenode.Unlock() + fs.root.treenode.Child(mount, func(inode) (inode, error) { return &lookupnode{ stale: fs.Stale, loadOne: fs.usersLoadOne, loadAll: fs.usersLoadAll, - inode: &treenode{ + treenode: treenode{ fs: fs, parent: fs.root, inodes: make(map[string]inode), @@ -92,6 +103,10 @@ func (fs *customFileSystem) MountUsers(mount string) { }) } +func (fs *customFileSystem) ForwardSlashNameSubstitution(repl string) { + fs.forwardSlashNameSubstitution = repl +} + // SiteFileSystem returns a FileSystem that maps collections and other // Arvados objects onto a filesystem layout. // @@ -106,10 +121,7 @@ func (c *Client) SiteFileSystem(kc keepClient) CustomFileSystem { } func (fs *customFileSystem) Sync() error { - fs.staleLock.Lock() - defer fs.staleLock.Unlock() - fs.staleThreshold = time.Now() - return nil + return fs.root.Sync() } // Stale returns true if information obtained at time t should be @@ -128,7 +140,7 @@ func (fs *customFileSystem) mountByID(parent inode, id string) inode { if strings.Contains(id, "-4zz18-") || pdhRegexp.MatchString(id) { return fs.mountCollection(parent, id) } else if strings.Contains(id, "-j7d0g-") { - return fs.newProjectNode(fs.root, id, id) + return fs.newProjectNode(fs.root, id, id, nil) } else { return nil } @@ -140,21 +152,21 @@ func (fs *customFileSystem) mountCollection(parent inode, id string) inode { if err != nil { return nil } - cfs, err := coll.FileSystem(fs, fs) + newfs, err := coll.FileSystem(fs, fs) if err != nil { return nil } - root := cfs.rootnode() - root.SetParent(parent, id) - return root + cfs := newfs.(*collectionFileSystem) + cfs.SetParent(parent, id) + return cfs } -func (fs *customFileSystem) newProjectNode(root inode, name, uuid string) inode { +func (fs *customFileSystem) newProjectNode(root inode, name, uuid string, properties map[string]interface{}) inode { return &lookupnode{ stale: fs.Stale, loadOne: func(parent inode, name string) (inode, error) { return fs.projectsLoadOne(parent, uuid, name) }, loadAll: func(parent inode) ([]inode, error) { return fs.projectsLoadAll(parent, uuid) }, - inode: &treenode{ + treenode: treenode{ fs: fs, parent: root, inodes: make(map[string]inode), @@ -162,29 +174,34 @@ func (fs *customFileSystem) newProjectNode(root inode, name, uuid string) inode name: name, modTime: time.Now(), mode: 0755 | os.ModeDir, + sys: &Group{ + GroupClass: "project", + UUID: uuid, + Properties: properties, + }, }, }, } } -// vdirnode wraps an inode by ignoring any requests to add/replace -// children, and calling a create() func when a non-existing child is -// looked up. +// vdirnode wraps an inode by rejecting (with ErrInvalidOperation) +// calls that add/replace children directly, instead calling a +// create() func when a non-existing child is looked up. // // create() can return either a new node, which will be added to the // treenode, or nil for ENOENT. type vdirnode struct { - inode + treenode create func(parent inode, name string) inode } func (vn *vdirnode) Child(name string, replace func(inode) (inode, error)) (inode, error) { - return vn.inode.Child(name, func(existing inode) (inode, error) { + return vn.treenode.Child(name, func(existing inode) (inode, error) { if existing == nil && vn.create != nil { existing = vn.create(vn, name) if existing != nil { existing.SetParent(vn, name) - vn.inode.(*treenode).fileinfo.modTime = time.Now() + vn.treenode.fileinfo.modTime = time.Now() } } if replace == nil { @@ -192,7 +209,7 @@ func (vn *vdirnode) Child(name string, replace func(inode) (inode, error)) (inod } else if tryRepl, err := replace(existing); err != nil { return existing, err } else if tryRepl != existing { - return existing, ErrInvalidArgument + return existing, ErrInvalidOperation } else { return existing, nil }