Skip to content

Commit f90741c

Browse files
HDDS-1120. Add a config to disable checksum verification during read even though checksum data is present in the persisted data.
1 parent 28d0bf9 commit f90741c

File tree

8 files changed

+146
-9
lines changed

8 files changed

+146
-9
lines changed

hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/storage/BlockInputStream.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class BlockInputStream extends InputStream implements Seekable {
6666
private long[] chunkOffset;
6767
private List<ByteBuffer> buffers;
6868
private int bufferIndex;
69+
private final boolean verifyChecksum;
6970

7071
/**
7172
* Creates a new BlockInputStream.
@@ -75,10 +76,12 @@ public class BlockInputStream extends InputStream implements Seekable {
7576
* @param xceiverClient client to perform container calls
7677
* @param chunks list of chunks to read
7778
* @param traceID container protocol call traceID
79+
* @param verifyChecksum verify checksum
7880
*/
7981
public BlockInputStream(
8082
BlockID blockID, XceiverClientManager xceiverClientManager,
81-
XceiverClientSpi xceiverClient, List<ChunkInfo> chunks, String traceID) {
83+
XceiverClientSpi xceiverClient, List<ChunkInfo> chunks, String traceID,
84+
boolean verifyChecksum) {
8285
this.blockID = blockID;
8386
this.traceID = traceID;
8487
this.xceiverClientManager = xceiverClientManager;
@@ -91,6 +94,7 @@ public BlockInputStream(
9194
initializeChunkOffset();
9295
this.buffers = null;
9396
this.bufferIndex = 0;
97+
this.verifyChecksum = verifyChecksum;
9498
}
9599

96100
private void initializeChunkOffset() {
@@ -318,7 +322,9 @@ private synchronized void readChunkFromContainer() throws IOException {
318322
}
319323
ChecksumData checksumData =
320324
ChecksumData.getFromProtoBuf(chunkInfo.getChecksumData());
321-
Checksum.verifyChecksum(byteString, checksumData);
325+
if (verifyChecksum) {
326+
Checksum.verifyChecksum(byteString, checksumData);
327+
}
322328
break;
323329
} catch (IOException ioe) {
324330
// we will end up in this situation only if the checksum mismatch

hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ public final class OzoneConfigKeys {
362362
public static final int OZONE_CLIENT_BYTES_PER_CHECKSUM_DEFAULT_BYTES =
363363
1024 * 1024;
364364
public static final int OZONE_CLIENT_BYTES_PER_CHECKSUM_MIN_SIZE = 256 * 1024;
365+
public static final String OZONE_CLIENT_VERIFY_CHECKSUM =
366+
"ozone.client.verify.checksum";
367+
public static final boolean OZONE_CLIENT_VERIFY_CHECKSUM_DEFAULT = true;
365368
public static final String OZONE_ACL_AUTHORIZER_CLASS =
366369
"ozone.acl.authorizer.class";
367370
public static final String OZONE_ACL_AUTHORIZER_CLASS_DEFAULT =

hadoop-hdds/common/src/main/resources/ozone-default.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,15 @@
14841484
</description>
14851485
</property>
14861486

1487+
<property>
1488+
<name>ozone.client.verify.checksum</name>
1489+
<value>true</value>
1490+
<tag>OZONE, CLIENT, MANAGEMENT</tag>
1491+
<description>
1492+
Ozone client to verify checksum of the checksum blocksize data.
1493+
</description>
1494+
</property>
1495+
14871496
<property>
14881497
<name>ozone.om.ratis.enable</name>
14891498
<value>false</value>

hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/KeyInputStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ public static LengthInputStream getFromOmKeyInfo(
265265
XceiverClientManager xceiverClientManager,
266266
StorageContainerLocationProtocolClientSideTranslatorPB
267267
storageContainerLocationClient,
268-
String requestId) throws IOException {
268+
String requestId, boolean verifyChecksum) throws IOException {
269269
long length = 0;
270270
long containerKey;
271271
KeyInputStream groupInputStream = new KeyInputStream();
@@ -311,7 +311,7 @@ public static LengthInputStream getFromOmKeyInfo(
311311
success = true;
312312
BlockInputStream inputStream = new BlockInputStream(
313313
omKeyLocationInfo.getBlockID(), xceiverClientManager, xceiverClient,
314-
chunks, requestId);
314+
chunks, requestId, verifyChecksum);
315315
groupInputStream.addStream(inputStream,
316316
omKeyLocationInfo.getLength());
317317
} finally {

hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public class RpcClient implements ClientProtocol {
112112
private final int chunkSize;
113113
private final ChecksumType checksumType;
114114
private final int bytesPerChecksum;
115+
private boolean verifyChecksum;
115116
private final UserGroupInformation ugi;
116117
private final OzoneAcl.OzoneACLRights userRights;
117118
private final OzoneAcl.OzoneACLRights groupRights;
@@ -198,6 +199,9 @@ public RpcClient(Configuration conf) throws IOException {
198199
OzoneConfigKeys.OZONE_CLIENT_CHECKSUM_TYPE,
199200
OzoneConfigKeys.OZONE_CLIENT_CHECKSUM_TYPE_DEFAULT);
200201
checksumType = ChecksumType.valueOf(checksumTypeStr);
202+
this.verifyChecksum =
203+
conf.getBoolean(OzoneConfigKeys.OZONE_CLIENT_VERIFY_CHECKSUM,
204+
OzoneConfigKeys.OZONE_CLIENT_VERIFY_CHECKSUM_DEFAULT);
201205
}
202206

203207
private InetSocketAddress getScmAddressForClient() throws IOException {
@@ -648,7 +652,7 @@ public OzoneInputStream getKey(
648652
LengthInputStream lengthInputStream =
649653
KeyInputStream.getFromOmKeyInfo(
650654
keyInfo, xceiverClientManager, storageContainerLocationClient,
651-
requestId);
655+
requestId, verifyChecksum);
652656
FileEncryptionInfo feInfo = keyInfo.getFileEncryptionInfo();
653657
if (feInfo != null) {
654658
final KeyProvider.KeyVersion decrypted = getDEK(feInfo);

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.concurrent.TimeUnit;
3232
import java.util.concurrent.atomic.AtomicInteger;
3333

34+
import org.apache.hadoop.conf.Configuration;
3435
import org.apache.hadoop.hdds.client.OzoneQuota;
3536
import org.apache.hadoop.hdds.client.ReplicationFactor;
3637
import org.apache.hadoop.hdds.client.ReplicationType;
@@ -47,6 +48,7 @@
4748
import org.apache.hadoop.ozone.HddsDatanodeService;
4849
import org.apache.hadoop.ozone.MiniOzoneCluster;
4950
import org.apache.hadoop.ozone.OzoneAcl;
51+
import org.apache.hadoop.ozone.OzoneConfigKeys;
5052
import org.apache.hadoop.ozone.OzoneConsts;
5153
import org.apache.hadoop.ozone.OzoneTestUtils;
5254
import org.apache.hadoop.ozone.client.BucketArgs;
@@ -763,6 +765,114 @@ public void testPutKeyRatisThreeNodesParallel() throws IOException,
763765

764766
}
765767

768+
769+
@Test
770+
public void testReadKeyWithVerifyChecksumFlagEnable() throws Exception {
771+
String volumeName = UUID.randomUUID().toString();
772+
String bucketName = UUID.randomUUID().toString();
773+
774+
String value = "sample value";
775+
store.createVolume(volumeName);
776+
OzoneVolume volume = store.getVolume(volumeName);
777+
volume.createBucket(bucketName);
778+
OzoneBucket bucket = volume.getBucket(bucketName);
779+
String keyName = UUID.randomUUID().toString();
780+
781+
// Write data into a key
782+
OzoneOutputStream out = bucket.createKey(keyName,
783+
value.getBytes().length, ReplicationType.RATIS,
784+
ReplicationFactor.ONE, new HashMap<>());
785+
out.write(value.getBytes());
786+
out.close();
787+
788+
// We need to find the location of the chunk file corresponding to the
789+
// data we just wrote.
790+
OzoneKey key = bucket.getKey(keyName);
791+
long containerID = ((OzoneKeyDetails) key).getOzoneKeyLocations().get(0)
792+
.getContainerID();
793+
794+
// Get the container by traversing the datanodes. Atleast one of the
795+
// datanode must have this container.
796+
Container container = null;
797+
for (HddsDatanodeService hddsDatanode : cluster.getHddsDatanodes()) {
798+
container = hddsDatanode.getDatanodeStateMachine().getContainer()
799+
.getContainerSet().getContainer(containerID);
800+
if (container != null) {
801+
break;
802+
}
803+
}
804+
Assert.assertNotNull("Container not found", container);
805+
corruptData(container, key);
806+
readCorruptedKey(volumeName, bucketName, keyName, true);
807+
808+
}
809+
810+
811+
@Test
812+
public void testReadKeyWithVerifyChecksumFlagDisable() throws Exception {
813+
String volumeName = UUID.randomUUID().toString();
814+
String bucketName = UUID.randomUUID().toString();
815+
816+
String value = "sample value";
817+
store.createVolume(volumeName);
818+
OzoneVolume volume = store.getVolume(volumeName);
819+
volume.createBucket(bucketName);
820+
OzoneBucket bucket = volume.getBucket(bucketName);
821+
String keyName = UUID.randomUUID().toString();
822+
823+
// Write data into a key
824+
OzoneOutputStream out = bucket.createKey(keyName,
825+
value.getBytes().length, ReplicationType.RATIS,
826+
ReplicationFactor.ONE, new HashMap<>());
827+
out.write(value.getBytes());
828+
out.close();
829+
830+
// We need to find the location of the chunk file corresponding to the
831+
// data we just wrote.
832+
OzoneKey key = bucket.getKey(keyName);
833+
long containerID = ((OzoneKeyDetails) key).getOzoneKeyLocations().get(0)
834+
.getContainerID();
835+
836+
// Get the container by traversing the datanodes. Atleast one of the
837+
// datanode must have this container.
838+
Container container = null;
839+
for (HddsDatanodeService hddsDatanode : cluster.getHddsDatanodes()) {
840+
container = hddsDatanode.getDatanodeStateMachine().getContainer()
841+
.getContainerSet().getContainer(containerID);
842+
if (container != null) {
843+
break;
844+
}
845+
}
846+
Assert.assertNotNull("Container not found", container);
847+
corruptData(container, key);
848+
readCorruptedKey(volumeName, bucketName, keyName, false);
849+
850+
}
851+
852+
853+
private void readCorruptedKey(String volumeName, String bucketName,
854+
String keyName, boolean verifyChecksum) throws IOException {
855+
try {
856+
Configuration configuration = cluster.getConf();
857+
configuration.setBoolean(OzoneConfigKeys.OZONE_CLIENT_VERIFY_CHECKSUM,
858+
verifyChecksum);
859+
RpcClient client = new RpcClient(configuration);
860+
OzoneInputStream is = client.getKey(volumeName, bucketName, keyName);
861+
is.read(new byte[100]);
862+
is.close();
863+
if (verifyChecksum) {
864+
fail("Reading corrupted data should fail, as verify checksum is " +
865+
"enabled");
866+
}
867+
} catch (OzoneChecksumException e) {
868+
if (!verifyChecksum) {
869+
fail("Reading corrupted data should not fail, as verify checksum is " +
870+
"disabled");
871+
}
872+
}
873+
}
874+
875+
766876
private void readKey(OzoneBucket bucket, String keyName, String data)
767877
throws IOException {
768878
OzoneKey key = bucket.getKey(keyName);

hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/storage/DistributedStorageHandler.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public final class DistributedStorageHandler implements StorageHandler {
8888
private final long blockSize;
8989
private final ChecksumType checksumType;
9090
private final int bytesPerChecksum;
91+
private final boolean verifyChecksum;
9192

9293
/**
9394
* Creates a new DistributedStorageHandler.
@@ -153,7 +154,9 @@ public DistributedStorageHandler(OzoneConfiguration conf,
153154
OzoneConfigKeys.OZONE_CLIENT_CHECKSUM_TYPE,
154155
OzoneConfigKeys.OZONE_CLIENT_CHECKSUM_TYPE_DEFAULT);
155156
this.checksumType = ChecksumType.valueOf(checksumTypeStr);
156-
157+
this.verifyChecksum =
158+
conf.getBoolean(OzoneConfigKeys.OZONE_CLIENT_VERIFY_CHECKSUM,
159+
OzoneConfigKeys.OZONE_CLIENT_VERIFY_CHECKSUM_DEFAULT);
157160
}
158161

159162
@Override
@@ -479,7 +482,7 @@ public LengthInputStream newKeyReader(KeyArgs args) throws IOException,
479482
OmKeyInfo keyInfo = ozoneManagerClient.lookupKey(keyArgs);
480483
return KeyInputStream.getFromOmKeyInfo(
481484
keyInfo, xceiverClientManager, storageContainerLocationClient,
482-
args.getRequestID());
485+
args.getRequestID(), verifyChecksum);
483486
}
484487

485488
@Override

hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestChunkStreams.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public void testReadGroupInputStream() throws Exception {
4848
for (int i = 0; i < 5; i++) {
4949
int tempOffset = offset;
5050
BlockInputStream in =
51-
new BlockInputStream(null, null, null, new ArrayList<>(), null) {
51+
new BlockInputStream(null, null, null, new ArrayList<>(), null,
52+
true) {
5253
private long pos = 0;
5354
private ByteArrayInputStream in =
5455
new ByteArrayInputStream(buf, tempOffset, 100);
@@ -104,7 +105,8 @@ public void testErrorReadGroupInputStream() throws Exception {
104105
for (int i = 0; i < 5; i++) {
105106
int tempOffset = offset;
106107
BlockInputStream in =
107-
new BlockInputStream(null, null, null, new ArrayList<>(), null) {
108+
new BlockInputStream(null, null, null, new ArrayList<>(), null,
109+
true) {
108110
private long pos = 0;
109111
private ByteArrayInputStream in =
110112
new ByteArrayInputStream(buf, tempOffset, 100);

0 commit comments

Comments
 (0)