]> Sergey Matveev's repositories - btrtrc.git/blob - mmap_span/mmap_span.go
gofumpt
[btrtrc.git] / mmap_span / mmap_span.go
1 package mmap_span
2
3 import (
4         "fmt"
5         "io"
6         "sync"
7
8         "github.com/anacrolix/torrent/segments"
9         "github.com/edsrzf/mmap-go"
10 )
11
12 type MMapSpan struct {
13         mu             sync.RWMutex
14         mMaps          []mmap.MMap
15         segmentLocater segments.Index
16 }
17
18 func (ms *MMapSpan) Append(mMap mmap.MMap) {
19         ms.mMaps = append(ms.mMaps, mMap)
20 }
21
22 func (ms *MMapSpan) Close() (errs []error) {
23         ms.mu.Lock()
24         defer ms.mu.Unlock()
25         for _, mMap := range ms.mMaps {
26                 err := mMap.Unmap()
27                 if err != nil {
28                         errs = append(errs, err)
29                 }
30         }
31         // This is for issue 211.
32         ms.mMaps = nil
33         ms.InitIndex()
34         return
35 }
36
37 func (me *MMapSpan) InitIndex() {
38         i := 0
39         me.segmentLocater = segments.NewIndex(func() (segments.Length, bool) {
40                 if i == len(me.mMaps) {
41                         return -1, false
42                 }
43                 l := int64(len(me.mMaps[i]))
44                 i++
45                 return l, true
46         })
47         // log.Printf("made mmapspan index: %v", me.segmentLocater)
48 }
49
50 func (ms *MMapSpan) ReadAt(p []byte, off int64) (n int, err error) {
51         // log.Printf("reading %v bytes at %v", len(p), off)
52         ms.mu.RLock()
53         defer ms.mu.RUnlock()
54         n = ms.locateCopy(func(a, b []byte) (_, _ []byte) { return a, b }, p, off)
55         if n != len(p) {
56                 err = io.EOF
57         }
58         return
59 }
60
61 func copyBytes(dst, src []byte) int {
62         return copy(dst, src)
63 }
64
65 func (ms *MMapSpan) locateCopy(copyArgs func(remainingArgument, mmapped []byte) (dst, src []byte), p []byte, off int64) (n int) {
66         ms.segmentLocater.Locate(segments.Extent{off, int64(len(p))}, func(i int, e segments.Extent) bool {
67                 mMapBytes := ms.mMaps[i][e.Start:]
68                 // log.Printf("got segment %v: %v, copying %v, %v", i, e, len(p), len(mMapBytes))
69                 _n := copyBytes(copyArgs(p, mMapBytes))
70                 p = p[_n:]
71                 n += _n
72                 if segments.Int(_n) != e.Length {
73                         panic(fmt.Sprintf("did %d bytes, expected to do %d", _n, e.Length))
74                 }
75                 return true
76         })
77         return
78 }
79
80 func (ms *MMapSpan) WriteAt(p []byte, off int64) (n int, err error) {
81         // log.Printf("writing %v bytes at %v", len(p), off)
82         ms.mu.RLock()
83         defer ms.mu.RUnlock()
84         n = ms.locateCopy(func(a, b []byte) (_, _ []byte) { return b, a }, p, off)
85         if n != len(p) {
86                 err = io.ErrShortWrite
87         }
88         return
89 }