Skip to content

Commit 470e426

Browse files
committed
AFSelector: Use single ConcurrentHashMap for registered/selected keys
Since we already have a ConcurrentHashMap, let's make use of the value, which now indicates the "selected" state. Introduce MapValueSet, which is a view over elements of the "keysRegistered" map, and precisely only those elements that have a certain value. For each call to select, we increment the expected value, and then set only the actually selected entries to that value, so we don't have to clear the entire map. #145
1 parent 889ca99 commit 470e426

2 files changed

Lines changed: 344 additions & 9 deletions

File tree

junixsocket-common/src/main/java/org/newsclub/net/unix/AFSelector.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Map;
3434
import java.util.Set;
3535
import java.util.concurrent.ConcurrentHashMap;
36+
import java.util.concurrent.atomic.AtomicInteger;
3637

3738
final class AFSelector extends AbstractSelector {
3839
private final AFPipe selectorPipe;
@@ -41,13 +42,15 @@ final class AFSelector extends AbstractSelector {
4142
private final ByteBuffer pipeMsgWakeUp = ByteBuffer.allocate(1);
4243
private final ByteBuffer pipeMsgReceiveBuffer = ByteBuffer.allocateDirect(256);
4344

44-
private final Map<AFSelectionKey, Boolean> keysRegistered = new ConcurrentHashMap<>();
45+
private final Map<AFSelectionKey, Integer> keysRegistered = new ConcurrentHashMap<>();
4546
private final Set<AFSelectionKey> keysRegisteredKeySet = keysRegistered.keySet();
4647
private final Set<SelectionKey> keysRegisteredPublic = Collections.unmodifiableSet(
4748
keysRegisteredKeySet);
4849

49-
private final Map<SelectionKey, SelectionKey> selectedKeysSet = new ConcurrentHashMap<>();
50-
private final Set<SelectionKey> selectedKeysPublic = new UngrowableSet<>(selectedKeysSet.keySet());
50+
private final AtomicInteger selectCount = new AtomicInteger(0);
51+
private final MapValueSet<SelectionKey, Integer> selectedKeysSet =
52+
new MapValueSet<SelectionKey, Integer>(keysRegistered, selectCount::get, 0);
53+
private final Set<SelectionKey> selectedKeysPublic = new UngrowableSet<>(selectedKeysSet);
5154

5255
private PollFd pollFd = null;
5356

@@ -63,7 +66,7 @@ protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object at
6366
AFSelectionKey key = new AFSelectionKey(this, ch, ops, att);
6467
synchronized (this) {
6568
pollFd = null;
66-
keysRegistered.put(key, Boolean.TRUE);
69+
selectedKeysSet.markRemoved(key);
6770
}
6871
return key;
6972
}
@@ -106,12 +109,15 @@ public int select() throws IOException {
106109
@SuppressWarnings("PMD.CognitiveComplexity")
107110
private int select0(int timeout) throws IOException {
108111
PollFd pfd;
112+
113+
int selectId = updateSelectCount();
114+
109115
synchronized (this) {
110116
if (!isOpen()) {
111117
throw new ClosedSelectorException();
112118
}
119+
113120
pfd = pollFd = initPollFd(pollFd);
114-
selectedKeysSet.clear();
115121
}
116122
int num;
117123
try {
@@ -121,7 +127,6 @@ private int select0(int timeout) throws IOException {
121127
end();
122128
}
123129
synchronized (this) {
124-
selectedKeysSet.clear();
125130
pfd = pollFd;
126131
if (pfd != null) {
127132
AFSelectionKey[] keys = pfd.keys;
@@ -138,7 +143,7 @@ private int select0(int timeout) throws IOException {
138143
}
139144
if (num > 0) {
140145
consumeAllBytesAfterPoll();
141-
setOpsReady(pfd); // updates keysSelected and numKeysSelected
146+
setOpsReady(pfd, selectId); // updates keysSelected and numKeysSelected
142147
}
143148
return selectedKeysSet.size();
144149
}
@@ -178,14 +183,24 @@ private synchronized void consumeAllBytesAfterPoll() throws IOException {
178183
}
179184
}
180185

181-
private synchronized void setOpsReady(PollFd pfd) {
186+
private int updateSelectCount() {
187+
int selectId = selectCount.incrementAndGet();
188+
if (selectId == 0) {
189+
// overflow (unlikely)
190+
selectedKeysSet.markAllRemoved();
191+
selectId = selectCount.incrementAndGet();
192+
}
193+
return selectId;
194+
}
195+
196+
private void setOpsReady(PollFd pfd, int selectId) {
182197
if (pfd != null) {
183198
for (int i = 1; i < pfd.rops.length; i++) {
184199
int rops = pfd.rops[i];
185200
AFSelectionKey key = pfd.keys[i];
186201
key.setOpsReady(rops);
187202
if (rops != 0) {
188-
selectedKeysSet.put(key, key);
203+
keysRegistered.computeIfPresent(key, (k, v) -> selectId);
189204
}
190205
}
191206
}

0 commit comments

Comments
 (0)