Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
028a274
test removing copy of read buffer
Unknow0 Mar 24, 2026
b132229
update chunked encoding
Unknow0 Mar 24, 2026
452f1f4
fix content
Unknow0 Mar 24, 2026
227cbb9
fix error
Unknow0 Mar 24, 2026
e163bc1
try fix race condition on OP_WRITE
Unknow0 Mar 24, 2026
2bf85cb
try fix race condition on op_write
Unknow0 Mar 26, 2026
70cae40
test without task
Unknow0 Mar 26, 2026
714f294
up
Unknow0 Mar 26, 2026
7f3bf24
cleanup write process & ssl
Unknow0 Mar 26, 2026
f72e4a0
missing update
Unknow0 Mar 26, 2026
4c2eb17
fix ssl closing
Unknow0 Mar 26, 2026
d3e3602
increase some buffer size & add bytebufferreader
Unknow0 Mar 26, 2026
67fe5a3
fix byteBuffers
Unknow0 Mar 27, 2026
e66baab
add some specialized decoder
Unknow0 Mar 27, 2026
a6ca3de
improve utf8Decoder
Unknow0 Mar 27, 2026
a245fc5
right fast decoder
Unknow0 Mar 27, 2026
480e595
add bench on Encoder/Decoder
Unknow0 Mar 27, 2026
e403457
update utf8 dec/enc
Unknow0 Mar 29, 2026
d3ca1bd
add some fix and
Unknow0 Mar 30, 2026
533f380
fix some error
Unknow0 Mar 31, 2026
0abc781
update utf8 decoder
Unknow0 Mar 31, 2026
b251ce8
update decoder fast path
Unknow0 Apr 1, 2026
58f1a05
update
Unknow0 Apr 2, 2026
6023603
up
Unknow0 Apr 2, 2026
fa4fc55
update encoder/decoder
Unknow0 Apr 12, 2026
5c59b4c
use ascii charsetencoder/decoder to speedup
Unknow0 Apr 12, 2026
5d5fb13
update from sonar
Unknow0 Apr 12, 2026
3b26d54
update
Unknow0 Apr 12, 2026
4681a8f
replace some emoji with escape sequence
Unknow0 Apr 13, 2026
38388a2
cleanup
Unknow0 Apr 13, 2026
c432de4
escape some more emoji
Unknow0 Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions unknow-server-bench/src/main/java/unknow/server/bench/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@

public class Main {
public static void main(String[] args) throws Exception {
Options o = new OptionsBuilder().forks(1).measurementIterations(10).verbosity(VerboseMode.SILENT).warmupIterations(5).build();

try (PrintStream w = args.length > 0 ? new PrintStream(Files.newOutputStream(Paths.get(args[0])), false, StandardCharsets.UTF_8) : System.out) {
for (Class<?> c : Arrays.asList(EncoderDecoder.class, BenchJaxb.class, BenchDocument.class, BenchProtostuff.class)) {
Options o = new OptionsBuilder().forks(1).measurementIterations(10).verbosity(VerboseMode.NORMAL).warmupIterations(5).build();

try (PrintStream w = args.length > 0 ? new PrintStream(Files.newOutputStream(Paths.get(args[0])), false, StandardCharsets.UTF_8) : System.err) {
for (Class<?> c : Arrays.asList(EncoderDecoder.class/*, BenchJaxb.class, BenchDocument.class, BenchProtostuff.class*/)) {
Collection<RunResult> result = new Runner(new OptionsBuilder().parent(o).include(c.getName()).build()).run();

w.println(c.getSimpleName());
w.println("```");
Collection<RunResult> result = new Runner(new OptionsBuilder().parent(o).include(c.getName()).build()).run();
ResultFormatFactory.getInstance(ResultFormatType.TEXT, w).writeOut(result);
w.println("```");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package unknow.server.nio;

/**
* statistics of a nio connection
*/
public class ConnectionStats {
private final boolean hasPengingWrite;
private final boolean closing;
Expand All @@ -13,18 +16,30 @@ public ConnectionStats(boolean hasPengingWrite, boolean closing, long lastCheck,
this.lastAction = lastAction;
}

/**
* @return true if the connection has pending write
*/
public boolean hasPengingWrite() {
return hasPengingWrite;
}

/**
* @return true if the connection is closing
*/
public boolean isClosing() {
return closing;
}

/**
* @return nanotime of last connection check
*/
public long lastCheck() {
return lastCheck;
}

/**
* @return nano time of last action on the connection
*/
public long lastAction() {
return lastAction;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.net.ssl.SSLEngine;

Expand All @@ -36,10 +37,13 @@ public final class NIOConnection extends NIOHandlerDelegate {
protected final SelectionKey key;
protected final SocketChannel channel;

private final AtomicBoolean writeScheduled;
private final WriteCheck writeCheck;

private InetSocketAddress local;
private InetSocketAddress remote;

final BlockingQueue<ByteBuffer> pending;
final Queue<ByteBuffer> pending;
final ByteBuffers writes;

long lastCheck;
Expand All @@ -59,8 +63,10 @@ public NIOConnection(NIOWorker worker, SelectionKey key, NIOConnectionHandler ha
this.worker = worker;
this.key = key;
this.channel = (SocketChannel) key.channel();
this.writeScheduled = new AtomicBoolean(false);
this.writeCheck = new WriteCheck();
this.out = new Out(this);
this.pending = new LinkedBlockingDeque<>();
this.pending = new ConcurrentLinkedQueue<>();
this.writes = new ByteBuffers(16);
}

Expand Down Expand Up @@ -91,25 +97,14 @@ public void init(NIOConnection co, long now, SSLEngine sslEngine) throws IOExcep
* add a buffers to the writing queue
*
* @param buf buffer to be written
* @throws InterruptedException in case of interruption
* @throws IOException
* @throws IOException in case of io error
*/
public final void write(ByteBuffer buf) throws InterruptedException, IOException {
public final void write(ByteBuffer buf) throws IOException {
if (!key.isValid())
throw new IOException("already closed");
pending.put(buf);
if (pending.size() > 10)
flush();
else
key.interestOpsOr(SelectionKey.OP_WRITE);
}

@SuppressWarnings("resource")
public final void flush() {
if (!hasPendingWrites())
return;
key.interestOpsOr(SelectionKey.OP_WRITE);
key.selector().wakeup();
pending.offer(buf);
if (writeScheduled.compareAndSet(false, true))
execute(writeCheck);
}

/**
Expand Down Expand Up @@ -161,17 +156,23 @@ public boolean isClosed() {
}

protected final void beforeWrite(long now) throws IOException {
while (writes.len < 16 && !pending.isEmpty())
handler.prepareWrite(pending.poll(), now, writes);
handler.beforeWrite(now, writes);
ByteBuffer b;
while ((b = pending.poll()) != null)
writes.accept(b);
handler.transformWrite(writes, now);
}

@Override
public final void onWrite(long now) throws IOException {
lastAction = now;
writes.compact();
if (!hasPendingWrites())
key.interestOpsAnd(~SelectionKey.OP_WRITE);
if (!hasPendingWrites()) {
writeScheduled.set(false);
if (!hasPendingWrites())
key.interestOpsAnd(~SelectionKey.OP_WRITE);
else if (writeScheduled.compareAndSet(false, true))
key.interestOpsOr(SelectionKey.OP_WRITE);
}
handler.onWrite(now);
}

Expand Down Expand Up @@ -203,18 +204,19 @@ public final void doneClosing() {

@Override
public String toString() {
return getClass() + "[local=" + getLocal() + " remote=" + getRemote() + "]";
return getClass() + "[local=" + getLocal() + " remote=" + getRemote() + "] writes: " + hasPendingWrites();
}

/** output stream for this connection */
public static final class Out extends OutputStream {
private static final int BUF_SIZE = 16 * 1024;
private NIOConnection h;

private ByteBuffer buf;

private Out(NIOConnection h) {
this.h = h;
this.buf = ByteBuffer.allocate(4096);
this.buf = ByteBuffer.allocate(BUF_SIZE);
}

@Override
Expand Down Expand Up @@ -246,15 +248,10 @@ public synchronized void write(byte[] b, int off, int len) throws IOException {
len -= r;
off += r;
writeBuffer();
if (len < 4096)
if (len < BUF_SIZE)
buf.put(b, off, len);
else
try {
h.write(ByteBuffer.wrap(Arrays.copyOfRange(b, off, off + len)));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
}
h.write(ByteBuffer.wrap(Arrays.copyOfRange(b, off, off + len)));
} else if (len == r) {
buf.put(b, off, len);
writeBuffer();
Expand All @@ -272,12 +269,7 @@ public synchronized void write(ByteBuffer b) throws IOException {
if (h == null)
throw new IOException("already closed");
writeBuffer();
try {
h.write(b);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
}
h.write(b);
}

@Override
Expand All @@ -302,19 +294,23 @@ public synchronized void flush() throws IOException {
if (h == null)
return;
writeBuffer();
h.flush();
}

private void writeBuffer() throws IOException {
if (h == null || buf.position() == 0)
return;
try {
h.write(buf.flip());
buf = ByteBuffer.allocate(4096);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
}
h.write(buf.flip());
buf = ByteBuffer.allocate(BUF_SIZE);
}
}

private class WriteCheck implements WorkerTask {
@Override
public void run(long now) {
if (hasPendingWrites())
key.interestOpsOr(SelectionKey.OP_WRITE);
else
writeScheduled.set(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

import javax.net.ssl.SSLEngine;

import unknow.server.util.io.ByteBuffers;

/**
* handle nio connection event
*/
@SuppressWarnings("unused")
public interface NIOConnectionHandler {

Expand Down Expand Up @@ -40,33 +45,21 @@ default void onHandshakeDone(SSLEngine sslEngine, long now) throws IOException {
/**
* called after some data has been read
*
* @param b the read buffers
* @param b the read buffers (should read all or copy content)
* @param now nanoTime
* @throws IOException on io exception
*/
default void onRead(ByteBuffer b, long now) throws IOException { // ok
}

/**
* called before a buffer is written (allow to collect buffers)
*
* @param b buffer to be written
* @param now nanoTime
* @param c consumer of generated buffers
* @throws IOException on io exception
*/
default void prepareWrite(ByteBuffer b, long now, Consumer<ByteBuffer> c) throws IOException {
c.accept(b);
}

/**
* called before a buffer is written
* called before some buffers are written
*
* @param buffers buffers to be written
* @param now nanoTime
* @param c consumer of generated buffers
* @throws IOException on io exception
*/
default void beforeWrite(long now, Consumer<ByteBuffer> c) throws IOException { // ok
default void transformWrite(ByteBuffers buffers, long now) throws IOException { // ok
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.function.Consumer;

import javax.net.ssl.SSLEngine;

import unknow.server.util.io.ByteBuffers;

public class NIOHandlerDelegate implements NIOConnectionHandler {
protected final NIOConnectionHandler handler;

Expand Down Expand Up @@ -34,13 +35,8 @@ public void onRead(ByteBuffer b, long now) throws IOException {
}

@Override
public void prepareWrite(ByteBuffer b, long now, Consumer<ByteBuffer> c) throws IOException {
handler.prepareWrite(b, now, c);
}

@Override
public void beforeWrite(long now, Consumer<ByteBuffer> c) throws IOException {
handler.beforeWrite(now, c);
public void transformWrite(ByteBuffers buffers, long now) throws IOException {
handler.transformWrite(buffers, now);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.slf4j.LoggerFactory;

/**
* basic selector loop
* @author unknow
*/
public class NIOLoop implements Runnable {
Expand Down
Loading
Loading