szetszwo commented on code in PR #10764:
URL: https://github.com/apache/ozone/pull/10764#discussion_r3942159309
##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java:
##########
@@ -2355,32 +2354,42 @@ private long readBlockImpl(ContainerCommandRequestProto
request, RandomAccessFil
return 0;
}
final List<ContainerProtos.ChunkInfo> chunkInfos = blockData.getChunks();
- final int bytesPerChunk = Math.toIntExact(chunkInfos.get(0).getLen());
final ChecksumType checksumType =
chunkInfos.get(0).getChecksumData().getType();
- ChecksumData checksumData = null;
int bytesPerChecksum = STREAMING_BYTES_PER_CHUNK;
- if (checksumType == ContainerProtos.ChecksumType.NONE) {
- checksumData = new ChecksumData(checksumType, 0);
- } else {
+ if (checksumType != ContainerProtos.ChecksumType.NONE) {
bytesPerChecksum =
chunkInfos.get(0).getChecksumData().getBytesPerChecksum();
}
- // We have to align the read to checksum boundaries, so whatever offset is
requested, we have to move back to the
- // previous checksum boundary.
- // eg if bytesPerChecksum is 512, and the requested offset is 600, we have
to move back to 512.
- // If the checksum type is NONE, we don't have to do this, but using no
checksums should be rare in practice and
- // it simplifies the code to always do this.
- final long offsetAlignment = readBlock.getOffset() % bytesPerChecksum;
- long adjustedOffset = readBlock.getOffset() - offsetAlignment;
+ // TODO: Support client-side flag to toggle checksum verification.
+ // If checksum is disabled, chunk offset adjustment can be skipped.
+ final ChecksumBoundaries checksumBoundaries =
getChecksumBoundaries(readBlock.getOffset(),
+ readBlock.getLength(), chunkInfos, bytesPerChecksum);
+ long adjustedOffset = checksumBoundaries.offset;
+ long adjustLength = checksumBoundaries.length;
+ int chunkIndex = checksumBoundaries.startIndex;
+
+ ChecksumData checksumData = new ChecksumData(checksumType,
bytesPerChecksum);
final ByteBuffer buffer = ByteBuffer.allocate(responseDataSize);
blockFile.position(adjustedOffset);
long totalDataLength = 0;
int numResponses = 0;
- final long rounded = roundUp(readBlock.getLength() + offsetAlignment,
bytesPerChecksum);
- final long requiredLength = Math.min(rounded, blockData.getSize() -
adjustedOffset);
+ final long requiredLength = Math.min(adjustLength, blockData.getSize() -
adjustedOffset);
LOG.debug("adjustedOffset {}, requiredLength {}, blockSize {}",
adjustedOffset, requiredLength, blockData.getSize());
for (boolean shouldRead = true; totalDataLength < requiredLength &&
shouldRead;) {
+
+ int bufferLimit = (int) Math.min(responseDataSize, requiredLength -
totalDataLength);
+ final ContainerProtos.ChunkInfo nextChunk = chunkInfos.get(
+ searchChunkByOffset(adjustedOffset + bufferLimit, chunkInfos));
+
+ if (bufferLimit < requiredLength - totalDataLength) {
+ // bytesPerChecksum must be a power of 2.
+ bufferLimit = (int) (((bufferLimit - (nextChunk.getOffset() -
adjustedOffset)) & -((long) bytesPerChecksum))
+ + (nextChunk.getOffset() - adjustedOffset));
+ }
Review Comment:
Thanks for the explanation. I got it now.
```java
// I should quote also these lines:
int bufferLimit = (int) Math.min(responseDataSize, requiredLength -
totalDataLength);
final ContainerProtos.ChunkInfo nextChunk = chunkInfos.get(
searchChunkByOffset(adjustedOffset + bufferLimit, chunkInfos));
```
- searchChunkByOffset(adjustedOffset + bufferLimit, ..) should use
adjustedOffset + bufferLimit - 1 for the end position (inclusive)
- Let's renmae nextChunk to endChunk.
- Since endChunk index is increasing, let's use linear search.
- Move the entire computation to a new class:
```java
static class BufferLimitComputation {
private final int responseDataSize;
private final int bitMask;
private final List<ContainerProtos.ChunkInfo> chunks;
private int chunkIndex;
private long lastPosition = 0;
BufferLimitComputation(int responseDataSize, int bytesPerChecksum,
List<ContainerProtos.ChunkInfo> chunks, int firstChunkIndex) {
this.responseDataSize = responseDataSize;
Preconditions.assertSame(1, Long.bitCount(bytesPerChecksum),
"bitCount" ); // check power of 2.
// Suppose bytesPerChecksum = 00001000 (a power of 2), then bitMask =
11111000.
// The following two computations are the same:
// We will use (n & bitMask) to compute ((n / bytesPerChecksum) *
bytesPerChecksum).
this.bitMask = -bytesPerChecksum;
this.chunks = chunks;
this.chunkIndex = firstChunkIndex;
}
int getChunkIndex() {
return chunkIndex;
}
/**
* @param position must be increasing in subsequent calls to this method.
* @return the chunk containing the given position.
*/
ContainerProtos.ChunkInfo findChunk(long position) {
Preconditions.assertTrue(position >= lastPosition);
lastPosition = position;
for(; chunkIndex < chunks.size(); chunkIndex++) {
final ContainerProtos.ChunkInfo chunk = chunks.get(chunkIndex);
if (position >= chunk.getOffset() && position < chunk.getOffset() +
chunk.getLen()) {
return chunk;
}
}
throw new IllegalStateException("Position " + position + " not found
in " + chunks);
}
int compute(long offset, long remainingLength) {
if (responseDataSize >= remainingLength) {
return Math.toIntExact(remainingLength);
}
final long end = offset + responseDataSize - 1; // inclusive
final ContainerProtos.ChunkInfo endChunk = findChunk(end);
final int lengthExcludingEndChunk =
Math.toIntExact(endChunk.getOffset() - offset);
// round down the length at endChunk
final int lengthAtEndChunk = (responseDataSize -
lengthExcludingEndChunk) & bitMask;
return lengthExcludingEndChunk + lengthAtEndChunk;
}
}
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]