You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2007/10/18 17:11:03 UTC
svn commit: r586000 - in
/harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal:
SelectionKeyImpl.java SelectorImpl.java
Author: tellison
Date: Thu Oct 18 08:10:59 2007
New Revision: 586000
URL: http://svn.apache.org/viewvc?rev=586000&view=rev
Log:
Apply patch HARMONY-4869 ([classlib][nio][performance] Selector improvements: moving away from O(n) at Java layer, part 1)
With minor code formatting modifications.
Modified:
harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectionKeyImpl.java
harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectorImpl.java
Modified: harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectionKeyImpl.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectionKeyImpl.java?rev=586000&r1=585999&r2=586000&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectionKeyImpl.java (original)
+++ harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectionKeyImpl.java Thu Oct 18 08:10:59 2007
@@ -28,9 +28,9 @@
*/
final class SelectionKeyImpl extends AbstractSelectionKey {
- private AbstractSelectableChannel channel;
+ static int stHash;
- int oldInterestOps;
+ private AbstractSelectableChannel channel;
private int interestOps;
@@ -38,12 +38,32 @@
private SelectorImpl selector;
+ private int index;
+
+ private int hashCode;
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final SelectionKeyImpl other = (SelectionKeyImpl) obj;
+ return hashCode == other.hashCode;
+ }
+
public SelectionKeyImpl(AbstractSelectableChannel channel, int operations,
Object attachment, SelectorImpl selector) {
super();
this.channel = channel;
interestOps = operations;
this.selector = selector;
+ this.hashCode = stHash++;
attach(attachment);
}
@@ -65,6 +85,7 @@
}
synchronized (selector.keysLock) {
interestOps = operations;
+ selector.modKey(this);
}
return this;
}
@@ -85,10 +106,17 @@
this.readyOps = readyOps;
}
+ int getIndex() {
+ return index;
+ }
+
+ void setIndex(int index) {
+ this.index = index;
+ }
+
private void checkValid() {
if (!isValid()) {
throw new CancelledKeyException();
}
}
-
-}
\ No newline at end of file
+}
Modified: harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectorImpl.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectorImpl.java?rev=586000&r1=585999&r2=586000&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectorImpl.java (original)
+++ harmony/enhanced/classlib/trunk/modules/nio/src/main/java/common/org/apache/harmony/nio/internal/SelectorImpl.java Thu Oct 18 08:10:59 2007
@@ -29,12 +29,11 @@
import java.nio.channels.spi.AbstractSelectionKey;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Set;
import org.apache.harmony.luni.platform.FileDescriptorHandler;
@@ -42,7 +41,6 @@
/*
* Default implementation of java.nio.channels.Selector
- *
*/
final class SelectorImpl extends AbstractSelector {
@@ -64,10 +62,14 @@
// before selection
final Object keysLock = new Object();
- private final Set<SelectionKey> keys = new HashSet<SelectionKey>();
+ boolean keySetChanged = true;
+
+ private SelectionKey[] keys = new SelectionKey[1];
+
+ private final Set<SelectionKey> keysSet = new HashSet<SelectionKey>();
private Set<SelectionKey> unmodifiableKeys = Collections
- .unmodifiableSet(keys);
+ .unmodifiableSet(keysSet);
private final Set<SelectionKey> selectedKeys = new HashSet<SelectionKey>();
@@ -78,16 +80,26 @@
private Pipe.SinkChannel sink;
private Pipe.SourceChannel source;
-
+
private FileDescriptor sourcefd;
-
- private SelectionKey[] readableChannels;
- private SelectionKey[] writableChannels;
+ private FileDescriptor[] readableFDs;
+
+ private FileDescriptor[] writableFDs;
+
+ private int lastKeyIndex = -1;
+
+ private int readableKeysCount = 0;
+
+ private int writableKeysCount = 0;
- private FileDescriptor[] readable;
+ private int[] keysToReadableFDs;
- private FileDescriptor[] writable;
+ private int[] keysToWritableFDs;
+
+ private int[] readableFDsToKeys;
+
+ private int[] writableFDsToKeys;
public SelectorImpl(SelectorProvider selectorProvider) {
super(selectorProvider);
@@ -95,8 +107,27 @@
Pipe mockSelector = selectorProvider.openPipe();
sink = mockSelector.sink();
source = mockSelector.source();
- sourcefd = ((FileDescriptorHandler)source).getFD();
+ sourcefd = ((FileDescriptorHandler) source).getFD();
source.configureBlocking(false);
+
+ readableFDs = new FileDescriptor[1];
+ writableFDs = new FileDescriptor[0];
+ keysToReadableFDs = new int[1];
+ keysToWritableFDs = new int[0];
+ readableFDsToKeys = new int[1];
+ writableFDsToKeys = new int[0];
+
+ // register sink channel
+ readableFDs[0] = sourcefd;
+ keys[0] = source.keyFor(this);
+
+ // index it
+ keysToReadableFDs[0] = 0;
+ readableFDsToKeys[0] = 0;
+
+ lastKeyIndex = 0;
+ readableKeysCount = 1;
+
} catch (IOException e) {
// do nothing
}
@@ -107,11 +138,13 @@
*/
protected void implCloseSelector() throws IOException {
synchronized (this) {
- synchronized (keys) {
+ synchronized (keysSet) {
synchronized (selectedKeys) {
doCancel();
for (SelectionKey sk : keys) {
- deregister((AbstractSelectionKey) sk);
+ if (sk != null) {
+ deregister((AbstractSelectionKey) sk);
+ }
}
wakeup();
}
@@ -119,6 +152,214 @@
}
}
+ private void ensureCapacity(int c) {
+ // TODO: rewrite array handling as some internal class
+ if (c >= keys.length) {
+ SelectionKey[] newKeys = new SelectionKey[(keys.length + 1) << 1];
+ System.arraycopy(keys, 0, newKeys, 0, keys.length);
+ keys = newKeys;
+ }
+
+ if (c >= keysToReadableFDs.length) {
+ int[] newKeysToReadableFDs = new int[(keysToReadableFDs.length + 1) << 1];
+ System.arraycopy(keysToReadableFDs, 0, newKeysToReadableFDs, 0,
+ keysToReadableFDs.length);
+ keysToReadableFDs = newKeysToReadableFDs;
+ }
+
+ if (c >= keysToWritableFDs.length) {
+ int[] newKeysToWritableFDs = new int[(keysToWritableFDs.length + 1) << 1];
+ System.arraycopy(keysToWritableFDs, 0, newKeysToWritableFDs, 0,
+ keysToWritableFDs.length);
+ keysToWritableFDs = newKeysToWritableFDs;
+ }
+
+ if (readableKeysCount >= readableFDs.length) {
+ FileDescriptor[] newReadableFDs = new FileDescriptor[(readableFDs.length + 1) << 1];
+ System.arraycopy(readableFDs, 0, newReadableFDs, 0,
+ readableFDs.length);
+ readableFDs = newReadableFDs;
+ }
+
+ if (readableKeysCount >= readableFDsToKeys.length) {
+ int[] newReadableFDsToKeys = new int[(readableFDsToKeys.length + 1) << 1];
+ System.arraycopy(readableFDsToKeys, 0, newReadableFDsToKeys, 0,
+ readableFDsToKeys.length);
+ readableFDsToKeys = newReadableFDsToKeys;
+ }
+
+ if (writableKeysCount >= writableFDs.length) {
+ FileDescriptor[] newWriteableFDs = new FileDescriptor[(writableFDs.length + 1) << 1];
+ System.arraycopy(writableFDs, 0, newWriteableFDs, 0,
+ writableFDs.length);
+ writableFDs = newWriteableFDs;
+ }
+
+ if (writableKeysCount >= writableFDsToKeys.length) {
+ int[] newWritableFDsToKeys = new int[(writableFDsToKeys.length + 1) << 1];
+ System.arraycopy(writableFDsToKeys, 0, newWritableFDsToKeys, 0,
+ writableFDsToKeys.length);
+ writableFDsToKeys = newWritableFDsToKeys;
+ }
+ }
+
+ private void limitCapacity() {
+ // TODO: implement array squeezing
+ }
+
+ /**
+ * Adds the specified key to storage and updates the indexes accordingly
+ *
+ * @param sk
+ * key to add
+ * @return index in the storage
+ */
+ private int addKey(SelectionKey sk) {
+
+ lastKeyIndex++;
+ int c = lastKeyIndex;
+
+ // make sure that enough space is available
+ ensureCapacity(c);
+
+ // add to keys storage
+ keys[c] = sk;
+
+ // cache the fields
+ int ops = sk.interestOps();
+ FileDescriptor fd = ((FileDescriptorHandler) sk.channel()).getFD();
+
+ // presume that we have no FD associated
+ keysToReadableFDs[c] = -1;
+ keysToWritableFDs[c] = -1;
+
+ // if readable operations requested
+ if (((SelectionKey.OP_ACCEPT | SelectionKey.OP_READ) & ops) != 0) {
+ // save as readable FD
+ readableFDs[readableKeysCount] = fd;
+
+ // create index
+ keysToReadableFDs[c] = readableKeysCount;
+ readableFDsToKeys[readableKeysCount] = c;
+
+ readableKeysCount++;
+ }
+
+ // if writable operations requested
+ if (((SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE) & ops) != 0) {
+ // save as writable FD
+ writableFDs[writableKeysCount] = fd;
+
+ // create index
+ keysToWritableFDs[c] = writableKeysCount;
+ writableFDsToKeys[writableKeysCount] = c;
+
+ writableKeysCount++;
+ }
+
+ return c;
+ }
+
+ /**
+ * Deletes the key from the internal storage and updates the indexes
+ * accordingly
+ *
+ * @param sk
+ * key to delete
+ */
+ private void delKey(SelectionKey sk) {
+ int index = ((SelectionKeyImpl) sk).getIndex();
+
+ // === deleting the key and FDs
+
+ // key is null now
+ keys[index] = null;
+
+ // free FDs connected with the key
+ // free indexes
+ int readableIndex = keysToReadableFDs[index];
+ if (readableIndex != -1) {
+ readableFDs[readableIndex] = null;
+ readableFDsToKeys[readableIndex] = -1;
+ keysToReadableFDs[index] = -1;
+ }
+
+ int writableIndex = keysToWritableFDs[index];
+ if (writableIndex != -1) {
+ writableFDs[writableIndex] = null;
+ writableFDsToKeys[writableIndex] = -1;
+ keysToWritableFDs[index] = -1;
+ }
+
+ // === compacting arrays and indexes
+
+ // key compaction
+ if (keys[lastKeyIndex] != null) {
+ keys[index] = keys[lastKeyIndex];
+ keys[lastKeyIndex] = null;
+
+ // update key index
+ ((SelectionKeyImpl) keys[index]).setIndex(index);
+
+ // the key in the new position references the same FDs
+ keysToReadableFDs[index] = keysToReadableFDs[lastKeyIndex];
+ keysToWritableFDs[index] = keysToWritableFDs[lastKeyIndex];
+
+ // associated FDs reference the same key at new index
+ if (keysToReadableFDs[index] != -1) {
+ readableFDsToKeys[keysToReadableFDs[index]] = index;
+ }
+
+ if (keysToWritableFDs[index] != -1) {
+ writableFDsToKeys[keysToWritableFDs[index]] = index;
+ }
+
+ }
+ lastKeyIndex--;
+
+ // readableFDs compaction
+ if (readableIndex != -1) {
+ if (readableFDs[readableKeysCount - 1] != null) {
+ readableFDs[readableIndex] = readableFDs[readableKeysCount - 1];
+
+ // new FD references the same key
+ readableFDsToKeys[readableIndex] = readableFDsToKeys[readableKeysCount - 1];
+
+ // the key references the same FD at new index
+ if (readableFDsToKeys[readableIndex] != -1) {
+ keysToReadableFDs[readableFDsToKeys[readableIndex]] = readableIndex;
+ }
+ }
+ readableKeysCount--;
+ }
+
+ // writableFDs compaction
+ if (writableIndex != -1) {
+ if (writableFDs[writableKeysCount - 1] != null) {
+ writableFDs[writableIndex] = writableFDs[writableKeysCount - 1];
+
+ // new FD references the same key
+ writableFDsToKeys[writableIndex] = writableFDsToKeys[writableKeysCount - 1];
+
+ // the key references the same FD at new index
+ if (writableFDsToKeys[writableIndex] != -1) {
+ keysToWritableFDs[writableFDsToKeys[writableIndex]] = writableIndex;
+ }
+ }
+ writableKeysCount--;
+ }
+ }
+
+ /**
+ *
+ * @param sk
+ */
+ void modKey(SelectionKey sk) {
+ // TODO: update indexes rather than recreate the key
+ delKey(sk);
+ addKey(sk);
+ }
+
/*
* @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel,
* int, java.lang.Object)
@@ -129,10 +370,15 @@
throw new IllegalSelectorException();
}
synchronized (this) {
- synchronized (keys) {
+ synchronized (keysSet) {
+
+ // create the key
SelectionKey sk = new SelectionKeyImpl(channel, operations,
attachment, this);
- keys.add(sk);
+
+ int index = addKey(sk);
+ ((SelectionKeyImpl) sk).setIndex(index);
+
return sk;
}
}
@@ -143,6 +389,18 @@
*/
public synchronized Set<SelectionKey> keys() {
closeCheck();
+
+ keysSet.clear();
+
+ if (keys.length != lastKeyIndex + 1) {
+ SelectionKey[] chompedKeys = new SelectionKey[lastKeyIndex + 1];
+ System.arraycopy(keys, 0, chompedKeys, 0, lastKeyIndex + 1);
+ keysSet.addAll(Arrays.asList(chompedKeys));
+ } else {
+ keysSet.addAll(Arrays.asList(keys));
+ }
+
+ keysSet.remove(source.keyFor(this));
return unmodifiableKeys;
}
@@ -179,7 +437,7 @@
private int selectInternal(long timeout) throws IOException {
closeCheck();
synchronized (this) {
- synchronized (keys) {
+ synchronized (keysSet) {
synchronized (selectedKeys) {
doCancel();
int[] readyChannels = null;
@@ -189,13 +447,14 @@
if (isBlock) {
begin();
}
- readyChannels = Platform.getNetworkSystem().select(readable, writable, timeout);
+ readyChannels = Platform.getNetworkSystem().select(
+ readableFDs, writableFDs, timeout);
} finally {
if (isBlock) {
end();
}
}
- return processSelectResult(readyChannels);
+ return processSelectResult(readyChannels);
}
}
}
@@ -211,45 +470,31 @@
// Prepares and adds channels to list for selection
private void prepareChannels() {
- int sizeGuess = keys.size();
- List<SelectionKey> readChannelList = new ArrayList<SelectionKey>(sizeGuess + 1);
- List<FileDescriptor> readableFDs = new ArrayList<FileDescriptor>(sizeGuess + 1);
-
- List<SelectionKey> writeChannelList = new ArrayList<SelectionKey>(sizeGuess);
- List<FileDescriptor> writableFDs = new ArrayList<FileDescriptor>(sizeGuess);
-
- // Always add in the "wake-up" channel
- readChannelList.add(source.keyFor(this));
- readableFDs.add(sourcefd);
-
- synchronized (keysLock) {
- for (SelectionKey skey : keys) {
- SelectionKeyImpl key = (SelectionKeyImpl) skey;
- key.oldInterestOps = key.interestOps();
- boolean isReadableChannel = ((SelectionKey.OP_ACCEPT | SelectionKey.OP_READ) & key.oldInterestOps) != 0;
- boolean isWritableChannel = ((SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE) & key.oldInterestOps) != 0;
- SelectableChannel channel = key.channel();
- if (isReadableChannel) {
- readChannelList.add(channel.keyFor(this));
- readableFDs.add(((FileDescriptorHandler)channel).getFD());
- }
- if (isWritableChannel) {
- writeChannelList.add(channel.keyFor(this));
- writableFDs.add(((FileDescriptorHandler)channel).getFD());
- }
- }
+
+ // chomp the arrays if needed
+
+ if (readableFDs.length != readableKeysCount) {
+ FileDescriptor[] chompedReadableFDs = new FileDescriptor[readableKeysCount];
+ System.arraycopy(readableFDs, 0, chompedReadableFDs, 0,
+ readableKeysCount);
+ readableFDs = chompedReadableFDs;
}
- readableChannels = readChannelList.toArray(new SelectionKey[readChannelList.size()]);
- writableChannels = writeChannelList.toArray(new SelectionKey[writeChannelList.size()]);
- readable = readableFDs.toArray(new FileDescriptor[readableFDs.size()]);
- writable = writableFDs.toArray(new FileDescriptor[writableFDs.size()]);
+
+ if (writableFDs.length != writableKeysCount) {
+ FileDescriptor[] chompedWriteableFDs = new FileDescriptor[writableKeysCount];
+ System.arraycopy(writableFDs, 0, chompedWriteableFDs, 0,
+ writableKeysCount);
+ writableFDs = chompedWriteableFDs;
+ }
+
}
- /* Analyses selected channels and adds keys of ready channels to
+ /*
+ * Analyses selected channels and adds keys of ready channels to
* selectedKeys list.
*
- * readyChannels are encoded as concatenated array of flags for
- * readable channels followed by writable channels.
+ * readyChannels are encoded as concatenated array of flags for readable
+ * channels followed by writable channels.
*/
private int processSelectResult(int[] readyChannels) throws IOException {
if (0 == readyChannels.length) {
@@ -263,46 +508,51 @@
}
}
int selected = 0;
- for (int i = 1; i < readyChannels.length; i++) {
- SelectionKeyImpl key = (SelectionKeyImpl) (i >= readable.length ? writableChannels[i
- - readable.length]
- : readableChannels[i]);
- if (null == key) {
- continue;
- }
- boolean isOldSelectedKey = selectedKeys.contains(key);
- int selectedOp = 0;
- // set ready ops
- switch (readyChannels[i]) {
- case NA:
- selectedOp = 0;
- break;
- case READABLE:
- selectedOp = (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)
- & key.oldInterestOps;
- break;
- case WRITEABLE:
- if (isConnected(key)) {
- selectedOp = SelectionKey.OP_WRITE & key.oldInterestOps;
- } else {
- selectedOp = SelectionKey.OP_CONNECT & key.oldInterestOps;
+
+ for (int i = 1; i < readyChannels.length; i++) {
+
+ if (readyChannels[i] != NA) {
+ SelectionKeyImpl key = (SelectionKeyImpl) (i >= readableKeysCount ? keys[writableFDsToKeys[i
+ - readableKeysCount]]
+ : keys[readableFDsToKeys[i]]);
+
+ if (null == key) {
+ continue;
}
- break;
- }
- if (0 != selectedOp) {
- if (isOldSelectedKey && key.readyOps() != selectedOp) {
- key.setReadyOps(key.readyOps() | selectedOp);
- selected++;
- } else if (!isOldSelectedKey) {
- key.setReadyOps(selectedOp);
- selectedKeys.add(key);
- selected++;
+ int ops = key.interestOps();
+ int selectedOp = 0;
+
+ switch (readyChannels[i]) {
+
+ case READABLE:
+ selectedOp = (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)
+ & ops;
+ break;
+ case WRITEABLE:
+ if (isConnected(key)) {
+ selectedOp = SelectionKey.OP_WRITE & ops;
+ } else {
+ selectedOp = SelectionKey.OP_CONNECT & ops;
+ }
+ break;
+ }
+
+ if (0 != selectedOp) {
+ boolean isOldSelectedKey = selectedKeys.contains(key);
+ if (isOldSelectedKey && key.readyOps() != selectedOp) {
+ key.setReadyOps(key.readyOps() | selectedOp);
+ selected++;
+ } else if (!isOldSelectedKey) {
+ key.setReadyOps(selectedOp);
+ selectedKeys.add(key);
+ selected++;
+ }
}
+
}
}
- readableChannels = null;
- writableChannels = null;
+
return selected;
}
@@ -319,12 +569,13 @@
synchronized (cancelledKeys) {
if (cancelledKeys.size() > 0) {
for (SelectionKey currentkey : cancelledKeys) {
+ delKey(currentkey);
deregister((AbstractSelectionKey) currentkey);
- keys.remove(currentkey);
selectedKeys.remove(currentkey);
}
}
cancelledKeys.clear();
+ limitCapacity();
}
}