-
Notifications
You must be signed in to change notification settings - Fork 81
/
leopard.go
80 lines (66 loc) · 1.7 KB
/
leopard.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
package rsmt2d
import (
"sync"
"github.com/klauspost/reedsolomon"
)
var _ Codec = &leoRSCodec{}
func init() {
registerCodec(Leopard, NewLeoRSCodec())
}
type leoRSCodec struct {
// Cache the encoders of various sizes to not have to re-instantiate those
// as it is costly.
//
// Note that past sizes are not removed from the cache at all as the various
// data sizes are expected to relatively small and will not cause any memory issue.
//
// TODO: switch to a generic version of sync.Map with type reedsolomon.Encoder
// once it made it into the standard lib
encCache sync.Map
}
func (l *leoRSCodec) Encode(data [][]byte) ([][]byte, error) {
dataLen := len(data)
enc, err := l.loadOrInitEncoder(dataLen)
if err != nil {
return nil, err
}
shards := make([][]byte, dataLen*2)
copy(shards, data)
for i := dataLen; i < len(shards); i++ {
shards[i] = make([]byte, len(data[0]))
}
if err := enc.Encode(shards); err != nil {
return nil, err
}
return shards[dataLen:], nil
}
func (l *leoRSCodec) Decode(data [][]byte) ([][]byte, error) {
half := len(data) / 2
enc, err := l.loadOrInitEncoder(half)
if err != nil {
return nil, err
}
err = enc.Reconstruct(data)
return data, err
}
func (l *leoRSCodec) loadOrInitEncoder(dataLen int) (reedsolomon.Encoder, error) {
enc, ok := l.encCache.Load(dataLen)
if !ok {
var err error
enc, err = reedsolomon.New(dataLen, dataLen, reedsolomon.WithLeopardGF(true))
if err != nil {
return nil, err
}
l.encCache.Store(dataLen, enc)
}
return enc.(reedsolomon.Encoder), nil
}
func (l *leoRSCodec) MaxChunks() int {
return 32768 * 32768
}
func (l *leoRSCodec) Name() string {
return Leopard
}
func NewLeoRSCodec() *leoRSCodec {
return &leoRSCodec{}
}