Siyao Meng created HDDS-17445:
---------------------------------

             Summary: Short-circuit GetBlock parks the opened block file in a 
map shared by all requests instead of handing it to the request's own context
                 Key: HDDS-17445
                 URL: https://issues.apache.org/jira/browse/HDDS-17445
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: MC-3-hand-short-circuit-block-file-to-own-request.patch

h3. Mechanism
For a GetBlock with {{requestShortCircuitAccess}} set, 
{{KeyValueHandler.handleGetBlock}} opens the block file 
({{ChunkManager.getShortCircuitFd}}), parks the {{RandomAccessFile}} in 
{{blockFileMap}} under {{BlockUtils.getBlockMapKey}} ({{clientId}}, {{callId}}, 
local ID, container ID) and sets {{shortCircuitAccessGranted}} in the response. 
The handler does this for any GetBlock that carries the flag, because it does 
not know which path dispatched the request, and the map is shared by all 
requests. Only the domain socket {{Receiver}} takes the file out again, through 
{{Handler.getBlockFile}} after dispatch, and closes it after sending the 
descriptor (HDDS-11627, HDDS-12883).

So the hand off between the handler and {{Receiver}} depends on a lookup by 
request fields rather than on the request itself:
* A GetBlock with the flag dispatched by another path ({{GrpcXceiverService}}, 
{{ContainerStateMachine.query}}) parks a file that nothing takes out, and its 
response reports {{shortCircuitAccessGranted=true}} although that path does not 
pass a descriptor.
* Requests with the same key use the same entry: a later put replaces an 
earlier file without closing it, and the {{Receiver}} task that looks second 
finds no entry.

A file that is parked and never taken out stays open while the map holds it, 
and a file replaced by a later put is closed only when it is collected.

h3. Reproduction
No standalone reproduction is attached. The regression test in the patch covers 
both cases at the handler level.

h3. Patch
[^MC-3-hand-short-circuit-block-file-to-own-request.patch], against 
69d77beff60b9106e2517c36a7a1b2cc726af568. It also applies to master at 
1acf315d546.

The opened file is handed to the request's own context instead of a shared map, 
and the flag is ignored on every other path. {{Receiver}} dispatches each 
request with its own {{DispatcherContext}} of the new op 
{{HANDLE_SHORT_CIRCUIT_READ}}; {{handleGetBlock}} opens the file only when it 
gets such a context, stores it there, and {{Receiver}} takes it from that 
context. A GetBlock with the flag dispatched without that context gets the 
block data and {{shortCircuitAccessGranted=false}}, which the read path already 
treats as "read normally". {{blockFileMap}}, {{KeyValueHandler.getBlockFile}} 
and the abstract {{Handler.getBlockFile}} are removed. The block token is still 
verified for the new op ({{Op.validateToken}} defaults to true), and there is 
no wire or protocol change.

Not changed: a successful GetBlock without the flag on the domain socket still 
has no file to send; that is the separate issue HDDS-17443. This patch and the 
patch of HDDS-17443 change adjacent lines in 
{{Receiver.ProcessRequestTask.run}}, so whichever is applied second needs a 
trivial rebase.

Covered by 
{{TestKeyValueHandler.testShortCircuitGetBlockHandsFileToOwnContext}}: a 
GetBlock with the flag dispatched without the domain socket context gets 
{{shortCircuitAccessGranted=false}} and counts no local bytes, a domain socket 
context without the flag gets no file, and two dispatches of the same request 
with their own contexts each get their own open file. On unmodified source the 
first part fails with "Expecting value to be false but was true"; the other two 
parts use the new context and do not compile there. {{testGetBlockMetrics}} now 
takes the file from the context, and {{TestHddsDispatcher}} lists the new op 
among those whose token is verified. With the patch {{TestKeyValueHandler}}, 
{{TestKeyValueHandlerWithUnhealthyContainer}} and {{TestHddsDispatcher}} pass 
(129 tests), as do {{TestXceiverServerDomainSocket}}, 
{{TestXceiverClientManagerSC}}, {{TestLocalChunkInputStream}} and 
{{TestDomainSocketFactory}} (17 tests), and checkstyle on 
{{hadoop-hdds/container-service}} is clean.

Found by TLA+ model checking and code review of the datanode short-circuit read 
paths under HDDS-15926, on commit 69d77beff60b9106e2517c36a7a1b2cc726af568. 
Checked against HDDS issues and apache/ozone pull requests for duplicates 
before filing. Related but not duplicates: HDDS-11627 (added GetBlock on the 
short-circuit channel and {{blockFileMap}}), HDDS-12883 (closes the block file 
after it is sent), HDDS-16918 (fallback to gRPC is not logged on the datanode), 
HDDS-16335 (concurrent access on the other side of the domain socket). 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