1
// Copyright 2022 The CubeFS Authors.
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
// implied. See the License for the specific language governing
13
// permissions and limitations under the License.
24
"github.com/stretchr/testify/require"
26
"github.com/cubefs/cubefs/blobstore/common/codemode"
27
"github.com/cubefs/cubefs/blobstore/util/bytespool"
30
var srcData = []byte("Hello world")
32
func copyShards(a [][]byte) [][]byte {
33
b := make([][]byte, len(a))
35
b[i] = append(b[i], a[i]...)
40
func TestEncoderNew(t *testing.T) {
42
_, err := NewEncoder(Config{CodeMode: codemode.Tactic{}})
43
require.ErrorIs(t, err, ErrInvalidCodeMode)
46
_, err := NewEncoder(Config{CodeMode: codemode.EC15P12.Tactic()})
47
require.NoError(t, err)
48
_, err = NewEncoder(Config{CodeMode: codemode.EC16P20L2.Tactic()})
49
require.NoError(t, err)
53
func TestEncoder(t *testing.T) {
55
CodeMode: codemode.EC15P12.Tactic(),
59
encoder, err := NewEncoder(cfg)
60
require.NoError(t, err)
63
shards, err := encoder.Split(srcData)
64
require.NoError(t, err)
67
err = encoder.Encode(shards)
68
require.NoError(t, err)
69
wbuff := bytes.NewBuffer(make([]byte, 0))
70
err = encoder.Join(wbuff, shards, len(srcData))
71
require.NoError(t, err)
72
require.Equal(t, srcData, wbuff.Bytes())
74
dataShards := encoder.GetDataShards(shards)
75
// set one data shards broken
76
for i := range dataShards[0] {
77
dataShards[0][i] = 222
79
// reconstruct data and check
80
err = encoder.ReconstructData(shards, []int{0})
81
require.NoError(t, err)
82
wbuff = bytes.NewBuffer(make([]byte, 0))
83
err = encoder.Join(wbuff, shards, len(srcData))
84
require.NoError(t, err)
85
require.Equal(t, srcData, wbuff.Bytes())
87
// reconstruct shard and check
88
parityShards := encoder.GetParityShards(shards)
89
for i := range parityShards[1] {
90
parityShards[1][i] = 11
92
err = encoder.Reconstruct(shards, []int{cfg.CodeMode.N + 1})
93
require.NoError(t, err)
94
ok, err := encoder.Verify(shards)
95
require.NoError(t, err)
97
wbuff = bytes.NewBuffer(make([]byte, 0))
98
err = encoder.Join(wbuff, shards, len(srcData))
99
require.NoError(t, err)
100
require.Equal(t, srcData, wbuff.Bytes())
102
ls := encoder.GetLocalShards(shards)
103
require.Equal(t, 0, len(ls))
104
si := encoder.GetShardsInIdc(shards, 0)
105
require.Equal(t, (cfg.CodeMode.N+cfg.CodeMode.M)/3, len(si))
108
func TestLrcEncoder(t *testing.T) {
110
CodeMode: codemode.EC6P10L2.Tactic(),
113
encoder, err := NewEncoder(cfg)
114
require.NoError(t, err)
116
_, err = encoder.Split([]byte{})
117
require.Error(t, err)
120
shards, err := encoder.Split(srcData)
121
require.NoError(t, err)
123
enoughBuff := make([]byte, 1<<10)
124
copy(enoughBuff, srcData)
125
enoughBuff = enoughBuff[:len(srcData)]
126
_, err := encoder.Split(enoughBuff)
127
require.NoError(t, err)
130
invalidShards := shards[:len(shards)-1]
131
require.ErrorIs(t, encoder.Encode(invalidShards), ErrInvalidShards)
132
require.ErrorIs(t, encoder.Encode(nil), ErrInvalidShards)
135
err = encoder.Encode(shards)
136
require.NoError(t, err)
137
wbuff := bytes.NewBuffer(make([]byte, 0))
138
err = encoder.Join(wbuff, shards, len(srcData))
139
require.NoError(t, err)
140
require.Equal(t, srcData, wbuff.Bytes())
142
dataShards := encoder.GetDataShards(shards)
143
// set one data shard broken
144
for i := range dataShards[0] {
145
dataShards[0][i] = 222
148
// test verify failed
149
ok, err := encoder.Verify(shards)
150
require.NoError(t, err)
153
// reconstruct data and check
154
err = encoder.ReconstructData(shards, []int{0})
155
require.NoError(t, err)
156
wbuff = bytes.NewBuffer(make([]byte, 0))
157
err = encoder.Join(wbuff, shards, len(srcData))
158
require.NoError(t, err)
159
require.Equal(t, srcData, wbuff.Bytes())
161
// Local reconstruct shard and check
162
localShardsInIdc := encoder.GetShardsInIdc(shards, 0)
163
for idx := 0; idx < len(localShardsInIdc); idx++ {
165
for i := range localShardsInIdc[idx] {
166
localShardsInIdc[idx][i] = 11
168
// check must be false when a shard broken
169
ok, err := encoder.Verify(shards)
170
require.NoError(t, err)
173
err = encoder.Reconstruct(localShardsInIdc, []int{idx})
174
require.NoError(t, err)
175
ok, err = encoder.Verify(shards)
176
require.NoError(t, err)
180
badIdxs := make([]int, 0)
182
// add a local broken
183
for j := range shards[cfg.CodeMode.N+cfg.CodeMode.M+1] {
184
shards[cfg.CodeMode.N+cfg.CodeMode.M+1][j] = 222
186
badIdxs = append(badIdxs, cfg.CodeMode.N+cfg.CodeMode.M+1)
188
// test local verify failed
189
ok, err = encoder.Verify(shards)
190
require.NoError(t, err)
193
// global reconstruct shard and check
194
dataShards = encoder.GetDataShards(shards)
195
parityShards := encoder.GetParityShards(shards)
196
for i := 0; i < cfg.CodeMode.M; i++ {
198
badIdxs = append(badIdxs, i)
200
if i < len(dataShards) {
201
for j := range dataShards[i] {
202
dataShards[i][j] = 222
206
badIdxs = append(badIdxs, cfg.CodeMode.N+i)
208
for j := range parityShards[i] {
209
parityShards[i][j] = 222
214
// test verify failed
215
ok, err = encoder.Verify(shards)
216
require.NoError(t, err)
219
err = encoder.Reconstruct(shards, badIdxs)
220
require.NoError(t, err)
221
ok, err = encoder.Verify(shards)
222
require.NoError(t, err)
224
wbuff = bytes.NewBuffer(make([]byte, 0))
225
err = encoder.Join(wbuff, shards, len(srcData))
226
require.NoError(t, err)
227
require.Equal(t, srcData, wbuff.Bytes())
229
ls := encoder.GetLocalShards(shards)
230
require.Equal(t, cfg.CodeMode.L, len(ls))
231
si := encoder.GetShardsInIdc(shards, 0)
232
require.Equal(t, (cfg.CodeMode.N+cfg.CodeMode.M+cfg.CodeMode.L)/cfg.CodeMode.AZCount, len(si))
235
shards[badIdxs[0]] = shards[badIdxs[0]][:0]
236
ok, err = encoder.Verify(shards)
237
require.Error(t, err)
240
err = encoder.Reconstruct(shards, badIdxs)
241
require.NoError(t, err)
243
shards[badIdxs[len(badIdxs)-1]] = shards[len(badIdxs)-1][:0]
244
ok, err = encoder.Verify(shards)
245
require.Error(t, err)
249
func TestLrcReconstruct(t *testing.T) {
250
for _, cm := range codemode.GetAllCodeModes() {
251
testLrcReconstruct(t, cm)
255
func testLrcReconstruct(t *testing.T, cm codemode.CodeMode) {
256
tactic := cm.Tactic()
257
cfg := Config{CodeMode: tactic, EnableVerify: true}
258
encoder, _ := NewEncoder(cfg)
260
data := make([]byte, (1<<16)+mrand.Intn(1<<16))
263
shards, err := encoder.Split(data)
264
require.NoError(t, err)
265
require.NoError(t, encoder.Encode(shards))
267
origin := copyShards(shards)
268
bads := make([]int, 0)
269
for badIdx := tactic.N + tactic.M; badIdx < cm.GetShardNum(); badIdx++ {
270
bads = append(bads, badIdx)
271
for _, idx := range bads {
272
bytespool.Zero(shards[idx])
273
shards[idx] = shards[idx][:0]
275
require.NoError(t, encoder.Reconstruct(shards, bads))
276
require.True(t, reflect.DeepEqual(origin, shards))
278
for badIdx := 0; badIdx < tactic.N+tactic.M; badIdx++ {
279
bads = append(bads, badIdx)
281
require.Error(t, encoder.Reconstruct(copyShards(shards), bads))
283
// use local ec reconstruct
284
for azIdx := 0; azIdx < tactic.AZCount; azIdx++ {
285
locals, n, m := tactic.LocalStripeInAZ(azIdx)
286
var localShards [][]byte
287
for _, idx := range locals {
288
localShards = append(localShards, shards[idx])
290
localOrigin := copyShards(localShards)
292
bads := make([]int, 0)
293
for badIdx := n; badIdx < n+m; badIdx++ {
294
bads = append(bads, badIdx)
295
for _, idx := range bads {
296
bytespool.Zero(localShards[idx])
297
localShards[idx] = localShards[idx][:0]
299
require.NoError(t, encoder.Reconstruct(localShards, bads))
300
require.True(t, reflect.DeepEqual(localOrigin, localShards))
303
bads = append(bads, n-1)
304
require.Error(t, encoder.Reconstruct(localShards, bads))