From 68b9d955f6e126834a9c33d3d8730d8ab884eb6c Mon Sep 17 00:00:00 2001 From: redkale Date: Wed, 5 Apr 2023 17:07:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96uriPathCaches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/redkale/net/DispatcherServlet.java | 6 +- .../org/redkale/net/http/HttpContext.java | 53 +++++++----- .../net/http/HttpDispatcherServlet.java | 11 +++ .../org/redkale/net/http/HttpRequest.java | 8 +- .../org/redkale/net/http/MultiContext.java | 2 +- src/main/java/org/redkale/util/ByteArray.java | 84 +++++++++++++------ 6 files changed, 112 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/redkale/net/DispatcherServlet.java b/src/main/java/org/redkale/net/DispatcherServlet.java index d9784d09a..213864e14 100644 --- a/src/main/java/org/redkale/net/DispatcherServlet.java +++ b/src/main/java/org/redkale/net/DispatcherServlet.java @@ -9,7 +9,7 @@ import java.io.Serializable; import java.util.*; import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Predicate; +import java.util.function.*; import java.util.logging.Level; import java.util.stream.Stream; import org.redkale.boot.Application; @@ -165,6 +165,10 @@ public abstract class DispatcherServlet consumer) { + mappings.forEach(consumer); + } + @Override @SuppressWarnings("unchecked") public void init(C context, AnyValue config) { diff --git a/src/main/java/org/redkale/net/http/HttpContext.java b/src/main/java/org/redkale/net/http/HttpContext.java index 7c8c12351..6d38bbcf1 100644 --- a/src/main/java/org/redkale/net/http/HttpContext.java +++ b/src/main/java/org/redkale/net/http/HttpContext.java @@ -5,10 +5,12 @@ */ package org.redkale.net.http; -import java.nio.channels.*; -import java.security.*; -import java.util.concurrent.*; -import java.util.function.*; +import java.nio.channels.CompletionHandler; +import java.nio.charset.Charset; +import java.security.SecureRandom; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import org.redkale.annotation.ConstructorParameters; import org.redkale.asm.*; import static org.redkale.asm.Opcodes.*; @@ -44,6 +46,9 @@ public class HttpContext extends Context { //所有Servlet方法都不需要读取http-header且RestBaseServlet不是自定义HttpServlet且不存在HttpFilter、WebSocket的情况下,lazyHeaders=true protected boolean lazyHeaders; //存在动态改值 + //不带通配符的mapping url的缓存对象 + final Map[] uriPathCaches = new Map[100]; + Function webSocketWriterIOThreadFunc; public HttpContext(HttpContextConfig config) { @@ -56,6 +61,29 @@ public class HttpContext extends Context { random.setSeed(Math.abs(System.nanoTime())); } + String loadUriPath(ByteArray array, boolean latin1, Charset charset) { + int index = array.length() >= uriPathCaches.length ? 0 : array.length(); + Map map = uriPathCaches[index]; + String uri = map == null ? null : map.get(array); + if (uri == null) { + uri = array.toString(latin1, charset); + } + return uri; + } + + String loadUriPath(ByteArray array, int sublen, boolean latin1, Charset charset) { + int pos = array.length(); + array.position(sublen); + int index = array.length() >= uriPathCaches.length ? 0 : array.length(); + Map map = uriPathCaches[index]; + String uri = map == null ? null : map.get(array); + if (uri == null) { + uri = array.toString(latin1, 0, sublen, charset); + } + array.position(pos); + return uri; + } + @Override protected void updateReadIOThread(AsyncConnection conn, AsyncIOThread ioReadThread) { super.updateReadIOThread(conn, ioReadThread); @@ -207,21 +235,4 @@ public class HttpContext extends Context { } - protected static class RequestURINode { - - public final byte[] bytes; - - public final String path; - - public RequestURINode(String path) { - this.path = path; - this.bytes = path.getBytes(); - } - - @Override - public String toString() { - return "RequestURINode{" + "path=" + path + '}'; - } - - } } diff --git a/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java b/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java index f6b45cf4a..57365734b 100644 --- a/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java +++ b/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java @@ -6,6 +6,7 @@ package org.redkale.net.http; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.locks.ReentrantLock; import java.util.function.*; @@ -506,6 +507,16 @@ public class HttpDispatcherServlet extends DispatcherServlet { s.postStart(context, getServletConf(s)); }); + forEachMappingKey((k, s) -> { + byte[] bs = k.getBytes(StandardCharsets.UTF_8); + int index = bs.length >= context.uriPathCaches.length ? 0 : bs.length; + Map map = context.uriPathCaches[index]; + if (map == null) { + map = new HashMap<>(); + context.uriPathCaches[index] = map; + } + map.put(new ByteArray().put(bs), k); + }); } public HttpServlet findServletByTopic(String topic) { diff --git a/src/main/java/org/redkale/net/http/HttpRequest.java b/src/main/java/org/redkale/net/http/HttpRequest.java index c37630e43..648e08142 100644 --- a/src/main/java/org/redkale/net/http/HttpRequest.java +++ b/src/main/java/org/redkale/net/http/HttpRequest.java @@ -594,7 +594,7 @@ public class HttpRequest extends Request { } size = bytes.length(); if (qst > 0) { //带?参数 - this.requestURI = decodeable ? toDecodeString(bytes, 0, qst, charset) : bytes.toString(latin1, 0, qst, charset); + this.requestURI = decodeable ? toDecodeString(bytes, 0, qst, charset) : context.loadUriPath(bytes, qst, latin1, charset);// bytes.toString(latin1, 0, qst, charset); int qlen = size - qst - 1; this.queryBytes = bytes.getBytes(qst + 1, qlen); this.lastRequestURIString = null; @@ -611,15 +611,15 @@ public class HttpRequest extends Request { this.lastRequestURIBytes = null; } else if (context.lazyHeaders) { byte[] lastURIBytes = lastRequestURIBytes; - if (lastURIBytes != null && lastURIBytes.length == size && bytes.equal(lastURIBytes)) { + if (lastURIBytes != null && lastURIBytes.length == size && bytes.deepEquals(lastURIBytes)) { this.requestURI = this.lastRequestURIString; } else { - this.requestURI = bytes.toString(latin1, charset); + this.requestURI = context.loadUriPath(bytes, latin1, charset);// bytes.toString(latin1, charset); this.lastRequestURIString = this.requestURI; this.lastRequestURIBytes = bytes.getBytes(); } } else { - this.requestURI = bytes.toString(latin1, charset); + this.requestURI = context.loadUriPath(bytes, latin1, charset); //bytes.toString(latin1, charset); this.lastRequestURIString = null; this.lastRequestURIBytes = null; } diff --git a/src/main/java/org/redkale/net/http/MultiContext.java b/src/main/java/org/redkale/net/http/MultiContext.java index 149fb22e3..4e608673e 100644 --- a/src/main/java/org/redkale/net/http/MultiContext.java +++ b/src/main/java/org/redkale/net/http/MultiContext.java @@ -408,7 +408,7 @@ public final class MultiContext { lasted = (byte) b; if (bd && bc == c) { buf.put(lasted); - if (buf.equal(this.endBoundarray)) { + if (buf.deepEquals(this.endBoundarray)) { break; } buf.removeLastByte(); diff --git a/src/main/java/org/redkale/util/ByteArray.java b/src/main/java/org/redkale/util/ByteArray.java index a140bbf73..2e6ae3638 100644 --- a/src/main/java/org/redkale/util/ByteArray.java +++ b/src/main/java/org/redkale/util/ByteArray.java @@ -52,6 +52,18 @@ public final class ByteArray implements ByteTuple { return this; } + /** + * 设置count的新位置 + * + * @param pos 新位置 + * + * @return ByteArray + */ + public ByteArray position(int pos) { + this.count = pos; + return this; + } + /** * 生成一个OutputStream * @@ -79,21 +91,11 @@ public final class ByteArray implements ByteTuple { * * @return 是否相同 */ - public boolean equal(final byte[] bytes) { + public boolean deepEquals(final byte[] bytes) { if (bytes == null) { return false; } - int len = count; - if (len != bytes.length) { - return false; - } - byte[] ba = content; - for (int i = 0; i < len; i++) { - if (ba[i] != bytes[i]) { - return false; - } - } - return true; + return deepEquals(bytes, 0, bytes.length); } /** @@ -105,7 +107,7 @@ public final class ByteArray implements ByteTuple { * * @return 是否相同 */ - public boolean equal(final byte[] bytes, int offset, int length) { + public boolean deepEquals(final byte[] bytes, int offset, int length) { if (bytes == null) { return false; } @@ -126,26 +128,58 @@ public final class ByteArray implements ByteTuple { /** * 比较内容是否相同 * - * @param bytes 待比较内容 + * @param tuple 待比较内容 * * @return 是否相同 */ - public boolean equal(final ByteArray bytes) { - if (bytes == null) { + public boolean deepEquals(final ByteTuple tuple) { + if (tuple == null) { return false; } - if (count != bytes.count) { + return deepEquals(tuple.content(), 0, tuple.length()); + } + + /** + * 比较内容是否相同 + * + * @param array 待比较内容 + * + * @return 是否相同 + */ + public boolean deepEquals(final ByteArray array) { + if (array == null) { return false; } - byte[] ba1 = content; - byte[] ba2 = bytes.content; - int len = count; - for (int i = 0; i < len; i++) { - if (ba1[i] != ba2[i]) { - return false; - } + return deepEquals(array.content, 0, array.count); + } + + /** + * 比较内容是否相同 + * + * @param obj 待比较内容 + * + * @return 是否相同 + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; } - return true; + if (!(obj instanceof ByteArray)) { + return false; + } + ByteArray array = (ByteArray) obj; + return deepEquals(array.content, 0, array.count); + } + + @Override + public int hashCode() { + int hash = this.count; + byte[] bs = content; + for (int i = 0; i < count; i++) { + hash = 31 * hash + bs[i]; + } + return hash; } /**