|
@@ -51,13 +51,15 @@ namespace PlatformBenchmarks
|
|
|
|
|
|
public HttpHandler()
|
|
|
{
|
|
|
-
|
|
|
+ RequestDispatchs = new BeetleX.Dispatchs.DispatchCenter<HttpToken>(OnRequest, Math.Min(Environment.ProcessorCount, 16));
|
|
|
}
|
|
|
|
|
|
- public Task Default(ReadOnlySpan<byte> url, PipeStream stream, HttpToken token, ISession session)
|
|
|
+ private BeetleX.Dispatchs.DispatchCenter<HttpToken> RequestDispatchs;
|
|
|
+
|
|
|
+ public Task Default(PipeStream stream, HttpToken token, ISession session)
|
|
|
{
|
|
|
stream.Write("<b> beetlex server</b><hr/>");
|
|
|
- stream.Write($"{Encoding.ASCII.GetString(url)} not found!");
|
|
|
+ stream.Write("path not found!");
|
|
|
OnCompleted(stream, session, token);
|
|
|
return Task.CompletedTask;
|
|
|
}
|
|
@@ -67,6 +69,8 @@ namespace PlatformBenchmarks
|
|
|
base.Connected(server, e);
|
|
|
e.Session.Socket.NoDelay = true;
|
|
|
var token = new HttpToken();
|
|
|
+ token.ThreadDispatcher = RequestDispatchs.Next();
|
|
|
+ token.Session = e.Session;
|
|
|
token.Db = new RawDb(new ConcurrentRandom(), Npgsql.NpgsqlFactory.Instance);
|
|
|
e.Session.Tag = token;
|
|
|
}
|
|
@@ -82,6 +86,14 @@ namespace PlatformBenchmarks
|
|
|
|
|
|
}
|
|
|
|
|
|
+ private void OnRequest(HttpToken token)
|
|
|
+ {
|
|
|
+ if (token.Requests.TryDequeue(out RequestData result))
|
|
|
+ {
|
|
|
+ OnStartRequest(result, token.Session, token, token.Session.Stream.ToPipeStream());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public override void SessionReceive(IServer server, SessionReceiveEventArgs e)
|
|
|
{
|
|
|
base.SessionReceive(server, e);
|
|
@@ -96,6 +108,7 @@ namespace PlatformBenchmarks
|
|
|
{
|
|
|
token.Requests.Enqueue(token.CurrentRequest);
|
|
|
token.CurrentRequest = null;
|
|
|
+ token.ThreadDispatcher.Enqueue(token);
|
|
|
}
|
|
|
pipeStream.ReadFree(result.Length);
|
|
|
}
|
|
@@ -103,10 +116,26 @@ namespace PlatformBenchmarks
|
|
|
{
|
|
|
if (token.CurrentRequest == null)
|
|
|
{
|
|
|
- token.CurrentRequest = new RequestData();
|
|
|
- var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(result.Length);
|
|
|
+ var request = new RequestData();
|
|
|
+
|
|
|
+ byte[] buffer = null;
|
|
|
+ if (Program.Debug)
|
|
|
+ buffer = new byte[result.Length];
|
|
|
+ else
|
|
|
+ buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(result.Length);
|
|
|
pipeStream.Read(buffer, 0, result.Length);
|
|
|
- token.CurrentRequest.Data = new ArraySegment<byte>(buffer, 0, result.Length);
|
|
|
+ request.Data = new ArraySegment<byte>(buffer, 0, result.Length);
|
|
|
+ AnalysisAction(request);
|
|
|
+ if (request.Action == ActionType.Plaintext)
|
|
|
+ {
|
|
|
+ token.CurrentRequest = request;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ pipeStream.ReadFree((int)pipeStream.Length);
|
|
|
+ OnStartRequest(request, e.Session, token, pipeStream);
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -118,41 +147,9 @@ namespace PlatformBenchmarks
|
|
|
else
|
|
|
break;
|
|
|
}
|
|
|
- if (pipeStream.Length == 0 && token.CurrentRequest == null)
|
|
|
- {
|
|
|
- ProcessReqeusts(token, pipeStream, e.Session);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private async Task ProcessReqeusts(HttpToken token, PipeStream pipeStream, ISession session)
|
|
|
- {
|
|
|
- PROCESS:
|
|
|
- if (token.EnterProcess())
|
|
|
- {
|
|
|
- while (true)
|
|
|
- {
|
|
|
- if (token.Requests.TryDequeue(out RequestData item))
|
|
|
- {
|
|
|
- using (item)
|
|
|
- {
|
|
|
- await OnProcess(item, pipeStream, token, session);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- session.Stream.Flush();
|
|
|
- token.CompletedProcess();
|
|
|
- if (!token.Requests.IsEmpty)
|
|
|
- {
|
|
|
- goto PROCESS;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- private Task OnProcess(RequestData requestData, PipeStream pipeStream, HttpToken token, ISession sessino)
|
|
|
+ private void AnalysisAction(RequestData requestData)
|
|
|
{
|
|
|
var line = _line.AsSpan();
|
|
|
int len = requestData.Data.Count;
|
|
@@ -187,14 +184,6 @@ namespace PlatformBenchmarks
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return OnStartLine(http, method, url, sessino, token, pipeStream);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- public virtual Task OnStartLine(ReadOnlySpan<byte> http, ReadOnlySpan<byte> method, ReadOnlySpan<byte> url, ISession session, HttpToken token, PipeStream stream)
|
|
|
- {
|
|
|
-
|
|
|
int queryIndex = AnalysisUrl(url);
|
|
|
ReadOnlySpan<byte> baseUrl = default;
|
|
|
ReadOnlySpan<byte> queryString = default;
|
|
@@ -202,62 +191,105 @@ namespace PlatformBenchmarks
|
|
|
{
|
|
|
baseUrl = url.Slice(0, queryIndex);
|
|
|
queryString = url.Slice(queryIndex + 1, url.Length - queryIndex - 1);
|
|
|
+ requestData.QueryString = Encoding.ASCII.GetString(queryString);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
baseUrl = url;
|
|
|
}
|
|
|
- OnWriteHeader(stream, token);
|
|
|
if (baseUrl.Length == _path_Plaintext.Length && baseUrl.StartsWith(_path_Plaintext))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Plaintext;
|
|
|
+ }
|
|
|
+ else if (baseUrl.Length == _path_Json.Length && baseUrl.StartsWith(_path_Json))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Json;
|
|
|
+ }
|
|
|
+ else if (baseUrl.Length == _path_Db.Length && baseUrl.StartsWith(_path_Db))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Db;
|
|
|
+ }
|
|
|
+ else if (baseUrl.Length == _path_Queries.Length && baseUrl.StartsWith(_path_Queries))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Queries;
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (baseUrl.Length == _cached_worlds.Length && baseUrl.StartsWith(_cached_worlds))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Caching;
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Updates;
|
|
|
+ }
|
|
|
+ else if (baseUrl.Length == _path_Fortunes.Length && baseUrl.StartsWith(_path_Fortunes))
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Fortunes;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ requestData.Action = ActionType.Other;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public virtual async Task OnStartRequest(RequestData data, ISession session, HttpToken token, PipeStream stream)
|
|
|
+ {
|
|
|
+ OnWriteHeader(stream, token);
|
|
|
+ ActionType type = data.Action;
|
|
|
+ if (type == ActionType.Plaintext)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeText.Data, 0, _headerContentTypeText.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return Plaintext(url, stream, token, session);
|
|
|
+ await Plaintext(stream, token, session);
|
|
|
}
|
|
|
- else if (baseUrl.Length == _path_Json.Length && baseUrl.StartsWith(_path_Json))
|
|
|
+ else if (type == ActionType.Json)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return Json(stream, token, session);
|
|
|
+ await Json(stream, token, session);
|
|
|
}
|
|
|
- else if (baseUrl.Length == _path_Db.Length && baseUrl.StartsWith(_path_Db))
|
|
|
+ else if (type == ActionType.Db)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return db(stream, token, session);
|
|
|
+ await db(stream, token, session);
|
|
|
}
|
|
|
- else if (baseUrl.Length == _path_Queries.Length && baseUrl.StartsWith(_path_Queries))
|
|
|
+ else if (type == ActionType.Queries)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return queries(Encoding.ASCII.GetString(queryString), stream, token, session);
|
|
|
+ await queries(data.QueryString, stream, token, session);
|
|
|
}
|
|
|
|
|
|
- else if (baseUrl.Length == _cached_worlds.Length && baseUrl.StartsWith(_cached_worlds))
|
|
|
+ else if (type == ActionType.Caching)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return caching(Encoding.ASCII.GetString(queryString), stream, token, session);
|
|
|
+ await caching(data.QueryString, stream, token, session);
|
|
|
}
|
|
|
|
|
|
- else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates))
|
|
|
+ else if (type == ActionType.Updates)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return updates(Encoding.ASCII.GetString(queryString), stream, token, session);
|
|
|
+ await updates(data.QueryString, stream, token, session);
|
|
|
}
|
|
|
- else if (baseUrl.Length == _path_Fortunes.Length && baseUrl.StartsWith(_path_Fortunes))
|
|
|
+ else if (type == ActionType.Fortunes)
|
|
|
{
|
|
|
stream.Write(_headerContentTypeHtml.Data, 0, _headerContentTypeHtml.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return fortunes(stream, token, session);
|
|
|
+ await fortunes(stream, token, session);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
stream.Write(_headerContentTypeHtml.Data, 0, _headerContentTypeHtml.Length);
|
|
|
OnWriteContentLength(stream, token);
|
|
|
- return Default(url, stream, token, session);
|
|
|
+ await Default(stream, token, session);
|
|
|
}
|
|
|
+ if (!Program.Debug)
|
|
|
+ data.Dispose();
|
|
|
+
|
|
|
}
|
|
|
|
|
|
private void OnWriteHeader(PipeStream stream, HttpToken token)
|
|
@@ -278,9 +310,10 @@ namespace PlatformBenchmarks
|
|
|
|
|
|
private void OnCompleted(PipeStream stream, ISession session, HttpToken token)
|
|
|
{
|
|
|
- stream.ReadFree((int)stream.Length);
|
|
|
- token.FullLength((stream.CacheLength - token.ContentPostion).ToString());
|
|
|
|
|
|
+ token.FullLength((stream.CacheLength - token.ContentPostion).ToString());
|
|
|
+ if (token.Requests.IsEmpty)
|
|
|
+ session.Stream.Flush();
|
|
|
}
|
|
|
|
|
|
}
|