-
Notifications
You must be signed in to change notification settings - Fork 28
/
erasurecode.go
82 lines (72 loc) · 2.03 KB
/
erasurecode.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
package encoder
import (
"bufio"
"bytes"
"errors"
. "github.com/0chain/gosdk/zboxcore/logger"
"github.com/klauspost/reedsolomon"
)
type codec interface {
Encode(in []byte) ([][]byte, error)
Decode(in [][]byte) ([]byte, error)
}
type StreamEncoder struct {
iDataShards int
iParityShards int
erasureCode reedsolomon.Encoder
data [][]byte
}
// Creates New encoder instance and return index for further access
func NewEncoder(iDataShards, iParityShards int) (*StreamEncoder, error) {
e := &StreamEncoder{}
var err error
e.erasureCode, err = reedsolomon.New(iDataShards, iParityShards, reedsolomon.WithAutoGoroutines(64*1024))
if err != nil {
return nil, err
}
e.iDataShards = iDataShards
e.iParityShards = iParityShards
return e, nil
}
// Encodes and returns the shards on success and error on fails
func (e *StreamEncoder) Encode(in []byte) ([][]byte, error) {
var err error
e.data, err = e.erasureCode.Split(in)
if err != nil {
Logger.Error("Split failed", err.Error())
return [][]byte{}, err
}
err = e.erasureCode.Encode(e.data)
if err != nil {
Logger.Error("Encode failed", err.Error())
return [][]byte{}, err
}
return e.data, nil
}
func (e *StreamEncoder) Decode(in [][]byte, shardSize int) ([]byte, error) {
// Verify the input
if (len(in) < e.iDataShards+e.iParityShards) || (shardSize <= 0) {
return []byte{}, errors.New("Invalid input length")
}
err := e.erasureCode.Reconstruct(in)
if err != nil {
Logger.Error("Reconstruct failed -", err)
return []byte{}, err
}
_, err = e.erasureCode.Verify(in)
if err != nil {
Logger.Error("Verification failed after reconstruction, data likely corrupted.", err.Error())
return []byte{}, err
}
var bytesBuf bytes.Buffer
bufWriter := bufio.NewWriter(&bytesBuf)
bufWriter = bufio.NewWriterSize(bufWriter, (shardSize * e.iDataShards))
err = e.erasureCode.Join(bufWriter, in, (shardSize * e.iDataShards))
if err != nil {
Logger.Error("join failed", err.Error())
return []byte{}, err
}
bufWriter.Flush()
outBuf := bytesBuf.Bytes()
return outBuf, nil
}