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