Skip to content

VPAAMP-558: restore per-host curl share locks; fix non-store USERDATA=NULL#1606

Open
pstroffolino wants to merge 2 commits into
dev_sprint_25_2from
feature/VPAAMP-558
Open

VPAAMP-558: restore per-host curl share locks; fix non-store USERDATA=NULL#1606
pstroffolino wants to merge 2 commits into
dev_sprint_25_2from
feature/VPAAMP-558

Conversation

@pstroffolino

Copy link
Copy Markdown
Contributor

Issue 1 (medium risk -- per-host DNS/SSL lock granularity):

Embed CurlDataShareLock mShareLock directly in curlstorestruct as a
value member. CURLSHOPT_USERDATA is now set to &CurlSock->mShareLock
so each CDN hostname gets its own three-way mutex (DNS / SSL / general),
restoring the parallelism lost by the VPAAMP-139 single-static-lock fix.

Safety: every cleanup path (RemoveCurlSock, ~CurlStore,
FlushCurlSockForHost) follows the order:
1. curl_easy_cleanup all queued handles (no further easy-hdl callbacks)
2. curl_share_cleanup(mCurlShared) (share teardown; lock may fire)
3. SAFE_DELETE(CurlSock) (destroys embedded mShareLock)
The embedded lock is therefore always alive when curl_share_cleanup
calls it, eliminating the original use-after-free without leaking memory.

Removes: CurlStore::mSharedCurlLock (static class member, no longer
needed) and the old large IMPORTANT comment block.

Issue 2 (low risk -- non-store path USERDATA=NULL inconsistency):

Replace static std::mutex gCurlShMutex with static CurlDataShareLock
gCurlShLock. CurlInit (non-store path) now passes &gCurlShLock as
CURLSHOPT_USERDATA instead of NULL, giving DNS/SSL/general lock
granularity parity with the store path. The defensive else branches
in curl_lock/unlock_callback are updated accordingly.

Test updates (CurlStoreTests.cpp):

T1 CreateCurlStore_UserDataDiffersAcrossHosts
Flipped from SAME to DIFFERENT: two hostname entries must now
receive distinct CURLSHOPT_USERDATA pointers (per-host lock).

T2 LockCallback_WorksWhileEntryIsAlive
Replaced: captures callbacks while entry is alive (count > 0) and
invokes them; verifies the embedded lock is functional.

T3 ShareCleanup_CalledOnEviction
Replaced: verifies that curl_share_cleanup is called with the
correct CURLSH handle when RemoveCurlSock evicts an entry, testing
the cleanup-order invariant that guarantees lock safety.

T4 LockCallback_HandlesAllLockDataTypes
Unchanged (still exercises DNS/SSL/generic branches).

…=NULL

Issue 1 (medium risk -- per-host DNS/SSL lock granularity):

  Embed CurlDataShareLock mShareLock directly in curlstorestruct as a
  value member.  CURLSHOPT_USERDATA is now set to &CurlSock->mShareLock
  so each CDN hostname gets its own three-way mutex (DNS / SSL / general),
  restoring the parallelism lost by the VPAAMP-139 single-static-lock fix.

  Safety: every cleanup path (RemoveCurlSock, ~CurlStore,
  FlushCurlSockForHost) follows the order:
    1. curl_easy_cleanup all queued handles (no further easy-hdl callbacks)
    2. curl_share_cleanup(mCurlShared)      (share teardown; lock may fire)
    3. SAFE_DELETE(CurlSock)               (destroys embedded mShareLock)
  The embedded lock is therefore always alive when curl_share_cleanup
  calls it, eliminating the original use-after-free without leaking memory.

  Removes: CurlStore::mSharedCurlLock (static class member, no longer
  needed) and the old large IMPORTANT comment block.

Issue 2 (low risk -- non-store path USERDATA=NULL inconsistency):

  Replace static std::mutex gCurlShMutex with static CurlDataShareLock
  gCurlShLock.  CurlInit (non-store path) now passes &gCurlShLock as
  CURLSHOPT_USERDATA instead of NULL, giving DNS/SSL/general lock
  granularity parity with the store path.  The defensive else branches
  in curl_lock/unlock_callback are updated accordingly.

Test updates (CurlStoreTests.cpp):

  T1 CreateCurlStore_UserDataDiffersAcrossHosts
     Flipped from SAME to DIFFERENT: two hostname entries must now
     receive distinct CURLSHOPT_USERDATA pointers (per-host lock).

  T2 LockCallback_WorksWhileEntryIsAlive
     Replaced: captures callbacks while entry is alive (count > 0) and
     invokes them; verifies the embedded lock is functional.

  T3 ShareCleanup_CalledOnEviction
     Replaced: verifies that curl_share_cleanup is called with the
     correct CURLSH handle when RemoveCurlSock evicts an entry, testing
     the cleanup-order invariant that guarantees lock safety.

  T4 LockCallback_HandlesAllLockDataTypes
     Unchanged (still exercises DNS/SSL/generic branches).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restores per-host libcurl share locking in CurlStore to regain DNS/SSL cache parallelism (lost in the prior single-static-lock fix), and fixes the non-store path to pass a valid CURLSHOPT_USERDATA pointer instead of NULL.

Changes:

  • Embed CurlDataShareLock as a value member in curlstorestruct and pass &CurlSock->mShareLock as CURLSHOPT_USERDATA for per-host lock granularity.
  • Replace the non-store global std::mutex fallback with a process-lifetime CurlDataShareLock and pass it via CURLSHOPT_USERDATA in CurlInit.
  • Update L1 tests to validate per-host distinct USERDATA pointers and the expected curl_share_cleanup eviction behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
downloader/AampCurlStore.h Adds per-host embedded share lock to the curl store entry struct; removes the static shared lock.
downloader/AampCurlStore.cpp Switches share USERDATA to per-entry lock; introduces process-lifetime lock for non-store path; adjusts callback fallback locking.
test/utests/tests/AampCurlStore/CurlStoreTests.cpp Updates regression tests to assert distinct per-host USERDATA and validate eviction cleanup ordering.

Comment thread downloader/AampCurlStore.h Outdated
Comment thread test/utests/tests/AampCurlStore/CurlStoreTests.cpp
Comment thread test/utests/tests/AampCurlStore/CurlStoreTests.cpp Outdated
Comment thread test/utests/tests/AampCurlStore/CurlStoreTests.cpp
Comment thread test/utests/tests/AampCurlStore/CurlStoreTests.cpp Outdated
… in tests

AampCurlStore.h:
  Reorder curlstorestruct constructor initializer list to match the
  member declaration order (mFreeQ, mCurlShared, mShareLock,
  mCurlStoreUserCount, timestamp).  The previous order triggered
  -Wreorder which is fatal in -Werror builds.

CurlStoreTests.cpp:
  CurlStore is a Meyer singleton that persists across all tests in the
  process.  Every GetHandleForHost call increments mCurlStoreUserCount;
  leaving it > 0 prevents RemoveCurlSock from evicting the entry,
  causing later tests to accumulate stale entries and making eviction-
  dependent behaviour order-sensitive.
  Fix: capture the CURL* returned by every GetHandleForHost call and
  add a matching ReturnHandleForHost at the end of each test body
  (T1, T2, T3, T4) so mCurlStoreUserCount returns to 0 before the
  test exits.  KeepInCurlStore does not trigger RemoveCurlSock, so
  there are no additional mock side-effects from the return calls.
@pstroffolino pstroffolino requested a review from Gnanesha June 12, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants