Siyao Meng created HDDS-17438:
---------------------------------

             Summary: Verify the block token of a stream init like WriteChunk, 
and set up a data stream only after its init succeeded
                 Key: HDDS-17438
                 URL: https://issues.apache.org/jira/browse/HDDS-17438
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: CR-10-verify-stream-init-block-token.patch

h3. Mechanism
A data stream write starts with a stream init request ({{StreamInit}}, and on 
master also {{StreamInitWithPutBlock}}) that names its block in 
{{writeChunk.blockID}}. {{ContainerStateMachine.stream}} dispatches the init 
through {{HddsDispatcher}} and then opens the block file for the stream with 
{{HddsDispatcher.getStreamDataChannel}}.

The invariant this change establishes: a stream init is a block write, so its 
block token is verified like that of a {{WriteChunk}} for the same block (the 
token's block and {{WRITE}} access), and a data stream is set up only when its 
init request succeeded, as {{ContainerStateMachine.streamCommand}} already 
requires for a stream command. {{BlockTokenVerifier}} takes the commands that 
carry a block token, and the block each one names, from 
{{HddsUtils.requireBlockToken}} and {{HddsUtils.getBlockID}}.

h3. Reproduction
The issue has no standalone reproduction attached. The regression tests in the 
patch cover the invariant and fail on unmodified source:
* {{TestBlockTokenVerifier.verifiesStreamInitLikeWriteChunk}} 
({{hadoop-hdds/framework}}, for both stream init types): a write token for the 
block is accepted for the stream init, and for other tokens the verifier 
reaches the same result for the stream init as for a {{WriteChunk}} of the same 
block.
* {{ContainerStateMachineTests.testStreamOpenedOnlyIfStreamInitSucceeds}} 
({{hadoop-hdds/container-service}}, run by {{TestContainerStateMachineLeader}} 
and {{TestContainerStateMachineFollower}}, for both stream init types): when 
the init dispatch does not succeed, {{ContainerStateMachine.stream}} fails with 
the init's result and no data channel is opened.

h3. Patch
[^CR-10-verify-stream-init-block-token.patch], against 
7212465c0bb19615708c144238317db51c2a696d. It also applies to master at 
1acf315d546.

* {{HddsUtils.requireBlockToken}} lists {{StreamInit}} and 
{{StreamInitWithPutBlock}}, and {{HddsUtils.getBlockID}} returns their 
{{writeChunk.blockID}}, so {{BlockTokenVerifier}} verifies a stream init as it 
verifies a {{WriteChunk}}.
* {{ContainerStateMachine.getStreamDataChannel}} throws a 
{{StorageContainerException}} with the init's result when the init dispatch is 
not {{SUCCESS}}, so {{stream}} fails before a data channel is opened.

Compatibility and behaviour:
* The stock {{BlockDataStreamOutput}} sets the block's token on the stream init 
since 1.4.0 (HDDS-8884), so stream writes of stock clients with block tokens 
enabled pass the check.
* Every member of the pipeline now verifies the init token when it sets up the 
stream, while a {{WriteChunk}} token is verified once, by the leader. A token 
very close to its expiry, or clock skew between datanodes, can therefore fail 
the stream setup on one member.
* The stream's Raft request at close carries the init request, so the leader 
also verifies that token at close, as it does for a {{WriteChunk}}. A stream 
open for longer than the token lifetime ({{hdds.block.token.expiry.time}}, 
default {{1d}}) fails at close.
* There is no wire or protocol change and no new configuration.
* The patch for the stream PutBlock checks, filed separately, also edits the 
stream test setup in {{ContainerStateMachineTests}} ({{setUpStream}}). The main 
code of the two patches merges cleanly; whichever lands second needs a small 
rebase of that test helper. The patch of HDDS-17431 also edits 
{{ContainerStateMachineTests}}; the same applies.

With the patch {{TestHddsUtils}}, {{TestBlockTokenVerifier}}, 
{{TestContainerTokenVerifier}}, {{TestHddsDispatcher}}, 
{{TestContainerStateMachineLeader}}, {{TestContainerStateMachineFollower}}, 
{{TestKeyValueHandler}} and {{TestKeyValueStreamDataChannel}} pass (171 tests), 
{{TestSecureContainerServer}}, {{TestBlockDataStreamOutput}} and 
{{TestOzoneAtRestEncryption}} in {{hadoop-ozone/integration-test}} (mini 
clusters with data streaming, the last one with block tokens and stream keys 
written by the stock client) pass (58 tests), and checkstyle on 
{{hadoop-hdds/common}}, {{hadoop-hdds/framework}} and 
{{hadoop-hdds/container-service}} is clean.

Found by code review of the datanode streaming PutBlock paths, as part of the 
TLA+ verification effort under HDDS-15926, on commit 
7212465c0bb19615708c144238317db51c2a696d. Checked against HDDS issues and 
apache/ozone pull requests for duplicates before filing. Related: HDDS-8884. 
The attached patch is a proposal for review. Generated with Specula (Claude 
Opus 5.5).



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to