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

Generated by: LCOV version 1.14