github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/internal/errorfs/errorfs.go (about)

     1  // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package errorfs
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  	"math/rand"
    21  	"os"
    22  	"sync"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	"github.com/zuoyebang/bitalosdb/internal/vfs"
    27  
    28  	"github.com/cockroachdb/errors"
    29  	"github.com/cockroachdb/errors/oserror"
    30  )
    31  
    32  var ErrInjected = errors.New("injected error")
    33  
    34  type Op int
    35  
    36  const (
    37  	OpCreate Op = iota
    38  	OpLink
    39  	OpOpen
    40  	OpOpenDir
    41  	OpRemove
    42  	OpRemoveAll
    43  	OpRename
    44  	OpReuseForRewrite
    45  	OpOpenForWrite
    46  	OpMkdirAll
    47  	OpLock
    48  	OpList
    49  	OpStat
    50  	OpGetDiskUsage
    51  	OpFileClose
    52  	OpFileRead
    53  	OpFileReadAt
    54  	OpFileWrite
    55  	OpFileSeek
    56  	OpFileStat
    57  	OpFileSync
    58  	OpFileFlush
    59  )
    60  
    61  func (o Op) OpKind() OpKind {
    62  	switch o {
    63  	case OpOpen, OpOpenDir, OpList, OpStat, OpGetDiskUsage, OpFileRead, OpFileReadAt, OpFileStat, OpFileSeek:
    64  		return OpKindRead
    65  	case OpCreate, OpLink, OpRemove, OpRemoveAll, OpRename, OpReuseForRewrite, OpMkdirAll, OpLock, OpFileClose, OpFileWrite, OpFileSync, OpFileFlush:
    66  		return OpKindWrite
    67  	default:
    68  		panic(fmt.Sprintf("unrecognized op %v\n", o))
    69  	}
    70  }
    71  
    72  type OpKind int
    73  
    74  const (
    75  	OpKindRead OpKind = iota
    76  	OpKindWrite
    77  )
    78  
    79  func OnIndex(index int32) *InjectIndex {
    80  	return &InjectIndex{index: index}
    81  }
    82  
    83  type InjectIndex struct {
    84  	index int32
    85  }
    86  
    87  func (ii *InjectIndex) Index() int32 { return atomic.LoadInt32(&ii.index) }
    88  
    89  func (ii *InjectIndex) SetIndex(v int32) { atomic.StoreInt32(&ii.index, v) }
    90  
    91  func (ii *InjectIndex) MaybeError(_ Op, _ string) error {
    92  	if atomic.AddInt32(&ii.index, -1) == -1 {
    93  		return errors.WithStack(ErrInjected)
    94  	}
    95  	return nil
    96  }
    97  
    98  func WithProbability(op OpKind, p float64) Injector {
    99  	mu := new(sync.Mutex)
   100  	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
   101  	return InjectorFunc(func(currOp Op, _ string) error {
   102  		mu.Lock()
   103  		defer mu.Unlock()
   104  		if currOp.OpKind() == op && rnd.Float64() < p {
   105  			return errors.WithStack(ErrInjected)
   106  		}
   107  		return nil
   108  	})
   109  }
   110  
   111  type InjectorFunc func(Op, string) error
   112  
   113  func (f InjectorFunc) MaybeError(op Op, path string) error { return f(op, path) }
   114  
   115  type Injector interface {
   116  	MaybeError(op Op, path string) error
   117  }
   118  
   119  type FS struct {
   120  	fs  vfs.FS
   121  	inj Injector
   122  }
   123  
   124  func Wrap(fs vfs.FS, inj Injector) *FS {
   125  	return &FS{
   126  		fs:  fs,
   127  		inj: inj,
   128  	}
   129  }
   130  
   131  func WrapFile(f vfs.File, inj Injector) vfs.File {
   132  	return &errorFile{file: f, inj: inj}
   133  }
   134  
   135  func (fs *FS) Unwrap() vfs.FS {
   136  	return fs.fs
   137  }
   138  
   139  func (fs *FS) Create(name string) (vfs.File, error) {
   140  	if err := fs.inj.MaybeError(OpCreate, name); err != nil {
   141  		return nil, err
   142  	}
   143  	f, err := fs.fs.Create(name)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	return &errorFile{name, f, fs.inj}, nil
   148  }
   149  
   150  func (fs *FS) Link(oldname, newname string) error {
   151  	if err := fs.inj.MaybeError(OpLink, oldname); err != nil {
   152  		return err
   153  	}
   154  	return fs.fs.Link(oldname, newname)
   155  }
   156  
   157  func (fs *FS) Open(name string, opts ...vfs.OpenOption) (vfs.File, error) {
   158  	if err := fs.inj.MaybeError(OpOpen, name); err != nil {
   159  		return nil, err
   160  	}
   161  	f, err := fs.fs.Open(name)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	ef := &errorFile{name, f, fs.inj}
   166  	for _, opt := range opts {
   167  		opt.Apply(ef)
   168  	}
   169  	return ef, nil
   170  }
   171  
   172  func (fs *FS) OpenDir(name string) (vfs.File, error) {
   173  	if err := fs.inj.MaybeError(OpOpenDir, name); err != nil {
   174  		return nil, err
   175  	}
   176  	f, err := fs.fs.OpenDir(name)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	return &errorFile{name, f, fs.inj}, nil
   181  }
   182  
   183  func (fs *FS) GetDiskUsage(path string) (vfs.DiskUsage, error) {
   184  	if err := fs.inj.MaybeError(OpGetDiskUsage, path); err != nil {
   185  		return vfs.DiskUsage{}, err
   186  	}
   187  	return fs.fs.GetDiskUsage(path)
   188  }
   189  
   190  func (fs *FS) PathBase(p string) string {
   191  	return fs.fs.PathBase(p)
   192  }
   193  
   194  func (fs *FS) PathDir(p string) string {
   195  	return fs.fs.PathDir(p)
   196  }
   197  
   198  func (fs *FS) PathJoin(elem ...string) string {
   199  	return fs.fs.PathJoin(elem...)
   200  }
   201  
   202  func (fs *FS) Remove(name string) error {
   203  	if _, err := fs.fs.Stat(name); oserror.IsNotExist(err) {
   204  		return nil
   205  	}
   206  
   207  	if err := fs.inj.MaybeError(OpRemove, name); err != nil {
   208  		return err
   209  	}
   210  	return fs.fs.Remove(name)
   211  }
   212  
   213  func (fs *FS) RemoveAll(fullname string) error {
   214  	if err := fs.inj.MaybeError(OpRemoveAll, fullname); err != nil {
   215  		return err
   216  	}
   217  	return fs.fs.RemoveAll(fullname)
   218  }
   219  
   220  func (fs *FS) Rename(oldname, newname string) error {
   221  	if err := fs.inj.MaybeError(OpRename, oldname); err != nil {
   222  		return err
   223  	}
   224  	return fs.fs.Rename(oldname, newname)
   225  }
   226  
   227  func (fs *FS) ReuseForWrite(oldname, newname string) (vfs.File, error) {
   228  	if err := fs.inj.MaybeError(OpReuseForRewrite, oldname); err != nil {
   229  		return nil, err
   230  	}
   231  	return fs.fs.ReuseForWrite(oldname, newname)
   232  }
   233  
   234  func (fs *FS) OpenForWrite(name string) (vfs.File, error) {
   235  	if err := fs.inj.MaybeError(OpOpenForWrite, name); err != nil {
   236  		return nil, err
   237  	}
   238  	return fs.fs.OpenForWrite(name)
   239  }
   240  
   241  func (fs *FS) OpenWR(name string) (vfs.File, error) {
   242  	if err := fs.inj.MaybeError(OpOpenForWrite, name); err != nil {
   243  		return nil, err
   244  	}
   245  	return fs.fs.OpenWR(name)
   246  }
   247  
   248  func (fs *FS) MkdirAll(dir string, perm os.FileMode) error {
   249  	if err := fs.inj.MaybeError(OpMkdirAll, dir); err != nil {
   250  		return err
   251  	}
   252  	return fs.fs.MkdirAll(dir, perm)
   253  }
   254  
   255  func (fs *FS) Lock(name string) (io.Closer, error) {
   256  	if err := fs.inj.MaybeError(OpLock, name); err != nil {
   257  		return nil, err
   258  	}
   259  	return fs.fs.Lock(name)
   260  }
   261  
   262  func (fs *FS) List(dir string) ([]string, error) {
   263  	if err := fs.inj.MaybeError(OpList, dir); err != nil {
   264  		return nil, err
   265  	}
   266  	return fs.fs.List(dir)
   267  }
   268  
   269  func (fs *FS) Stat(name string) (os.FileInfo, error) {
   270  	if err := fs.inj.MaybeError(OpStat, name); err != nil {
   271  		return nil, err
   272  	}
   273  	return fs.fs.Stat(name)
   274  }
   275  
   276  type errorFile struct {
   277  	path string
   278  	file vfs.File
   279  	inj  Injector
   280  }
   281  
   282  func (f *errorFile) Close() error {
   283  	return f.file.Close()
   284  }
   285  
   286  func (f *errorFile) Read(p []byte) (int, error) {
   287  	if err := f.inj.MaybeError(OpFileRead, f.path); err != nil {
   288  		return 0, err
   289  	}
   290  	return f.file.Read(p)
   291  }
   292  
   293  func (f *errorFile) ReadAt(p []byte, off int64) (int, error) {
   294  	if err := f.inj.MaybeError(OpFileReadAt, f.path); err != nil {
   295  		return 0, err
   296  	}
   297  	return f.file.ReadAt(p, off)
   298  }
   299  
   300  func (f *errorFile) Write(p []byte) (int, error) {
   301  	if err := f.inj.MaybeError(OpFileWrite, f.path); err != nil {
   302  		return 0, err
   303  	}
   304  	return f.file.Write(p)
   305  }
   306  
   307  func (f *errorFile) Seek(offset int64, whence int) (int64, error) {
   308  	if err := f.inj.MaybeError(OpFileSeek, f.path); err != nil {
   309  		return 0, err
   310  	}
   311  	return f.file.Seek(offset, whence)
   312  }
   313  
   314  func (f *errorFile) Stat() (os.FileInfo, error) {
   315  	if err := f.inj.MaybeError(OpFileStat, f.path); err != nil {
   316  		return nil, err
   317  	}
   318  	return f.file.Stat()
   319  }
   320  
   321  func (f *errorFile) Sync() error {
   322  	if err := f.inj.MaybeError(OpFileSync, f.path); err != nil {
   323  		return err
   324  	}
   325  	return f.file.Sync()
   326  }