2014-04-09 00:36:05 +08:00
|
|
|
package mmap_span
|
2013-09-26 11:42:24 +08:00
|
|
|
|
|
|
|
import (
|
2020-05-31 19:00:19 +08:00
|
|
|
"fmt"
|
2013-09-26 11:42:24 +08:00
|
|
|
"io"
|
2018-01-06 13:39:52 +08:00
|
|
|
"sync"
|
2014-04-08 17:39:34 +08:00
|
|
|
|
2020-05-31 19:00:19 +08:00
|
|
|
"github.com/anacrolix/torrent/segments"
|
2015-12-23 00:50:34 +08:00
|
|
|
"github.com/edsrzf/mmap-go"
|
2013-09-26 11:42:24 +08:00
|
|
|
)
|
|
|
|
|
2014-12-05 14:54:55 +08:00
|
|
|
type MMapSpan struct {
|
2020-05-31 19:00:19 +08:00
|
|
|
mu sync.RWMutex
|
|
|
|
mMaps []mmap.MMap
|
|
|
|
segmentLocater segments.Index
|
2014-12-05 14:54:55 +08:00
|
|
|
}
|
2013-09-26 11:42:24 +08:00
|
|
|
|
2020-05-31 19:00:19 +08:00
|
|
|
func (ms *MMapSpan) Append(mMap mmap.MMap) {
|
|
|
|
ms.mMaps = append(ms.mMaps, mMap)
|
2013-09-26 11:42:24 +08:00
|
|
|
}
|
|
|
|
|
2020-05-31 19:00:19 +08:00
|
|
|
func (ms *MMapSpan) Close() (errs []error) {
|
2018-01-06 13:39:52 +08:00
|
|
|
ms.mu.Lock()
|
|
|
|
defer ms.mu.Unlock()
|
2020-05-31 19:00:19 +08:00
|
|
|
for _, mMap := range ms.mMaps {
|
|
|
|
err := mMap.Unmap()
|
2016-03-28 19:40:29 +08:00
|
|
|
if err != nil {
|
2020-05-31 19:00:19 +08:00
|
|
|
errs = append(errs, err)
|
2016-03-28 19:40:29 +08:00
|
|
|
}
|
2013-09-26 17:49:15 +08:00
|
|
|
}
|
2020-05-31 19:00:19 +08:00
|
|
|
// This is for issue 211.
|
|
|
|
ms.mMaps = nil
|
|
|
|
ms.InitIndex()
|
|
|
|
return
|
2013-09-26 17:49:15 +08:00
|
|
|
}
|
|
|
|
|
2020-05-31 19:00:19 +08:00
|
|
|
func (me *MMapSpan) InitIndex() {
|
|
|
|
i := 0
|
|
|
|
me.segmentLocater = segments.NewIndex(func() (segments.Length, bool) {
|
|
|
|
if i == len(me.mMaps) {
|
|
|
|
return -1, false
|
|
|
|
}
|
|
|
|
l := int64(len(me.mMaps[i]))
|
|
|
|
i++
|
|
|
|
return l, true
|
|
|
|
})
|
|
|
|
//log.Printf("made mmapspan index: %v", me.segmentLocater)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *MMapSpan) ReadAt(p []byte, off int64) (n int, err error) {
|
|
|
|
//log.Printf("reading %v bytes at %v", len(p), off)
|
2018-01-06 13:39:52 +08:00
|
|
|
ms.mu.RLock()
|
|
|
|
defer ms.mu.RUnlock()
|
2020-05-31 19:00:19 +08:00
|
|
|
n = ms.locateCopy(func(a, b []byte) (_, _ []byte) { return a, b }, p, off)
|
|
|
|
if n != len(p) {
|
|
|
|
err = io.EOF
|
2013-09-26 11:42:24 +08:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-31 19:00:19 +08:00
|
|
|
func copyBytes(dst, src []byte) int {
|
|
|
|
return copy(dst, src)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *MMapSpan) locateCopy(copyArgs func(remainingArgument, mmapped []byte) (dst, src []byte), p []byte, off int64) (n int) {
|
|
|
|
ms.segmentLocater.Locate(segments.Extent{off, int64(len(p))}, func(i int, e segments.Extent) bool {
|
|
|
|
mMapBytes := ms.mMaps[i][e.Start:]
|
|
|
|
//log.Printf("got segment %v: %v, copying %v, %v", i, e, len(p), len(mMapBytes))
|
|
|
|
_n := copyBytes(copyArgs(p, mMapBytes))
|
2013-09-26 11:42:24 +08:00
|
|
|
p = p[_n:]
|
|
|
|
n += _n
|
2020-05-31 19:00:19 +08:00
|
|
|
if segments.Int(_n) != e.Length {
|
|
|
|
panic(fmt.Sprintf("did %d bytes, expected to do %d", _n, e.Length))
|
|
|
|
}
|
|
|
|
return true
|
2013-09-26 11:42:24 +08:00
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-06 13:39:52 +08:00
|
|
|
func (ms *MMapSpan) WriteAt(p []byte, off int64) (n int, err error) {
|
2020-11-11 23:10:05 +08:00
|
|
|
// log.Printf("writing %v bytes at %v", len(p), off)
|
2018-01-06 13:39:52 +08:00
|
|
|
ms.mu.RLock()
|
|
|
|
defer ms.mu.RUnlock()
|
2020-05-31 19:00:19 +08:00
|
|
|
n = ms.locateCopy(func(a, b []byte) (_, _ []byte) { return b, a }, p, off)
|
|
|
|
if n != len(p) {
|
2013-10-02 17:54:23 +08:00
|
|
|
err = io.ErrShortWrite
|
2013-09-26 11:42:24 +08:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|