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 }