Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lock all read/writes of selected keys via the public key set #147

Conversation

ThePumpingLemma
Copy link
Contributor

This ensures that the selector and its clients use the same lock to synchronize access to the selected keys

Changes:

  • Always lock on selectedKeysPublic to be consistent with clients
  • Synchronize on selectedKeysPublic when adding or clearing selected keys
  • Reorder the calls to consumeAllBytesAfterPoll and selectedKeysPublic.clear() after polling in order to push down the lock on selectedKeysPublic. This should be safe since neither the channel closing loop nor consumeAllBytesAfterPoll operates on the selected key set
  • Remove redudnant use of synchronized on methods that are always called under a lock on this. Use assertions to document what locks are required for the given method instead

With our PoC at
https://github.com/kevink-sq/jetty-concurrency-issue-poc/tree/575469b3453e7b09d9d60f6460cdab8117b8e773,
we noticed that there is unbounded growth of file descriptors when
running our simple load test:

```bash
seq 1 15000 | xargs -P1500 -I{} curl --unix-socket ./junix-ingress.sock http://localhost/process
```

Leading to timeouts from curl and timeout exceptions in jetty:

```
java.util.concurrent.TimeoutException: Idle timeout expired: 32422/30000 ms
        at org.eclipse.jetty.io.IdleTimeout.checkIdleTimeout(IdleTimeout.java:170)
        at org.eclipse.jetty.io.IdleTimeout.idleCheck(IdleTimeout.java:112)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at java.base/java.lang.Thread.run(Thread.java:833)
```

This patch fixes the issue by ensuring that keys with the `OP_INVALID`
bit are still tracked in the selected key set and cancelled accordingly

Changes:
* Add invalid keys to `selectedKeysSet` in `setOpsReady` and mark as
  cancelled, ensuring that the fd is cleaned up timely
* Switch from `cancelNoRemove` to `cancel` now that the registered keys
  are modified separately in the select implementation
* Prefer `!key.isValid()` over `key.hasOpInvalid()` since the former is
  a superset of the latter
* In `implCloseSelector`, cancel the keys before clearing
  `keysRegistered` since `keys()` is backed by `keysRegistered`
* Store cancelled keys in a deque instead of a hash set, which should
  be a little more efficient
* Remove dead code
This ensures that the selector and its clients use the same lock to
synchronize access to the selected keys

Changes:
* Always lock on `selectedKeysPublic` to be consistent with clients
* Synchronize on `selectedKeysPublic` when adding or clearing selected
  keys
* Reorder the calls to `consumeAllBytesAfterPoll` and
  `selectedKeysPublic.clear()` after polling in order to push down the
  lock on `selectedKeysPublic`. This should be safe since neither the
  channel closing loop nor `consumeAllBytesAfterPoll` operates on the
  selected key set
* Remove redudnant use of `synchronized` on methods that are always
  called under a lock on `this`. Use assertions to document what locks
  are required for the given method instead
@kohlschuetter
Copy link
Member

I guess with the latest changes, this is no longer being pursued?

@ThePumpingLemma
Copy link
Contributor Author

I guess with the latest changes, this is no longer being pursued?

I don't think the new locking strategy is compatible with this PR, so I'll close this for now.

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