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  }