Name: nt126004 Date: 09/14/2001
java version "1.4.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta2-b77)
Java HotSpot(TM) Client VM (build 1.4.0-beta2-b77, mixed mode)
I am using the new java.nio.channels package to write a server application
that needs to support thousands of concurrent users. These are not short
running HTTP requests, but rather long running sessions. The way to go is to
use non-blocking IO. After spending some time figuring out how to use the
package I tried running some stress tests. Everything was fine until I hit
it with more then 62 users, when I did I got the following error:
java.lang.UnsupportedOperationException: Implementation allows only 63 channels
per Selector
at sun.nio.ch.PollArrayWrapper.addEntry(PollArrayWrapper.java:123)
at sun.nio.ch.PollSelectorImpl.implRegister(PollSelectorImpl.java:144)
at sun.nio.ch.SelectorImpl.register(SelectorImpl.java:112)
at java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSele
ctableChannel.java:166)
at NBTest.startServer(NBTest.java:85)
at NBTest.main(NBTest.java:111)
63 Channels per selector is utterly useless if you want to write a scalable
server application, the reason for java.nio.channels to exist in the first
place.
I have run the same test on Solaris and on Linux and the problem did not occur
there, although I did need to increase the number of file handles the system
allows for Redhat Linux 7.1
Code to reproduce the problem:
/*
* NBTest.java
*
* Created on 01 September 2001, 21:20
*/
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.net.*;
import java.util.*;
/**
*
* @author Administrator
* @version
*/
public class NBTest {
/** Creates new NBTest */
public NBTest()
{
}
private static void debug(String s)
{
System.out.println(s);
}
private static void printKeyInfo(SelectionKey sk)
{
String s = new String();
s = "Att: " + (sk.attachment() == null ? "no" : "yes");
s += ", Read: " + sk.isReadable();
s += ", Acpt: " + sk.isAcceptable();
s += ", Cnct: " + sk.isConnectable();
s += ", Wrt: " + sk.isWritable();
s += ", Valid: " + sk.isValid();
s += ", Ops: " + sk.interestOps();
debug(s);
}
public void startServer() throws Exception
{
int channels = 0;
int nKeys = 0;
int currentSelector = 0;
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress
(InetAddress.getLocalHost(),9000);
ssc.socket().bind(address);
ssc.configureBlocking(false);
SelectionKey s = ssc.register(selector, SelectionKey.OP_ACCEPT);
printKeyInfo(s);
while(true)
{
debug("NBTest: Starting select");
nKeys = selector.select();
if(nKeys > 0)
{
debug("NBTest: Number of keys after select operation: " +
nKeys);
Set selectedKeys = selector.selectedKeys();
Iterator i = selectedKeys.iterator();
while(i.hasNext())
{
s = (SelectionKey) i.next();
printKeyInfo(s);
debug("NBTest: Nr Keys in selector: " + selector.keys().size
());
i.remove();
if(s.isAcceptable())
{
// Get the SocketChannel
Socket socket = ((ServerSocketChannel) s.channel
()).accept();
SocketChannel sc = socket.getChannel();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ |
SelectionKey.OP_WRITE);
System.out.println(++channels);
}
else
{
debug("NBTest: Channel not acceptable");
}
}
}
else
{
debug("NBTest: Select finished without any keys.");
}
}
}
/**
* @param args the command line arguments
*/
public static void main (String args[])
{
NBTest nbTest = new NBTest();
try
{
nbTest.startServer();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Run this application and telnet to port 9000. It doesn't do much, it just
accepts incoming connections and adds those to the selector.
(Review ID: 131555)
======================================================================
Name: nt126004 Date: 09/14/2001
java version "1.4.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta2-b77)
Java HotSpot(TM) Client VM (build 1.4.0-beta2-b77, mixed mode)
The problem is simple, if we try to register more than 63 SocketChannel on one
Selector we get :
java.lang.UnsupportedOperationException: Implementation allows only 63 channels
per Selector
at sun.nio.ch.PollArrayWrapper.addEntry(PollArrayWrapper.java:123)
at sun.nio.ch.PollSelectorImpl.implRegister(PollSelectorImpl.java:144)
at sun.nio.ch.SelectorImpl.register(SelectorImpl.java:112)
at java.nio.channels.spi.AbstractSelectableChannel.register
(AbstractSelectableChannel.java:166)
For a server more than 63 concurrent sessions is far to be exceptional.
I can see 3 possible origins to this limitation :
1) This limitation is due to the way the implementation of the Selector (or one
of its dependencies) has been done. --> implementation should be extended
2) This limitation has been artificially added because of a performance
degradation due to some native bottleneck on the selection of the socket -->
should eventually let us the choice to go above this limit
3) This is a limitation of the native calls to select a socket --> not much one
can do about it, but it should be documented somewhere.
(Review ID: 131887)
======================================================================