X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/b29442ebd118d522f9be9508f5111f2a68eae1a4..3aaefcb3c76ff470b475d950398d01255e87712a:/sdk/go/arvados/fs_base.go diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go index fa43cca0fa..aa75fee7c4 100644 --- a/sdk/go/arvados/fs_base.go +++ b/sdk/go/arvados/fs_base.go @@ -31,6 +31,10 @@ var ( ErrPermission = os.ErrPermission ) +type syncer interface { + Sync() error +} + // A File is an *os.File-like interface for reading and writing files // in a FileSystem. type File interface { @@ -58,6 +62,9 @@ type FileSystem interface { // while locking multiple inodes. locker() sync.Locker + // throttle for limiting concurrent background writers + throttle() *throttle + // create a new node with nil parent. newNode(name string, perm os.FileMode, modTime time.Time) (node inode, err error) @@ -86,7 +93,19 @@ type FileSystem interface { Remove(name string) error RemoveAll(name string) error Rename(oldname, newname string) error + + // Write buffered data from memory to storage, returning when + // all updates have been saved to persistent storage. Sync() error + + // Write buffered data from memory to storage, but don't wait + // for all writes to finish before returning. If shortBlocks + // is true, flush everything; otherwise, if there's less than + // a full block of buffered data at the end of a stream, leave + // it buffered in memory in case more data can be appended. If + // path is "", flush all dirs/streams; otherwise, flush only + // the specified dir/stream. + Flush(path string, shortBlocks bool) error } type inode interface { @@ -284,16 +303,37 @@ func (n *treenode) Readdir() (fi []os.FileInfo, err error) { return } +func (n *treenode) Sync() error { + n.RLock() + defer n.RUnlock() + for _, inode := range n.inodes { + syncer, ok := inode.(syncer) + if !ok { + return ErrInvalidOperation + } + err := syncer.Sync() + if err != nil { + return err + } + } + return nil +} + type fileSystem struct { root inode fsBackend mutex sync.Mutex + thr *throttle } func (fs *fileSystem) rootnode() inode { return fs.root } +func (fs *fileSystem) throttle() *throttle { + return fs.thr +} + func (fs *fileSystem) locker() sync.Locker { return &fs.mutex } @@ -452,7 +492,7 @@ func (fs *fileSystem) Rename(oldname, newname string) error { // call nca.FS().Rename() instead of proceeding. Until then // it's awkward for filesystems to implement their own Rename // methods effectively: the only one that runs is the one on - // the root filesystem exposed to the caller (webdav, fuse, + // the root FileSystem exposed to the caller (webdav, fuse, // etc). // When acquiring locks on multiple inodes, avoid deadlock by @@ -556,7 +596,14 @@ func (fs *fileSystem) remove(name string, recursive bool) error { } func (fs *fileSystem) Sync() error { - log.Printf("TODO: sync fileSystem") + if syncer, ok := fs.root.(syncer); ok { + return syncer.Sync() + } + return ErrInvalidOperation +} + +func (fs *fileSystem) Flush(string, bool) error { + log.Printf("TODO: flush fileSystem") return ErrInvalidOperation } @@ -589,3 +636,7 @@ func rlookup(start inode, path string) (node inode, err error) { } return } + +func permittedName(name string) bool { + return name != "" && name != "." && name != ".." && !strings.Contains(name, "/") +}