Skip to content

Commit e5b76dc

Browse files
authored
HADOOP-19180. EC: Fix calculation errors caused by special index order (#6813). Contributed by zhengchenyu.
Reviewed-by: He Xiaoqiao <hexiaoqiao@apache.org> Signed-off-by: Shuyan Zhang <zhangshuyan@apache.org>
1 parent 59dba6e commit e5b76dc

File tree

5 files changed

+195
-62
lines changed

5 files changed

+195
-62
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/erasurecode/rawcoder/RSRawDecoder.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public class RSRawDecoder extends RawErasureDecoder {
5151
private byte[] gfTables;
5252
private int[] cachedErasedIndexes;
5353
private int[] validIndexes;
54-
private int numErasedDataUnits;
5554
private boolean[] erasureFlags;
5655

5756
public RSRawDecoder(ErasureCoderOptions coderOptions) {
@@ -120,14 +119,10 @@ private void processErasures(int[] erasedIndexes) {
120119
this.gfTables = new byte[getNumAllUnits() * getNumDataUnits() * 32];
121120

122121
this.erasureFlags = new boolean[getNumAllUnits()];
123-
this.numErasedDataUnits = 0;
124122

125123
for (int i = 0; i < erasedIndexes.length; i++) {
126124
int index = erasedIndexes[i];
127125
erasureFlags[index] = true;
128-
if (index < getNumDataUnits()) {
129-
numErasedDataUnits++;
130-
}
131126
}
132127

133128
generateDecodeMatrix(erasedIndexes);
@@ -156,21 +151,22 @@ private void generateDecodeMatrix(int[] erasedIndexes) {
156151

157152
GF256.gfInvertMatrix(tmpMatrix, invertMatrix, getNumDataUnits());
158153

159-
for (i = 0; i < numErasedDataUnits; i++) {
160-
for (j = 0; j < getNumDataUnits(); j++) {
161-
decodeMatrix[getNumDataUnits() * i + j] =
162-
invertMatrix[getNumDataUnits() * erasedIndexes[i] + j];
163-
}
164-
}
165-
166-
for (p = numErasedDataUnits; p < erasedIndexes.length; p++) {
167-
for (i = 0; i < getNumDataUnits(); i++) {
168-
s = 0;
154+
for (p = 0; p < erasedIndexes.length; p++) {
155+
int erasedIndex = erasedIndexes[p];
156+
if (erasedIndex < getNumDataUnits()) {
169157
for (j = 0; j < getNumDataUnits(); j++) {
170-
s ^= GF256.gfMul(invertMatrix[j * getNumDataUnits() + i],
171-
encodeMatrix[getNumDataUnits() * erasedIndexes[p] + j]);
158+
decodeMatrix[getNumDataUnits() * p + j] =
159+
invertMatrix[getNumDataUnits() * erasedIndexes[p] + j];
160+
}
161+
} else {
162+
for (i = 0; i < getNumDataUnits(); i++) {
163+
s = 0;
164+
for (j = 0; j < getNumDataUnits(); j++) {
165+
s ^= GF256.gfMul(invertMatrix[j * getNumDataUnits() + i],
166+
encodeMatrix[getNumDataUnits() * erasedIndexes[p] + j]);
167+
}
168+
decodeMatrix[getNumDataUnits() * p + i] = s;
172169
}
173-
decodeMatrix[getNumDataUnits() * p + i] = s;
174170
}
175171
}
176172
}

hadoop-common-project/hadoop-common/src/main/native/src/org/apache/hadoop/io/erasurecode/erasure_coder.c

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,6 @@ static int processErasures(IsalDecoder* pCoder, unsigned char** inputs,
132132
index = erasedIndexes[i];
133133
pCoder->erasedIndexes[i] = index;
134134
pCoder->erasureFlags[index] = 1;
135-
if (index < numDataUnits) {
136-
pCoder->numErasedDataUnits++;
137-
}
138135
}
139136

140137
pCoder->numErased = numErased;
@@ -175,7 +172,6 @@ int decode(IsalDecoder* pCoder, unsigned char** inputs,
175172

176173
// Clear variables used per decode call
177174
void clearDecoder(IsalDecoder* decoder) {
178-
decoder->numErasedDataUnits = 0;
179175
decoder->numErased = 0;
180176
memset(decoder->gftbls, 0, sizeof(decoder->gftbls));
181177
memset(decoder->decodeMatrix, 0, sizeof(decoder->decodeMatrix));
@@ -205,24 +201,24 @@ int generateDecodeMatrix(IsalDecoder* pCoder) {
205201
h_gf_invert_matrix(pCoder->tmpMatrix,
206202
pCoder->invertMatrix, numDataUnits);
207203

208-
for (i = 0; i < pCoder->numErasedDataUnits; i++) {
204+
for (p = 0; p < pCoder->numErased; p++) {
209205
for (j = 0; j < numDataUnits; j++) {
210-
pCoder->decodeMatrix[numDataUnits * i + j] =
211-
pCoder->invertMatrix[numDataUnits *
212-
pCoder->erasedIndexes[i] + j];
213-
}
214-
}
215-
216-
for (p = pCoder->numErasedDataUnits; p < pCoder->numErased; p++) {
217-
for (i = 0; i < numDataUnits; i++) {
218-
s = 0;
219-
for (j = 0; j < numDataUnits; j++) {
220-
s ^= h_gf_mul(pCoder->invertMatrix[j * numDataUnits + i],
221-
pCoder->encodeMatrix[numDataUnits *
222-
pCoder->erasedIndexes[p] + j]);
206+
int erasedIndex = pCoder->erasedIndexes[p];
207+
if (erasedIndex < numDataUnits) {
208+
pCoder->decodeMatrix[numDataUnits * p + j] =
209+
pCoder->invertMatrix[numDataUnits *
210+
pCoder->erasedIndexes[p] + j];
211+
} else {
212+
for (i = 0; i < numDataUnits; i++) {
213+
s = 0;
214+
for (j = 0; j < numDataUnits; j++) {
215+
s ^= h_gf_mul(pCoder->invertMatrix[j * numDataUnits + i],
216+
pCoder->encodeMatrix[numDataUnits *
217+
pCoder->erasedIndexes[p] + j]);
218+
}
219+
pCoder->decodeMatrix[numDataUnits * p + i] = s;
220+
}
223221
}
224-
225-
pCoder->decodeMatrix[numDataUnits * p + i] = s;
226222
}
227223
}
228224

hadoop-common-project/hadoop-common/src/main/native/src/org/apache/hadoop/io/erasurecode/erasure_coder.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ typedef struct _IsalDecoder {
6262
unsigned char erasureFlags[MMAX];
6363
int erasedIndexes[MMAX];
6464
int numErased;
65-
int numErasedDataUnits;
6665
unsigned char* realInputs[MMAX];
6766
} IsalDecoder;
6867

hadoop-common-project/hadoop-common/src/main/native/src/test/org/apache/hadoop/io/erasurecode/erasure_code_test.c

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,27 @@
2727
#include "erasure_code.h"
2828
#include "gf_util.h"
2929
#include "erasure_coder.h"
30+
#include "dump.h"
3031

3132
#include <stdio.h>
3233
#include <stdlib.h>
3334
#include <string.h>
3435

3536
int main(int argc, char *argv[]) {
36-
int i, j;
37+
int i, j, k, l;
3738
char err[256];
3839
size_t err_len = sizeof(err);
3940
int chunkSize = 1024;
4041
int numDataUnits = 6;
4142
int numParityUnits = 3;
43+
int numTotalUnits = numDataUnits + numParityUnits;
4244
unsigned char** dataUnits;
4345
unsigned char** parityUnits;
4446
IsalEncoder* pEncoder;
45-
int erasedIndexes[2];
47+
int erasedIndexes[3];
4648
unsigned char* allUnits[MMAX];
4749
IsalDecoder* pDecoder;
48-
unsigned char* decodingOutput[2];
50+
unsigned char* decodingOutput[3];
4951
unsigned char** backupUnits;
5052

5153
if (0 == build_support_erasurecode()) {
@@ -82,6 +84,11 @@ int main(int argc, char *argv[]) {
8284
}
8385
}
8486

87+
// Allocate decode output
88+
for (i = 0; i < 3; i++) {
89+
decodingOutput[i] = malloc(chunkSize);
90+
}
91+
8592
pEncoder = (IsalEncoder*)malloc(sizeof(IsalEncoder));
8693
memset(pEncoder, 0, sizeof(*pEncoder));
8794
initEncoder(pEncoder, numDataUnits, numParityUnits);
@@ -95,26 +102,53 @@ int main(int argc, char *argv[]) {
95102
memcpy(allUnits + numDataUnits, parityUnits,
96103
numParityUnits * (sizeof (unsigned char*)));
97104

98-
erasedIndexes[0] = 1;
99-
erasedIndexes[1] = 7;
100-
101-
backupUnits[0] = allUnits[1];
102-
backupUnits[1] = allUnits[7];
103-
104-
allUnits[0] = NULL; // Not to read
105-
allUnits[1] = NULL;
106-
allUnits[7] = NULL;
107-
108-
decodingOutput[0] = malloc(chunkSize);
109-
decodingOutput[1] = malloc(chunkSize);
110-
111-
decode(pDecoder, allUnits, erasedIndexes, 2, decodingOutput, chunkSize);
112-
113-
for (i = 0; i < pDecoder->numErased; i++) {
114-
if (0 != memcmp(decodingOutput[i], backupUnits[i], chunkSize)) {
115-
fprintf(stderr, "Decoding failed\n\n");
116-
dumpDecoder(pDecoder);
117-
return -1;
105+
for (i = 0; i < numTotalUnits; i++) {
106+
for (j = 0; j < numTotalUnits; j++) {
107+
for (k = 0; k < numTotalUnits; k++) {
108+
int numErased;
109+
if (i == j && j == k) {
110+
erasedIndexes[0] = i;
111+
numErased = 1;
112+
backupUnits[0] = allUnits[i];
113+
allUnits[i] = NULL;
114+
} else if (i == j) {
115+
erasedIndexes[0] = i;
116+
erasedIndexes[1] = k;
117+
numErased = 2;
118+
backupUnits[0] = allUnits[i];
119+
backupUnits[1] = allUnits[k];
120+
allUnits[i] = NULL;
121+
allUnits[k] = NULL;
122+
} else if (i == k || j == k) {
123+
erasedIndexes[0] = i;
124+
erasedIndexes[1] = j;
125+
numErased = 2;
126+
backupUnits[0] = allUnits[i];
127+
backupUnits[1] = allUnits[j];
128+
allUnits[i] = NULL;
129+
allUnits[j] = NULL;
130+
} else {
131+
erasedIndexes[0] = i;
132+
erasedIndexes[1] = j;
133+
erasedIndexes[2] = k;
134+
numErased = 3;
135+
backupUnits[0] = allUnits[i];
136+
backupUnits[1] = allUnits[j];
137+
backupUnits[2] = allUnits[k];
138+
allUnits[i] = NULL;
139+
allUnits[j] = NULL;
140+
allUnits[k] = NULL;
141+
}
142+
decode(pDecoder, allUnits, erasedIndexes, numErased, decodingOutput, chunkSize);
143+
for (l = 0; l < pDecoder->numErased; l++) {
144+
if (0 != memcmp(decodingOutput[l], backupUnits[l], chunkSize)) {
145+
printf("Decoding failed\n");
146+
dumpDecoder(pDecoder);
147+
return -1;
148+
}
149+
allUnits[erasedIndexes[l]] = backupUnits[l];
150+
}
151+
}
118152
}
119153
}
120154

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.io.erasurecode;
20+
21+
import org.apache.hadoop.conf.Configuration;
22+
import org.apache.hadoop.io.erasurecode.rawcoder.RawErasureDecoder;
23+
import org.apache.hadoop.io.erasurecode.rawcoder.RawErasureEncoder;
24+
import org.junit.Test;
25+
26+
import java.util.Random;
27+
28+
import static org.junit.Assert.assertArrayEquals;
29+
30+
public class TestErasureCodingEncodeAndDecode {
31+
32+
private final static int CHUNCK = 1024;
33+
private final static int DATAB_LOCKS = 6;
34+
private final static int PARITY_BLOCKS = 3;
35+
private final static int TOTAL_BLOCKS = DATAB_LOCKS + PARITY_BLOCKS;
36+
37+
@Test
38+
public void testEncodeAndDecode() throws Exception {
39+
Configuration conf = new Configuration();
40+
int totalBytes = CHUNCK * DATAB_LOCKS;
41+
Random random = new Random();
42+
byte[] tmpBytes = new byte[totalBytes];
43+
random.nextBytes(tmpBytes);
44+
byte[][] data = new byte[DATAB_LOCKS][CHUNCK];
45+
for (int i = 0; i < DATAB_LOCKS; i++) {
46+
System.arraycopy(tmpBytes, i * CHUNCK, data[i], 0, CHUNCK);
47+
}
48+
ErasureCoderOptions coderOptions = new ErasureCoderOptions(DATAB_LOCKS, PARITY_BLOCKS);
49+
50+
// 1 Encode
51+
RawErasureEncoder encoder =
52+
CodecUtil.createRawEncoder(conf, ErasureCodeConstants.RS_CODEC_NAME, coderOptions);
53+
byte[][] parity = new byte[PARITY_BLOCKS][CHUNCK];
54+
encoder.encode(data, parity);
55+
56+
// 2 Compose the complete data
57+
byte[][] all = new byte[DATAB_LOCKS + PARITY_BLOCKS][CHUNCK];
58+
for (int i = 0; i < DATAB_LOCKS; i++) {
59+
System.arraycopy(data[i], 0, all[i], 0, CHUNCK);
60+
}
61+
for (int i = 0; i < PARITY_BLOCKS; i++) {
62+
System.arraycopy(parity[i], 0, all[i + DATAB_LOCKS], 0, CHUNCK);
63+
}
64+
65+
// 3 Decode
66+
RawErasureDecoder rawDecoder =
67+
CodecUtil.createRawDecoder(conf, ErasureCodeConstants.RS_CODEC_NAME, coderOptions);
68+
byte[][] backup = new byte[PARITY_BLOCKS][CHUNCK];
69+
for (int i = 0; i < TOTAL_BLOCKS; i++) {
70+
for (int j = 0; j < TOTAL_BLOCKS; j++) {
71+
for (int k = 0; k < TOTAL_BLOCKS; k++) {
72+
int[] erasedIndexes;
73+
if (i == j && j == k) {
74+
erasedIndexes = new int[]{i};
75+
backup[0] = all[i];
76+
all[i] = null;
77+
} else if (i == j) {
78+
erasedIndexes = new int[]{i, k};
79+
backup[0] = all[i];
80+
backup[1] = all[k];
81+
all[i] = null;
82+
all[k] = null;
83+
} else if ((i == k) || ((j == k))) {
84+
erasedIndexes = new int[]{i, j};
85+
backup[0] = all[i];
86+
backup[1] = all[j];
87+
all[i] = null;
88+
all[j] = null;
89+
} else {
90+
erasedIndexes = new int[]{i, j, k};
91+
backup[0] = all[i];
92+
backup[1] = all[j];
93+
backup[2] = all[k];
94+
all[i] = null;
95+
all[j] = null;
96+
all[k] = null;
97+
}
98+
byte[][] decoded = new byte[erasedIndexes.length][CHUNCK];
99+
rawDecoder.decode(all, erasedIndexes, decoded);
100+
for (int l = 0; l < erasedIndexes.length; l++) {
101+
assertArrayEquals(backup[l], decoded[l]);
102+
all[erasedIndexes[l]] = backup[l];
103+
}
104+
}
105+
}
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)