NetSelector.java
package space.sunqian.fs.net;
import space.sunqian.annotation.Nonnull;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Set;
/**
* A wrapper for {@link Selector} that provides protection against known {@link Selector} bugs, such as the epoll empty
* poll bug on Linux systems.
* <p>
* The epoll empty poll bug is a known issue where {@link Selector#select()} may continuously return 0 without blocking,
* causing high CPU usage. This interface provides a safe abstraction that automatically detects and mitigates such
* issues by rebuilding the {@link Selector} when necessary.
* <p>
* Implementations of this interface should handle:
* <ul>
* <li>Detection of empty poll cycles</li>
* <li>Automatic {@link Selector} rebuilding when thresholds are exceeded</li>
* <li>Migration of registered channels to the new {@link Selector}</li>
* <li>Thread-safe operations</li>
* </ul>
* <p>
* Note this interface does not guarantee thread safety because the underlying {@link Selector} may be replaced
* internally. Callers must ensure that all operations on this interface are synchronized.
*
* @author sunqian
* @see Selector
*/
public interface NetSelector {
/**
* The default empty select threshold.
*/
int DEFAULT_EMPTY_SELECT_THRESHOLD = 512;
/**
* Opens and returns a new {@link NetSelector} instance with the default empty select threshold.
*
* @return a new {@link NetSelector} instance
* @throws NetException if an I/O error occurs
*/
static @Nonnull NetSelector open() throws NetException {
return open(DEFAULT_EMPTY_SELECT_THRESHOLD);
}
/**
* Opens and returns a new {@link NetSelector} instance with the specified empty select threshold.
*
* @param emptySelectThreshold the empty select threshold to use
* @return a new {@link NetSelector} instance with the specified empty select threshold
* @throws NetException if an I/O error occurs
*/
static @Nonnull NetSelector open(int emptySelectThreshold) throws NetException {
return new NetSelectorImpl(emptySelectThreshold);
}
/**
* Returns the underlying {@link Selector} instance. This method always returns a valid {@link Selector} that is
* safe to use for channel registration and selection operations.
* <p>
* The returned {@link Selector} may be replaced internally if the implementation detects issues such as the epoll
* empty poll bug. Callers should cache the result of this method only for short periods and should call this method
* again if they need to ensure they have the current {@link Selector} instance.
*
* @return the underlying {@link Selector} instance, never {@code null}
*/
@Nonnull
Selector selector();
/**
* Performs a selection operation that may block for up to the specified timeout. This method is equivalent to
* calling {@link Selector#select(long)} on the underlying {@link Selector}.
*
* @param timeout the timeout in milliseconds; if positive, block for up to timeout milliseconds, more or less,
* while waiting for a channel to become ready; if zero, block indefinitely; must not be negative
* @return the number of keys, possibly zero, whose ready-operation sets were updated
* @throws IllegalArgumentException if the timeout is negative
* @throws NetException if an I/O error occurs
*/
int select(long timeout) throws IllegalArgumentException, NetException;
/**
* Returns this selector's selected-key set. This method is equivalent to calling {@link Selector#selectedKeys()} on
* the underlying {@link Selector}.
*
* @return the selected-key set, never {@code null}
* @throws NetException if an I/O error occurs
*/
@Nonnull
Set<SelectionKey> selectedKeys() throws NetException;
/**
* Returns this selector's key set. This method is equivalent to calling {@link Selector#keys()} on the underlying
* {@link Selector}.
*
* @return the key set, never {@code null}
* @throws NetException if an I/O error occurs
*/
@Nonnull
Set<SelectionKey> keys() throws NetException;
/**
* Wakes up the selector if it is currently blocked in a selection operation. This method is equivalent to calling
* {@link Selector#wakeup()} on the underlying {@link Selector}.
*/
void wakeup();
/**
* Closes the selector and releases any resources associated with it. This method is equivalent to calling
* {@link Selector#close()} on the underlying {@link Selector}.
*
* @throws NetException if an I/O error occurs
*/
void close() throws NetException;
/**
* Cancels the selection key for the specified channel. This method is equivalent to calling
* {@link SelectionKey#cancel()} on the underlying {@link SelectionKey}.
*
* @param channel the channel to cancel
* @throws NetException if an I/O error occurs
*/
void cancel(@Nonnull SelectableChannel channel) throws NetException;
/**
* Rebuilds the underlying {@link Selector} instance by creating a new {@link Selector} instance and migrating all
* registered channels to it.
* <p>
* This method should be invoked automatically by the implementation when the empty select thresholds are exceeded.
*
* @throws NetException if an I/O error occurs
*/
void rebuildSelector() throws NetException;
}