github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/vfs/vfs.go (about) 1 // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package vfs 6 7 import ( 8 "io" 9 "os" 10 "syscall" 11 ) 12 13 // File is a readable, writable sequence of bytes. 14 // 15 // Typically, it will be an *os.File, but test code may choose to substitute 16 // memory-backed implementations. 17 type File interface { 18 io.Closer 19 io.Reader 20 io.ReaderAt 21 io.Writer 22 Stat() (os.FileInfo, error) 23 Sync() error 24 } 25 26 // OpenOptions provide an interface to do work on file handles in the Open() 27 // call. 28 type OpenOption interface { 29 // Apply is called on the file handle after it's opened. 30 Apply(File) 31 } 32 33 // FS is a namespace for files. 34 // 35 // The names are filepath names: they may be / separated or \ separated, 36 // depending on the underlying operating system. 37 type FS interface { 38 // Create creates the named file for writing, truncating it if it already 39 // exists. 40 Create(name string) (File, error) 41 42 // Link creates newname as a hard link to the oldname file. 43 Link(oldname, newname string) error 44 45 // Open opens the named file for reading. openOptions provides 46 Open(name string, opts ...OpenOption) (File, error) 47 48 // OpenDir opens the named directory for syncing. 49 OpenDir(name string) (File, error) 50 51 // Remove removes the named file or directory. 52 Remove(name string) error 53 54 // Rename renames a file. It overwrites the file at newname if one exists, 55 // the same as os.Rename. 56 Rename(oldname, newname string) error 57 58 // MkdirAll creates a directory and all necessary parents. The permission 59 // bits perm have the same semantics as in os.MkdirAll. If the directory 60 // already exists, MkdirAll does nothing and returns nil. 61 MkdirAll(dir string, perm os.FileMode) error 62 63 // Lock locks the given file, creating the file if necessary, and 64 // truncating the file if it already exists. The lock is an exclusive lock 65 // (a write lock), but locked files should neither be read from nor written 66 // to. Such files should have zero size and only exist to co-ordinate 67 // ownership across processes. 68 // 69 // A nil Closer is returned if an error occurred. Otherwise, close that 70 // Closer to release the lock. 71 // 72 // On Linux and OSX, a lock has the same semantics as fcntl(2)'s advisory 73 // locks. In particular, closing any other file descriptor for the same 74 // file will release the lock prematurely. 75 // 76 // Attempting to lock a file that is already locked by the current process 77 // has undefined behavior. 78 // 79 // Lock is not yet implemented on other operating systems, and calling it 80 // will return an error. 81 Lock(name string) (io.Closer, error) 82 83 // List returns a listing of the given directory. The names returned are 84 // relative to dir. 85 List(dir string) ([]string, error) 86 87 // Stat returns an os.FileInfo describing the named file. 88 Stat(name string) (os.FileInfo, error) 89 } 90 91 // Default is a FS implementation backed by the underlying operating system's 92 // file system. 93 var Default FS = defaultFS{} 94 95 type defaultFS struct{} 96 97 func (defaultFS) Create(name string) (File, error) { 98 return os.OpenFile(name, os.O_RDWR|os.O_CREATE|syscall.O_CLOEXEC, 0666) 99 } 100 101 func (defaultFS) Link(oldname, newname string) error { 102 return os.Link(oldname, newname) 103 } 104 105 func (defaultFS) Open(name string, opts ...OpenOption) (File, error) { 106 file, err := os.OpenFile(name, os.O_RDONLY|syscall.O_CLOEXEC, 0) 107 if err != nil { 108 return nil, err 109 } 110 for _, opt := range opts { 111 opt.Apply(file) 112 } 113 return file, nil 114 } 115 116 func (defaultFS) OpenDir(name string) (File, error) { 117 return os.OpenFile(name, syscall.O_CLOEXEC, 0) 118 } 119 120 func (defaultFS) Remove(name string) error { 121 return os.Remove(name) 122 } 123 124 func (defaultFS) Rename(oldname, newname string) error { 125 return os.Rename(oldname, newname) 126 } 127 128 func (defaultFS) MkdirAll(dir string, perm os.FileMode) error { 129 return os.MkdirAll(dir, perm) 130 } 131 132 func (defaultFS) List(dir string) ([]string, error) { 133 f, err := os.Open(dir) 134 if err != nil { 135 return nil, err 136 } 137 defer f.Close() 138 return f.Readdirnames(-1) 139 } 140 141 func (defaultFS) Stat(name string) (os.FileInfo, error) { 142 return os.Stat(name) 143 } 144 145 146 type randomReadsOption struct{} 147 148 // RandomReadsOption is an OpenOption that optimizes opened file handle for 149 // random reads, by calling fadvise() with POSIX_FADV_RANDOM on Linux systems 150 // to disable readahead. Only works when specified to defaultFS. 151 var RandomReadsOption OpenOption = &randomReadsOption{} 152 153 // Apply implements the OpenOption interface. 154 func (randomReadsOption) Apply(f File) { 155 if osFile, ok := f.(*os.File); ok { 156 _ = fadviseRandom(osFile.Fd()) 157 } 158 }