Dmitry Werner created IGNITE-29206:
--------------------------------------

             Summary: DirectMessageWriter retains oversized temporary 
serialization buffer per connection
                 Key: IGNITE-29206
                 URL: https://issues.apache.org/jira/browse/IGNITE-29206
             Project: Ignite
          Issue Type: Improvement
            Reporter: Dmitry Werner
            Assignee: Dmitry Werner


Problem

DirectMessageWriter serializes @Compress fields and pending raw fields into a 
reusable heap scratch buffer (tmpBuf). The data is then compressed or copied 
out of it. Three things together cause the problem:

- The buffer starts at 10 KB and doubles until the whole field fits.
- It is never shrunk.
- The nested tmpWriter streams keep a reference to it too.

A writer lives as long as its NIO session, because it is stored in the session 
meta. So every connection ends up holding a buffer as large as the biggest 
field it has ever serialized, up to twice that field's raw size.

The exchange coordinator is hit hardest. It sends GridDhtPartitionsFullMessage 
to every node. On large clusters, compressed fields such as locParts can reach 
tens of megabytes of raw data. After a PME, each of the N communication 
sessions keeps such a buffer. That adds up to potentially hundreds of megabytes 
on large clusters of heap that is never released. Other nodes are affected the 
same way by GridDhtPartitionsSingleMessage.

The read side (DirectMessageReader) does not have this issue. The decompressed 
payload is allocated per message, and releasePayload() resets the stream 
references once it has been read.

Fix

- Once the temporary buffer has been used, release it if its capacity is above 
256 KB. "Used" means deflated into the CompressedMessage chunks or copied into 
a RawField.
- On release, also reset the nested tmpWriter and all its state-item streams to 
a shared empty buffer, so nothing keeps the large array reachable. This mirrors 
DirectMessageReader#releasePayload().
- Buffers up to 256 KB are still reused, so small and medium fields keep 
serializing with no per-message allocations.
- An oversized field now grows a fresh buffer each time. That copying is 
negligible compared to serializing and compressing such a field.
- The wire format is unchanged.

Tests

- New test CompressedMessageTest#testLargeTemporaryBufferReleased. It writes a 
small message, then a large GridDhtPartitionsFullMessage twice, through the 
same writer. After each write it checks that neither the writer nor its 
tmpWriter streams hold a buffer above the limit, and that the message reads 
back correctly. The test fails without the fix.
- Existing serialization tests pass: CompressedMessageTest, 
DirectMarshallingMessagesTest, RollingUpgradeMessageSerializationTest, 
*MessageSerializationTest.



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

Reply via email to