优化uriPathCaches
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 + '}';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user