github.com/anacrolix/torrent@v1.61.0/mmap-span/mmap-span.go (about)

     1  package mmapSpan
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"io/fs"
     7  	"sync"
     8  
     9  	"github.com/anacrolix/missinggo/v2/panicif"
    10  
    11  	"github.com/anacrolix/torrent/segments"
    12  )
    13  
    14  type Mmap interface {
    15  	Flush() error
    16  	Unmap() error
    17  	Bytes() []byte
    18  }
    19  
    20  type MMapSpan struct {
    21  	mu             sync.RWMutex
    22  	closed         bool
    23  	mMaps          []Mmap
    24  	segmentLocater segments.Index
    25  }
    26  
    27  func New(mMaps []Mmap, index segments.Index) *MMapSpan {
    28  	return &MMapSpan{
    29  		mMaps:          mMaps,
    30  		segmentLocater: index,
    31  	}
    32  }
    33  
    34  func (ms *MMapSpan) Flush() (err error) {
    35  	ms.mu.RLock()
    36  	defer ms.mu.RUnlock()
    37  	for _, mMap := range ms.mMaps {
    38  		err = errors.Join(err, mMap.Flush())
    39  	}
    40  	return
    41  }
    42  
    43  func (ms *MMapSpan) Close() (err error) {
    44  	ms.mu.Lock()
    45  	defer ms.mu.Unlock()
    46  	for _, mMap := range ms.mMaps {
    47  		err = errors.Join(err, mMap.Unmap())
    48  	}
    49  	// This is for issue 211.
    50  	ms.mMaps = nil
    51  	ms.closed = true
    52  	return
    53  }
    54  
    55  func (ms *MMapSpan) ReadAt(p []byte, off int64) (n int, err error) {
    56  	// log.Printf("reading %v bytes at %v", len(p), off)
    57  	ms.mu.RLock()
    58  	defer ms.mu.RUnlock()
    59  	if ms.closed {
    60  		err = fs.ErrClosed
    61  		return
    62  	}
    63  	n = ms.locateCopy(func(a, b []byte) (_, _ []byte) { return a, b }, p, off)
    64  	if n != len(p) {
    65  		err = io.EOF
    66  	}
    67  	return
    68  }
    69  
    70  func copyBytes(dst, src []byte) int {
    71  	return copy(dst, src)
    72  }
    73  
    74  func (ms *MMapSpan) locateCopy(
    75  	copyArgs func(remainingArgument, mmapped []byte) (dst, src []byte),
    76  	p []byte,
    77  	off int64,
    78  ) (n int) {
    79  	for i, e := range ms.segmentLocater.LocateIter(segments.Extent{off, int64(len(p))}) {
    80  		mMapBytes := ms.mMaps[i].Bytes()[e.Start:]
    81  		// log.Printf("got segment %v: %v, copying %v, %v", i, e, len(p), len(mMapBytes))
    82  		_n := copyBytes(copyArgs(p, mMapBytes))
    83  		p = p[_n:]
    84  		n += _n
    85  		panicif.NotEq(segments.Int(_n), e.Length)
    86  	}
    87  	return
    88  }
    89  
    90  func (ms *MMapSpan) WriteAt(p []byte, off int64) (n int, err error) {
    91  	// log.Printf("writing %v bytes at %v", len(p), off)
    92  	ms.mu.RLock()
    93  	defer ms.mu.RUnlock()
    94  	n = ms.locateCopy(func(a, b []byte) (_, _ []byte) { return b, a }, p, off)
    95  	if n != len(p) {
    96  		err = io.ErrShortWrite
    97  	}
    98  	return
    99  }