github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/database/ffldb/mockfile_test.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  // This file is part of the ffldb package rather than the ffldb_test package as
     7  // it is part of the whitebox testing.
     8  
     9  package ffldb
    10  
    11  import (
    12  	"errors"
    13  	"io"
    14  	"sync"
    15  )
    16  
    17  // Errors used for the mock file.
    18  var (
    19  	// errMockFileClosed is used to indicate a mock file is closed.
    20  	errMockFileClosed = errors.New("file closed")
    21  
    22  	// errInvalidOffset is used to indicate an offset that is out of range
    23  	// for the file was provided.
    24  	errInvalidOffset = errors.New("invalid offset")
    25  
    26  	// errSyncFail is used to indicate simulated sync failure.
    27  	errSyncFail = errors.New("simulated sync failure")
    28  )
    29  
    30  // mockFile implements the filer interface and used in order to force failures
    31  // the database code related to reading and writing from the flat block files.
    32  // A maxSize of -1 is unlimited.
    33  type mockFile struct {
    34  	sync.RWMutex
    35  	maxSize      int64
    36  	data         []byte
    37  	forceSyncErr bool
    38  	closed       bool
    39  }
    40  
    41  // Close closes the mock file without releasing any data associated with it.
    42  // This allows it to be "reopened" without losing the data.
    43  //
    44  // This is part of the filer implementation.
    45  func (f *mockFile) Close() error {
    46  	f.Lock()
    47  	defer f.Unlock()
    48  
    49  	if f.closed {
    50  		return errMockFileClosed
    51  	}
    52  	f.closed = true
    53  	return nil
    54  }
    55  
    56  // ReadAt reads len(b) bytes from the mock file starting at byte offset off. It
    57  // returns the number of bytes read and the error, if any.  ReadAt always
    58  // returns a non-nil error when n < len(b). At end of file, that error is
    59  // io.EOF.
    60  //
    61  // This is part of the filer implementation.
    62  func (f *mockFile) ReadAt(b []byte, off int64) (int, error) {
    63  	f.RLock()
    64  	defer f.RUnlock()
    65  
    66  	if f.closed {
    67  		return 0, errMockFileClosed
    68  	}
    69  	maxSize := int64(len(f.data))
    70  	if f.maxSize > -1 && maxSize > f.maxSize {
    71  		maxSize = f.maxSize
    72  	}
    73  	if off < 0 || off > maxSize {
    74  		return 0, errInvalidOffset
    75  	}
    76  
    77  	// Limit to the max size field, if set.
    78  	numToRead := int64(len(b))
    79  	endOffset := off + numToRead
    80  	if endOffset > maxSize {
    81  		numToRead = maxSize - off
    82  	}
    83  
    84  	copy(b, f.data[off:off+numToRead])
    85  	if numToRead < int64(len(b)) {
    86  		return int(numToRead), io.EOF
    87  	}
    88  	return int(numToRead), nil
    89  }
    90  
    91  // Truncate changes the size of the mock file.
    92  //
    93  // This is part of the filer implementation.
    94  func (f *mockFile) Truncate(size int64) error {
    95  	f.Lock()
    96  	defer f.Unlock()
    97  
    98  	if f.closed {
    99  		return errMockFileClosed
   100  	}
   101  	maxSize := int64(len(f.data))
   102  	if f.maxSize > -1 && maxSize > f.maxSize {
   103  		maxSize = f.maxSize
   104  	}
   105  	if size > maxSize {
   106  		return errInvalidOffset
   107  	}
   108  
   109  	f.data = f.data[:size]
   110  	return nil
   111  }
   112  
   113  // Write writes len(b) bytes to the mock file. It returns the number of bytes
   114  // written and an error, if any.  Write returns a non-nil error any time
   115  // n != len(b).
   116  //
   117  // This is part of the filer implementation.
   118  func (f *mockFile) WriteAt(b []byte, off int64) (int, error) {
   119  	f.Lock()
   120  	defer f.Unlock()
   121  
   122  	if f.closed {
   123  		return 0, errMockFileClosed
   124  	}
   125  	maxSize := f.maxSize
   126  	if maxSize < 0 {
   127  		maxSize = 100 * 1024 // 100KiB
   128  	}
   129  	if off < 0 || off > maxSize {
   130  		return 0, errInvalidOffset
   131  	}
   132  
   133  	// Limit to the max size field, if set, and grow the slice if needed.
   134  	numToWrite := int64(len(b))
   135  	if off+numToWrite > maxSize {
   136  		numToWrite = maxSize - off
   137  	}
   138  	if off+numToWrite > int64(len(f.data)) {
   139  		newData := make([]byte, off+numToWrite)
   140  		copy(newData, f.data)
   141  		f.data = newData
   142  	}
   143  
   144  	copy(f.data[off:], b[:numToWrite])
   145  	if numToWrite < int64(len(b)) {
   146  		return int(numToWrite), io.EOF
   147  	}
   148  	return int(numToWrite), nil
   149  }
   150  
   151  // Sync doesn't do anything for mock files.  However, it will return an error if
   152  // the mock file's forceSyncErr flag is set.
   153  //
   154  // This is part of the filer implementation.
   155  func (f *mockFile) Sync() error {
   156  	if f.forceSyncErr {
   157  		return errSyncFail
   158  	}
   159  
   160  	return nil
   161  }
   162  
   163  // Ensure the mockFile type implements the filer interface.
   164  var _ filer = (*mockFile)(nil)