优化uriPathCaches

This commit is contained in:
redkale
2023-04-05 17:07:59 +08:00
parent 39ac48884f
commit 68b9d955f6
6 changed files with 112 additions and 52 deletions

View File

@@ -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<K extends Serializable, C extends Contex
return mappings.get(key);
}
protected void forEachMappingKey(BiConsumer<K, S> consumer) {
mappings.forEach(consumer);
}
@Override
@SuppressWarnings("unchecked")
public void init(C context, AnyValue config) {

View File

@@ -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<ByteArray, String>[] uriPathCaches = new Map[100];
Function<WebSocket, WebSocketWriteIOThread> 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<ByteArray, String> 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<ByteArray, String> 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 + '}';
}
}
}

View File

@@ -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<String, HttpContext
getServlets().forEach(s -> {
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<ByteArray, String> 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) {

View File

@@ -594,7 +594,7 @@ public class HttpRequest extends Request<HttpContext> {
}
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<HttpContext> {
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;
}

View File

@@ -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();

View File

@@ -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;
}
/**