Skip to content

HDDS-16388. Datanode putBlock Support StorageType - #11223

Open
xichen01 wants to merge 3 commits into
apache:HDDS-11233from
xichen01:HDDS-16388
Open

xichen01 wants to merge 3 commits into
apache:HDDS-11233from
xichen01:HDDS-16388

Conversation

@xichen01

@xichen01 xichen01 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Datanode putBlock Support StroageType

  • BlockID add field storageType to record the specific Block replica's storageType on the Datanode.
  • putBlock OP will persist the BlockID, so the Block replica's storageType will be persisted.
  • writeChunk and putBlock are unified by passing StorageType information in protobuf DatanodeBlockID.
    Datanode putBlock Support StroageType

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-16388

How was this patch tested?

new test

@xichen01

xichen01 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

@devmadhuu @amaliujia @greenwich @chungen0126 @ivandika3 @peterxcli Please help to review

Objects.requireNonNull(blockData.getBlockID());
if (blockData.getBlockID().getStorageType() != null
&& kvContainer.getContainerData().getStorageType() != null) {
Preconditions.checkArgument(blockData.getBlockID().getStorageType() ==

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @xichen01, I have a small quesiton.
Could this cause a healthy container to be marked unhealthy when the storage types differ?
Because checkArgument throws IllegalArgumentException when the condition is false, and IllegalArgumentException extends RuntimeException. KeyValueHandler.handle() wraps RuntimeException as CONTAINER_INTERNAL_ERROR, which is not ignored by HddsDispatcher when deciding whether to mark the container unhealthy.

@xichen01 xichen01 Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can change this, I changed this to return INVALID_ARGUMENT, this is a canIgnoreException.

Objects.requireNonNull(blockData.getBlockID());
if (blockData.getBlockID().getStorageType() != null
&& kvContainer.getContainerData().getStorageType() != null) {
Preconditions.checkArgument(blockData.getBlockID().getStorageType() ==

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think , the mismatch is enforced with Preconditions.checkArgument which throws IllegalArgumentException. That method's try/catch doesn't catch it, so it bubbles up to handle()'s catch (RuntimeException) and becomes CONTAINER_INTERNAL_ERROR. Since that result isn't in canIgnoreException(), the container gets marked UNHEALTHY (and re-replicated).

@xichen01 xichen01 Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to return INVALID_ARGUMENT, this is a canIgnoreException.

BlockID blockID = BlockID.getFromProtobuf(writeChunk.getBlockID());
if (blockID.getStorageType() != null
&& kvContainer.getContainerData().getStorageType() != null) {
Preconditions.checkArgument(blockID.getStorageType() ==

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above here also.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about if we add STORAGE_TYPE_MISMATCH a dedicated result code ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the existing canIgnoreException INVALID_ARGUMENT

"cannot be negative");
if (data.getBlockID().getStorageType() != null
&& container.getContainerData().getStorageType() != null) {
Preconditions.checkArgument(data.getBlockID().getStorageType() ==

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue here.

* using a single RPC. Calls BlockManager and ChunkManager to process the
* request.
*/
ContainerCommandResponseProto handlePutSmallFile(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @xichen01 .
One question: Should we add the storageType validations present in handleWriteChunk and handlePutBlock, to handlePutSmallFile as well? It calls chunkManager.writeChunk directly so the write there isn't validated, though the putBlock flow is covered by the check in persistPutBlock.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can add check to handlePutSmallFile.

blkIDBuilder.setReplicaIndex(replicationIndex);
}
// TODO: Replica to the method parameter
blkIDBuilder.setStorageTypeID(StorageTypeUtils.getID(StorageType.DISK));

@greenwich greenwich Sep 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this stay unset? HDDS-15882 will set the real type at the writeChunkAsync call below, which wouldn't touch this builder, so this line would be easy to leave behind claiming DISK.

Objects.requireNonNull(data, "data == null");
Preconditions.checkState(data.getContainerID() >= 0, "Container Id " +
"cannot be negative");
if (data.getBlockID().getStorageType() != null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth extracting a small helper? PutBlock and PutSmallFile also run it twice, since persistPutBlock repeats it underneath


@Test
public void testCreateContainerRejectsInvalidStorageType() throws IOException {
public void testInvalidStorageTypeDoesNotMarkContainerUnhealthy() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a valid write now preceding it, this exercises the new dispatch-level guard rather than the create-path check in handleCreateContainer. Could the original be kept as a separate test so both paths stay covered?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants