Skip to content

HDDS-15723. Ignore writes after PutBlock with end-of-block flag - #10967

Open
prathmesh12-coder wants to merge 4 commits into
apache:masterfrom
prathmesh12-coder:HDDS-15723
Open

HDDS-15723. Ignore writes after PutBlock with end-of-block flag#10967
prathmesh12-coder wants to merge 4 commits into
apache:masterfrom
prathmesh12-coder:HDDS-15723

Conversation

@prathmesh12-coder

@prathmesh12-coder prathmesh12-coder commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

  • Currently, the datanode will finalize a block if it encounters PutBlock with eof flag set. There should only be one PutBlock with eof flag since PutBlock is not idempotent. Currently this is not caught which can cause issue like HDDS-12007 to not be detected.

  • Therefore, we need to assert that once we encounter block EOF, there will not be any more writes on that block.
    We should throw exception (or ignore) if there are some writes after EOF. This change ignores them and logs a warning.

  • Added eofBlockCache on open/closing containers to track blocks finalized by an EOF PutBlock.

  • In BlockManagerImpl#persistPutBlock, ignored subsequent writes on those blocks.

What is the link to the Apache JIRA

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

How was this patch tested?

@chihsuan chihsuan left a comment

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 for working on this! @prathmesh12-coder

I noticed that KeyValueContainerData.finalizedBlockSet seems to represent a similar state, but persists it and checks it earlier.

I wonder if we could reuse that mechanism for explicit EOF PutBlocks instead of maintaining a separate in-memory cache? What do you think?

I've also added a few inline comments. thanks!

+ "by a PutBlock with the end-of-block flag set. PutBlock is not "
+ "idempotent",
data.getBlockID());
return data.getSize();

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.

This skips the PutBlock but still reports success with its new BCS ID. The client may then record a BCS ID that the datanode never persisted, causing later reads to fail. Would it make sense to change this to throw exception with BLOCK_ALREADY_FINALIZED instead?

// writes to the container. So pendingPutBlockCache is not needed.
// writes to the container. So pendingPutBlockCache and eofBlockCache are not needed.
this.pendingPutBlockCache = new HashSet<>();
this.eofBlockCache = new HashSet<>();

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.

This state is lost when a replica restarts. A later Raft entry could then be skipped by replicas that retained the cache but persisted by the restarted replica. Could the EOF state be persisted and restored with the container?

long localID = data.getLocalID();

// PutBlock is not idempotent; ignore duplicate eof writes (HDDS-12007).
if (container.isBlockFinalizedByEof(localID)) {

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.

This check may be too late for a piggybacked WriteChunk, sinceKeyValueHandler writes the chunk before calling putBlock.

The data may therefore already be changed when this check skips the metadata update. Could the finalized-state check happen before chunk processing as well?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants