LCOV - code coverage report
Current view: top level - pebble/vfs - mem_fs.go (source / functions) Hit Total Coverage
Test: 2023-10-13 08:16Z ede31f1a - tests + meta.lcov Lines: 485 564 86.0 %
Date: 2023-10-13 08:17:52 Functions: 0 0 -

          Line data    Source code
       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 // import "github.com/cockroachdb/pebble/vfs"
       6             : 
       7             : import (
       8             :         "bytes"
       9             :         "fmt"
      10             :         "io"
      11             :         "os"
      12             :         "path"
      13             :         "sort"
      14             :         "strings"
      15             :         "sync"
      16             :         "sync/atomic"
      17             :         "syscall"
      18             :         "time"
      19             : 
      20             :         "github.com/cockroachdb/errors"
      21             :         "github.com/cockroachdb/errors/oserror"
      22             :         "github.com/cockroachdb/pebble/internal/invariants"
      23             : )
      24             : 
      25             : const sep = "/"
      26             : 
      27             : // NewMem returns a new memory-backed FS implementation.
      28           2 : func NewMem() *MemFS {
      29           2 :         return &MemFS{
      30           2 :                 root: newRootMemNode(),
      31           2 :         }
      32           2 : }
      33             : 
      34             : // NewStrictMem returns a "strict" memory-backed FS implementation. The behaviour is strict wrt
      35             : // needing a Sync() call on files or directories for the state changes to be finalized. Any
      36             : // changes that are not finalized are visible to reads until MemFS.ResetToSyncedState() is called,
      37             : // at which point they are discarded and no longer visible.
      38             : //
      39             : // Expected usage:
      40             : //
      41             : //      strictFS := NewStrictMem()
      42             : //      db := Open(..., &Options{FS: strictFS})
      43             : //      // Do and commit various operations.
      44             : //      ...
      45             : //      // Prevent any more changes to finalized state.
      46             : //      strictFS.SetIgnoreSyncs(true)
      47             : //      // This will finish any ongoing background flushes, compactions but none of these writes will
      48             : //      // be finalized since syncs are being ignored.
      49             : //      db.Close()
      50             : //      // Discard unsynced state.
      51             : //      strictFS.ResetToSyncedState()
      52             : //      // Allow changes to finalized state.
      53             : //      strictFS.SetIgnoreSyncs(false)
      54             : //      // Open the DB. This DB should have the same state as if the earlier strictFS operations and
      55             : //      // db.Close() were not called.
      56             : //      db := Open(..., &Options{FS: strictFS})
      57           2 : func NewStrictMem() *MemFS {
      58           2 :         return &MemFS{
      59           2 :                 root:   newRootMemNode(),
      60           2 :                 strict: true,
      61           2 :         }
      62           2 : }
      63             : 
      64             : // NewMemFile returns a memory-backed File implementation. The memory-backed
      65             : // file takes ownership of data.
      66           1 : func NewMemFile(data []byte) File {
      67           1 :         n := &memNode{}
      68           1 :         n.refs.Store(1)
      69           1 :         n.mu.data = data
      70           1 :         n.mu.modTime = time.Now()
      71           1 :         return &memFile{
      72           1 :                 n:    n,
      73           1 :                 read: true,
      74           1 :         }
      75           1 : }
      76             : 
      77             : // MemFS implements FS.
      78             : type MemFS struct {
      79             :         mu   sync.Mutex
      80             :         root *memNode
      81             : 
      82             :         // lockFiles holds a map of open file locks. Presence in this map indicates
      83             :         // a file lock is currently held. Keys are strings holding the path of the
      84             :         // locked file. The stored value is untyped and  unused; only presence of
      85             :         // the key within the map is significant.
      86             :         lockedFiles sync.Map
      87             :         strict      bool
      88             :         ignoreSyncs bool
      89             :         // Windows has peculiar semantics with respect to hard links and deleting
      90             :         // open files. In tests meant to exercise this behavior, this flag can be
      91             :         // set to error if removing an open file.
      92             :         windowsSemantics bool
      93             : }
      94             : 
      95             : var _ FS = &MemFS{}
      96             : 
      97             : // UseWindowsSemantics configures whether the MemFS implements Windows-style
      98             : // semantics, in particular with respect to whether any of an open file's links
      99             : // may be removed. Windows semantics default to off.
     100           1 : func (y *MemFS) UseWindowsSemantics(windowsSemantics bool) {
     101           1 :         y.mu.Lock()
     102           1 :         defer y.mu.Unlock()
     103           1 :         y.windowsSemantics = windowsSemantics
     104           1 : }
     105             : 
     106             : // String dumps the contents of the MemFS.
     107           1 : func (y *MemFS) String() string {
     108           1 :         y.mu.Lock()
     109           1 :         defer y.mu.Unlock()
     110           1 : 
     111           1 :         s := new(bytes.Buffer)
     112           1 :         y.root.dump(s, 0)
     113           1 :         return s.String()
     114           1 : }
     115             : 
     116             : // SetIgnoreSyncs sets the MemFS.ignoreSyncs field. See the usage comment with NewStrictMem() for
     117             : // details.
     118           1 : func (y *MemFS) SetIgnoreSyncs(ignoreSyncs bool) {
     119           1 :         y.mu.Lock()
     120           1 :         if !y.strict {
     121           0 :                 // noop
     122           0 :                 return
     123           0 :         }
     124           1 :         y.ignoreSyncs = ignoreSyncs
     125           1 :         y.mu.Unlock()
     126             : }
     127             : 
     128             : // ResetToSyncedState discards state in the FS that is not synced. See the usage comment with
     129             : // NewStrictMem() for details.
     130           1 : func (y *MemFS) ResetToSyncedState() {
     131           1 :         if !y.strict {
     132           0 :                 // noop
     133           0 :                 return
     134           0 :         }
     135           1 :         y.mu.Lock()
     136           1 :         y.root.resetToSyncedState()
     137           1 :         y.mu.Unlock()
     138             : }
     139             : 
     140             : // walk walks the directory tree for the fullname, calling f at each step. If
     141             : // f returns an error, the walk will be aborted and return that same error.
     142             : //
     143             : // Each walk is atomic: y's mutex is held for the entire operation, including
     144             : // all calls to f.
     145             : //
     146             : // dir is the directory at that step, frag is the name fragment, and final is
     147             : // whether it is the final step. For example, walking "/foo/bar/x" will result
     148             : // in 3 calls to f:
     149             : //   - "/", "foo", false
     150             : //   - "/foo/", "bar", false
     151             : //   - "/foo/bar/", "x", true
     152             : //
     153             : // Similarly, walking "/y/z/", with a trailing slash, will result in 3 calls to f:
     154             : //   - "/", "y", false
     155             : //   - "/y/", "z", false
     156             : //   - "/y/z/", "", true
     157           2 : func (y *MemFS) walk(fullname string, f func(dir *memNode, frag string, final bool) error) error {
     158           2 :         y.mu.Lock()
     159           2 :         defer y.mu.Unlock()
     160           2 : 
     161           2 :         // For memfs, the current working directory is the same as the root directory,
     162           2 :         // so we strip off any leading "/"s to make fullname a relative path, and
     163           2 :         // the walk starts at y.root.
     164           2 :         for len(fullname) > 0 && fullname[0] == sep[0] {
     165           2 :                 fullname = fullname[1:]
     166           2 :         }
     167           2 :         dir := y.root
     168           2 : 
     169           2 :         for {
     170           2 :                 frag, remaining := fullname, ""
     171           2 :                 i := strings.IndexRune(fullname, rune(sep[0]))
     172           2 :                 final := i < 0
     173           2 :                 if !final {
     174           2 :                         frag, remaining = fullname[:i], fullname[i+1:]
     175           2 :                         for len(remaining) > 0 && remaining[0] == sep[0] {
     176           0 :                                 remaining = remaining[1:]
     177           0 :                         }
     178             :                 }
     179           2 :                 if err := f(dir, frag, final); err != nil {
     180           1 :                         return err
     181           1 :                 }
     182           2 :                 if final {
     183           2 :                         break
     184             :                 }
     185           2 :                 child := dir.children[frag]
     186           2 :                 if child == nil {
     187           2 :                         return &os.PathError{
     188           2 :                                 Op:   "open",
     189           2 :                                 Path: fullname,
     190           2 :                                 Err:  oserror.ErrNotExist,
     191           2 :                         }
     192           2 :                 }
     193           2 :                 if !child.isDir {
     194           1 :                         return &os.PathError{
     195           1 :                                 Op:   "open",
     196           1 :                                 Path: fullname,
     197           1 :                                 Err:  errors.New("not a directory"),
     198           1 :                         }
     199           1 :                 }
     200           2 :                 dir, fullname = child, remaining
     201             :         }
     202           2 :         return nil
     203             : }
     204             : 
     205             : // Create implements FS.Create.
     206           2 : func (y *MemFS) Create(fullname string) (File, error) {
     207           2 :         var ret *memFile
     208           2 :         err := y.walk(fullname, func(dir *memNode, frag string, final bool) error {
     209           2 :                 if final {
     210           2 :                         if frag == "" {
     211           0 :                                 return errors.New("pebble/vfs: empty file name")
     212           0 :                         }
     213           2 :                         n := &memNode{name: frag}
     214           2 :                         dir.children[frag] = n
     215           2 :                         ret = &memFile{
     216           2 :                                 n:     n,
     217           2 :                                 fs:    y,
     218           2 :                                 read:  true,
     219           2 :                                 write: true,
     220           2 :                         }
     221             :                 }
     222           2 :                 return nil
     223             :         })
     224           2 :         if err != nil {
     225           1 :                 return nil, err
     226           1 :         }
     227           2 :         ret.n.refs.Add(1)
     228           2 :         return ret, nil
     229             : }
     230             : 
     231             : // Link implements FS.Link.
     232           2 : func (y *MemFS) Link(oldname, newname string) error {
     233           2 :         var n *memNode
     234           2 :         err := y.walk(oldname, func(dir *memNode, frag string, final bool) error {
     235           2 :                 if final {
     236           2 :                         if frag == "" {
     237           0 :                                 return errors.New("pebble/vfs: empty file name")
     238           0 :                         }
     239           2 :                         n = dir.children[frag]
     240             :                 }
     241           2 :                 return nil
     242             :         })
     243           2 :         if err != nil {
     244           0 :                 return err
     245           0 :         }
     246           2 :         if n == nil {
     247           1 :                 return &os.LinkError{
     248           1 :                         Op:  "link",
     249           1 :                         Old: oldname,
     250           1 :                         New: newname,
     251           1 :                         Err: oserror.ErrNotExist,
     252           1 :                 }
     253           1 :         }
     254           2 :         return y.walk(newname, func(dir *memNode, frag string, final bool) error {
     255           2 :                 if final {
     256           2 :                         if frag == "" {
     257           0 :                                 return errors.New("pebble/vfs: empty file name")
     258           0 :                         }
     259           2 :                         if _, ok := dir.children[frag]; ok {
     260           1 :                                 return &os.LinkError{
     261           1 :                                         Op:  "link",
     262           1 :                                         Old: oldname,
     263           1 :                                         New: newname,
     264           1 :                                         Err: oserror.ErrExist,
     265           1 :                                 }
     266           1 :                         }
     267           2 :                         dir.children[frag] = n
     268             :                 }
     269           2 :                 return nil
     270             :         })
     271             : }
     272             : 
     273           2 : func (y *MemFS) open(fullname string, openForWrite bool) (File, error) {
     274           2 :         var ret *memFile
     275           2 :         err := y.walk(fullname, func(dir *memNode, frag string, final bool) error {
     276           2 :                 if final {
     277           2 :                         if frag == "" {
     278           2 :                                 ret = &memFile{
     279           2 :                                         n:  dir,
     280           2 :                                         fs: y,
     281           2 :                                 }
     282           2 :                                 return nil
     283           2 :                         }
     284           2 :                         if n := dir.children[frag]; n != nil {
     285           2 :                                 ret = &memFile{
     286           2 :                                         n:     n,
     287           2 :                                         fs:    y,
     288           2 :                                         read:  true,
     289           2 :                                         write: openForWrite,
     290           2 :                                 }
     291           2 :                         }
     292             :                 }
     293           2 :                 return nil
     294             :         })
     295           2 :         if err != nil {
     296           2 :                 return nil, err
     297           2 :         }
     298           2 :         if ret == nil {
     299           2 :                 return nil, &os.PathError{
     300           2 :                         Op:   "open",
     301           2 :                         Path: fullname,
     302           2 :                         Err:  oserror.ErrNotExist,
     303           2 :                 }
     304           2 :         }
     305           2 :         ret.n.refs.Add(1)
     306           2 :         return ret, nil
     307             : }
     308             : 
     309             : // Open implements FS.Open.
     310           2 : func (y *MemFS) Open(fullname string, opts ...OpenOption) (File, error) {
     311           2 :         return y.open(fullname, false /* openForWrite */)
     312           2 : }
     313             : 
     314             : // OpenReadWrite implements FS.OpenReadWrite.
     315           2 : func (y *MemFS) OpenReadWrite(fullname string, opts ...OpenOption) (File, error) {
     316           2 :         f, err := y.open(fullname, true /* openForWrite */)
     317           2 :         pathErr, ok := err.(*os.PathError)
     318           2 :         if ok && pathErr.Err == oserror.ErrNotExist {
     319           2 :                 return y.Create(fullname)
     320           2 :         }
     321           2 :         return f, err
     322             : }
     323             : 
     324             : // OpenDir implements FS.OpenDir.
     325           2 : func (y *MemFS) OpenDir(fullname string) (File, error) {
     326           2 :         return y.open(fullname, false /* openForWrite */)
     327           2 : }
     328             : 
     329             : // Remove implements FS.Remove.
     330           2 : func (y *MemFS) Remove(fullname string) error {
     331           2 :         return y.walk(fullname, func(dir *memNode, frag string, final bool) error {
     332           2 :                 if final {
     333           2 :                         if frag == "" {
     334           0 :                                 return errors.New("pebble/vfs: empty file name")
     335           0 :                         }
     336           2 :                         child, ok := dir.children[frag]
     337           2 :                         if !ok {
     338           1 :                                 return oserror.ErrNotExist
     339           1 :                         }
     340           2 :                         if y.windowsSemantics {
     341           1 :                                 // Disallow removal of open files/directories which implements
     342           1 :                                 // Windows semantics. This ensures that we don't regress in the
     343           1 :                                 // ordering of operations and try to remove a file while it is
     344           1 :                                 // still open.
     345           1 :                                 if n := child.refs.Load(); n > 0 {
     346           1 :                                         return oserror.ErrInvalid
     347           1 :                                 }
     348             :                         }
     349           2 :                         if len(child.children) > 0 {
     350           1 :                                 return errNotEmpty
     351           1 :                         }
     352           2 :                         delete(dir.children, frag)
     353             :                 }
     354           2 :                 return nil
     355             :         })
     356             : }
     357             : 
     358             : // RemoveAll implements FS.RemoveAll.
     359           1 : func (y *MemFS) RemoveAll(fullname string) error {
     360           1 :         err := y.walk(fullname, func(dir *memNode, frag string, final bool) error {
     361           1 :                 if final {
     362           1 :                         if frag == "" {
     363           0 :                                 return errors.New("pebble/vfs: empty file name")
     364           0 :                         }
     365           1 :                         _, ok := dir.children[frag]
     366           1 :                         if !ok {
     367           1 :                                 return nil
     368           1 :                         }
     369           1 :                         delete(dir.children, frag)
     370             :                 }
     371           1 :                 return nil
     372             :         })
     373             :         // Match os.RemoveAll which returns a nil error even if the parent
     374             :         // directories don't exist.
     375           1 :         if oserror.IsNotExist(err) {
     376           1 :                 err = nil
     377           1 :         }
     378           1 :         return err
     379             : }
     380             : 
     381             : // Rename implements FS.Rename.
     382           2 : func (y *MemFS) Rename(oldname, newname string) error {
     383           2 :         var n *memNode
     384           2 :         err := y.walk(oldname, func(dir *memNode, frag string, final bool) error {
     385           2 :                 if final {
     386           2 :                         if frag == "" {
     387           0 :                                 return errors.New("pebble/vfs: empty file name")
     388           0 :                         }
     389           2 :                         n = dir.children[frag]
     390           2 :                         delete(dir.children, frag)
     391             :                 }
     392           2 :                 return nil
     393             :         })
     394           2 :         if err != nil {
     395           0 :                 return err
     396           0 :         }
     397           2 :         if n == nil {
     398           1 :                 return &os.PathError{
     399           1 :                         Op:   "open",
     400           1 :                         Path: oldname,
     401           1 :                         Err:  oserror.ErrNotExist,
     402           1 :                 }
     403           1 :         }
     404           2 :         return y.walk(newname, func(dir *memNode, frag string, final bool) error {
     405           2 :                 if final {
     406           2 :                         if frag == "" {
     407           0 :                                 return errors.New("pebble/vfs: empty file name")
     408           0 :                         }
     409           2 :                         dir.children[frag] = n
     410           2 :                         n.name = frag
     411             :                 }
     412           2 :                 return nil
     413             :         })
     414             : }
     415             : 
     416             : // ReuseForWrite implements FS.ReuseForWrite.
     417           1 : func (y *MemFS) ReuseForWrite(oldname, newname string) (File, error) {
     418           1 :         if err := y.Rename(oldname, newname); err != nil {
     419           1 :                 return nil, err
     420           1 :         }
     421           1 :         f, err := y.Open(newname)
     422           1 :         if err != nil {
     423           0 :                 return nil, err
     424           0 :         }
     425           1 :         y.mu.Lock()
     426           1 :         defer y.mu.Unlock()
     427           1 : 
     428           1 :         mf := f.(*memFile)
     429           1 :         mf.read = false
     430           1 :         mf.write = true
     431           1 :         return f, nil
     432             : }
     433             : 
     434             : // MkdirAll implements FS.MkdirAll.
     435           2 : func (y *MemFS) MkdirAll(dirname string, perm os.FileMode) error {
     436           2 :         return y.walk(dirname, func(dir *memNode, frag string, final bool) error {
     437           2 :                 if frag == "" {
     438           1 :                         if final {
     439           1 :                                 return nil
     440           1 :                         }
     441           0 :                         return errors.New("pebble/vfs: empty file name")
     442             :                 }
     443           2 :                 child := dir.children[frag]
     444           2 :                 if child == nil {
     445           2 :                         dir.children[frag] = &memNode{
     446           2 :                                 name:     frag,
     447           2 :                                 children: make(map[string]*memNode),
     448           2 :                                 isDir:    true,
     449           2 :                         }
     450           2 :                         return nil
     451           2 :                 }
     452           2 :                 if !child.isDir {
     453           0 :                         return &os.PathError{
     454           0 :                                 Op:   "open",
     455           0 :                                 Path: dirname,
     456           0 :                                 Err:  errors.New("not a directory"),
     457           0 :                         }
     458           0 :                 }
     459           2 :                 return nil
     460             :         })
     461             : }
     462             : 
     463             : // Lock implements FS.Lock.
     464           2 : func (y *MemFS) Lock(fullname string) (io.Closer, error) {
     465           2 :         // FS.Lock excludes other processes, but other processes cannot see this
     466           2 :         // process' memory. However some uses (eg, Cockroach tests) may open and
     467           2 :         // close the same MemFS-backed database multiple times. We want mutual
     468           2 :         // exclusion in this case too. See cockroachdb/cockroach#110645.
     469           2 :         _, loaded := y.lockedFiles.Swap(fullname, nil /* the value itself is insignificant */)
     470           2 :         if loaded {
     471           1 :                 // This file lock has already been acquired. On unix, this results in
     472           1 :                 // either EACCES or EAGAIN so we mimic.
     473           1 :                 return nil, syscall.EAGAIN
     474           1 :         }
     475             :         // Otherwise, we successfully acquired the lock. Locks are visible in the
     476             :         // parent directory listing, and they also must be created under an existent
     477             :         // directory. Create the path so that we have the normal detection of
     478             :         // non-existent directory paths, and make the lock visible when listing
     479             :         // directory entries.
     480           2 :         f, err := y.Create(fullname)
     481           2 :         if err != nil {
     482           1 :                 // "Release" the lock since we failed.
     483           1 :                 y.lockedFiles.Delete(fullname)
     484           1 :                 return nil, err
     485           1 :         }
     486           2 :         return &memFileLock{
     487           2 :                 y:        y,
     488           2 :                 f:        f,
     489           2 :                 fullname: fullname,
     490           2 :         }, nil
     491             : }
     492             : 
     493             : // List implements FS.List.
     494           2 : func (y *MemFS) List(dirname string) ([]string, error) {
     495           2 :         if !strings.HasSuffix(dirname, sep) {
     496           2 :                 dirname += sep
     497           2 :         }
     498           2 :         var ret []string
     499           2 :         err := y.walk(dirname, func(dir *memNode, frag string, final bool) error {
     500           2 :                 if final {
     501           2 :                         if frag != "" {
     502           0 :                                 panic("unreachable")
     503             :                         }
     504           2 :                         ret = make([]string, 0, len(dir.children))
     505           2 :                         for s := range dir.children {
     506           2 :                                 ret = append(ret, s)
     507           2 :                         }
     508             :                 }
     509           2 :                 return nil
     510             :         })
     511           2 :         return ret, err
     512             : }
     513             : 
     514             : // Stat implements FS.Stat.
     515           2 : func (y *MemFS) Stat(name string) (os.FileInfo, error) {
     516           2 :         f, err := y.Open(name)
     517           2 :         if err != nil {
     518           2 :                 if pe, ok := err.(*os.PathError); ok {
     519           2 :                         pe.Op = "stat"
     520           2 :                 }
     521           2 :                 return nil, err
     522             :         }
     523           2 :         defer f.Close()
     524           2 :         return f.Stat()
     525             : }
     526             : 
     527             : // PathBase implements FS.PathBase.
     528           2 : func (*MemFS) PathBase(p string) string {
     529           2 :         // Note that MemFS uses forward slashes for its separator, hence the use of
     530           2 :         // path.Base, not filepath.Base.
     531           2 :         return path.Base(p)
     532           2 : }
     533             : 
     534             : // PathJoin implements FS.PathJoin.
     535           2 : func (*MemFS) PathJoin(elem ...string) string {
     536           2 :         // Note that MemFS uses forward slashes for its separator, hence the use of
     537           2 :         // path.Join, not filepath.Join.
     538           2 :         return path.Join(elem...)
     539           2 : }
     540             : 
     541             : // PathDir implements FS.PathDir.
     542           2 : func (*MemFS) PathDir(p string) string {
     543           2 :         // Note that MemFS uses forward slashes for its separator, hence the use of
     544           2 :         // path.Dir, not filepath.Dir.
     545           2 :         return path.Dir(p)
     546           2 : }
     547             : 
     548             : // GetDiskUsage implements FS.GetDiskUsage.
     549           2 : func (*MemFS) GetDiskUsage(string) (DiskUsage, error) {
     550           2 :         return DiskUsage{}, ErrUnsupported
     551           2 : }
     552             : 
     553             : // memNode holds a file's data or a directory's children, and implements os.FileInfo.
     554             : type memNode struct {
     555             :         name  string
     556             :         isDir bool
     557             :         refs  atomic.Int32
     558             : 
     559             :         // Mutable state.
     560             :         // - For a file: data, syncedDate, modTime: A file is only being mutated by a single goroutine,
     561             :         //   but there can be concurrent readers e.g. DB.Checkpoint() which can read WAL or MANIFEST
     562             :         //   files that are being written to. Additionally Sync() calls can be concurrent with writing.
     563             :         // - For a directory: children and syncedChildren. Concurrent writes are possible, and
     564             :         //   these are protected using MemFS.mu.
     565             :         mu struct {
     566             :                 sync.Mutex
     567             :                 data       []byte
     568             :                 syncedData []byte
     569             :                 modTime    time.Time
     570             :         }
     571             : 
     572             :         children       map[string]*memNode
     573             :         syncedChildren map[string]*memNode
     574             : }
     575             : 
     576           2 : func newRootMemNode() *memNode {
     577           2 :         return &memNode{
     578           2 :                 name:     "/", // set the name to match what file systems do
     579           2 :                 children: make(map[string]*memNode),
     580           2 :                 isDir:    true,
     581           2 :         }
     582           2 : }
     583             : 
     584           1 : func (f *memNode) IsDir() bool {
     585           1 :         return f.isDir
     586           1 : }
     587             : 
     588           0 : func (f *memNode) ModTime() time.Time {
     589           0 :         f.mu.Lock()
     590           0 :         defer f.mu.Unlock()
     591           0 :         return f.mu.modTime
     592           0 : }
     593             : 
     594           0 : func (f *memNode) Mode() os.FileMode {
     595           0 :         if f.isDir {
     596           0 :                 return os.ModeDir | 0755
     597           0 :         }
     598           0 :         return 0755
     599             : }
     600             : 
     601           1 : func (f *memNode) Name() string {
     602           1 :         return f.name
     603           1 : }
     604             : 
     605           2 : func (f *memNode) Size() int64 {
     606           2 :         f.mu.Lock()
     607           2 :         defer f.mu.Unlock()
     608           2 :         return int64(len(f.mu.data))
     609           2 : }
     610             : 
     611           0 : func (f *memNode) Sys() interface{} {
     612           0 :         return nil
     613           0 : }
     614             : 
     615           1 : func (f *memNode) dump(w *bytes.Buffer, level int) {
     616           1 :         if f.isDir {
     617           1 :                 w.WriteString("          ")
     618           1 :         } else {
     619           1 :                 f.mu.Lock()
     620           1 :                 fmt.Fprintf(w, "%8d  ", len(f.mu.data))
     621           1 :                 f.mu.Unlock()
     622           1 :         }
     623           1 :         for i := 0; i < level; i++ {
     624           1 :                 w.WriteString("  ")
     625           1 :         }
     626           1 :         w.WriteString(f.name)
     627           1 :         if !f.isDir {
     628           1 :                 w.WriteByte('\n')
     629           1 :                 return
     630           1 :         }
     631           1 :         if level > 0 { // deal with the fact that the root's name is already "/"
     632           1 :                 w.WriteByte(sep[0])
     633           1 :         }
     634           1 :         w.WriteByte('\n')
     635           1 :         names := make([]string, 0, len(f.children))
     636           1 :         for name := range f.children {
     637           1 :                 names = append(names, name)
     638           1 :         }
     639           1 :         sort.Strings(names)
     640           1 :         for _, name := range names {
     641           1 :                 f.children[name].dump(w, level+1)
     642           1 :         }
     643             : }
     644             : 
     645           1 : func (f *memNode) resetToSyncedState() {
     646           1 :         if f.isDir {
     647           1 :                 f.children = make(map[string]*memNode)
     648           1 :                 for k, v := range f.syncedChildren {
     649           1 :                         f.children[k] = v
     650           1 :                 }
     651           1 :                 for _, v := range f.children {
     652           1 :                         v.resetToSyncedState()
     653           1 :                 }
     654           1 :         } else {
     655           1 :                 f.mu.Lock()
     656           1 :                 f.mu.data = append([]byte(nil), f.mu.syncedData...)
     657           1 :                 f.mu.Unlock()
     658           1 :         }
     659             : }
     660             : 
     661             : // memFile is a reader or writer of a node's data, and implements File.
     662             : type memFile struct {
     663             :         n           *memNode
     664             :         fs          *MemFS // nil for a standalone memFile
     665             :         rpos        int
     666             :         wpos        int
     667             :         read, write bool
     668             : }
     669             : 
     670             : var _ File = (*memFile)(nil)
     671             : 
     672           2 : func (f *memFile) Close() error {
     673           2 :         if n := f.n.refs.Add(-1); n < 0 {
     674           0 :                 panic(fmt.Sprintf("pebble: close of unopened file: %d", n))
     675             :         }
     676           2 :         f.n = nil
     677           2 :         return nil
     678             : }
     679             : 
     680           2 : func (f *memFile) Read(p []byte) (int, error) {
     681           2 :         if !f.read {
     682           0 :                 return 0, errors.New("pebble/vfs: file was not opened for reading")
     683           0 :         }
     684           2 :         if f.n.isDir {
     685           0 :                 return 0, errors.New("pebble/vfs: cannot read a directory")
     686           0 :         }
     687           2 :         f.n.mu.Lock()
     688           2 :         defer f.n.mu.Unlock()
     689           2 :         if f.rpos >= len(f.n.mu.data) {
     690           2 :                 return 0, io.EOF
     691           2 :         }
     692           2 :         n := copy(p, f.n.mu.data[f.rpos:])
     693           2 :         f.rpos += n
     694           2 :         return n, nil
     695             : }
     696             : 
     697           2 : func (f *memFile) ReadAt(p []byte, off int64) (int, error) {
     698           2 :         if !f.read {
     699           0 :                 return 0, errors.New("pebble/vfs: file was not opened for reading")
     700           0 :         }
     701           2 :         if f.n.isDir {
     702           0 :                 return 0, errors.New("pebble/vfs: cannot read a directory")
     703           0 :         }
     704           2 :         f.n.mu.Lock()
     705           2 :         defer f.n.mu.Unlock()
     706           2 :         if off >= int64(len(f.n.mu.data)) {
     707           0 :                 return 0, io.EOF
     708           0 :         }
     709           2 :         n := copy(p, f.n.mu.data[off:])
     710           2 :         if n < len(p) {
     711           1 :                 return n, io.EOF
     712           1 :         }
     713           2 :         return n, nil
     714             : }
     715             : 
     716           2 : func (f *memFile) Write(p []byte) (int, error) {
     717           2 :         if !f.write {
     718           0 :                 return 0, errors.New("pebble/vfs: file was not created for writing")
     719           0 :         }
     720           2 :         if f.n.isDir {
     721           0 :                 return 0, errors.New("pebble/vfs: cannot write a directory")
     722           0 :         }
     723           2 :         f.n.mu.Lock()
     724           2 :         defer f.n.mu.Unlock()
     725           2 :         f.n.mu.modTime = time.Now()
     726           2 :         if f.wpos+len(p) <= len(f.n.mu.data) {
     727           2 :                 n := copy(f.n.mu.data[f.wpos:f.wpos+len(p)], p)
     728           2 :                 if n != len(p) {
     729           0 :                         panic("stuff")
     730             :                 }
     731           2 :         } else {
     732           2 :                 f.n.mu.data = append(f.n.mu.data[:f.wpos], p...)
     733           2 :         }
     734           2 :         f.wpos += len(p)
     735           2 : 
     736           2 :         if invariants.Enabled {
     737           2 :                 // Mutate the input buffer to flush out bugs in Pebble which expect the
     738           2 :                 // input buffer to be unmodified.
     739           2 :                 for i := range p {
     740           2 :                         p[i] ^= 0xff
     741           2 :                 }
     742             :         }
     743           2 :         return len(p), nil
     744             : }
     745             : 
     746           2 : func (f *memFile) WriteAt(p []byte, ofs int64) (int, error) {
     747           2 :         if !f.write {
     748           0 :                 return 0, errors.New("pebble/vfs: file was not created for writing")
     749           0 :         }
     750           2 :         if f.n.isDir {
     751           0 :                 return 0, errors.New("pebble/vfs: cannot write a directory")
     752           0 :         }
     753           2 :         f.n.mu.Lock()
     754           2 :         defer f.n.mu.Unlock()
     755           2 :         f.n.mu.modTime = time.Now()
     756           2 : 
     757           2 :         for len(f.n.mu.data) < int(ofs)+len(p) {
     758           2 :                 f.n.mu.data = append(f.n.mu.data, 0)
     759           2 :         }
     760             : 
     761           2 :         n := copy(f.n.mu.data[int(ofs):int(ofs)+len(p)], p)
     762           2 :         if n != len(p) {
     763           0 :                 panic("stuff")
     764             :         }
     765             : 
     766           2 :         return len(p), nil
     767             : }
     768             : 
     769           2 : func (f *memFile) Prefetch(offset int64, length int64) error { return nil }
     770           2 : func (f *memFile) Preallocate(offset, length int64) error    { return nil }
     771             : 
     772           2 : func (f *memFile) Stat() (os.FileInfo, error) {
     773           2 :         return f.n, nil
     774           2 : }
     775             : 
     776           2 : func (f *memFile) Sync() error {
     777           2 :         if f.fs != nil && f.fs.strict {
     778           2 :                 f.fs.mu.Lock()
     779           2 :                 defer f.fs.mu.Unlock()
     780           2 :                 if f.fs.ignoreSyncs {
     781           1 :                         return nil
     782           1 :                 }
     783           2 :                 if f.n.isDir {
     784           2 :                         f.n.syncedChildren = make(map[string]*memNode)
     785           2 :                         for k, v := range f.n.children {
     786           2 :                                 f.n.syncedChildren[k] = v
     787           2 :                         }
     788           2 :                 } else {
     789           2 :                         f.n.mu.Lock()
     790           2 :                         f.n.mu.syncedData = append([]byte(nil), f.n.mu.data...)
     791           2 :                         f.n.mu.Unlock()
     792           2 :                 }
     793             :         }
     794           2 :         return nil
     795             : }
     796             : 
     797           2 : func (f *memFile) SyncData() error {
     798           2 :         return f.Sync()
     799           2 : }
     800             : 
     801           0 : func (f *memFile) SyncTo(length int64) (fullSync bool, err error) {
     802           0 :         // NB: This SyncTo implementation lies, with its return values claiming it
     803           0 :         // synced the data up to `length`. When fullSync=false, SyncTo provides no
     804           0 :         // durability guarantees, so this can help surface bugs where we improperly
     805           0 :         // rely on SyncTo providing durability.
     806           0 :         return false, nil
     807           0 : }
     808             : 
     809           2 : func (f *memFile) Fd() uintptr {
     810           2 :         return InvalidFd
     811           2 : }
     812             : 
     813             : // Flush is a no-op and present only to prevent buffering at higher levels
     814             : // (e.g. it prevents sstable.Writer from using a bufio.Writer).
     815           1 : func (f *memFile) Flush() error {
     816           1 :         return nil
     817           1 : }
     818             : 
     819             : type memFileLock struct {
     820             :         y        *MemFS
     821             :         f        File
     822             :         fullname string
     823             : }
     824             : 
     825           2 : func (l *memFileLock) Close() error {
     826           2 :         if l.y == nil {
     827           0 :                 return nil
     828           0 :         }
     829           2 :         l.y.lockedFiles.Delete(l.fullname)
     830           2 :         l.y = nil
     831           2 :         return l.f.Close()
     832             : }

Generated by: LCOV version 1.14