[Store] Fix source refcnt leak in CopyEnd/MoveEnd on invalid source#2628
[Store] Fix source refcnt leak in CopyEnd/MoveEnd on invalid source#2628he-yufeng wants to merge 1 commit into
Conversation
CopyStart/MoveStart call source->inc_refcnt() to pin the source replica during the transfer, and the CopyEnd/MoveEnd success paths release it with dec_refcnt(). The error path taken when the source becomes invalid mid-transfer (source non-null but has_invalid_mem_handle(), or !is_completed()) returns early without decrementing, so the inc_refcnt() is never balanced. The branch erases the copy/move targets, not the source, so the source replica stays pinned and can never be evicted. Release the refcnt for a non-null source on the error path, mirroring the existing CopyRevoke/MoveRevoke handling.
There was a problem hiding this comment.
Code Review
This pull request addresses a potential resource leak in MasterService::CopyEnd and MasterService::MoveEnd by ensuring that the reference count of the source replica is decremented when the source becomes invalid during data transfer. This prevents the source replica from remaining pinned and unable to be evicted. There are no review comments, so no additional feedback is provided.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
LGTM. This balances the CopyStart/MoveStart source refcnt on the invalid-source End paths. |
Problem
CopyStartincrements the source replica's refcnt to protect it from eviction while the copy is in flight:CopyEndis expected to release it. The success path does, at the end:But the error path that fires when the source becomes invalid mid-transfer returns early without decrementing:
When
sourceis non-null buthas_invalid_mem_handle()is true (its segment was unmounted during the transfer) or!is_completed(), theinc_refcnt()fromCopyStartis never balanced. The cleanup in this branch erases the copy targets (task.replica_ids), not the source, so the source replica stays in metadata with an elevated refcnt and can never be evicted.MoveEndhas the identical pattern againstMoveStart'sinc_refcnt().Fix
Release the refcnt on the error path for a non-null source, mirroring what
CopyRevoke/MoveRevokealready do:The added guard only decrements when
source != nullptr, so the genuinesource == nullptrcase (nothing to release) is unaffected, and the success path is unchanged.Verification
The replica refcnt isn't observable through the public
MasterServiceAPI (the leak only surfaces later as a source replica that can't be evicted), so I haven't added a focused unit test that would be reliable without reaching into internals. The change is a two-line symmetry fix that makes the error path balance theinc_refcnt()exactly like the success path and the existing*Revokepaths; it relies on CI for the build and the existing master-service tests for regression coverage.