-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.go
99 lines (76 loc) · 1.64 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package dextk
import (
"io"
)
const (
cacheShift = 12
cacheSize = 1 << cacheShift
cacheMask = cacheSize - 1
)
type cachedReader struct {
slots int
store []byte
mapping []int64
lengths []int
r io.ReaderAt
}
func newCachedReader(r io.ReaderAt, slots int) *cachedReader {
store := make([]byte, cacheSize*slots)
mappings := make([]int64, slots)
lengths := make([]int, slots)
for i := 0; i < slots; i++ {
mappings[i] = -1
}
return &cachedReader{
slots,
store,
mappings,
lengths,
r,
}
}
func (r *cachedReader) ReadAt(tgt []byte, pos int64) (int, error) {
remaining := len(tgt)
cur := 0
for remaining > 0 {
chunk := pos >> cacheShift
inner := int(pos & cacheMask)
data, err := r.getChunk(chunk)
if err != nil {
return len(tgt) - remaining, err
}
rsize := len(data) - inner
if rsize > remaining {
rsize = remaining
}
copy(tgt[cur:cur+rsize], data[inner:inner+rsize])
remaining -= rsize
cur += rsize
pos += int64(rsize)
if remaining > 0 && rsize != cacheSize-inner {
return len(tgt) - remaining, io.EOF
}
}
if remaining > 0 {
panic("remaining != 0")
}
return len(tgt), nil
}
func (r *cachedReader) getChunk(chunk int64) ([]byte, error) {
slot := chunk % int64(r.slots)
slotStart := int(slot << cacheShift)
slotEnd := slotStart + cacheSize
if r.mapping[slot] == chunk {
l := r.lengths[slot]
return r.store[slotStart : slotStart+l], nil
}
data := r.store[slotStart:slotEnd]
size, err := r.r.ReadAt(data, chunk<<cacheShift)
if err != nil && err != io.EOF {
return nil, err
}
r.mapping[slot] = chunk
r.lengths[slot] = size
block := data[:size]
return block, nil
}