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

Generated by: LCOV version 1.14