Siyao Meng created HDDS-17369:
---------------------------------
Summary: Mapped chunk read that fails on a later piece releases
the quota of earlier pieces a second time, raising the effective mmap limit
until restart
Key: HDDS-17369
URL: https://issues.apache.org/jira/browse/HDDS-17369
Project: Apache Ozone
Issue Type: Bug
Reporter: Siyao Meng
Attachments:
MC-2-release-only-unsettled-quota-on-failed-mapped-read.patch
h3. Mechanism
The mapped branch of {{ChunkUtils.readData}} reserves one permit per piece with
{{MappedBufferManager.getQuota(bufferNum)}}. Each piece then settles its own
permit in {{MappedBufferManager.computeIfAbsent}}: a cache hit releases it at
once, a miss hands it to the new cache entry, which the cleanup in {{getQuota}}
reclaims after GC has cleared it. When a later piece fails to map, the failure
handler calls {{releaseQuota(bufferNum)}} and so releases the permits of the
pieces that already settled a second time. The quota {{Semaphore}} has no
ceiling, so the extra permits stay.
h3. Trigger
# Mapped reads are enabled ({{ozone.chunk.read.mapped.buffer.max.count}} > 0,
default 0).
# A read is served from the mapped path, which needs a buffer capacity above
{{ozone.chunk.read.mapped.buffer.threshold}} (32KB). The default 16KB per
checksum does not reach it.
# The read is split into several pieces, and a later piece fails to map after
an earlier one has settled, for example because the block file on disk is
shorter than the chunk being read, or because the map call fails.
h3. Impact
* Each such failure raises the effective mmap limit of the manager by the
number of pieces that settled before it, and the limit stays raised until the
datanode restarts. The configured value of
{{ozone.chunk.read.mapped.buffer.max.count}} does not change.
* More mappings can then be live at the same time than {{max.count}} allows: at
once for pieces that were cache hits, and for newly mapped pieces after GC and
the cleanup have reclaimed their entries.
* That limit was added in HDDS-10488 to keep the datanode from running out of
map areas. What running out would do here is argued from that issue, not run.
h3. Reproduction
No standalone reproduction is attached. The regression test in the patch,
{{TestChunkUtils#testFailedMappedReadReleasesOnlyUnsettledQuota}}, covers it:
it calls {{ChunkUtils.readData}} directly with a buffer capacity of 64KB, above
the threshold, on a block file that holds one piece, and checks the quota after
a failed two piece read in three cases: first piece a cache hit, no piece
mapped, first piece newly mapped. On unmodified source it fails in the cache
hit case with {{expected: <3> but was: <4>}}.
h3. Patch
[^MC-2-release-only-unsettled-quota-on-failed-mapped-read.patch], against
5fed99dab3c3204cd7bf1516074969a38d5eb00d. It also applies to master at
76b5c6947a2.
The list of mapped pieces is declared before the {{try}}, and the failure
handler releases only {{bufferNum - buffers.size()}} permits. A piece is added
to that list only after {{computeIfAbsent}} returned it, that is after it
settled its permit. A failure before the first piece still releases all
permits, a failure after the last piece releases none, and successful reads are
unchanged.
With the patch {{TestMappedBufferManager}} (1 test), {{TestChunkUtils}} (7),
{{TestFilePerBlockStrategy}} (21), {{TestFilePerChunkStrategy}} (17),
{{TestChunkManagerDummyImpl}} (2), {{TestKeyValueHandler}} (43) and
{{TestKeyValueHandlerWithUnhealthyContainer}} (68) pass, 159 tests in total,
and checkstyle on {{hadoop-hdds/container-service}} is clean. It does not
conflict with the patches for the two related quota accounting issues in
{{MappedBufferManager}} found in the same review (HDDS-17368, a replaced
cleared cache entry, and HDDS-17367, the cache map shared by both chunk
layouts).
The defect is in every release from 2.0.0 to 2.2.1. It came in with HDDS-10488,
which added the mapped read path.
Found by TLA+ model checking and code review of the datanode memory mapped
chunk read path under HDDS-15926, on commit
5fed99dab3c3204cd7bf1516074969a38d5eb00d. Checked against HDDS issues and
apache/ozone PRs for duplicates before filing. Related but not duplicates:
HDDS-10488 (introduced the mapped read path and its limit), HDDS-15357 (other
quota races in {{MappedBufferManager}}). 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]