[GH-ISSUE #522] Cache causing deadlock #178

Closed
opened 2026-02-26 04:34:18 +03:00 by kerem · 1 comment
Owner

Originally created by @mageddo on GitHub (Jul 31, 2024).
Original GitHub issue: https://github.com/mageddo/dns-proxy-server/issues/522

What is Happening

A dead lock is occurring at the cache

thread-dump-lock.txt

Changes

  • As the issue is at the cache implementation, migrate cache to ready cache impl, caffeine

Specs

  • Docker Version: docker version
  • DPS Version: 3.25.1

Relates to #511

Originally created by @mageddo on GitHub (Jul 31, 2024). Original GitHub issue: https://github.com/mageddo/dns-proxy-server/issues/522 ## What is Happening A dead lock is occurring at the cache [thread-dump-lock.txt](https://github.com/user-attachments/files/16435725/thread-dump-lock.txt) ## Changes * As the issue is at the cache implementation, migrate cache to ready cache impl, caffeine ## Specs * Docker Version: `docker version` * DPS Version: 3.25.1 Relates to #511
kerem 2026-02-26 04:34:18 +03:00
Author
Owner

@mageddo commented on GitHub (Aug 1, 2024):

Issue wasn't fixed yet, the previous cache isn't the issue, the issue is the mixing of .compute and .clear methods.

All the DPS solving steps ran inside a '.compute' block which is a lock by key, eventually the block will also call '.clear' method

What is Happening

I was capable to cause deadlock using .clear() inside .compute using at least two threads, see a MRE.

Explanation

  • Thread 1 acquires lock on key 1 by using computemethod
  • Thread 2 acquires lock on key 2 by using computemethod
  • Thread 1 call clear method to clear the cache, now waiting for thread 2 to exit compute method
  • Thread 2 call clear method, now waiting on thread 1 to exit compute and clear methods
  • Deadlock :/

this.store.compute(key, (k, v) -> {

  log("status=computing, key=%s", key);

  sleep(1_000);

  if (r.nextBoolean()) {
    log("status=clearing, key=%s", key);
    this.store.clear();
  }

  if (isEmpty(v)) {
    log("status=computed, key=%s", key);
    return r.nextBoolean();
  }

  return v;
});

  Number of locked synchronizers = 1
  - java.util.concurrent.ThreadPoolExecutor$Worker@378bf509

ref

Changes

  • I will keep using caffeine as concurrent and memory optimized cache is a complex feature, better to use a specialized solution
  • Change the caching strategy to work without or at least minimize the locks
  • .clear method can be called by only one thread
<!-- gh-comment-id:2263481601 --> @mageddo commented on GitHub (Aug 1, 2024): Issue wasn't fixed yet, the previous cache isn't the issue, the issue is the mixing of .compute and .clear methods. All the DPS solving steps ran inside a '.compute' block which is a lock by key, eventually the block will also call '.clear' method ## What is Happening I was capable to cause deadlock using `.clear()` inside `.compute` using at least two threads, see a [MRE](https://github.com/mageddo/java-examples/blob/e31d24bc0ee128e27667bd56bf4a2353e84a295d/vanilla/src/main/java/vanillajavaexamples/concurrency/ConcurrentHashMapLock.java). **Explanation** * Thread 1 acquires lock on `key 1` by using `compute`method * Thread 2 acquires lock on `key 2` by using `compute`method * Thread 1 call `clear` method to clear the cache, now waiting for thread 2 to exit `compute` method * Thread 2 call `clear` method, now waiting on thread 1 to exit `compute` and `clear` methods * Deadlock :/ ```java this.store.compute(key, (k, v) -> { log("status=computing, key=%s", key); sleep(1_000); if (r.nextBoolean()) { log("status=clearing, key=%s", key); this.store.clear(); } if (isEmpty(v)) { log("status=computed, key=%s", key); return r.nextBoolean(); } return v; }); ``` ``` Number of locked synchronizers = 1 - java.util.concurrent.ThreadPoolExecutor$Worker@378bf509 ``` [ref][1] ## Changes * [x] I will keep using caffeine as concurrent and memory optimized cache is a complex feature, better to use a specialized solution * [x] Change the caching strategy to work without or at least minimize the locks * [x] `.clear` method can be called by only one thread [1]: https://stackoverflow.com/a/78818904/2979435
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/dns-proxy-server-mageddo#178
No description provided.