Browse Source

Merge branch 'TechEmpower:master' into master

Huang ziquan 5 months ago
parent
commit
aaf15d1325
73 changed files with 2218 additions and 465 deletions
  1. 40 20
      frameworks/CSharp/sisk/benchmark_config.json
  2. 15 2
      frameworks/CSharp/sisk/config.toml
  3. 19 0
      frameworks/CSharp/sisk/sisk-cadente.dockerfile
  4. 36 0
      frameworks/CSharp/sisk/sisk-cadente/Program.cs
  5. 15 0
      frameworks/CSharp/sisk/sisk-cadente/sisk.csproj
  6. 13 17
      frameworks/CSharp/sisk/sisk/Program.cs
  7. 2 2
      frameworks/CSharp/sisk/sisk/sisk.csproj
  8. 13 12
      frameworks/Java/helidon/nima/pom.xml
  9. 23 18
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java
  10. 18 10
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java
  11. 5 1
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java
  12. 143 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPool.java
  13. 35 68
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java
  14. 34 19
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java
  15. 40 5
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java
  16. 0 1
      frameworks/Java/helidon/nima/src/main/resources/application.yaml
  17. 2 0
      frameworks/Java/helidon/nima/src/main/resources/views/fortunes.jte
  18. 0 24
      frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html
  19. 12 9
      frameworks/Java/inverno/README.md
  20. 1 2
      frameworks/Java/inverno/inverno-postgres.dockerfile
  21. 1 2
      frameworks/Java/inverno/inverno.dockerfile
  22. 54 10
      frameworks/Java/inverno/pom.xml
  23. 3 4
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java
  24. 54 106
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java
  25. 132 0
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java
  26. 38 0
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java
  27. 0 66
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java
  28. 3 0
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java
  29. 3 0
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java
  30. 6 5
      frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java
  31. 3 6
      frameworks/Java/inverno/src/main/java/module-info.java
  32. 1 1
      frameworks/Java/wicket/pom.xml
  33. 26 0
      frameworks/PHP/cyberphp/README.md
  34. 57 0
      frameworks/PHP/cyberphp/app/config.php
  35. 74 0
      frameworks/PHP/cyberphp/app/controller/Index.php
  36. 84 0
      frameworks/PHP/cyberphp/app/helpers.php
  37. 14 0
      frameworks/PHP/cyberphp/app/route.php
  38. 62 0
      frameworks/PHP/cyberphp/app/views/errors/exception.html
  39. 30 0
      frameworks/PHP/cyberphp/benchmark_config.json
  40. 41 0
      frameworks/PHP/cyberphp/bootstrap.php
  41. 29 0
      frameworks/PHP/cyberphp/composer.json
  42. 26 0
      frameworks/PHP/cyberphp/cyberphp.dockerfile
  43. 11 0
      frameworks/PHP/cyberphp/php.ini
  44. BIN
      frameworks/PHP/cyberphp/public/favicon.ico
  45. 23 0
      frameworks/PHP/cyberphp/public/index.php
  46. 85 0
      frameworks/PHP/cyberphp/server.php
  47. 154 0
      frameworks/PHP/cyberphp/src/App.php
  48. 48 0
      frameworks/PHP/cyberphp/src/Middleware.php
  49. 232 0
      frameworks/PHP/cyberphp/src/Request.php
  50. 218 0
      frameworks/PHP/cyberphp/src/Response.php
  51. 61 0
      frameworks/PHP/cyberphp/src/Route.php
  52. 47 0
      frameworks/PHP/cyberphp/src/Utility.php
  53. 24 0
      frameworks/PHP/laravel/deploy/franken/Caddyfile
  54. 1 2
      frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile
  55. 4 5
      frameworks/PHP/laravel/laravel-ripple.dockerfile
  56. 5 2
      frameworks/PHP/php/deploy/franken/Caddyfile
  57. 5 2
      frameworks/PHP/reactphp/app.php
  58. 20 1
      frameworks/PHP/reactphp/benchmark_config.json
  59. 35 0
      frameworks/PHP/reactphp/reactphp-libuv.dockerfile
  60. 1 1
      frameworks/PHP/reactphp/reactphp.dockerfile
  61. 3 0
      frameworks/PHP/reactphp/server.php
  62. 6 11
      frameworks/PHP/symfony/deploy/Caddyfile
  63. 0 1
      frameworks/PHP/symfony/symfony-franken.dockerfile
  64. 1 1
      frameworks/Perl/feersum/cpanfile
  65. 1 1
      frameworks/Ruby/agoo/Gemfile.lock
  66. 3 5
      frameworks/Ruby/rack-sequel/Gemfile.lock
  67. 6 6
      frameworks/Ruby/rack-sequel/benchmark_config.json
  68. 5 5
      frameworks/Ruby/rack/benchmark_config.json
  69. 4 4
      frameworks/Ruby/rails/Gemfile.lock
  70. 1 1
      frameworks/Ruby/rails/rails-iodine.dockerfile
  71. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile
  72. 2 2
      frameworks/Rust/axum/Cargo.lock
  73. 4 4
      frameworks/Rust/ohkami/Cargo.lock

+ 40 - 20
frameworks/CSharp/sisk/benchmark_config.json

@@ -1,21 +1,41 @@
 {
 {
-  "framework": "sisk",
-  "tests": [{
-    "default": {
-      "plaintext_url": "/plaintext",
-      "json_url": "/json",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Fullstack",
-      "database": "None",
-      "framework": "Sisk",
-      "language": "C#",
-      "orm": "Raw",
-      "platform": ".NET",
-      "webserver": "Sisk",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "Sisk Framework"
-    }
-  }]
-}
+    "framework": "sisk",
+    "tests": [
+        {
+            "default": {
+                "plaintext_url": "/plaintext",
+                "json_url": "/json",
+                "port": 8080,
+                "approach": "Realistic",
+                "classification": "Micro",
+                "database": "None",
+                "framework": "Sisk",
+                "language": "C#",
+                "orm": "Raw",
+                "platform": ".NET",
+                "webserver": "HttpListener",
+                "os": "Linux",
+                "database_os": "Linux",
+                "display_name": "Sisk Framework"
+            }
+        },
+        {
+            "cadente": {
+                "plaintext_url": "/plaintext",
+                "json_url": "/json",
+                "port": 8080,
+                "approach": "Realistic",
+                "classification": "Platform",
+                "database": "None",
+                "framework": "Sisk",
+                "language": "C#",
+                "orm": "Raw",
+                "platform": ".NET",
+                "webserver": "Cadente",
+                "os": "Linux",
+                "database_os": "Linux",
+                "display_name": "Sisk Framework (Cadente)"
+            }
+        }
+    ]
+}

+ 15 - 2
frameworks/CSharp/sisk/config.toml

@@ -5,11 +5,24 @@ name = "sisk"
 urls.plaintext = "/plaintext"
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 approach = "Realistic"
 approach = "Realistic"
-classification = "Fullstack"
+classification = "Micro"
 database = "None"
 database = "None"
 database_os = "Linux"
 database_os = "Linux"
 os = "Linux"
 os = "Linux"
 orm = "Raw"
 orm = "Raw"
 platform = ".NET"
 platform = ".NET"
-webserver = "Sisk"
+webserver = "HttpListener"
+versus = "None"
+
+[cadente]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+approach = "Realistic"
+classification = "Platform"
+database = "None"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = ".NET"
+webserver = "Cadente"
 versus = "None"
 versus = "None"

+ 19 - 0
frameworks/CSharp/sisk/sisk-cadente.dockerfile

@@ -0,0 +1,19 @@
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+WORKDIR /source
+
+# copy csproj and restore as distinct layers
+COPY sisk-cadente/*.csproj .
+RUN dotnet restore -r linux-musl-x64
+
+# copy and publish app and libraries
+COPY sisk-cadente/ .
+RUN dotnet publish -c release -o /app -r linux-musl-x64
+
+# final stage/image
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
+WORKDIR /app
+COPY --from=build /app .
+
+ENTRYPOINT ["dotnet", "./sisk.dll"]
+
+EXPOSE 8080

+ 36 - 0
frameworks/CSharp/sisk/sisk-cadente/Program.cs

@@ -0,0 +1,36 @@
+using System.Text;
+using System.Text.Json;
+using Sisk.Cadente;
+
+var host = new HttpHost ( 8080, session => {
+    var request = session.Request;
+
+    if (request.Path == "/plaintext") {
+        SerializePlainTextResponse ( session.Response );
+    }
+    else if (request.Path == "/json") {
+        SerializeJsonResponse ( session.Response );
+    }
+    else {
+        session.Response.StatusCode = 404;
+    }
+} );
+
+host.Start ();
+Thread.Sleep ( Timeout.Infinite );
+
+static void SerializePlainTextResponse ( HttpResponse response ) {
+    var contentBytes = Encoding.UTF8.GetBytes ( "Hello, world!" );
+
+    response.Headers.Add ( new HttpHeader ( "Content-Type", "text/plain" ) );
+    response.ResponseStream = new MemoryStream ( contentBytes );
+}
+
+static void SerializeJsonResponse ( HttpResponse response ) {
+    var contentBytes = JsonSerializer.SerializeToUtf8Bytes ( new {
+        message = "Hello, world!"
+    } );
+
+    response.Headers.Add ( new HttpHeader ( "Content-Type", "application/json; charset=utf-8" ) );
+    response.ResponseStream = new MemoryStream ( contentBytes );
+}

+ 15 - 0
frameworks/CSharp/sisk/sisk-cadente/sisk.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+	<PropertyGroup>
+		<OutputType>Exe</OutputType>
+		<TargetFramework>net8.0</TargetFramework>
+		<ImplicitUsings>enable</ImplicitUsings>
+		<Nullable>enable</Nullable>
+		<ServerGarbageCollection>true</ServerGarbageCollection>
+	</PropertyGroup>
+
+	<ItemGroup>
+	  <PackageReference Include="Sisk.Cadente" Version="0.1.42-alpha1" />
+	</ItemGroup>
+
+</Project>

+ 13 - 17
frameworks/CSharp/sisk/sisk/Program.cs

@@ -1,26 +1,22 @@
-using Sisk.Core.Http;
+using System.Net.Http.Json;
+using Sisk.Core.Http;
 using Sisk.Core.Routing;
 using Sisk.Core.Routing;
-using System.Net.Http.Json;
 
 
-var app = HttpServer.CreateBuilder(host =>
-{
-    host.UseListeningPort("http://+:8080/");
-});
+var app = HttpServer.CreateBuilder ( host => {
+    host.UseListeningPort ( "http://+:8080/" );
+} ).Build ();
 
 
-app.Router.SetRoute(RouteMethod.Get, "/plaintext", PlainText);
-app.Router.SetRoute(RouteMethod.Get, "/json", Json);
+app.Router.SetRoute ( RouteMethod.Get, "/plaintext", PlainText );
+app.Router.SetRoute ( RouteMethod.Get, "/json", Json );
 
 
-app.Start();
+app.Start ();
 
 
-static HttpResponse PlainText(HttpRequest request)
-{
-    return new HttpResponse().WithContent("Hello, world!");
+static HttpResponse PlainText ( HttpRequest request ) {
+    return new HttpResponse ( "Hello, world!" );
 }
 }
 
 
-static HttpResponse Json(HttpRequest request)
-{
-    return new HttpResponse().WithContent(JsonContent.Create(new
-    {
+static HttpResponse Json ( HttpRequest request ) {
+    return new HttpResponse ( JsonContent.Create ( new {
         message = "Hello, world!"
         message = "Hello, world!"
-    }));
+    } ) );
 }
 }

+ 2 - 2
frameworks/CSharp/sisk/sisk/sisk.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
 
 	<PropertyGroup>
 	<PropertyGroup>
 		<OutputType>Exe</OutputType>
 		<OutputType>Exe</OutputType>
@@ -9,7 +9,7 @@
 	</PropertyGroup>
 	</PropertyGroup>
 
 
 	<ItemGroup>
 	<ItemGroup>
-	  <PackageReference Include="Sisk.HttpServer" Version="0.16.2" />
+		<PackageReference Include="Sisk.HttpServer" Version="1.4.0-beta3" />
 	</ItemGroup>
 	</ItemGroup>
 
 
 </Project>
 </Project>

+ 13 - 12
frameworks/Java/helidon/nima/pom.xml

@@ -21,7 +21,7 @@
     <parent>
     <parent>
         <groupId>io.helidon.applications</groupId>
         <groupId>io.helidon.applications</groupId>
         <artifactId>helidon-se</artifactId>
         <artifactId>helidon-se</artifactId>
-        <version>4.1.2</version>
+        <version>4.1.5</version>
         <relativePath/>
         <relativePath/>
     </parent>
     </parent>
 
 
@@ -38,6 +38,7 @@
         <rocker.version>1.3.0</rocker.version>
         <rocker.version>1.3.0</rocker.version>
         <vertx-pg-client.version>4.5.3</vertx-pg-client.version>
         <vertx-pg-client.version>4.5.3</vertx-pg-client.version>
         <jsoniter.version>0.9.23</jsoniter.version>
         <jsoniter.version>0.9.23</jsoniter.version>
+        <jte.version>3.1.15</jte.version>
     </properties>
     </properties>
 
 
     <dependencies>
     <dependencies>
@@ -78,9 +79,9 @@
             <version>42.6.1</version>
             <version>42.6.1</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
-            <groupId>com.fizzed</groupId>
-            <artifactId>rocker-runtime</artifactId>
-            <version>${rocker.version}</version>
+            <groupId>gg.jte</groupId>
+            <artifactId>jte</artifactId>
+            <version>${jte.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>io.helidon.common.testing</groupId>
             <groupId>io.helidon.common.testing</groupId>
@@ -98,7 +99,6 @@
             <scope>test</scope>
             <scope>test</scope>
         </dependency>
         </dependency>
     </dependencies>
     </dependencies>
-
     <build>
     <build>
         <plugins>
         <plugins>
             <plugin>
             <plugin>
@@ -125,20 +125,21 @@
                     </execution>
                     </execution>
                 </executions>
                 </executions>
             </plugin>
             </plugin>
+
             <plugin>
             <plugin>
-                <groupId>com.fizzed</groupId>
-                <artifactId>rocker-maven-plugin</artifactId>
-                <version>${rocker.version}</version>
+                <groupId>gg.jte</groupId>
+                <artifactId>jte-maven-plugin</artifactId>
+                <version>${jte.version}</version>
+                <configuration>
+                    <sourceDirectory>${project.basedir}/src/main/resources/views</sourceDirectory>
+                    <contentType>Html</contentType>
+                </configuration>
                 <executions>
                 <executions>
                     <execution>
                     <execution>
-                        <id>generate-rocker-templates</id>
                         <phase>generate-sources</phase>
                         <phase>generate-sources</phase>
                         <goals>
                         <goals>
                             <goal>generate</goal>
                             <goal>generate</goal>
                         </goals>
                         </goals>
-                        <configuration>
-                            <templateDirectory>src/main/resources</templateDirectory>
-                        </configuration>
                     </execution>
                     </execution>
                 </executions>
                 </executions>
             </plugin>
             </plugin>

+ 23 - 18
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java

@@ -2,8 +2,8 @@ package io.helidon.benchmark.nima;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Arrays;
-import java.util.Map;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 import com.jsoniter.output.JsonStream;
 import com.jsoniter.output.JsonStream;
 import com.jsoniter.output.JsonStreamPool;
 import com.jsoniter.output.JsonStreamPool;
@@ -15,7 +15,7 @@ public class JsonSerializer {
     }
     }
 
 
     /**
     /**
-     * Serialize an instance into a JSON object and return it as a byte array.
+     * Serialize an instance into a byte array.
      *
      *
      * @param obj the instance
      * @param obj the instance
      * @return the byte array
      * @return the byte array
@@ -28,19 +28,31 @@ public class JsonSerializer {
             return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
             return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
         } catch (IOException e) {
         } catch (IOException e) {
             throw new JsonException(e);
             throw new JsonException(e);
-        } finally {
-            JsonStreamPool.returnJsonStream(stream);
         }
         }
     }
     }
 
 
     /**
     /**
-     * Serialize a map of strings into a JSON object and return it as a byte array.
+     * Serialize an instance into a JSON stream.
+     *
+     * @param obj the instance
+     * @param stream the JSON stream
+     */
+    public static void serialize(Object obj, JsonStream stream) {
+        try {
+            stream.reset(null);
+            stream.writeVal(obj.getClass(), obj);
+        } catch (IOException e) {
+            throw new JsonException(e);
+        }
+    }
+
+    /**
+     * Serialize a map of strings into a JSON stream.
      *
      *
      * @param map the map
      * @param map the map
-     * @return the byte array
+     * @param stream the JSON stream
      */
      */
-    public static byte[] serialize(Map<String, String> map) {
-        JsonStream stream = JsonStreamPool.borrowJsonStream();
+    public static void serialize(Map<String, String> map, JsonStream stream) {
         try {
         try {
             stream.reset(null);
             stream.reset(null);
             stream.writeObjectStart();
             stream.writeObjectStart();
@@ -53,22 +65,18 @@ public class JsonSerializer {
                 }
                 }
             });
             });
             stream.writeObjectEnd();
             stream.writeObjectEnd();
-            return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
         } catch (IOException e) {
         } catch (IOException e) {
             throw new JsonException(e);
             throw new JsonException(e);
-        } finally {
-            JsonStreamPool.returnJsonStream(stream);
         }
         }
     }
     }
 
 
     /**
     /**
-     * Serialize a list of objects into a JSON array and return it as a byte array.
+     * Serialize a list of objects into a JSON stream.
      *
      *
      * @param objs the list of objects
      * @param objs the list of objects
-     * @return the byte array
+     * @param stream the JSON stream
      */
      */
-    public static byte[] serialize(List<?> objs) {
-        JsonStream stream = JsonStreamPool.borrowJsonStream();
+    public static void serialize(List<?> objs, JsonStream stream) {
         try {
         try {
             stream.reset(null);
             stream.reset(null);
             stream.writeArrayStart();
             stream.writeArrayStart();
@@ -82,11 +90,8 @@ public class JsonSerializer {
 
 
             }
             }
             stream.writeArrayEnd();
             stream.writeArrayEnd();
-            return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
         } catch (IOException e) {
         } catch (IOException e) {
             throw new JsonException(e);
             throw new JsonException(e);
-        } finally {
-            JsonStreamPool.returnJsonStream(stream);
         }
         }
     }
     }
 }
 }

+ 18 - 10
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates.
+ * Copyright (c) 2022, 2025 Oracle and/or its affiliates.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -19,16 +19,18 @@ package io.helidon.benchmark.nima;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
+import com.jsoniter.output.JsonStream;
+import com.jsoniter.output.JsonStreamPool;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.HikariJdbcRepository;
 import io.helidon.benchmark.nima.models.HikariJdbcRepository;
 import io.helidon.benchmark.nima.models.PgClientRepository;
 import io.helidon.benchmark.nima.models.PgClientRepository;
 import io.helidon.benchmark.nima.services.DbService;
 import io.helidon.benchmark.nima.services.DbService;
 import io.helidon.benchmark.nima.services.FortuneHandler;
 import io.helidon.benchmark.nima.services.FortuneHandler;
+import io.helidon.config.Config;
+import io.helidon.config.ConfigException;
 import io.helidon.http.Header;
 import io.helidon.http.Header;
 import io.helidon.http.HeaderNames;
 import io.helidon.http.HeaderNames;
 import io.helidon.http.HeaderValues;
 import io.helidon.http.HeaderValues;
-import io.helidon.config.Config;
-import io.helidon.config.ConfigException;
 import io.helidon.logging.common.LogConfig;
 import io.helidon.logging.common.LogConfig;
 import io.helidon.webserver.WebServer;
 import io.helidon.webserver.WebServer;
 import io.helidon.webserver.http.Handler;
 import io.helidon.webserver.http.Handler;
@@ -93,7 +95,7 @@ public final class Main {
 
 
     static class PlaintextHandler implements Handler {
     static class PlaintextHandler implements Handler {
         static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE,
         static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE,
-                                                                     "text/plain; charset=UTF-8");
+                "text/plain; charset=UTF-8");
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13");
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13");
         private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8);
         private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8);
 
 
@@ -110,14 +112,20 @@ public final class Main {
         private static final String MESSAGE = "Hello, World!";
         private static final String MESSAGE = "Hello, World!";
         private static final int JSON_LENGTH = serialize(new Message(MESSAGE)).length;
         private static final int JSON_LENGTH = serialize(new Message(MESSAGE)).length;
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH,
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH,
-                                                                       String.valueOf(JSON_LENGTH));
+                String.valueOf(JSON_LENGTH));
 
 
         @Override
         @Override
         public void handle(ServerRequest req, ServerResponse res) {
         public void handle(ServerRequest req, ServerResponse res) {
-            res.header(CONTENT_LENGTH);
-            res.header(HeaderValues.CONTENT_TYPE_JSON);
-            res.header(Main.SERVER);
-            res.send(serialize(new Message(MESSAGE)));
+            JsonStream stream = JsonStreamPool.borrowJsonStream();
+            try {
+                res.header(CONTENT_LENGTH);
+                res.header(HeaderValues.CONTENT_TYPE_JSON);
+                res.header(Main.SERVER);
+                serialize(new Message(MESSAGE), stream);
+                res.send(stream.buffer().data(), 0, stream.buffer().tail());
+            } finally {
+                JsonStreamPool.returnJsonStream(stream);
+            }
         }
         }
     }
     }
 
 
@@ -147,4 +155,4 @@ public final class Main {
             return message;
             return message;
         }
         }
     }
     }
-}
+}

+ 5 - 1
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java

@@ -1,7 +1,7 @@
 
 
 package io.helidon.benchmark.nima.models;
 package io.helidon.benchmark.nima.models;
 
 
-public final class Fortune {
+public final class Fortune implements Comparable<Fortune> {
     public int id;
     public int id;
     public String message;
     public String message;
 
 
@@ -17,4 +17,8 @@ public final class Fortune {
     public String getMessage() {
     public String getMessage() {
         return message;
         return message;
     }
     }
+    @Override
+    public int compareTo(Fortune other) {
+        return message.compareTo(other.message);
+    }
 }
 }

+ 143 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPool.java

@@ -0,0 +1,143 @@
+
+package io.helidon.benchmark.nima.models;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+import io.vertx.core.Vertx;
+import io.vertx.pgclient.PgConnectOptions;
+import io.vertx.pgclient.PgConnection;
+import io.vertx.sqlclient.PreparedQuery;
+import io.vertx.sqlclient.Row;
+import io.vertx.sqlclient.RowSet;
+
+class PgClientConnectionPool implements AutoCloseable {
+
+    private final Vertx vertx;
+    private final PgConnectOptions options;
+    private final ReentrantLock lock = new ReentrantLock();
+    private final Map<String, PgClientConnection> connectionMap = new HashMap<>();
+
+    public PgClientConnectionPool(Vertx vertx, PgConnectOptions options) {
+        this.vertx = vertx;
+        this.options = options;
+    }
+
+    public PgClientConnection clientConnection() {
+        String carrierThread = carrierThread();
+        PgClientConnection connection = connectionMap.get(carrierThread);
+        if (connection == null) {
+            try {
+                lock.lock();
+                connection = connectionMap.get(carrierThread);
+                if (connection == null) {
+                    connection = newConnection();
+                    connectionMap.put(carrierThread, connection);
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+        return connection;
+    }
+
+    @Override
+    public void close() {
+        try {
+            for (PgClientConnection connection : connectionMap.values()) {
+                connection.close();
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private PgClientConnection newConnection() {
+        try {
+            PgConnection conn = PgConnection.connect(vertx, options)
+                    .toCompletionStage().toCompletableFuture().get();
+            PgClientConnection clientConn = new PgClientConnection(conn);
+            clientConn.prepare();
+            return clientConn;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static String carrierThread() {
+        String threadName = Thread.currentThread().toString();
+        return threadName.substring(threadName.indexOf('@') + 1);
+    }
+
+    public static class PgClientConnection implements AutoCloseable {
+        static final int UPDATE_QUERIES = 500;
+        private static String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";
+        private static String SELECT_FORTUNE = "SELECT * from FORTUNE";
+
+        private PreparedQuery<RowSet<Row>> worldQuery;
+        private PreparedQuery<RowSet<Row>> fortuneQuery;
+        private PreparedQuery<RowSet<Row>>[] updateQuery;
+
+        private final PgConnection conn;
+
+        PgClientConnection(PgConnection conn) {
+            this.conn = conn;
+        }
+
+        public PgConnection pgConnection() {
+            return conn;
+        }
+
+        @Override
+        public void close() {
+            conn.close();
+        }
+
+        public PreparedQuery<RowSet<Row>> worldQuery() {
+            return worldQuery;
+        }
+
+        public PreparedQuery<RowSet<Row>> fortuneQuery() {
+            return fortuneQuery;
+        }
+
+        public PreparedQuery<RowSet<Row>> updateQuery(int queryCount) {
+            return updateQuery[queryCount - 1];
+        }
+
+        @SuppressWarnings("unchecked")
+        void prepare() {
+            try {
+                worldQuery = conn.prepare(SELECT_WORLD)
+                        .toCompletionStage().toCompletableFuture().get().query();
+                fortuneQuery = conn.prepare(SELECT_FORTUNE)
+                        .toCompletionStage().toCompletableFuture().get().query();
+                updateQuery = (PreparedQuery<RowSet<Row>>[]) new PreparedQuery<?>[UPDATE_QUERIES];
+                for (int i = 0; i < UPDATE_QUERIES; i++) {
+                    updateQuery[i] = conn.prepare(singleUpdate(i + 1))
+                            .toCompletionStage().toCompletableFuture().get().query();
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private static String singleUpdate(int count) {
+            StringBuilder sql = new StringBuilder();
+            sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID");
+            for (int i = 0; i < count; i++) {
+                int k = i * 2 + 1;
+                sql.append(" WHEN $").append(k).append(" THEN $").append(k + 1);
+            }
+            sql.append(" ELSE RANDOMNUMBER");
+            sql.append(" END WHERE ID IN ($1");
+            for (int i = 1; i < count; i++) {
+                int k = i * 2 + 1;
+                sql.append(",$").append(k);
+            }
+            sql.append(")");
+            return sql.toString();
+        }
+    }
+}

+ 35 - 68
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java

@@ -2,7 +2,6 @@ package io.helidon.benchmark.nima.models;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 import io.helidon.config.Config;
 import io.helidon.config.Config;
@@ -10,58 +9,46 @@ import io.vertx.core.Future;
 import io.vertx.core.Vertx;
 import io.vertx.core.Vertx;
 import io.vertx.core.VertxOptions;
 import io.vertx.core.VertxOptions;
 import io.vertx.pgclient.PgConnectOptions;
 import io.vertx.pgclient.PgConnectOptions;
-import io.vertx.pgclient.PgPool;
-import io.vertx.sqlclient.PoolOptions;
 import io.vertx.sqlclient.PreparedQuery;
 import io.vertx.sqlclient.PreparedQuery;
 import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.RowSet;
 import io.vertx.sqlclient.RowSet;
-import io.vertx.sqlclient.SqlClient;
 import io.vertx.sqlclient.Tuple;
 import io.vertx.sqlclient.Tuple;
 
 
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
+import static io.helidon.benchmark.nima.models.PgClientConnectionPool.PgClientConnection.UPDATE_QUERIES;
 
 
 public class PgClientRepository implements DbRepository {
 public class PgClientRepository implements DbRepository {
     private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName());
     private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName());
-    private static final int UPDATE_QUERIES = 500;
 
 
-    private final SqlClient updatePool;
-
-    private final PreparedQuery<RowSet<Row>> getFortuneQuery;
-    private final PreparedQuery<RowSet<Row>> getWorldQuery;
-    private final PreparedQuery<RowSet<Row>>[] updateWorldSingleQuery;
+    private final PgClientConnectionPool connectionPool;
 
 
     @SuppressWarnings("unchecked")
     @SuppressWarnings("unchecked")
     public PgClientRepository(Config config) {
     public PgClientRepository(Config config) {
-        Vertx vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true));
+        VertxOptions vertxOptions = new VertxOptions()
+                .setPreferNativeTransport(true)
+                .setBlockedThreadCheckInterval(100000);
+        Vertx vertx = Vertx.vertx(vertxOptions);
         PgConnectOptions connectOptions = new PgConnectOptions()
         PgConnectOptions connectOptions = new PgConnectOptions()
                 .setPort(config.get("port").asInt().orElse(5432))
                 .setPort(config.get("port").asInt().orElse(5432))
-                .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true))
                 .setHost(config.get("host").asString().orElse("tfb-database"))
                 .setHost(config.get("host").asString().orElse("tfb-database"))
                 .setDatabase(config.get("db").asString().orElse("hello_world"))
                 .setDatabase(config.get("db").asString().orElse("hello_world"))
                 .setUser(config.get("username").asString().orElse("benchmarkdbuser"))
                 .setUser(config.get("username").asString().orElse("benchmarkdbuser"))
                 .setPassword(config.get("password").asString().orElse("benchmarkdbpass"))
                 .setPassword(config.get("password").asString().orElse("benchmarkdbpass"))
+                .setCachePreparedStatements(true)
+                .setPreparedStatementCacheMaxSize(UPDATE_QUERIES + 2)
+                .setPreparedStatementCacheSqlFilter(s -> true)          // cache all
+                .setTcpNoDelay(true)
+                .setTcpQuickAck(true)
+                .setTcpKeepAlive(true)
                 .setPipeliningLimit(100000);
                 .setPipeliningLimit(100000);
-
-        int sqlPoolSize = config.get("sql-pool-size").asInt().orElse(64);
-        PoolOptions clientOptions = new PoolOptions().setMaxSize(sqlPoolSize);
-        LOGGER.info("sql-pool-size is " + sqlPoolSize);
-
-        SqlClient queryPool = PgPool.client(vertx, connectOptions, clientOptions);
-        updatePool = PgPool.client(vertx, connectOptions, clientOptions);
-
-        getWorldQuery = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1");
-        getFortuneQuery = queryPool.preparedQuery("SELECT id, message FROM fortune");
-
-        updateWorldSingleQuery = new PreparedQuery[UPDATE_QUERIES];
-        for (int i = 0; i < UPDATE_QUERIES; i++) {
-            updateWorldSingleQuery[i] = queryPool.preparedQuery(singleUpdate(i + 1));
-        }
+        connectionPool = new PgClientConnectionPool(vertx, connectOptions);
     }
     }
 
 
     @Override
     @Override
     public World getWorld(int id) {
     public World getWorld(int id) {
         try {
         try {
-            return getWorldQuery.execute(Tuple.of(id))
+            PreparedQuery<RowSet<Row>> worldQuery = connectionPool.clientConnection().worldQuery();
+            return worldQuery.execute(Tuple.of(id))
                     .map(rows -> {
                     .map(rows -> {
                         Row r = rows.iterator().next();
                         Row r = rows.iterator().next();
                         return new World(r.getInteger(0), r.getInteger(1));
                         return new World(r.getInteger(0), r.getInteger(1));
@@ -74,13 +61,14 @@ public class PgClientRepository implements DbRepository {
     @Override
     @Override
     public List<World> getWorlds(int count) {
     public List<World> getWorlds(int count) {
         try {
         try {
+            PreparedQuery<RowSet<Row>> worldQuery = connectionPool.clientConnection().worldQuery();
             List<Future<?>> futures = new ArrayList<>();
             List<Future<?>> futures = new ArrayList<>();
             for (int i = 0; i < count; i++) {
             for (int i = 0; i < count; i++) {
-                futures.add(getWorldQuery.execute(Tuple.of(randomWorldNumber()))
-                                    .map(rows -> {
-                                        Row r = rows.iterator().next();
-                                        return new World(r.getInteger(0), r.getInteger(1));
-                                    }));
+                futures.add(worldQuery.execute(Tuple.of(randomWorldNumber()))
+                        .map(rows -> {
+                            Row r = rows.iterator().next();
+                            return new World(r.getInteger(0), r.getInteger(1));
+                        }));
             }
             }
             return Future.all(futures).toCompletionStage().toCompletableFuture().get().list();
             return Future.all(futures).toCompletionStage().toCompletableFuture().get().list();
         } catch (Exception e) {
         } catch (Exception e) {
@@ -92,7 +80,18 @@ public class PgClientRepository implements DbRepository {
     public List<World> updateWorlds(int count) {
     public List<World> updateWorlds(int count) {
         List<World> worlds = getWorlds(count);
         List<World> worlds = getWorlds(count);
         try {
         try {
-            return updateWorlds(worlds, count, updatePool);
+            PreparedQuery<RowSet<Row>> updateQuery = connectionPool.clientConnection().updateQuery(count);
+            List<Integer> updateParams = new ArrayList<>(count * 2);
+            for (World world : worlds) {
+                updateParams.add(world.id);
+                world.randomNumber = randomWorldNumber();
+                updateParams.add(world.randomNumber);
+            }
+            return updateQuery.execute(Tuple.wrap(updateParams))
+                    .toCompletionStage()
+                    .thenApply(rows -> worlds)
+                    .toCompletableFuture()
+                    .get();
         } catch (Exception e) {
         } catch (Exception e) {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
@@ -101,7 +100,8 @@ public class PgClientRepository implements DbRepository {
     @Override
     @Override
     public List<Fortune> getFortunes() {
     public List<Fortune> getFortunes() {
         try {
         try {
-            return getFortuneQuery.execute()
+            PreparedQuery<RowSet<Row>> fortuneQuery = connectionPool.clientConnection().fortuneQuery();
+            return fortuneQuery.execute()
                     .map(rows -> {
                     .map(rows -> {
                         List<Fortune> fortunes = new ArrayList<>(rows.size() + 1);
                         List<Fortune> fortunes = new ArrayList<>(rows.size() + 1);
                         for (Row r : rows) {
                         for (Row r : rows) {
@@ -113,37 +113,4 @@ public class PgClientRepository implements DbRepository {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
     }
     }
-
-    private List<World> updateWorlds(List<World> worlds, int count, SqlClient pool)
-            throws ExecutionException, InterruptedException {
-        int size = worlds.size();
-        List<Integer> updateParams = new ArrayList<>(size * 2);
-        for (World world : worlds) {
-            updateParams.add(world.id);
-            world.randomNumber = randomWorldNumber();
-            updateParams.add(world.randomNumber);
-        }
-        return updateWorldSingleQuery[count - 1].execute(Tuple.wrap(updateParams))
-                .toCompletionStage()
-                .thenApply(rows -> worlds)
-                .toCompletableFuture()
-                .get();
-    }
-
-    private static String singleUpdate(int count) {
-        StringBuilder sql = new StringBuilder();
-        sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID");
-        for (int i = 0; i < count; i++) {
-            int k = i * 2 + 1;
-            sql.append(" WHEN $").append(k).append(" THEN $").append(k + 1);
-        }
-        sql.append(" ELSE RANDOMNUMBER");
-        sql.append(" END WHERE ID IN ($1");
-        for (int i = 1; i < count; i++) {
-            int k = i * 2 + 1;
-            sql.append(",$").append(k);
-        }
-        sql.append(")");
-        return sql.toString();
-    }
 }
 }

+ 34 - 19
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java

@@ -1,21 +1,19 @@
-
 package io.helidon.benchmark.nima.services;
 package io.helidon.benchmark.nima.services;
 
 
-import java.util.List;
-
+import com.jsoniter.output.JsonStream;
+import com.jsoniter.output.JsonStreamPool;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.DbRepository;
-import io.helidon.benchmark.nima.models.World;
+import io.helidon.common.mapper.OptionalValue;
 import io.helidon.common.parameters.Parameters;
 import io.helidon.common.parameters.Parameters;
 import io.helidon.http.HeaderValues;
 import io.helidon.http.HeaderValues;
 import io.helidon.webserver.http.HttpRules;
 import io.helidon.webserver.http.HttpRules;
 import io.helidon.webserver.http.HttpService;
 import io.helidon.webserver.http.HttpService;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerResponse;
 import io.helidon.webserver.http.ServerResponse;
-import io.helidon.common.mapper.OptionalValue;
 
 
+import static io.helidon.benchmark.nima.JsonSerializer.serialize;
 import static io.helidon.benchmark.nima.Main.SERVER;
 import static io.helidon.benchmark.nima.Main.SERVER;
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
-import static io.helidon.benchmark.nima.JsonSerializer.serialize;
 
 
 public class DbService implements HttpService {
 public class DbService implements HttpService {
 
 
@@ -33,24 +31,41 @@ public class DbService implements HttpService {
     }
     }
 
 
     private void db(ServerRequest req, ServerResponse res) {
     private void db(ServerRequest req, ServerResponse res) {
-        res.header(SERVER);
-        res.header(HeaderValues.CONTENT_TYPE_JSON);
-        res.send(serialize(repository.getWorld(randomWorldNumber())));
+        JsonStream stream = JsonStreamPool.borrowJsonStream();
+        try {
+            res.header(SERVER);
+            res.header(HeaderValues.CONTENT_TYPE_JSON);
+            serialize(repository.getWorld(randomWorldNumber()), stream);
+            res.send(stream.buffer().data(), 0, stream.buffer().tail());
+        } finally {
+            JsonStreamPool.returnJsonStream(stream);
+        }
     }
     }
 
 
     private void queries(ServerRequest req, ServerResponse res) {
     private void queries(ServerRequest req, ServerResponse res) {
-        res.header(SERVER);
-        res.header(HeaderValues.CONTENT_TYPE_JSON);
-        int count = parseQueryCount(req.query());
-        res.send(serialize(repository.getWorlds(count)));
+        JsonStream stream = JsonStreamPool.borrowJsonStream();
+        try {
+            res.header(SERVER);
+            res.header(HeaderValues.CONTENT_TYPE_JSON);
+            int count = parseQueryCount(req.query());
+            serialize(repository.getWorlds(count), stream);
+            res.send(stream.buffer().data(), 0, stream.buffer().tail());
+        } finally {
+            JsonStreamPool.returnJsonStream(stream);
+        }
     }
     }
 
 
     private void updates(ServerRequest req, ServerResponse res) {
     private void updates(ServerRequest req, ServerResponse res) {
-        res.header(SERVER);
-        res.header(HeaderValues.CONTENT_TYPE_JSON);
-        int count = parseQueryCount(req.query());
-        List<World> worlds = repository.updateWorlds(count);
-        res.send(serialize(worlds));
+        JsonStream stream = JsonStreamPool.borrowJsonStream();
+        try {
+            res.header(SERVER);
+            res.header(HeaderValues.CONTENT_TYPE_JSON);
+            int count = parseQueryCount(req.query());
+            serialize(repository.updateWorlds(count), stream);
+            res.send(stream.buffer().data(), 0, stream.buffer().tail());
+        } finally {
+            JsonStreamPool.returnJsonStream(stream);
+        }
     }
     }
 
 
     private int parseQueryCount(Parameters parameters) {
     private int parseQueryCount(Parameters parameters) {
@@ -66,4 +81,4 @@ public class DbService implements HttpService {
         }
         }
         return Math.min(500, Math.max(1, parsedValue));
         return Math.min(500, Math.max(1, parsedValue));
     }
     }
-}
+}

+ 40 - 5
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java

@@ -1,16 +1,21 @@
 
 
 package io.helidon.benchmark.nima.services;
 package io.helidon.benchmark.nima.services;
 
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Comparator;
 import java.util.Comparator;
 import java.util.List;
 import java.util.List;
 
 
-import com.fizzed.rocker.runtime.ArrayOfByteArraysOutput;
+import gg.jte.TemplateOutput;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.Fortune;
 import io.helidon.benchmark.nima.models.Fortune;
 import io.helidon.webserver.http.Handler;
 import io.helidon.webserver.http.Handler;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerResponse;
 import io.helidon.webserver.http.ServerResponse;
-import views.fortunes;
+
+import gg.jte.html.OwaspHtmlTemplateOutput;
+import gg.jte.generated.precompiled.JtefortunesGenerated;
 
 
 import static io.helidon.benchmark.nima.Main.CONTENT_TYPE_HTML;
 import static io.helidon.benchmark.nima.Main.CONTENT_TYPE_HTML;
 import static io.helidon.benchmark.nima.Main.SERVER;
 import static io.helidon.benchmark.nima.Main.SERVER;
@@ -33,8 +38,38 @@ public class FortuneHandler implements Handler {
         List<Fortune> fortuneList = repository.getFortunes();
         List<Fortune> fortuneList = repository.getFortunes();
         fortuneList.add(ADDITIONAL_FORTUNE);
         fortuneList.add(ADDITIONAL_FORTUNE);
         fortuneList.sort(Comparator.comparing(Fortune::getMessage));
         fortuneList.sort(Comparator.comparing(Fortune::getMessage));
-        res.send(fortunes.template(fortuneList)
-                .render(ArrayOfByteArraysOutput.FACTORY)
-                .toByteArray());
+        try (OutputStream os = res.outputStream()) {
+            JtefortunesGenerated.render(new OwaspHtmlTemplateOutput(new HelidonTemplateOutput(os)),
+                    null, fortuneList);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
     }
     }
+
+    static class HelidonTemplateOutput implements TemplateOutput{
+        private final OutputStream os;
+
+        HelidonTemplateOutput(OutputStream os) {
+            this.os = os;
+        }
+
+        @Override
+        public void writeContent(String value) {
+            writeBinaryContent(value.getBytes(StandardCharsets.UTF_8));
+        }
+
+        @Override
+        public void writeContent(String value, int beginIndex, int endIndex) {
+            writeBinaryContent(value.substring(beginIndex, endIndex).getBytes(StandardCharsets.UTF_8));
+        }
+
+        @Override
+        public void writeBinaryContent(byte[] value) {
+            try {
+                os.write(value);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    };
 }
 }

+ 0 - 1
frameworks/Java/helidon/nima/src/main/resources/application.yaml

@@ -36,6 +36,5 @@ host: "tfb-database"
 db: "hello_world"
 db: "hello_world"
 username: benchmarkdbuser
 username: benchmarkdbuser
 password: benchmarkdbpass
 password: benchmarkdbpass
-sql-pool-size: 300
 db-repository: "pgclient"     # "pgclient" (default) or "hikari"
 db-repository: "pgclient"     # "pgclient" (default) or "hikari"
 
 

+ 2 - 0
frameworks/Java/helidon/nima/src/main/resources/views/fortunes.jte

@@ -0,0 +1,2 @@
+@param java.util.List<io.helidon.benchmark.nima.models.Fortune> fortunes
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>@for(io.helidon.benchmark.nima.models.Fortune fortune : fortunes)<tr><td>${fortune.getId()}</td><td>${fortune.getMessage()}</td></tr>@endfor</table></body></html>

+ 0 - 24
frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html

@@ -1,24 +0,0 @@
-@import io.helidon.benchmark.nima.models.Fortune
-@import java.util.List
-@args (List<Fortune> fortunes)
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>Fortunes</title>
-</head>
-<body>
-<table>
-    <tr>
-        <th>id</th>
-        <th>message</th>
-    </tr>
-    @for (f : fortunes) {
-    <tr>
-        <td>@f.getId()</td>
-        <td>@f.getMessage()</td>
-    </tr>
-    }
-</table>
-</body>
-</html>

+ 12 - 9
frameworks/Java/inverno/README.md

@@ -2,20 +2,23 @@
 
 
 ### Test Type Implementation Source Code
 ### Test Type Implementation Source Code
 
 
-* [JSON](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
-* [PLAINTEXT](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
-* [DB](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
-* [QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
-* [CACHED QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
-* [UPDATE](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
-* [FORTUNES](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java)
+* [JSON](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
+* [PLAINTEXT](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
+* [DB](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
+* [QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
+* [CACHED QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
+* [UPDATE](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
+* [FORTUNES](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java)
 
 
 ## Important Libraries
 ## Important Libraries
+
 The tests were run with:
 The tests were run with:
-* [Java OpenJDK 16](https://openjdk.java.net/)
-* [Inverno 1.4.1](https://inverno.io)
+* [Java OpenJDK 21](https://openjdk.java.net/)
+* [Inverno 1.12.0](https://inverno.io)
+* [DSL-JSON 2.0.2](https://github.com/ngs-doo/dsl-json)
 
 
 ## Test URLs
 ## Test URLs
+
 ### JSON
 ### JSON
 
 
 http://localhost:8080/json
 http://localhost:8080/json

+ 1 - 2
frameworks/Java/inverno/inverno-postgres.dockerfile

@@ -1,8 +1,7 @@
-FROM maven:3.9.6-amazoncorretto-21 as maven
+FROM maven:3.9.9-eclipse-temurin-21 as maven
 WORKDIR /inverno
 WORKDIR /inverno
 COPY src src
 COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
-RUN yum -y install binutils
 RUN mvn package -q -Pio.inverno.io_uring
 RUN mvn package -q -Pio.inverno.io_uring
 
 
 EXPOSE 8080
 EXPOSE 8080

+ 1 - 2
frameworks/Java/inverno/inverno.dockerfile

@@ -1,8 +1,7 @@
-FROM maven:3.9.6-amazoncorretto-21 as maven
+FROM maven:3.9.9-eclipse-temurin-21 as maven
 WORKDIR /inverno
 WORKDIR /inverno
 COPY src src
 COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
-RUN yum -y install binutils
 RUN mvn package -q -Pio.inverno.io_uring
 RUN mvn package -q -Pio.inverno.io_uring
 
 
 EXPOSE 8080
 EXPOSE 8080

+ 54 - 10
frameworks/Java/inverno/pom.xml

@@ -6,7 +6,7 @@
 	<parent>
 	<parent>
 		<groupId>io.inverno.dist</groupId>
 		<groupId>io.inverno.dist</groupId>
 		<artifactId>inverno-parent</artifactId>
 		<artifactId>inverno-parent</artifactId>
-		<version>1.10.0</version>
+		<version>1.12.0</version>
 	</parent>
 	</parent>
 	<groupId>com.techempower</groupId>
 	<groupId>com.techempower</groupId>
 	<artifactId>inverno-benchmark</artifactId>
 	<artifactId>inverno-benchmark</artifactId>
@@ -53,6 +53,11 @@
 			<artifactId>unbescape</artifactId>
 			<artifactId>unbescape</artifactId>
 			<version>1.1.6.RELEASE</version>
 			<version>1.1.6.RELEASE</version>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>com.dslplatform</groupId>
+			<artifactId>dsl-json</artifactId>
+			<version>2.0.2</version>
+		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>io.vertx</groupId>
 			<groupId>io.vertx</groupId>
 			<artifactId>vertx-pg-client</artifactId>
 			<artifactId>vertx-pg-client</artifactId>
@@ -82,7 +87,52 @@
 			<artifactId>log4j-core</artifactId>
 			<artifactId>log4j-core</artifactId>
 		</dependency>
 		</dependency>
 	</dependencies>
 	</dependencies>
-	
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>default-compile</id>
+						<configuration>
+							<annotationProcessorPaths combine.children="append">
+								<path>
+									<groupId>com.dslplatform</groupId>
+									<artifactId>dsl-json</artifactId>
+									<version>2.0.2</version>
+								</path>
+							</annotationProcessorPaths>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>io.inverno.tool</groupId>
+					<artifactId>inverno-maven-plugin</artifactId>
+					<configuration>
+						<moduleOverrides combine.children="append">
+							<module>
+								<name>com.dslplatform.dsl.json</name>
+								<uses>
+									<use>
+										<type>com.dslplatform.json.Configuration</type>
+									</use>
+								</uses>
+							</module>
+						</moduleOverrides>
+						<vmOptions>-Dlog4j2.simplelogLevel=INFO -Dlog4j2.level=INFO --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json</vmOptions>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+
 	<profiles>
 	<profiles>
 		<profile>
 		<profile>
 			<id>io.inverno.epoll</id>
 			<id>io.inverno.epoll</id>
@@ -110,7 +160,7 @@
 									<launchers>
 									<launchers>
 										<launcher>
 										<launcher>
 											<name>inverno-benchmark</name>
 											<name>inverno-benchmark</name>
-											<vmOptions>-Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64</vmOptions>
+											<vmOptions>-Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64 --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json</vmOptions>
 										</launcher>
 										</launcher>
 									</launchers>
 									</launchers>
 									<archiveFormats>
 									<archiveFormats>
@@ -119,9 +169,6 @@
 								</configuration>
 								</configuration>
 							</execution>
 							</execution>
 						</executions>
 						</executions>
-						<configuration>
-							<vmOptions>--add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64</vmOptions>
-						</configuration>
 					</plugin>
 					</plugin>
 				</plugins>
 				</plugins>
 			</build>
 			</build>
@@ -157,7 +204,7 @@
 									<launchers>
 									<launchers>
 										<launcher>
 										<launcher>
 											<name>inverno-benchmark</name>
 											<name>inverno-benchmark</name>
-											<vmOptions>-Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64</vmOptions>
+											<vmOptions>-Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64 --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json</vmOptions>
 										</launcher>
 										</launcher>
 									</launchers>
 									</launchers>
 									<archiveFormats>
 									<archiveFormats>
@@ -166,9 +213,6 @@
 								</configuration>
 								</configuration>
 							</execution>
 							</execution>
 						</executions>
 						</executions>
-						<configuration>
-							<vmOptions>--add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64</vmOptions>
-						</configuration>
 					</plugin>
 					</plugin>
 				</plugins>
 				</plugins>
 			</build>
 			</build>

+ 3 - 4
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java

@@ -1,17 +1,16 @@
 package com.techempower.inverno.benchmark;
 package com.techempower.inverno.benchmark;
 
 
-import java.io.IOException;
-import java.util.function.Supplier;
-
 import io.inverno.core.annotation.Bean;
 import io.inverno.core.annotation.Bean;
 import io.inverno.core.v1.Application;
 import io.inverno.core.v1.Application;
 import io.inverno.mod.configuration.ConfigurationSource;
 import io.inverno.mod.configuration.ConfigurationSource;
 import io.inverno.mod.configuration.source.BootstrapConfigurationSource;
 import io.inverno.mod.configuration.source.BootstrapConfigurationSource;
+import java.io.IOException;
+import java.util.function.Supplier;
 
 
 public class Main {
 public class Main {
 
 
 	@Bean
 	@Bean
-	public interface AppConfigurationSource extends Supplier<ConfigurationSource<?, ?, ?>> {}
+	public interface AppConfigurationSource extends Supplier<ConfigurationSource> {}
 	
 	
 	public static void main(String[] args) throws IllegalStateException, IOException {
 	public static void main(String[] args) throws IllegalStateException, IOException {
 		Application.with(new Benchmark.Builder()
 		Application.with(new Benchmark.Builder()

+ 54 - 106
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java

@@ -1,7 +1,5 @@
 package com.techempower.inverno.benchmark.internal;
 package com.techempower.inverno.benchmark.internal;
 
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.techempower.inverno.benchmark.model.Fortune;
 import com.techempower.inverno.benchmark.model.Fortune;
 import com.techempower.inverno.benchmark.model.Message;
 import com.techempower.inverno.benchmark.model.Message;
 import com.techempower.inverno.benchmark.model.World;
 import com.techempower.inverno.benchmark.model.World;
@@ -14,15 +12,14 @@ import io.inverno.mod.base.Charsets;
 import io.inverno.mod.base.concurrent.Reactor;
 import io.inverno.mod.base.concurrent.Reactor;
 import io.inverno.mod.base.concurrent.ReactorScope;
 import io.inverno.mod.base.concurrent.ReactorScope;
 import io.inverno.mod.base.converter.ConverterException;
 import io.inverno.mod.base.converter.ConverterException;
+import io.inverno.mod.base.reflect.Types;
 import io.inverno.mod.http.base.ExchangeContext;
 import io.inverno.mod.http.base.ExchangeContext;
 import io.inverno.mod.http.base.HttpException;
 import io.inverno.mod.http.base.HttpException;
-import io.inverno.mod.http.base.InternalServerErrorException;
 import io.inverno.mod.http.base.Parameter;
 import io.inverno.mod.http.base.Parameter;
 import io.inverno.mod.http.base.Status;
 import io.inverno.mod.http.base.Status;
-import io.inverno.mod.http.server.Exchange;
 import io.inverno.mod.http.server.ErrorExchange;
 import io.inverno.mod.http.server.ErrorExchange;
+import io.inverno.mod.http.server.Exchange;
 import io.inverno.mod.http.server.ServerController;
 import io.inverno.mod.http.server.ServerController;
-import io.inverno.mod.sql.SqlClient;
 import io.inverno.mod.sql.UnsafeSqlOperations;
 import io.inverno.mod.sql.UnsafeSqlOperations;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.buffer.Unpooled;
@@ -30,13 +27,14 @@ import io.netty.channel.EventLoopGroup;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpHeaderValues;
 import io.netty.handler.codec.http.HttpHeaderValues;
 import io.netty.util.AsciiString;
 import io.netty.util.AsciiString;
+import java.lang.reflect.Type;
 import java.time.ZonedDateTime;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
@@ -51,36 +49,32 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 	private static final String PATH_FORTUNES = "/fortunes";
 	private static final String PATH_FORTUNES = "/fortunes";
 	
 	
 	public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1";
 	public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1";
-	public static final String DB_UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2";
-	public static final String DB_SELECT_FORTUNE = "SELECT id, message from FORTUNE";
-	
+
 	private static final CharSequence STATIC_SERVER = AsciiString.cached("inverno");
 	private static final CharSequence STATIC_SERVER = AsciiString.cached("inverno");
 
 
+	private static final Type LIST_WORLD_TYPE = Types.type(List.class).type(World.class).and().build();
+
 	private final Reactor reactor;
 	private final Reactor reactor;
-	private final ObjectMapper mapper;
-	private final ReactorScope<Mono<SqlClient>> sqlClient;
+	private final ReactorScope<JsonSerializer> jsonSerializer;
+	private final ReactorScope<Mono<DbRepository>> dbRepository;
 	
 	
 	private EventLoopGroup dateEventLoopGroup;
 	private EventLoopGroup dateEventLoopGroup;
 	
 	
 	private CharSequence date;
 	private CharSequence date;
 	
 	
 	public Controller(Reactor reactor, 
 	public Controller(Reactor reactor, 
-			ObjectMapper mapper,
-			ReactorScope<Mono<SqlClient>> sqlClient
+			ReactorScope<JsonSerializer> jsonSerializer,
+			ReactorScope<Mono<DbRepository>> dbRepository
 		) {
 		) {
 		this.reactor = reactor;
 		this.reactor = reactor;
-		this.mapper = mapper;
-		this.sqlClient = sqlClient;
+		this.jsonSerializer = jsonSerializer;
+		this.dbRepository = dbRepository;
 	}
 	}
 	
 	
 	@Init
 	@Init
 	public void init() {
 	public void init() {
 		this.dateEventLoopGroup = this.reactor.createIoEventLoopGroup(1);
 		this.dateEventLoopGroup = this.reactor.createIoEventLoopGroup(1);
-		this.dateEventLoopGroup.scheduleAtFixedRate(() -> {
-			this.date = new AsciiString(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()));
-		}, 0, 1000, TimeUnit.MILLISECONDS);
-		
-		
+		this.dateEventLoopGroup.scheduleAtFixedRate(() -> this.date = new AsciiString(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())), 0, 1000, TimeUnit.MILLISECONDS);
 	}
 	}
 	
 	
 	@Destroy
 	@Destroy
@@ -139,15 +133,8 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 	}
 	}
 	
 	
 	private static final CharSequence STATIC_PLAINTEXT_LEN_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN));
 	private static final CharSequence STATIC_PLAINTEXT_LEN_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN));
-	
-	private static class PlaintextSupplier implements Supplier<ByteBuf> {
-		@Override
-		public ByteBuf get() {
-			return STATIC_PLAINTEXT_BYTEBUF.duplicate();
-		}
-	}
-	
-	private static final Mono<ByteBuf> PLAIN_TEXT_MONO = Mono.fromSupplier(new PlaintextSupplier());
+
+	private static final Mono<ByteBuf> PLAIN_TEXT_MONO = Mono.fromSupplier(STATIC_PLAINTEXT_BYTEBUF::duplicate);
 	
 	
 	public void handle_plaintext(Exchange<ExchangeContext> exchange) throws HttpException {
 	public void handle_plaintext(Exchange<ExchangeContext> exchange) throws HttpException {
 		exchange.response()
 		exchange.response()
@@ -163,20 +150,15 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 	}
 	}
 	
 	
 	public void handle_json(Exchange<ExchangeContext> exchange) throws HttpException {
 	public void handle_json(Exchange<ExchangeContext> exchange) throws HttpException {
-		try {
-			exchange.response()
-				.headers(h -> h
-					.add(HttpHeaderNames.SERVER, STATIC_SERVER)
-					.add(HttpHeaderNames.DATE, this.date)
-					.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
-				)
-				.body()
-					.raw()
-						.value(Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(new Message("Hello, World!"))));
-		} 
-		catch (JsonProcessingException | IllegalStateException e) {
-			throw new InternalServerErrorException("Error serializing message as JSON", e);
-		}
+		exchange.response()
+			.headers(h -> h
+				.add(HttpHeaderNames.SERVER, STATIC_SERVER)
+				.add(HttpHeaderNames.DATE, this.date)
+				.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
+			)
+			.body()
+			.raw()
+			.value(this.jsonSerializer.get().serialize(new Message("Hello, World!"), Message.class));
 	}
 	}
 
 
 	private static int randomWorldId() {
 	private static int randomWorldId() {
@@ -191,20 +173,10 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 				.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
 				.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
 			)
 			)
 			.body()
 			.body()
-				.raw().stream(this.sqlClient.get().flatMap(client -> 
-					client.queryForObject(
-						DB_SELECT_WORLD, 
-						row -> {
-							try {
-								return Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(new World(row.getInteger(0), row.getInteger(1))));
-							} 
-							catch (JsonProcessingException e) {
-								throw new InternalServerErrorException(e);
-							}
-						}, 
-						randomWorldId()
-					)
-				));
+				.raw().stream(this.dbRepository.get()
+					.flatMap(repository -> repository.getWorld(randomWorldId()))
+					.map(world -> this.jsonSerializer.get().serialize(world, World.class))
+				);
 	}
 	}
 	
 	
 	private static final String PARAMETER_QUERIES = "queries";
 	private static final String PARAMETER_QUERIES = "queries";
@@ -227,8 +199,8 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 				.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
 				.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
 			)
 			)
 			.body()
 			.body()
-				.raw().stream(this.sqlClient.get()
-					.flatMapMany(client -> ((UnsafeSqlOperations)client)
+				.raw().stream(this.dbRepository.get()
+					.flatMapMany(repository -> ((UnsafeSqlOperations)repository.getSqlClient())
 						.batchQueries(ops -> 
 						.batchQueries(ops -> 
 							Flux.range(0, queries)
 							Flux.range(0, queries)
 								.map(ign -> ops.queryForObject(
 								.map(ign -> ops.queryForObject(
@@ -239,58 +211,39 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 						)
 						)
 					)
 					)
 					.collectList()
 					.collectList()
-					.map(worlds -> {
-						try {
-							return Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(worlds));
-						} 
-						catch (JsonProcessingException e) {
-							throw new InternalServerErrorException(e);
-						}
-					})
+					.map(worlds -> this.jsonSerializer.get().serialize(worlds, LIST_WORLD_TYPE))
 				);
 				);
 	}
 	}
 	
 	
 	public void handle_updates(Exchange<ExchangeContext> exchange) throws HttpException {
 	public void handle_updates(Exchange<ExchangeContext> exchange) throws HttpException {
 		int queries = this.extractQueriesParameter(exchange);
 		int queries = this.extractQueriesParameter(exchange);
-		
 		exchange.response()
 		exchange.response()
-		.headers(h -> h
-			.add(HttpHeaderNames.SERVER, STATIC_SERVER)
-			.add(HttpHeaderNames.DATE, this.date)
-			.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
-		)
-		.body()
-			.raw().stream(this.sqlClient.get()
-				.flatMapMany(client -> Flux.from(((UnsafeSqlOperations)client)
-					.batchQueries(ops -> 
-						Flux.range(0, queries)
-							.map(ign -> ops.queryForObject(
-								DB_SELECT_WORLD, 
-								row -> new World(row.getInteger(0), randomWorldId()), 
-								randomWorldId()
-							))
-					))
-					.collectSortedList()
-					.delayUntil(worlds -> client.batchUpdate(
-							DB_UPDATE_WORLD, 
-							worlds.stream().map(world -> new Object[] { world.getRandomNumber(), world.getId() })
-						)
+			.headers(h -> h
+				.add(HttpHeaderNames.SERVER, STATIC_SERVER)
+				.add(HttpHeaderNames.DATE, this.date)
+				.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
+			)
+			.body()
+				.raw().stream(this.dbRepository.get()
+					.flatMapMany(repository -> Flux.from(((UnsafeSqlOperations)repository.getSqlClient())
+						.batchQueries(ops ->
+							Flux.range(0, queries)
+								.map(ign -> ops.queryForObject(
+									DB_SELECT_WORLD,
+									row -> new World(row.getInteger(0), randomWorldId()),
+									randomWorldId()
+								))
+						))
+						.collectSortedList()
+						.delayUntil(repository::updateWorlds)
+						.map(worlds -> this.jsonSerializer.get().serialize(worlds, LIST_WORLD_TYPE))
 					)
 					)
-					.map(worlds -> {
-						try {
-							return Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(worlds));
-						} 
-						catch (JsonProcessingException e) {
-							throw new InternalServerErrorException(e);
-						}
-					})
-				)
-			);
+				);
 	}
 	}
 	
 	
 	private static final CharSequence MEDIA_TEXT_HTML_UTF8 = AsciiString.cached("text/html; charset=utf-8");
 	private static final CharSequence MEDIA_TEXT_HTML_UTF8 = AsciiString.cached("text/html; charset=utf-8");
 	
 	
-	private static final FortunesTemplate.Renderer<CompletableFuture<ByteBuf>> FORTUNES_RENDERER = FortunesTemplate.bytebuf(() -> Unpooled.buffer());
+	private static final FortunesTemplate.Renderer<CompletableFuture<ByteBuf>> FORTUNES_RENDERER = FortunesTemplate.bytebuf(Unpooled::buffer);
 	
 	
 	public void handle_fortunes(Exchange<ExchangeContext> exchange) throws HttpException {
 	public void handle_fortunes(Exchange<ExchangeContext> exchange) throws HttpException {
 		exchange.response()
 		exchange.response()
@@ -300,12 +253,7 @@ public class Controller implements ServerController<ExchangeContext, Exchange<Ex
 				.add(HttpHeaderNames.CONTENT_TYPE, MEDIA_TEXT_HTML_UTF8)
 				.add(HttpHeaderNames.CONTENT_TYPE, MEDIA_TEXT_HTML_UTF8)
 			)
 			)
 			.body()
 			.body()
-				.raw().stream(this.sqlClient.get().flatMapMany(client -> 
-					client.query(
-							DB_SELECT_FORTUNE, 
-							row -> new Fortune(row.getInteger(0), row.getString(1))
-						)
-					)
+				.raw().stream(this.dbRepository.get().flatMapMany(DbRepository::listFortunes)
 					.collectList()
 					.collectList()
 					.flatMap(fortunes -> {
 					.flatMap(fortunes -> {
 						fortunes.add(new Fortune(0, "Additional fortune added at request time."));
 						fortunes.add(new Fortune(0, "Additional fortune added at request time."));

+ 132 - 0
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java

@@ -0,0 +1,132 @@
+package com.techempower.inverno.benchmark.internal;
+
+import com.techempower.inverno.benchmark.AppConfiguration;
+import com.techempower.inverno.benchmark.model.Fortune;
+import com.techempower.inverno.benchmark.model.World;
+import io.inverno.core.annotation.Bean;
+import io.inverno.core.annotation.Destroy;
+import io.inverno.core.annotation.Init;
+import io.inverno.mod.base.concurrent.Reactor;
+import io.inverno.mod.base.concurrent.VertxReactor;
+import io.inverno.mod.sql.PreparedStatement;
+import io.inverno.mod.sql.SqlClient;
+import io.inverno.mod.sql.vertx.ConnectionSqlClient;
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.pgclient.PgConnectOptions;
+import io.vertx.pgclient.PgConnection;
+import java.util.ArrayList;
+import java.util.List;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class DbRepository {
+
+	public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1";
+	public static final String DB_SELECT_FORTUNE = "SELECT id, message from FORTUNE";
+
+	private final SqlClient sqlClient;
+
+	private final PreparedStatement selectWorldByIdQuery;
+	private final PreparedStatement selectFortuneQuery;
+	private final PreparedStatement[] updateWorldQueries;
+
+	public DbRepository(SqlClient sqlClient) {
+		this.sqlClient = sqlClient;
+
+		this.selectWorldByIdQuery = sqlClient.preparedStatement(DB_SELECT_WORLD);
+		this.selectFortuneQuery = sqlClient.preparedStatement(DB_SELECT_FORTUNE);
+		this.updateWorldQueries = new PreparedStatement[500];
+		for(int i=0;i<this.updateWorldQueries.length;i++) {
+			updateWorldQueries[i] = sqlClient.preparedStatement(buildAggregatedUpdateQuery(i + 1));
+		}
+	}
+
+	private static String buildAggregatedUpdateQuery(int len) {
+		StringBuilder sql = new StringBuilder();
+		sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID");
+		for (int i = 0; i < len; i++) {
+			int offset = (i * 2) + 1;
+			sql.append(" WHEN $").append(offset).append(" THEN $").append(offset + 1);
+		}
+		sql.append(" ELSE RANDOMNUMBER");
+		sql.append(" END WHERE ID IN ($1");
+		for (int i = 1; i < len; i++) {
+			int offset = (i * 2) + 1;
+			sql.append(",$").append(offset);
+		}
+		sql.append(")");
+		return sql.toString();
+	}
+
+	public SqlClient getSqlClient() {
+		return sqlClient;
+	}
+
+	public Mono<World> getWorld(int id) {
+		return Mono.from(this.selectWorldByIdQuery.bind(id).execute(row -> new World(row.getInteger(0), row.getInteger(1))));
+	}
+
+	public Flux<Fortune> listFortunes() {
+		return Flux.from(this.selectFortuneQuery.execute(row -> new Fortune(row.getInteger(0), row.getString(1))));
+	}
+
+	public Mono<Void> updateWorlds(List<World> worlds) {
+		int len = worlds.size();
+		List<Object> parameters = new ArrayList<>(len * 2);
+		for(World world : worlds) {
+			parameters.add(world.getId());
+			parameters.add(world.getRandomNumber());
+		}
+		return Mono.when(this.updateWorldQueries[len - 1].bind(parameters).execute());
+	}
+
+	@Bean( name = "dbRespository", visibility = Bean.Visibility.PRIVATE )
+	public static class ReactorScope extends io.inverno.mod.base.concurrent.ReactorScope<Mono<DbRepository>> {
+
+		private final AppConfiguration configuration;
+		private final Reactor reactor;
+
+		private Vertx vertx;
+		private PgConnectOptions connectOptions;
+
+		public ReactorScope(AppConfiguration configuration, Reactor reactor) {
+			this.configuration = configuration;
+			this.reactor = reactor;
+		}
+
+		@Init
+		public void init() {
+			if(this.reactor instanceof VertxReactor) {
+				this.vertx = ((VertxReactor)this.reactor).getVertx();
+			}
+			else {
+				this.vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(this.configuration.boot().prefer_native_transport()));
+			}
+
+			this.connectOptions = new PgConnectOptions()
+				.setHost(this.configuration.db_host())
+				.setPort(this.configuration.db_port())
+				.setDatabase(this.configuration.db_database())
+				.setUser(this.configuration.db_username())
+				.setPassword(this.configuration.db_password())
+				.setCachePreparedStatements(true)
+				.setPreparedStatementCacheMaxSize(1024)
+				.setPipeliningLimit(100_100);
+		}
+
+		@Destroy
+		public void destroy() {
+			if(!(this.reactor instanceof VertxReactor)) {
+				this.vertx.close();
+			}
+		}
+
+		@Override
+		protected Mono<DbRepository> create() {
+			return Mono.fromCompletionStage(() -> PgConnection.connect(this.vertx, this.connectOptions).toCompletionStage())
+				.map(pgConn -> new DbRepository(new ConnectionSqlClient(pgConn)))
+				.cacheInvalidateWhen(repository -> ((ConnectionSqlClient)repository.getSqlClient()).onClose());
+		}
+	}
+}

+ 38 - 0
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java

@@ -0,0 +1,38 @@
+package com.techempower.inverno.benchmark.internal;
+
+import com.dslplatform.json.DslJson;
+import com.dslplatform.json.JsonWriter;
+import io.inverno.core.annotation.Bean;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.lang.reflect.Type;
+
+public class JsonSerializer {
+
+	private static final DslJson<Object> DSL_JSON = new DslJson<>();
+
+	private final JsonWriter jsonWriter;
+
+	public JsonSerializer() {
+		this.jsonWriter = DSL_JSON.newWriter();
+	}
+
+	public <T> ByteBuf serialize(T value, Type type) {
+		try {
+			DSL_JSON.serialize(this.jsonWriter, type, value);
+			return Unpooled.wrappedBuffer(this.jsonWriter.toByteArray());
+		}
+		finally {
+			this.jsonWriter.reset();
+		}
+	}
+
+	@Bean( name = "jsonSerializer", visibility = Bean.Visibility.PRIVATE )
+	public static class ReactorScope extends io.inverno.mod.base.concurrent.ReactorScope<JsonSerializer> {
+
+		@Override
+		protected JsonSerializer create() {
+			return new JsonSerializer();
+		}
+	}
+}

+ 0 - 66
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java

@@ -1,66 +0,0 @@
-package com.techempower.inverno.benchmark.internal;
-
-import com.techempower.inverno.benchmark.AppConfiguration;
-
-import io.inverno.core.annotation.Bean;
-import io.inverno.core.annotation.Bean.Visibility;
-import io.inverno.core.annotation.Destroy;
-import io.inverno.core.annotation.Init;
-import io.inverno.mod.base.concurrent.Reactor;
-import io.inverno.mod.base.concurrent.ReactorScope;
-import io.inverno.mod.base.concurrent.VertxReactor;
-import io.inverno.mod.sql.SqlClient;
-import io.inverno.mod.sql.vertx.ConnectionSqlClient;
-import io.vertx.core.Vertx;
-import io.vertx.core.VertxOptions;
-import io.vertx.pgclient.PgConnectOptions;
-import io.vertx.pgclient.PgConnection;
-import reactor.core.publisher.Mono;
-
-@Bean( name = "SqlClient", visibility = Visibility.PRIVATE )
-public class SqlClientReactorScope extends ReactorScope<Mono<SqlClient>> {
-
-	private final AppConfiguration configuration;
-	private final Reactor reactor;
-	
-	private Vertx vertx;
-	private PgConnectOptions connectOptions;
-	
-	public SqlClientReactorScope(AppConfiguration configuration, Reactor reactor) {
-		this.configuration = configuration;
-		this.reactor = reactor;
-	}
-	
-	@Init
-	public void init() {
-		if(this.reactor instanceof VertxReactor) {
-			this.vertx = ((VertxReactor)this.reactor).getVertx();			
-		}
-		else {
-			this.vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(this.configuration.boot().prefer_native_transport()));
-		}
-		
-		this.connectOptions = new PgConnectOptions()
-				.setHost(this.configuration.db_host())
-				.setPort(this.configuration.db_port())
-				.setDatabase(this.configuration.db_database())
-				.setUser(this.configuration.db_username())
-				.setPassword(this.configuration.db_password())
-				.setCachePreparedStatements(true)
-				.setPipeliningLimit(100_100);
-	}
-	
-	@Destroy
-	public void destroy() {
-		if(!(this.reactor instanceof VertxReactor)) {
-			this.vertx.close();			
-		}
-	}
-	
-	@Override
-	protected Mono<SqlClient> create() {
-		return Mono.fromCompletionStage(() -> PgConnection.connect(this.vertx, this.connectOptions).toCompletionStage())
-			.map(pgConn -> (SqlClient)new ConnectionSqlClient(pgConn))
-			.cacheInvalidateWhen(client -> ((ConnectionSqlClient)client).onClose());
-	}
-}

+ 3 - 0
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java

@@ -1,5 +1,8 @@
 package com.techempower.inverno.benchmark.model;
 package com.techempower.inverno.benchmark.model;
 
 
+import com.dslplatform.json.CompiledJson;
+
+@CompiledJson
 public final class Fortune implements Comparable<Fortune> {
 public final class Fortune implements Comparable<Fortune> {
 
 
 	private final int id;
 	private final int id;

+ 3 - 0
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java

@@ -1,5 +1,8 @@
 package com.techempower.inverno.benchmark.model;
 package com.techempower.inverno.benchmark.model;
 
 
+import com.dslplatform.json.CompiledJson;
+
+@CompiledJson
 public final class Message {
 public final class Message {
 
 
 	private final String message;
 	private final String message;

+ 6 - 5
frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java

@@ -1,14 +1,15 @@
 package com.techempower.inverno.benchmark.model;
 package com.techempower.inverno.benchmark.model;
 
 
+import com.dslplatform.json.CompiledJson;
+
+@CompiledJson
 public final class World implements Comparable<World> {
 public final class World implements Comparable<World> {
 
 
-	private final int id;
+	private int id;
 	private int randomNumber;
 	private int randomNumber;
 
 
-	public World(int id) {
-		this.id = id;
-	}
-	
+	public World() {}
+
 	public World(int id, int randomNumber) {
 	public World(int id, int randomNumber) {
 		this.id = id;
 		this.id = id;
 		this.randomNumber = randomNumber;
 		this.randomNumber = randomNumber;

+ 3 - 6
frameworks/Java/inverno/src/main/java/module-info.java

@@ -10,16 +10,13 @@ module com.techempower.inverno.benchmark {
 	requires io.netty.common;
 	requires io.netty.common;
 	requires io.netty.codec.http;
 	requires io.netty.codec.http;
 	requires unbescape;
 	requires unbescape;
-	
+	requires static dsl.json;
+
 	requires io.vertx.client.sql.pg;
 	requires io.vertx.client.sql.pg;
 	requires io.vertx.client.sql;
 	requires io.vertx.client.sql;
 	requires io.vertx.core;
 	requires io.vertx.core;
 	requires java.sql;
 	requires java.sql;
-	
-	//requires transitive io.netty.transport;
-	//requires static io.netty.transport.unix.common;
-	//requires static io.netty.transport.epoll;
-	
+
 	exports com.techempower.inverno.benchmark;
 	exports com.techempower.inverno.benchmark;
 	exports com.techempower.inverno.benchmark.model;
 	exports com.techempower.inverno.benchmark.model;
 }
 }

+ 1 - 1
frameworks/Java/wicket/pom.xml

@@ -24,7 +24,7 @@
 		<maven.compiler.target>11</maven.compiler.target>
 		<maven.compiler.target>11</maven.compiler.target>
 		<jackson.version>2.13.0</jackson.version>
 		<jackson.version>2.13.0</jackson.version>
 		<slf4j.version>1.7.25</slf4j.version>
 		<slf4j.version>1.7.25</slf4j.version>
-		<wicket.version>9.18.0</wicket.version>
+		<wicket.version>9.19.0</wicket.version>
 	</properties>
 	</properties>
 	<dependencies>
 	<dependencies>
 		<!-- WICKET DEPENDENCIES -->
 		<!-- WICKET DEPENDENCIES -->

+ 26 - 0
frameworks/PHP/cyberphp/README.md

@@ -0,0 +1,26 @@
+# CyberPHP Benchmarking Test
+
+## Test URLs
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+### DB
+
+http://localhost:8080/db
+
+### QUERY
+
+http://localhost:8080/queries/[count]
+
+### UPDATE
+
+http://localhost:8080/updates/[count]
+
+### FORTUNES
+
+http://localhost:8080/fortunes

+ 57 - 0
frameworks/PHP/cyberphp/app/config.php

@@ -0,0 +1,57 @@
+<?php
+return [
+    'app_name' => 'Cyber',
+    // Request middleware runs after obtaining request body and before parsing route
+    // Mainly used for blacklist, whitelist, system maintenance, request filtering, data access, etc.
+    'request_middleware' => [
+        // \app\common\middleware\IpBlacklistMiddleware::class,// IP blacklist middleware
+        // \app\middleware\RateLimitMiddleware::class,// Rate limit middleware
+        // \app\middleware\SecurityMiddleware::class, // Security protection (CSRF/XSS filtering/SQL injection) middleware
+    ],
+    // Business middleware runs after parsing route and before executing controller method
+    // Mainly used for common business such as user authentication
+    'middleware' => [
+        // \app\common\middleware\Route1Middleware::class,
+        // \app\common\middleware\Route2Middleware::class,
+    ],
+    'orm' => 'pdo',
+    'pdo' => [
+        'dsn' => 'pgsql:host=tfb-database;dbname=hello_world',
+        'username' => 'benchmarkdbuser',
+        'password' => 'benchmarkdbpass',
+        'options' => [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,PDO::ATTR_EMULATE_PREPARES    => false]
+    ],
+    'eloquent' => [
+        'driver' => 'mysql',
+        'host' => '127.0.0.1',
+        'database' => 'lavaman',
+        'username' => 'root',
+        'password' => 'root',
+        'charset' => 'utf8mb4',
+        'prefix' => '',
+    ],
+    'thinkorm' => [
+        'default'    =>    'mysql',
+        'connections'    =>    [
+            'mysql'    =>    [
+                'type'        => 'mysql', // Database type
+                'hostname'    => '127.0.0.1',// Server address
+                'database'    => 'lavaman',// Database name
+                'username'    => 'root',// Database username
+                'password'    => 'root',// Database password
+                'hostport'    => '',// Database connection port
+                'params'      => [],
+                'charset'     => 'utf8mb4',// Database encoding default utf8
+                'prefix'      => '',// Table prefix
+            ],
+        ],
+    ],
+    'cookie' => [
+        'expires' => 0,
+        'path' => '/',
+        'domain' => '',
+        'secure' => true,
+        'httponly' => true,
+        'samesite' => 'Lax'  // None, Lax, Strict
+    ]
+];

+ 74 - 0
frameworks/PHP/cyberphp/app/controller/Index.php

@@ -0,0 +1,74 @@
+<?php
+namespace app\controller;
+
+use Cyber\Response;
+class Index {
+
+    public function json()
+    {
+        return Response::json(['message' => 'Hello, World!']);
+    }
+
+    public function plaintext()
+    {
+        return Response::text('Hello, World!');
+    }
+
+    public function db()
+    {
+        $prepare = app()->dbWorld;
+        $prepare->execute([mt_rand(1, 10000)]);
+        $data = $prepare->fetch();
+        return Response::json($data);
+    }
+    public function fortunes()
+    {
+        $fortune = app()->dbFortune;
+        $fortune->execute();
+        $arr    = $fortune->fetchAll(\PDO::FETCH_KEY_PAIR);
+        $arr[0] = 'Additional fortune added at request time.';
+        \asort($arr);
+        $html = '';
+        foreach ($arr as $id => $message) {
+            $message = \htmlspecialchars($message, \ENT_QUOTES, 'UTF-8');
+            $html .= "<tr><td>$id</td><td>$message</td></tr>";
+        }
+        return Response::html("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>$html</table></body></html>");
+    }
+
+    public function queries($q=1)
+    {
+        $statement = app()->dbWorld;
+        $query_count = max(min(intval($q), 500), 1);
+        $arr = [];
+        while ($query_count--) {
+            $statement->execute([mt_rand(1, 10000)]);
+            $arr[] = $statement->fetch();
+        }
+        return Response::json($arr);
+    }
+
+    public function updates($q=1)
+    {
+        static $updates = [];
+
+        $random = app()->dbWorld;
+        $count = max(min(intval($q), 500), 1);
+
+        $worlds = $keys = $values = [];
+        for ($i = 0; $i < $count; ++ $i) {
+            $values[] = $keys[] = $id = mt_rand(1, 10000);
+            $random->execute([$id]);
+            $row = $random->fetch();
+            $values[] = $row['randomNumber'] = mt_rand(1, 10000);
+            $worlds[] = $row;
+        }
+        if (!isset($updates[$count])) {
+            $sql = 'UPDATE World SET randomNumber = CASE id' . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $count) . 'END WHERE id IN (' . str_repeat('?::INTEGER,', $count - 1) . '?::INTEGER)';
+            $updates[$count] = app()->db->prepare($sql);
+        }
+        $updates[$count]->execute([...$values, ...$keys]);
+
+        return Response::json($worlds);
+    }
+}

+ 84 - 0
frameworks/PHP/cyberphp/app/helpers.php

@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+
+/**
+* Get the application instance
+* If there is a configuration file, create the application instance
+* If there is no configuration file, return the already created instance
+* If there is no configuration file and no instance has been created, throw an exception
+* @param string $bootstrap Configuration file
+* @return \Cyber\App
+*/
+if (!function_exists('app')) {
+    function app(): \Cyber\App
+    {
+        return \Cyber\App::getInstance();
+    }
+}
+
+/**
+* Get configuration information
+* config();                  // Returns all configurations
+* config('app.name');        // Gets the value of app.name
+* config('db.mysql.host');   // Gets the value of db.mysql.host
+* @param string|null $key Configuration key name, supports multi-level configuration separated by dots, e.g., 'app.debug'
+* @param mixed $default Default value, returned when the configuration item does not exist
+* @return mixed
+*/
+if (!function_exists('config')) {
+    function config(?string $key = null, $default = null)
+    {
+        return \Cyber\App::getInstance()->getConfig($key) ?? $default;
+    }
+}
+
+function renderExceptionPage($e, $debug = true, $templateFile = ''): string
+{
+    // Determine template path
+    $templateFile = !empty($templateFile) ? $templateFile : __DIR__ . '/views/errors/exception.html';
+    // Prepare template variables
+    $data = [
+        'code' => $e->getCode(),
+        'message' => $debug ? $e->getMessage() : 'The current server is experiencing an error, please contact the administrator or try again later.',
+        'error' => $e->getMessage(),
+    ];
+    // Add more information in debug mode
+    if ($debug) {
+        $data['trace'] = [];
+        $data['file'] = $e->getFile();
+        $data['line'] = $e->getLine();
+        $traceFiles = $e->getTrace();
+        array_unshift($traceFiles, ['file' => $data['file'], 'line' => $data['line']]);
+        foreach ($traceFiles as $v) {
+            try {
+                if (isset($v['file']) && isset($v['line'])) {
+                    $startline = max(1, $v['line'] - 10);
+                    $contents  = file($v['file']);
+                    $data['trace'][] = [
+                        'file' => $v['file'],
+                        'line' => $v['line'],
+                        'source0' => $contents ? array_slice($contents, 0, 1) : '',
+                        'source' => [
+                            'startline' => $startline,
+                            'content' => array_slice($contents, $startline - 1, 16)
+                        ]
+                    ];
+                }
+            } catch (\Throwable $e) {
+                continue;
+            }
+        }
+    }
+    // Render error page
+    if (!file_exists($templateFile)) {
+        $msg = '<div style="margin:100px auto 20px;text-align:center"><h1>Error ' . $data['code'] . '</h1></div>';
+        $msg .= '<div style="margin:0px auto;text-align:center">Sorry, the server encountered an error</div>';
+        $msg .= '<div style="margin:50px auto;text-align:center"><h2><pre>' . htmlspecialchars($data['message']) . '</pre></h2></div>';
+        $msg .= '<div style="margin:100px auto;text-align:center"><a href="/"><button>Return to Home</button></a></div>';
+        return $msg;
+    }
+    extract($data);
+    ob_start();
+    include $templateFile;
+    return ob_get_clean();
+}

+ 14 - 0
frameworks/PHP/cyberphp/app/route.php

@@ -0,0 +1,14 @@
+<?php
+use Cyber\Request;
+
+return [
+    ['/', 'GET', 'app\controller\Index@hello'],
+    ['/json', 'GET', 'app\controller\Index@json'],
+    ['/plaintext', 'GET', 'app\controller\Index@plaintext'],
+    ['/db', 'GET', 'app\controller\Index@db'],
+    ['/fortunes', 'GET', 'app\controller\Index@fortunes'],
+    ['/queries/', 'GET', 'app\controller\Index@queries'],
+    ['/queries/{q}', 'GET', 'app\controller\Index@queries'],
+    ['/updates/', 'GET', 'app\controller\Index@updates'],
+    ['/updates/{q}', 'GET', 'app\controller\Index@updates'],
+];

+ 62 - 0
frameworks/PHP/cyberphp/app/views/errors/exception.html

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>An Error Occurred</title>
+    <style>
+        body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;line-height:1.6;margin:0;padding:0;background:#f8f9fa;color:#343a40}
+        pre{margin:0;padding:0;}
+        .container{max-width:80%;margin:50px auto;padding:20px;background:#fff;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}
+        .error-code{font-size:72px;font-weight:bold;color:#dc3545;margin:0;line-height:1}
+        .error-title{font-size:24px;color:#495057;margin:20px 0}
+        .error-message{font-size:16px;color:#6c757d;margin-bottom:30px;padding:15px;background:#f8f9fa;border-radius:4px;border-left:4px solid #dc3545}
+        .back-link{display:inline-block;margin-top:20px;padding:10px 20px;background:#007bff;color:#fff;text-decoration:none;border-radius:4px;transition:background-color 0.2s}
+        .back-link:hover{background:#0056b3}
+
+        .source-box{margin:10px 0;padding:0px;}
+        .source-box a{color:#369;font-weight:900;}
+        .source-file{padding:5px 10px;background:#f8f9fa;}
+        .source-code{padding:4px 0px;border: 0px solid #ddd;background: #f1f2f3;overflow-x: auto;}
+        .source-code ol,.source-code ul{margin: 0;color: #555;font-size:14px;}
+        .source-code code{border-left: 1px solid #ccc;padding-left:5px;font-family: "Consolas";}
+        .source-error{color:#000;background:#dc354533!important}
+        .source-error code{font-weight:900;}
+    </style>
+</head>
+<body>
+    <div class="container">
+        <h1 class="error-code">Error <?php echo htmlspecialchars($code); ?></h1>
+        <h2 class="error-title">Sorry, an error occurred</h2>
+        <div class="error-message"><?php echo htmlspecialchars($message); ?></div>
+        <!-- <?php echo htmlspecialchars($error); ?> -->
+        <?php if (isset($trace)) { ?>
+            <?php foreach ($trace as $k => $v) { ?>
+                <div class="source-box">
+                    <div class="source-file">#<?= $k ?> <a href="view-source:file:///<?php echo $v['file']; ?>"><?php echo $v['file']; ?></a> Line <?php echo $v['line']; ?></div>
+                    <div class="source-code">
+                        <pre><?php
+                        if (!empty($v['source0'])) {
+                            echo '<ol start="0"><li><code>'.htmlentities($v['source0'][0]).'</code></li></ol>';
+                        }
+                        if (!empty($v['source'])) {
+                            echo '<ol start="'.htmlentities($v['source']['startline']).'">';
+                            foreach ((array) $v['source']['content'] as $key => $value) {
+                                if (($key + $v['source']['startline']) == $v['line']) {
+                                    echo '<li class="source-error"><code>'.htmlentities($value).'</code></li>';
+                                } else {
+                                    echo '<li><code>'.htmlentities($value).'</code></li>';
+                                }
+                            }
+                            echo '</ol>';
+                        }
+                        ?></pre>
+                    </div>
+                </div>
+            <?php } ?>
+        <?php } ?>
+        <a href="/" class="back-link">Return to Home</a>
+</body>
+
+</html>

+ 30 - 0
frameworks/PHP/cyberphp/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+  "framework": "cyberphp",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries/",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates/",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "cyberphp",
+        "language": "PHP",
+        "flavor": "PHP8",
+        "orm": "Raw",
+        "platform": "workerman",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "cyberphp",
+        "notes": "",
+        "versus": "workerman"
+      }
+    }
+  ]
+}

+ 41 - 0
frameworks/PHP/cyberphp/bootstrap.php

@@ -0,0 +1,41 @@
+<?php
+return [
+
+    // Route configuration
+    'route_path' =>  __DIR__ .'/app/route.php',
+
+    // Application configuration file location can be modified freely
+
+    // Key represents the name of the sub-application; sub-applications not listed cannot be accessed
+    'config' => [
+        // Default configuration
+        '' => require 'app/config.php',
+        // If a sub-application does not mention a configuration, the content of the default configuration file will be used
+        // 'admin'=> (require 'app/admin/config.php') + (require 'app/config.php'),
+
+        // Or only use the default configuration
+        // 'phone'=> require 'app/config.php',
+
+        // Or do not use the default configuration, directly use your custom sub-application configuration, you can change the name freely
+        // 'phone'=> require 'app/config_phone.php',
+
+        // Or this way, each configuration item is introduced separately
+        // 'admin'=> [
+        //     'app_name' => 'admin',
+        //     'request_middleware' => require 'app/admin/config_request_middleware.php',
+        //     'middleware' => require 'app/admin/config_middleware.php',
+        //     'database' => require 'app/admin/config_database.php',
+        //     'cookie' => require 'app/admin/config_cookie.php',
+        //     'database' => require 'app/admin/config_database.php',
+        // ],
+    ],
+
+    // Create route manager
+    'Route' => \DI\create(\Cyber\Route::class),
+    'Middleware' => \DI\create(\Cyber\Middleware::class),
+
+    // Create request object for handling HTTP requests
+    'Request' => \DI\create(\Cyber\Request::class),
+    // Create response object for generating HTTP responses
+    'Response' => \DI\create(\Cyber\Response::class),
+];

+ 29 - 0
frameworks/PHP/cyberphp/composer.json

@@ -0,0 +1,29 @@
+{
+    "name": "eoioer/cyberphp",
+    "authors": [
+        {
+            "name": "eoioer",
+            "email": "[email protected]"
+        }
+    ],
+    "type": "project",
+    "description": "The Fastest and Smallest PHP Framework",
+    "license": "MIT",
+    "require": {
+        "php": ">=8.3",
+        "php-di/php-di": "^7.0",
+        "nikic/fast-route": "^1.3",
+        "workerman/workerman": "^4.1"
+    },
+    "autoload": {
+        "psr-4": {
+            "app\\": "app/",
+            "Cyber\\": "src/"
+        },
+		"files": [
+			"app/helpers.php"
+		]
+    },
+    "minimum-stability": "stable",
+    "prefer-stable": true
+}

+ 26 - 0
frameworks/PHP/cyberphp/cyberphp.dockerfile

@@ -0,0 +1,26 @@
+FROM ubuntu:24.04
+
+ENV TEST_TYPE default
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null
+RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
+    apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null
+
+RUN apt-get install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null
+
+COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+
+RUN apt-get update -yqq && apt-get install -y php-pear php8.4-dev libevent-dev git  > /dev/null
+RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini
+
+WORKDIR /cyberphp
+COPY --link . .
+
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
+COPY php.ini /etc/php/8.4/cli/conf.d/10-opcache.ini
+
+EXPOSE 8080
+
+CMD php /cyberphp/server.php start

+ 11 - 0
frameworks/PHP/cyberphp/php.ini

@@ -0,0 +1,11 @@
+zend_extension=opcache.so
+opcache.enable=1
+opcache.enable_cli=1
+opcache.validate_timestamps=0
+opcache.save_comments=0
+opcache.enable_file_override=1
+opcache.huge_code_pages=1
+mysqlnd.collect_statistics = Off
+memory_limit = 512M
+opcache.jit_buffer_size=128M
+opcache.jit=tracing

BIN
frameworks/PHP/cyberphp/public/favicon.ico


+ 23 - 0
frameworks/PHP/cyberphp/public/index.php

@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+use Cyber\Response;
+use Cyber\App;
+
+require dirname(__DIR__) . '/vendor/autoload.php';
+
+
+$app = App::bootstrap(dirname(__DIR__) . '/bootstrap.php');
+
+try {
+    $response = $app->run();
+    if (!$response instanceof Response) {
+        $response = Response::html($response ?? '');
+    }
+    echo $response->send();
+} catch (Exception $e) {
+    echo renderExceptionPage($e);
+} catch (Throwable $e) {
+    echo renderExceptionPage($e);
+}

+ 85 - 0
frameworks/PHP/cyberphp/server.php

@@ -0,0 +1,85 @@
+<?php
+/**
+ * Workerman HTTP server startup file
+ * Based on Workerman to implement an HTTP server, integrated with the ThinkPHP framework
+ */
+
+use Workerman\Worker;
+use Workerman\Connection\TcpConnection;
+use Workerman\Protocols\Http\Request as WorkermanRequest;
+use Cyber\Response;
+
+// Load Composer autoload file
+require __DIR__ . '/vendor/autoload.php';
+
+// Create a Worker listening on port 8099, using HTTP protocol for communication
+$http_worker = new Worker("http://0.0.0.0:8080");
+
+// Set the number of processes (set according to the number of CPU cores, recommended to be 1-4 times the number of CPU cores)
+$http_worker->count = 4;
+
+// Initialize ThinkPHP application
+$app = \Cyber\App::bootstrap(__DIR__.'/bootstrap.php');
+
+/**
+ * Callback function to handle HTTP requests
+ * @param TcpConnection $connection Client connection object
+ * @param WorkermanRequest $request HTTP request object
+ */
+$http_worker->onMessage = function(TcpConnection $connection, WorkermanRequest $request) use ($app) {
+    // Initialize request object
+    $_GET = $request->get();  // Get GET parameters
+    $_POST = $request->post(); // Get POST parameters
+    $_FILES = $request->file(); // Get file uploads
+    $_COOKIE = $request->cookie(); // Get COOKIE
+
+    // Merge server variables
+    $_SERVER = array_merge($_SERVER, [
+        'RAW_BODY' => $request->rawBody(), // Raw request body
+        'REQUEST_METHOD' => $request->method(), // Request method
+        'REQUEST_URI' => $request->uri(), // Request URI
+        'QUERY_STRING' => $request->queryString(), // Query string
+        'REMOTE_ADDR' => $connection->getRemoteIp(), // Client IP
+        'REMOTE_PORT' => $connection->getRemotePort(), // Client port
+        'SERVER_PROTOCOL' => 'HTTP/'.$request->protocolVersion(), // Protocol version
+    ]);
+
+    // Handle request headers
+    foreach ($request->header() as $key => $value) {
+        $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', $key))] = $value;
+    }
+
+    try {
+        ob_start(); // Start output buffering
+        $response = $app->run(); // Run ThinkPHP application
+
+        // Handle response
+        if(!$response instanceof Response){
+            // If not a Response object, directly output content
+            echo $response;
+            $content = ob_get_clean();
+            $connection->send($content);
+        }else{
+            // If it is a Response object, send HTTP response
+            echo $response->send();
+            $content = ob_get_clean();
+            $connection->send(new Workerman\Protocols\Http\Response(
+                $response->getStatusCode(), // Status code
+                $response->getHeaders(), // Response headers
+                $content // Response content
+            ));
+        }
+    } catch (Exception $e) {
+        // Catch exceptions and render error page
+        $connection->send(renderExceptionPage($e));
+    } catch (Throwable $e) {
+        // Catch all errors
+        $connection->send(renderExceptionPage($e));
+    }
+};
+
+/**
+ * Run all Worker instances
+ * This method will block the current process until all Workers stop
+ */
+Worker::runAll();

+ 154 - 0
frameworks/PHP/cyberphp/src/App.php

@@ -0,0 +1,154 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Cyber;
+
+use DI\Container;
+use Cyber\Request;
+use Cyber\Response;
+use Cyber\Middleware;
+use Cyber\Utility;
+use PDO;
+
+class App
+{
+    /** App instance object */
+    private static ?self $instance = null;
+    /** Container instance */
+    public Container $container;
+    /** Application configuration */
+    public array $config;
+    public  $data;
+    /** Request configuration */
+    public Request $request;
+    /** Response configuration */
+    public Response $response;
+    /** Middleware */
+    public Middleware $middleware;
+
+    /** Route configuration */
+    public array $routes;
+    /** Route manager */
+    public Route $route;
+
+    /** Application name */
+    public string $appName;
+    public $db;
+    public $dbWorld;
+    public $dbFortune;
+
+    public $start_time;
+    public $timestamps;
+    /**
+    * Constructor
+    * Configuration check, initialization configuration, container
+    */
+    public function __construct($containerConfig = null)
+    {
+        $this->start_time = time();
+
+        /* Build container instance */
+        $this->container = new Container($containerConfig);
+
+        /* Load route configuration */
+        $routes = require $this->container->get('route_path');
+        /* Create route manager */
+        $this->route = $this->container->get('Route');
+        /* Call route dispatcher */
+        $this->route->dispatcher($routes);
+
+        /* Configuration */
+        $this->config = $this->container->get('config');
+        /* Request object */
+        $this->request = $this->container->get('Request');
+
+        /* Database */
+        $pdo =  new PDO(...$this->getConfig('pdo'));
+        $this->db = $pdo;
+        $this->dbWorld = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        $this->dbFortune = $pdo->prepare('SELECT id,message FROM Fortune');
+
+    }
+    /**
+    * Run application
+    */
+    public function run()
+    {
+        $this->timestamps = time();
+        /* cli mode maintains database connection */
+        if (php_sapi_name() === 'cli' and time() - $this->start_time > 1) {
+            $this->start_time = time();
+            $pdo =  new PDO(...$this->getConfig('pdo'));
+            $this->db = $pdo;
+            $this->dbWorld = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+            $this->dbFortune = $pdo->prepare('SELECT id,message FROM Fortune');
+        }
+
+        /* Return response */
+        return $this->route->handleRoute();
+    }
+
+    /**
+    * Get the current application configuration
+    * $app->getConfig();                         // Returns the entire configuration content of the current application
+    * $app->getConfig('app_name');               // Get the value of ['app_name'] in the current application configuration
+    * $app->getConfig('cookie.expires');         // Get the value of ['cookie']['expires']
+    * $app->getConfig(null, 'admin');            // Returns the entire configuration content of the admin application
+    * $app->getConfig('app_name', 'admin');      // Get the value of ['app_name'] in the admin application configuration
+    * $app->getConfig('cookie.expires','admin'); // Get the value of ['cookie']['expires'] in the admin application configuration
+    */
+    public function getConfig($key = null, $appName = null): mixed
+    {
+        $appName = $appName ?? $this->appName ?? '';
+        $config = $this->config[$appName] ?? null;
+        // Get the entire application configuration
+        if ($key === null) {
+            return $config;
+        }
+        // Split the key into an array
+        $keys = explode('.', $key);
+        // Traverse the key array and get the configuration layer by layer
+        foreach ($keys as $k) {
+            if (is_array($config) && array_key_exists($k, $config)) {
+                $config = $config[$k];
+            } else {
+                return null; // If a layer does not exist, return null
+            }
+        }
+        return $config; // Return the final configuration value
+    }
+    /**
+    * Initialize the application
+    * @param string $bootstrap Configuration file
+    * @return self
+    */
+    public static function bootstrap($bootstrap = null): self
+    {
+        if (!$bootstrap) {
+            throw new \Exception('App::bootstrap parameter does not exist');
+        }
+        if (self::$instance === null) {
+            /* Load container configuration file */
+            if (!file_exists($bootstrap) || !is_readable($bootstrap)) {
+                throw new \Exception("App::bootstrap parameter {$bootstrap} path error");
+            }
+            $containerConfig = require_once $bootstrap;
+            self::$instance = new self($containerConfig);
+            return self::$instance;
+        }else{
+            throw new \Exception('Application has started');
+        }
+    }
+    /**
+    * Get the application singleton instance
+    * @return self
+    */
+    public static function getInstance(): self
+    {
+        if (self::$instance === null) {
+            throw new \Exception('Application has not started');
+        }
+        return self::$instance;
+    }
+}

+ 48 - 0
frameworks/PHP/cyberphp/src/Middleware.php

@@ -0,0 +1,48 @@
+<?php
+namespace Cyber;
+
+class Middleware
+{
+
+    public function handleRequest(array $requestMiddlewares)
+    {
+        $request = app()->request;
+        foreach ($requestMiddlewares as $middleware) {
+            if (!class_exists($middleware)) {
+                throw new \Exception("The parameter class {$middleware} for processing the request middleware does not exist");
+            }
+            $instance = app()->container->get($middleware);
+            if (!method_exists($instance, 'handle')) {
+                throw new \Exception("The parameter class {$middleware} for processing the request middleware does not have a handle method");
+            }
+            /* Call the handle method of the request data middleware */
+            $request = $instance->handle($request);
+        }
+        return $request;
+    }
+
+    public function handle(array $Middlewares, callable $finalHandler)
+    {
+        $request = app()->request;
+        $container = app()->container;
+        // Start wrapping the handler from the last middleware layer by layer
+        $response = array_reduce(
+            array_reverse($Middlewares),
+            function($next, $middleware) use ($request,$container) {
+                if (!class_exists($middleware)) {
+                    throw new \Exception("The middleware parameter class {$middleware} does not exist");
+                }
+                $instance = $container->get($middleware);
+                if (!method_exists($instance, 'handle')) {
+                    throw new \Exception("The middleware parameter class {$middleware} does not have a handle method");
+                }
+                return function() use ($instance, $request, $next) {
+                    return $instance->handle($request, $next);
+                };
+            },
+            $finalHandler
+        );
+        // Execute the middleware chain
+        return $response();
+    }
+}

+ 232 - 0
frameworks/PHP/cyberphp/src/Request.php

@@ -0,0 +1,232 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Cyber;
+
+/**
+* HTTP Request Class
+*
+* This class encapsulates HTTP request information and provides a standard interface for accessing request data.
+* The design references Laravel's Request class and implements common request handling functions.
+*/
+class Request
+{
+    public static function getPathInfo(): string
+    {
+        $requestUri = $_SERVER['REQUEST_URI'] ?? '/';
+
+        // Remove query string
+        if (($pos = strpos($requestUri, '?')) !== false) {
+            $requestUri = substr($requestUri, 0, $pos);
+        }
+
+        // Remove script name (if any)
+        $scriptName = $_SERVER['SCRIPT_NAME'] ?? '';
+        if ($scriptName && strpos($requestUri, $scriptName) === 0) {
+            $requestUri = substr($requestUri, strlen($scriptName));
+        }
+        return $requestUri ?: '/';
+    }
+    /**
+    * Get application name
+    *
+    * @return string|null
+    */
+    public function getAppName(): ?string
+    {
+        // Get the current request URI
+        $uri = static::getPathInfo();
+        $segments = explode('/', trim($uri, '/')); // Split the URI by slashes
+        // Return application name
+        return isset($segments[0]) ? $segments[0] : '';
+    }
+    /**
+    * Get request method
+    *
+    * @return string
+    */
+    public function getMethod(): string
+    {
+        return strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
+    }
+
+    /**
+    * Get GET parameter
+    *
+    * @param string|null $key Parameter name
+    * @param mixed $default Default value
+    * @return mixed
+    */
+    public function query(?string $key = null, $default = null)
+    {
+        if ($key === null) {
+            return $_GET;
+        }
+        return $_GET[$key] ?? $default;
+    }
+
+    /**
+    * Get POST parameter
+    *
+    * @param string|null $key Parameter name
+    * @param mixed $default Default value
+    * @return mixed
+    */
+    public function post(?string $key = null, $default = null)
+    {
+        if ($key === null) {
+            return $_POST;
+        }
+        return $_POST[$key] ?? $default;
+    }
+
+    /**
+    * Get all input parameters (GET + POST)
+    *
+    * @param string|null $key Parameter name
+    * @param mixed $default Default value
+    * @return mixed
+    */
+    public function all(?string $key = null, $default = null)
+    {
+        $data = array_merge($_GET, $_POST, self::getParsedContent());
+
+        if ($key === null) {
+            return $data;
+        }
+        return $data[$key] ?? $default;
+    }
+
+    /**
+    * Get parsed request content
+    *
+    * @return array
+    */
+    protected function getParsedContent(): array
+    {
+        $parsedContent = file_get_contents('php://input');
+
+        if (self::isJson()) {
+            $content = json_decode($parsedContent, true);
+            if (json_last_error() === JSON_ERROR_NONE) {
+                $parsedContent = $content;
+            }
+        }
+        return $parsedContent;
+    }
+
+    /**
+    * Get Cookie value
+    *
+    * @param string|null $key Cookie name
+    * @param mixed $default Default value
+    * @return mixed
+    */
+    public function cookie(?string $key = null, $default = null)
+    {
+        if ($key === null) {
+            return $_COOKIE;
+        }
+        return $_COOKIE[$key] ?? $default;
+    }
+
+    /**
+    * Check if it is an AJAX request
+    *
+    * @return bool
+    */
+    public function isAjax(): bool
+    {
+        return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
+    }
+
+    /**
+    * Check if it is a JSON request
+    *
+    * @return bool
+    */
+    public function isJson(): bool
+    {
+        $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
+        return str_contains($contentType, '/json') || str_contains($contentType, '+json');
+    }
+    /**
+    * Check if it is a JSON request
+    *
+    * @return bool
+    */
+    public function rawBody(): bool
+    {
+        return $_SERVER['RAW_BODY'] ?? file_get_contents("php://input");
+    }
+
+    /**
+    * Get client IP address
+    *
+    * @return string
+    */
+    public function getClientIp(): string
+    {
+        $keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
+
+        foreach ($keys as $key) {
+            if (isset($_SERVER[$key])) {
+                return $_SERVER[$key];
+            }
+        }
+
+        return '';
+    }
+
+    /**
+    * Get the complete URL of the request
+    *
+    * @return string
+    */
+    public function getUrl(): string
+    {
+        $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'];
+        $uri = $_SERVER['REQUEST_URI'] ?? '';
+        return "{$host}{$uri}";
+    }
+
+    /**
+    * Get specified request header
+    *
+    * @param string $key Request header name
+    * @param mixed $default Default value
+    * @return mixed
+    */
+    public function header($key=null, $default = null)
+    {
+        if($key === null) {
+            $headers = [];
+            foreach ($_SERVER as $key => $value) {
+                if (strpos($key, 'HTTP_') === 0) {
+                    $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))));
+                    $headers[$key] = $value;
+                }
+            }
+            ksort($headers);
+            return $headers;
+        }
+        return $_SERVER['HTTP_'.strtoupper(str_replace('-', '_', $key))] ?? $default;
+    }
+    /**
+    * Set request header
+    * @param string $key Header information name
+    * @param string $value Header information value
+    * @return void
+    */
+    public function setHeader(string $key, string $value): void
+    {
+        if(is_array($key)){
+            foreach ($key as $k => $v) {
+                $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', $k))] = $v;
+            }
+        }else{
+            $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', $key))] = $value;
+        }
+    }
+}

+ 218 - 0
frameworks/PHP/cyberphp/src/Response.php

@@ -0,0 +1,218 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Cyber;
+
+use Exception;
+
+class Response
+{
+    /**
+     * HTTP status codes and their descriptions
+     */
+    private const HTTP_STATUS = [
+        // 2xx Success
+        200 => 'OK',
+        201 => 'Created',
+        204 => 'No Content',
+
+        // 3xx Redirection
+        301 => 'Moved Permanently',
+        302 => 'Found',
+        304 => 'Not Modified',
+
+        // 4xx Client Errors
+        400 => 'Bad Request',
+        401 => 'Unauthorized',
+        403 => 'Forbidden',
+        404 => 'Not Found',
+        405 => 'Method Not Allowed',
+        408 => 'Request Timeout',
+        422 => 'Unprocessable Entity',
+        429 => 'Too Many Requests',
+
+        // 5xx Server Errors
+        500 => 'Internal Server Error',
+        502 => 'Bad Gateway',
+        503 => 'Service Unavailable',
+        504 => 'Gateway Timeout'
+    ];
+
+    protected string $content = '';
+    protected int $statusCode = 200;
+    protected array $headers = [];
+    protected bool $sent = false;
+
+    public function __construct(string $content = '', int $statusCode = 200, array $headers = [])
+    {
+        $this->content = $content;
+        $this->statusCode = $statusCode;
+        $this->headers = $headers;
+    }
+
+    /**
+     * Get status code description
+     */
+    public function getStatusText(): string
+    {
+        return self::HTTP_STATUS[$this->statusCode];
+    }
+    /**
+     * Get response body
+     */
+    public function getStatusCode(): int
+    {
+        return $this->statusCode;
+    }
+    /**
+     * Get response body
+     */
+    public function getContent(): string
+    {
+        return $this->content;
+    }
+
+    /**
+     * Get all response headers
+     */
+    public function getHeaders(): array
+    {
+        return $this->headers;
+    }
+
+    /**
+     * Add response header
+     *
+     * @throws Exception
+     */
+    public function withHeader(string $name, string|array $value): static
+    {
+        // Validate header name legality
+        if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) {
+            throw new Exception('Header name can only contain letters, numbers, and special characters');
+        }
+        if (empty($name)) {
+            throw new Exception('Header name cannot be empty');
+        }
+
+        $clone = clone $this;
+        $clone->headers[$name] = is_array($value) ? $value : [$value];
+        return $clone;
+    }
+
+    /**
+     * Add multiple response headers
+     */
+    public function withHeaders(array $headers): static
+    {
+        $clone = clone $this;
+        foreach ($headers as $name => $value) {
+            $clone = $clone->withHeader($name, $value);
+        }
+        return $clone;
+    }
+
+    /**
+     * Create JSON response
+     *
+     * @throws Exception
+     */
+    public static function json(mixed $data, int $status = 200, array $headers = []): static
+    {
+        try {
+            $json = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
+        } catch (\JsonException $e) {
+            throw new Exception('Unable to encode data to JSON', 0, $e);
+        }
+
+        $headers['Content-Type'] = 'application/json; charset=utf-8';
+        $headers['Date'] = gmdate('D, d M Y H:i:s').' GMT';
+        return new static($json, $status, $headers);
+    }
+
+    /**
+     * Create HTML response
+     */
+    public static function html(string $html, int $status = 200, array $headers = []): static
+    {
+        $headers['Content-Type'] = 'text/html; charset=utf-8';
+        $headers['Date'] = gmdate('D, d M Y H:i:s').' GMT';
+        return new static($html, $status, $headers);
+    }
+
+    /**
+     * Create text response
+     */
+    public static function text(string $text, int $status = 200, array $headers = []): static
+    {
+        $headers['Content-Type'] = 'text/plain; charset=utf-8';
+        $headers['Date'] = gmdate('D, d M Y H:i:s').' GMT';
+        return new static($text, $status, $headers);
+    }
+    /**
+     * Create file response
+     */
+    public static function file(string $file, string $filename, int $status = 200, array $headers = []): static
+    {
+        $headers['Content-Type'] = 'application/octet-stream';
+        $headers['Date'] = gmdate('D, d M Y H:i:s').' GMT';
+        $headers['Content-Disposition'] = 'attachment; filename="' . $filename . '"';
+        return new static(file_get_contents($file), $status, $headers);
+    }
+
+    /**
+     * Create redirect response
+     *
+     * @throws Exception
+     */
+    public static function redirect(string $url, int $status = 302, array $headers = []): static
+    {
+        if (!filter_var($url, FILTER_VALIDATE_URL) && !str_starts_with($url, '/')) {
+            throw new Exception('Invalid URL format');
+        }
+        return new static('', $status, array_merge($headers, ['Location' => $url]));
+    }
+
+    /**
+     * Send response
+     *
+     * @throws Exception
+     */
+    public function send(): void
+    {
+        if ($this->isSent()) {
+            throw new Exception('Response already sent');
+        }
+        if (!headers_sent()) {
+        //     // 发送状态码
+            http_response_code($this->statusCode);
+
+        //     // 确保有 Content-Type 头
+            if (!isset($this->headers['Content-Type'])) {
+                $this->headers['Content-Type'] = ['text/html; charset=utf-8'];
+            }
+
+        //     // 发送响应头
+            foreach ($this->headers as $name => $values) {
+                $values = (array) $values;
+                foreach ($values as $value) {
+                    header($name . ': ' . $value, false);
+                }
+            }
+        }
+
+        // // 发送响应内容
+        echo $this->content;
+
+        // $this->sent = true;
+    }
+
+    /**
+     * Check if the response has been sent
+     */
+    public function isSent(): bool
+    {
+        return $this->sent;
+    }
+}

+ 61 - 0
frameworks/PHP/cyberphp/src/Route.php

@@ -0,0 +1,61 @@
+<?php
+namespace Cyber;
+
+use DI\Container;
+use FastRoute;
+use FastRoute\RouteCollector;
+
+class Route
+{
+    public $dispatcher;
+    // Route dispatch
+    public function dispatcher($routes)
+    {
+        $this->dispatcher = FastRoute\simpleDispatcher(function (RouteCollector $r) use ($routes) {
+            foreach ($routes as $route) {
+                // Check the number of array members. Three members indicate a single route configuration.
+                if (count($route) == 3) {
+                    $r->addRoute(preg_split('/\s*,\s*/', $route[1]), $route[0], $route[2]);
+                    // Two members indicate a group route.
+                } elseif (count($route) == 2) {
+                    $r->addGroup($route[0], function (RouteCollector $r) use ($route) {
+                        foreach ($route[1] as $childRoute) {
+                            $r->addRoute(preg_split('/\s*,\s*/', trim($childRoute[1])), $childRoute[0], $childRoute[2]);
+                        }
+                    });
+                }
+            }
+        });
+    }
+    public function handleRoute()
+    {
+        $request = app()->request;
+        $container = app()->container;
+        // Parse the current route
+        $routeInfo = $this->dispatcher->dispatch($request->getMethod(), $request->getPathInfo());
+        if ($routeInfo[0] == 0) {
+            throw new \Exception('Page not found', 404);
+        } elseif ($routeInfo[0] == 2) {
+            throw new \Exception('Request method error', 405);
+        } elseif ($routeInfo[0] == 1) {
+            $handler = $routeInfo[1];
+            $vars = $routeInfo[2];
+            $parameters = [...array_values($vars)];
+
+            // Create a closure to pass to your middleware to execute the final handler
+            $finalHandler = function() use ($handler, $parameters, $container) {
+                // If handler is a string (controller@method)
+                if (is_string($handler)) {
+                    list($controller, $method) = explode('@', $handler);
+                    $ctrl = $container->get($controller);
+                    return $ctrl->$method(...$parameters);
+                } elseif (is_callable($handler)) {
+                    return $handler(...$parameters);
+                } else {
+                    throw new \Exception('Route handler configuration error');
+                }
+            };
+            return $finalHandler();
+        }
+    }
+}

+ 47 - 0
frameworks/PHP/cyberphp/src/Utility.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace Cyber;
+
+class Utility
+{
+    /**
+     * Check if required PHP extensions are installed
+     *
+     * @throws Exception Throws an exception when required extensions are not installed
+     * @return bool Returns true if all extensions check passed
+     */
+    public static function checkPHPenv(): bool
+    {
+        /* Check PHP version */
+        if (version_compare(PHP_VERSION, '8.0', '<')) {
+            throw new \Exception('Current PHP (' . PHP_VERSION . ') version is too low! Minimum required PHP version is (8.0)');
+        }
+        // List of required extensions
+        $requiredExtensions =  [
+            'json' => 'Handling JSON data',
+            'mbstring' => 'Handling multibyte strings',
+            'pdo' => 'Database connection',
+            'pdo_mysql' => 'MySQL database support',
+            'openssl' => 'Encryption and HTTPS support'
+        ];
+        // Check required extensions
+        $missingExtensions = [];
+        foreach ($requiredExtensions as $extension => $purpose) {
+            if (!extension_loaded($extension)) {
+                $missingExtensions[] = sprintf(
+                    "- %s (%s)",
+                    $extension,
+                    $purpose
+                );
+            }
+        }
+        // If there are missing required extensions, throw an exception
+        if (!empty($missingExtensions)) {
+            throw new \Exception(sprintf(
+                "Missing required PHP extensions:\n%s\nPlease install these extensions before running the program.",
+                implode("\n", $missingExtensions)
+            ));
+        }
+        return true;
+    }
+}

+ 24 - 0
frameworks/PHP/laravel/deploy/franken/Caddyfile

@@ -0,0 +1,24 @@
+{
+	{$CADDY_GLOBAL_OPTIONS}
+
+	admin {$CADDY_SERVER_ADMIN_HOST}:{$CADDY_SERVER_ADMIN_PORT}
+
+	frankenphp {
+		worker "{$APP_PUBLIC_PATH}/frankenphp-worker.php" {$CADDY_SERVER_WORKER_COUNT}
+	}
+}
+
+{$CADDY_SERVER_SERVER_NAME} {
+	route {
+		# Mercure configuration is injected here...
+		{$CADDY_SERVER_EXTRA_DIRECTIVES}
+
+		# FrankenPHP!
+		# disable static files for this benchmark
+		# by using php instead of php_server
+		rewrite frankenphp-worker.php
+		php {
+			root "{$APP_PUBLIC_PATH}"
+		}
+	}
+}

+ 1 - 2
frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile

@@ -1,7 +1,6 @@
 FROM dunglas/frankenphp
 FROM dunglas/frankenphp
  
  
 RUN install-php-extensions \
 RUN install-php-extensions \
-    intl \
 	opcache \
 	opcache \
 	pcntl \
 	pcntl \
     pdo_mysql \
     pdo_mysql \
@@ -26,4 +25,4 @@ RUN frankenphp -v
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-ENTRYPOINT ["php", "artisan", "octane:frankenphp", "--port=8080"]
+ENTRYPOINT ["php", "artisan", "octane:frankenphp", "--port=8080", "--caddyfile=/app/deploy/franken/Caddyfile"]

+ 4 - 5
frameworks/PHP/laravel/laravel-ripple.dockerfile

@@ -33,14 +33,13 @@ RUN mkdir -p bootstrap/cache \
             storage/framework/views \
             storage/framework/views \
             storage/framework/cache
             storage/framework/cache
 
 
-RUN echo "PRP_HTTP_LISTEN=http://0.0.0.0:8080" >> .env
-RUN echo "PRP_HTTP_WORKERS=64" >> .env
-RUN echo "PRP_HTTP_RELOAD=0" >> .env
-RUN echo "PRP_HTTP_SANDBOX=1" >> .env
+RUN echo "RIP_HTTP_LISTEN=http://0.0.0.0:8080" >> .env
+RUN echo "RIP_HTTP_WORKERS=64" >> .env
+RUN echo "RIP_HTTP_RELOAD=0" >> .env
 
 
 # Configure
 # Configure
 RUN composer install --quiet
 RUN composer install --quiet
-RUN composer require cloudtay/ripple-driver --quiet
+RUN composer require cloudtay/laravel-ripple --quiet
 RUN php artisan vendor:publish --tag=ripple-config
 RUN php artisan vendor:publish --tag=ripple-config
 RUN php artisan optimize
 RUN php artisan optimize
 
 

+ 5 - 2
frameworks/PHP/php/deploy/franken/Caddyfile

@@ -11,11 +11,14 @@
 :8080
 :8080
 
 
 route {
 route {
-    root * /php
 
 
     # FrankenPHP!
     # FrankenPHP!
+    # disable static files for this benchmark
+    # by using php instead of php_server
     @phpFiles path *.php
     @phpFiles path *.php
-    php @phpFiles
+    php @phpFiles {
+        root /php
+    }
 
 
     respond 404
     respond 404
 }
 }

+ 5 - 2
frameworks/PHP/reactphp/app.php

@@ -10,6 +10,7 @@ use React\MySQL\QueryResult;
 use React\Promise\PromiseInterface;
 use React\Promise\PromiseInterface;
 
 
 use function React\Promise\all;
 use function React\Promise\all;
+use function React\Promise\resolve;
 
 
 /** @return Closure(Request):ResponseInterface */
 /** @return Closure(Request):ResponseInterface */
 function requestHandler(): Closure
 function requestHandler(): Closure
@@ -29,7 +30,7 @@ function requestHandler(): Closure
     };
     };
 
 
     return static function (Request $request) use ($world, $fortune, $update): ResponseInterface | PromiseInterface {
     return static function (Request $request) use ($world, $fortune, $update): ResponseInterface | PromiseInterface {
-        return match($request->getUri()->getPath()) {
+        return resolve((match($request->getUri()->getPath()) {
             '/plaintext' => Response::plaintext('Hello, World!'),
             '/plaintext' => Response::plaintext('Hello, World!'),
             '/json'      => Response::json(['message' => 'Hello, World!']),
             '/json'      => Response::json(['message' => 'Hello, World!']),
             '/db'        => db($world),
             '/db'        => db($world),
@@ -38,7 +39,9 @@ function requestHandler(): Closure
             '/update'    => updateraw(queryCount($request), $world, $update),
             '/update'    => updateraw(queryCount($request), $world, $update),
             // '/info'      => info(),
             // '/info'      => info(),
             default      => new Response(404, [], 'Error 404'),
             default      => new Response(404, [], 'Error 404'),
-        };
+        }))->catch(
+            static fn (Throwable $error): PromiseInterface => resolve(Response::plaintext($error->getMessage())->withStatus(500)),
+        );
     };
     };
 }
 }
 
 

+ 20 - 1
frameworks/PHP/reactphp/benchmark_config.json

@@ -17,9 +17,28 @@
       "webserver": "None",
       "webserver": "None",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
-      "display_name": "reactphp",
+      "display_name": "reactphp [libevent]",
       "notes": "",
       "notes": "",
       "versus": "php"
       "versus": "php"
+    },
+    "libuv": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "framework": "reactphp",
+      "language": "PHP",
+      "flavor": "PHP8",
+      "database": "MySQL",
+      "orm": "Raw",
+      "platform": "reactphp",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "reactphp [libuv]",
+      "notes": "",
+      "versus": "reactphp"
     }
     }
   }]
   }]
 }
 }

+ 35 - 0
frameworks/PHP/reactphp/reactphp-libuv.dockerfile

@@ -0,0 +1,35 @@
+FROM ubuntu:24.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null
+RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null
+RUN apt-get update -yqq > /dev/null && \
+    apt-get install -yqq git unzip wget curl build-essential \
+    php8.4-cli php8.4-mbstring php8.4-dev php8.4-xml > /dev/null
+
+# An extension is required!
+# We deal with concurrencies over 1k, which stream_select doesn't support.
+# libuv
+RUN apt-get install -yqq libuv1-dev > /dev/null \
+     && pecl install uv-beta > /dev/null \
+     && echo "extension=uv.so" > /etc/php/8.4/cli/conf.d/uv.ini
+
+# libevent
+# RUN apt-get install -y libevent-dev > /dev/null \
+#    && pecl install event-3.1.4 > /dev/null \
+#    && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini
+
+COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+
+COPY --link deploy/conf/* /etc/php/8.4/cli/conf.d/
+
+WORKDIR /reactphp
+COPY --link . .
+
+RUN composer install --prefer-dist --optimize-autoloader --no-dev --quiet
+
+EXPOSE 8080
+
+ENTRYPOINT ["/usr/bin/php"]
+CMD ["server.php"]

+ 1 - 1
frameworks/PHP/reactphp/reactphp.dockerfile

@@ -27,7 +27,7 @@ COPY --link deploy/conf/* /etc/php/8.4/cli/conf.d/
 WORKDIR /reactphp
 WORKDIR /reactphp
 COPY --link . .
 COPY --link . .
 
 
-RUN composer install --prefer-dist --optimize-autoloader --no-dev
+RUN composer install --prefer-dist --optimize-autoloader --no-dev --quiet
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 

+ 3 - 0
frameworks/PHP/reactphp/server.php

@@ -8,6 +8,9 @@ require __DIR__ . '/vendor/autoload.php';
 require_once __DIR__.'/app.php';
 require_once __DIR__.'/app.php';
 
 
 $server = new HttpServer(requestHandler());
 $server = new HttpServer(requestHandler());
+$server->on('error', function (\Throwable $error) {
+    echo $error->getMessage(), PHP_EOL;
+});
 $socket = new SocketServer('0.0.0.0:8080');
 $socket = new SocketServer('0.0.0.0:8080');
 $server->listen($socket);
 $server->listen($socket);
 
 

+ 6 - 11
frameworks/PHP/symfony/deploy/Caddyfile

@@ -11,18 +11,13 @@
 :8080
 :8080
 
 
 route {
 route {
-    root * /symfony/public
 
 
-    # If the requested file does not exist, try index files
-    @indexFiles file {
-        try_files {path} {path}/runtime.php runtime.php
-        split_path .php
+	# FrankenPHP!
+	# disable static files for this benchmark
+	# by using php instead of php_server
+    rewrite runtime.php
+    php {
+        root /symfony/public
     }
     }
-    rewrite @indexFiles {http.matchers.file.relative}
-    
-    # FrankenPHP!
-    @phpFiles path *.php
-    php @phpFiles
 
 
-    respond 404
 }
 }

+ 0 - 1
frameworks/PHP/symfony/symfony-franken.dockerfile

@@ -2,7 +2,6 @@ FROM dunglas/frankenphp
 
 
 # add additional extensions here:
 # add additional extensions here:
 RUN install-php-extensions \
 RUN install-php-extensions \
-    intl \
     opcache \
     opcache \
     pdo_pgsql \
     pdo_pgsql \
     zip > /dev/null
     zip > /dev/null

+ 1 - 1
frameworks/Perl/feersum/cpanfile

@@ -1,4 +1,4 @@
-requires 'Feersum', '== 1.503';
+requires 'Feersum', '== 1.504';
 requires 'JSON::XS', '== 4.03';
 requires 'JSON::XS', '== 4.03';
 requires 'DBD::MariaDB', '== 1.23';
 requires 'DBD::MariaDB', '== 1.23';
 requires 'DBD::Pg', '== 3.18.0';
 requires 'DBD::Pg', '== 3.18.0';

+ 1 - 1
frameworks/Ruby/agoo/Gemfile.lock

@@ -7,7 +7,7 @@ GEM
     oj (3.16.3)
     oj (3.16.3)
       bigdecimal (>= 3.0)
       bigdecimal (>= 3.0)
     pg (1.5.6)
     pg (1.5.6)
-    rack (3.0.11)
+    rack (3.0.12)
 
 
 PLATFORMS
 PLATFORMS
   ruby
   ruby

+ 3 - 5
frameworks/Ruby/rack-sequel/Gemfile.lock

@@ -7,17 +7,16 @@ GEM
     kgio (2.11.4)
     kgio (2.11.4)
     mysql2 (0.5.6)
     mysql2 (0.5.6)
     nio4r (2.7.4)
     nio4r (2.7.4)
-    passenger (6.0.23)
+    passenger (6.0.26)
       rack (>= 1.6.13)
       rack (>= 1.6.13)
-      rackup
+      rackup (>= 2.0.0)
       rake (>= 12.3.3)
       rake (>= 12.3.3)
     pg (1.5.8)
     pg (1.5.8)
     puma (6.5.0)
     puma (6.5.0)
       nio4r (~> 2.0)
       nio4r (~> 2.0)
     rack (3.1.8)
     rack (3.1.8)
-    rackup (2.1.0)
+    rackup (2.2.1)
       rack (>= 3)
       rack (>= 3)
-      webrick (~> 1.8)
     raindrops (0.20.1)
     raindrops (0.20.1)
     rake (13.2.1)
     rake (13.2.1)
     sequel (5.85.0)
     sequel (5.85.0)
@@ -28,7 +27,6 @@ GEM
     unicorn (6.1.0)
     unicorn (6.1.0)
       kgio (~> 2.6)
       kgio (~> 2.6)
       raindrops (~> 0.7)
       raindrops (~> 0.7)
-    webrick (1.8.2)
 
 
 PLATFORMS
 PLATFORMS
   ruby
   ruby

+ 6 - 6
frameworks/Ruby/rack-sequel/benchmark_config.json

@@ -8,7 +8,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "database": "MySQL",
         "database": "MySQL",
         "framework": "rack",
         "framework": "rack",
@@ -28,7 +28,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "database": "Postgres",
         "database": "Postgres",
         "framework": "rack",
         "framework": "rack",
@@ -48,7 +48,7 @@
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "plaintext_url": "/plaintext",
         "plaintext_url": "/plaintext",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "database": "MySQL",
         "database": "MySQL",
         "framework": "rack",
         "framework": "rack",
@@ -68,7 +68,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "database": "Postgres",
         "database": "Postgres",
         "framework": "rack",
         "framework": "rack",
@@ -88,7 +88,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "database": "MySQL",
         "database": "MySQL",
         "framework": "rack",
         "framework": "rack",
@@ -108,7 +108,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "database": "Postgres",
         "database": "Postgres",
         "framework": "rack",
         "framework": "rack",

+ 5 - 5
frameworks/Ruby/rack/benchmark_config.json

@@ -10,7 +10,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "orm": "raw",
         "orm": "raw",
         "database": "Postgres",
         "database": "Postgres",
@@ -31,7 +31,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "orm": "raw",
         "orm": "raw",
         "database": "Postgres",
         "database": "Postgres",
@@ -52,7 +52,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "orm": "raw",
         "orm": "raw",
         "database": "Postgres",
         "database": "Postgres",
@@ -73,7 +73,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "orm": "raw",
         "orm": "raw",
         "database": "Postgres",
         "database": "Postgres",
@@ -94,7 +94,7 @@
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
         "update_url": "/updates?queries=",
         "port": 8080,
         "port": 8080,
-        "approach": "Stripped",
+        "approach": "Realistic",
         "classification": "Micro",
         "classification": "Micro",
         "orm": "raw",
         "orm": "raw",
         "database": "Postgres",
         "database": "Postgres",

+ 4 - 4
frameworks/Ruby/rails/Gemfile.lock

@@ -167,12 +167,12 @@ GEM
     net-smtp (0.5.0)
     net-smtp (0.5.0)
       net-protocol
       net-protocol
     nio4r (2.7.4)
     nio4r (2.7.4)
-    nokogiri (1.16.8)
+    nokogiri (1.18.3)
       mini_portile2 (~> 2.8.2)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
       racc (~> 1.4)
-    nokogiri (1.16.8-x86_64-darwin)
+    nokogiri (1.18.3-x86_64-darwin)
       racc (~> 1.4)
       racc (~> 1.4)
-    nokogiri (1.16.8-x86_64-linux)
+    nokogiri (1.18.3-x86_64-linux-gnu)
       racc (~> 1.4)
       racc (~> 1.4)
     openssl (3.2.0)
     openssl (3.2.0)
     pg (1.5.9)
     pg (1.5.9)
@@ -197,7 +197,7 @@ GEM
     puma (6.5.0)
     puma (6.5.0)
       nio4r (~> 2.0)
       nio4r (~> 2.0)
     racc (1.8.1)
     racc (1.8.1)
-    rack (3.1.8)
+    rack (3.1.10)
     rack-session (2.0.0)
     rack-session (2.0.0)
       rack (>= 3.0.0)
       rack (>= 3.0.0)
     rack-test (2.1.0)
     rack-test (2.1.0)

+ 1 - 1
frameworks/Ruby/rails/rails-iodine.dockerfile

@@ -24,4 +24,4 @@ ENV RAILS_ENV=production_postgresql
 ENV PORT=8080
 ENV PORT=8080
 ENV REDIS_URL=redis://localhost:6379/0
 ENV REDIS_URL=redis://localhost:6379/0
 CMD service redis-server start && \
 CMD service redis-server start && \
-    bundle exec iodine
+    bundle exec iodine -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1)

+ 1 - 1
frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile

@@ -17,4 +17,4 @@ ENV DBTYPE=postgresql
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD bundle exec iodine -p 8080
+CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1)

+ 2 - 2
frameworks/Rust/axum/Cargo.lock

@@ -913,9 +913,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
 
 [[package]]
 [[package]]
 name = "hickory-proto"
 name = "hickory-proto"
-version = "0.24.2"
+version = "0.24.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5"
+checksum = "2ad3d6d98c648ed628df039541a5577bee1a7c83e9e16fe3dbedeea4cdfeb971"
 dependencies = [
 dependencies = [
  "async-trait",
  "async-trait",
  "cfg-if",
  "cfg-if",

+ 4 - 4
frameworks/Rust/ohkami/Cargo.lock

@@ -815,9 +815,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 
 [[package]]
 [[package]]
 name = "openssl"
 name = "openssl"
-version = "0.10.66"
+version = "0.10.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
 dependencies = [
 dependencies = [
  "bitflags 2.6.0",
  "bitflags 2.6.0",
  "cfg-if",
  "cfg-if",
@@ -847,9 +847,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 
 [[package]]
 [[package]]
 name = "openssl-sys"
 name = "openssl-sys"
-version = "0.9.103"
+version = "0.9.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
 dependencies = [
 dependencies = [
  "cc",
  "cc",
  "libc",
  "libc",