From a599716b0e74fa8ef154fefbaaa543419bdacda5 Mon Sep 17 00:00:00 2001 From: AkazawaYun <62974697+AkazawaYun@users.noreply.github.com> Date: Fri, 7 Nov 2025 04:52:30 +0800 Subject: [PATCH 001/130] update version to fix websocket bug (#10243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add new test : CSharp/akazawayun.pro * modify config and code * add content-type * update url * update package version * add 3 new tests: db、queries、updates 1. add 3 new tests: db、queries、updates; 2. split code to multi files; * - * use generated sql instead const string. * update version * fix bug of db query * set port to 8080 * 升级 akazawayun.pro 框架版本到 14 * i forget to update the port change... * test self whether work fine.. * update nuget version * why pr failed... * 不小心多提交了别人的框架...改回 * akazawayun fix bug * remove db test there is some error in mysql * confirmed there is bug in mysql.data 9.5.0 还是用8080端口吧- -b, 都用8080, 改其他的对比测时不方便 * downgrade mysql.data back to 9.4.0 * fix bug of akazawayun.pro * update version of akazawayun.pro * update version * add platform test * update nupkg version --- .../AkazawaYun.Benchmark.Platform.csproj | 2 +- .../AkazawaYun.Benchmark.Platform/Program.cs | 18 ++++++++---------- .../AkazawaYun.Benchmark.WebApi.csproj | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj index 64baee178a5..f59eaf8f615 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj @@ -15,7 +15,7 @@ - + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs index 44dd91c0a3a..269c16f48be 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs @@ -9,27 +9,25 @@ class Program static Program() { - akzLog.War("AkazawaYun.PRO 压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); + akzLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); akzJson.Config(null, AotJsonContext.Default); builder = akzWebBuilder.Shared.SetPort(port).SetDev(true) .Add(() => null) .Add(() => new MyBenchmarkReceptor()) - .Add(() => new(port) - { - LogLevel = 0 - }).Build(); + .Add(() => new(port)) + .Build(); } static async Task Main() { await builder.Launch(); - akzLog.Inf("[API SELF-TEST]"); + Console.WriteLine("[API SELF-TEST]"); string url = $"http://localhost:{port}/plaintext"; - akzLog.Inf(" REQ URL :" + url); + Console.WriteLine(" REQ URL :" + url); string res = await akzHttpClient.Shared.Get(url).FetchString(); - akzLog.Inf(" RES LEN :" + res.Length); - akzLog.Inf(" RES BODY:" + res); - akzLog.Inf("[OK, I WORK FINE]"); + Console.WriteLine(" RES LEN :" + res.Length); + Console.WriteLine(" RES BODY:" + res); + Console.WriteLine("[OK, I WORK FINE]"); akzLog.Default = akzLog.Output.NoneButWar; await Task.Delay(-1); diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj index 469e112ef00..547064216f4 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj @@ -15,7 +15,7 @@ - + From 2ccf30277a6824966e0ce2902743d92b033a391d Mon Sep 17 00:00:00 2001 From: Edgar Espina Date: Thu, 6 Nov 2025 15:52:52 -0500 Subject: [PATCH 002/130] jooby: 4.0.11 (#10244) - fix classpath issue on jetty/undertow tests --- frameworks/Java/jooby/jooby-jetty.dockerfile | 2 +- frameworks/Java/jooby/jooby-mvc.dockerfile | 2 +- frameworks/Java/jooby/jooby-netty.dockerfile | 2 +- frameworks/Java/jooby/jooby-pgclient.dockerfile | 2 +- frameworks/Java/jooby/jooby.dockerfile | 2 +- frameworks/Java/jooby/pom.xml | 6 +++--- .../Java/jooby/src/main/java/com/techempower/App.java | 1 - .../jooby/src/main/java/com/techempower/ReactivePg.java | 3 +-- .../Java/jooby/src/main/java/com/techempower/Util.java | 2 +- frameworks/Kotlin/kooby/kooby.dockerfile | 2 +- frameworks/Kotlin/kooby/pom.xml | 6 +++--- 11 files changed, 14 insertions(+), 16 deletions(-) diff --git a/frameworks/Java/jooby/jooby-jetty.dockerfile b/frameworks/Java/jooby/jooby-jetty.dockerfile index 0c3c605cc1b..fb23bc745c4 100644 --- a/frameworks/Java/jooby/jooby-jetty.dockerfile +++ b/frameworks/Java/jooby/jooby-jetty.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-eclipse-temurin-24-noble as maven +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-mvc.dockerfile b/frameworks/Java/jooby/jooby-mvc.dockerfile index ec8150d3fae..e88198b64bd 100644 --- a/frameworks/Java/jooby/jooby-mvc.dockerfile +++ b/frameworks/Java/jooby/jooby-mvc.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-eclipse-temurin-24-noble as maven +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-netty.dockerfile b/frameworks/Java/jooby/jooby-netty.dockerfile index daf8bed238c..cee8fa0aef4 100644 --- a/frameworks/Java/jooby/jooby-netty.dockerfile +++ b/frameworks/Java/jooby/jooby-netty.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-eclipse-temurin-24-noble as maven +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-pgclient.dockerfile b/frameworks/Java/jooby/jooby-pgclient.dockerfile index e5917ae2af5..e4ddf09382f 100644 --- a/frameworks/Java/jooby/jooby-pgclient.dockerfile +++ b/frameworks/Java/jooby/jooby-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-eclipse-temurin-24-noble as maven +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby.dockerfile b/frameworks/Java/jooby/jooby.dockerfile index 4685ba51c95..3170040c2de 100644 --- a/frameworks/Java/jooby/jooby.dockerfile +++ b/frameworks/Java/jooby/jooby.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-eclipse-temurin-24-noble as maven +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/pom.xml b/frameworks/Java/jooby/pom.xml index 1c86733ddc9..eef2366bd98 100644 --- a/frameworks/Java/jooby/pom.xml +++ b/frameworks/Java/jooby/pom.xml @@ -11,12 +11,12 @@ jooby - 4.0.9 + 4.0.11 2.0.2 42.7.7 UTF-8 - 24 - 24 + 25 + 25 com.techempower.App diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/App.java b/frameworks/Java/jooby/src/main/java/com/techempower/App.java index fbc4bdb8164..0c11074d79f 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/App.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/App.java @@ -5,7 +5,6 @@ import static io.jooby.ExecutionMode.EVENT_LOOP; import static io.jooby.MediaType.JSON; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java b/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java index 385c7180539..9123447f1a2 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java @@ -110,10 +110,9 @@ public class ReactivePg extends Jooby { private void selectWorlds(Context ctx, int queries, Consumer> consumer) { sqlClient.group( client -> { - var statement = client.preparedQuery(SELECT_WORLD); List worlds = new ArrayList<>(queries); for (int i = 0; i < queries; i++) { - statement + client.preparedQuery(SELECT_WORLD) .execute(Tuple.of(Util.boxedRandomWorld())) .map(rs -> new World(rs.iterator().next().getInteger(0), Util.boxedRandomWorld())) .onComplete( diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/Util.java b/frameworks/Java/jooby/src/main/java/com/techempower/Util.java index fd2f14c86ca..e54ae1074a6 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/Util.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/Util.java @@ -24,7 +24,7 @@ public static int randomWorld() { return 1 + ThreadLocalRandom.current().nextInt(10000); } - public static int boxedRandomWorld() { + public static Integer boxedRandomWorld() { final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001); return BOXED_RND[rndValue - 1]; } diff --git a/frameworks/Kotlin/kooby/kooby.dockerfile b/frameworks/Kotlin/kooby/kooby.dockerfile index b689c6e7348..d337708c0df 100644 --- a/frameworks/Kotlin/kooby/kooby.dockerfile +++ b/frameworks/Kotlin/kooby/kooby.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-eclipse-temurin-24-noble as maven +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /kooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Kotlin/kooby/pom.xml b/frameworks/Kotlin/kooby/pom.xml index a27aaaa2a03..3255a6f63a5 100644 --- a/frameworks/Kotlin/kooby/pom.xml +++ b/frameworks/Kotlin/kooby/pom.xml @@ -12,11 +12,11 @@ kooby: jooby+kotlin - 4.0.9 + 4.0.11 42.7.7 UTF-8 - 24 - 24 + 25 + 25 2.2.0 From 0a405afedc01a25b33e20b4472abd2e15f2cad7b Mon Sep 17 00:00:00 2001 From: ruroru <111705692+ruroru@users.noreply.github.com> Date: Thu, 6 Nov 2025 22:54:17 +0200 Subject: [PATCH 003/130] Replace openjdk:25-jdk-slim with amazoncorretto:25 (#10245) openjdk images have been deprecated and 25-jdk-slim image was removed Did not upgrade reitit-async due to failing run --- frameworks/Clojure/aleph/aleph.dockerfile | 2 +- frameworks/Clojure/donkey/donkey.dockerfile | 2 +- frameworks/Clojure/kit/kit-majavat.dockerfile | 2 +- frameworks/Clojure/kit/kit.dockerfile | 2 +- frameworks/Clojure/luminus/luminus.dockerfile | 2 +- .../ring-http-exchange/ring-http-exchange-robaho.dockerfile | 2 +- .../Clojure/ring-http-exchange/ring-http-exchange.dockerfile | 2 +- frameworks/Java/httpserver/httpserver-postgres.dockerfile | 2 +- .../Java/httpserver/httpserver-robaho-postgres.dockerfile | 2 +- frameworks/Java/httpserver/httpserver-robaho.dockerfile | 2 +- frameworks/Java/httpserver/httpserver.dockerfile | 2 +- frameworks/Java/jetty/jetty-servlet.dockerfile | 2 +- frameworks/Java/jetty/jetty.dockerfile | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frameworks/Clojure/aleph/aleph.dockerfile b/frameworks/Clojure/aleph/aleph.dockerfile index e8268bd6b15..7f5e9642a2c 100644 --- a/frameworks/Clojure/aleph/aleph.dockerfile +++ b/frameworks/Clojure/aleph/aleph.dockerfile @@ -4,7 +4,7 @@ COPY src src COPY project.clj project.clj RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /aleph COPY --from=lein /aleph/target/hello-aleph-standalone.jar app.jar diff --git a/frameworks/Clojure/donkey/donkey.dockerfile b/frameworks/Clojure/donkey/donkey.dockerfile index cd7e6d18e57..5afe93e10c3 100644 --- a/frameworks/Clojure/donkey/donkey.dockerfile +++ b/frameworks/Clojure/donkey/donkey.dockerfile @@ -4,7 +4,7 @@ COPY src src COPY project.clj project.clj RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 COPY --from=lein /donkey/target/hello-donkey-standalone.jar app.jar EXPOSE 8080 diff --git a/frameworks/Clojure/kit/kit-majavat.dockerfile b/frameworks/Clojure/kit/kit-majavat.dockerfile index fbea7e95bd4..c4b1990a3f8 100644 --- a/frameworks/Clojure/kit/kit-majavat.dockerfile +++ b/frameworks/Clojure/kit/kit-majavat.dockerfile @@ -6,7 +6,7 @@ COPY . / RUN clj -Sforce -T:build all -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/kit.dockerfile b/frameworks/Clojure/kit/kit.dockerfile index fbea7e95bd4..c4b1990a3f8 100644 --- a/frameworks/Clojure/kit/kit.dockerfile +++ b/frameworks/Clojure/kit/kit.dockerfile @@ -6,7 +6,7 @@ COPY . / RUN clj -Sforce -T:build all -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/luminus/luminus.dockerfile b/frameworks/Clojure/luminus/luminus.dockerfile index b5aa5430694..9ea8a1607ac 100644 --- a/frameworks/Clojure/luminus/luminus.dockerfile +++ b/frameworks/Clojure/luminus/luminus.dockerfile @@ -6,7 +6,7 @@ COPY resources resources COPY src src RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /luminus COPY --from=lein /luminus/target/hello.jar app.jar diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile index e31848de2e6..b53eb194c09 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile @@ -5,7 +5,7 @@ COPY resources resources COPY src src RUN lein with-profile robaho uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /ring-http-exchange COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile index b558aa938cf..0910a6d9850 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile @@ -5,7 +5,7 @@ COPY resources resources COPY src src RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /ring-http-exchange COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar diff --git a/frameworks/Java/httpserver/httpserver-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-postgres.dockerfile index 4cb88012254..5991ae20026 100644 --- a/frameworks/Java/httpserver/httpserver-postgres.dockerfile +++ b/frameworks/Java/httpserver/httpserver-postgres.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /httpserver COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile index 7e204f66f52..e7bdfb11102 100644 --- a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn compile -P robaho assembly:single -q -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /httpserver-robaho COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/httpserver/httpserver-robaho.dockerfile b/frameworks/Java/httpserver/httpserver-robaho.dockerfile index 1d09e486ef1..77f57658d2a 100644 --- a/frameworks/Java/httpserver/httpserver-robaho.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn compile -P robaho assembly:single -q -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /httpserver-robaho COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/httpserver/httpserver.dockerfile b/frameworks/Java/httpserver/httpserver.dockerfile index 01aaecc935c..b50fbadc157 100644 --- a/frameworks/Java/httpserver/httpserver.dockerfile +++ b/frameworks/Java/httpserver/httpserver.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /httpserver COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/jetty/jetty-servlet.dockerfile b/frameworks/Java/jetty/jetty-servlet.dockerfile index a352022e489..aafe6afc370 100644 --- a/frameworks/Java/jetty/jetty-servlet.dockerfile +++ b/frameworks/Java/jetty/jetty-servlet.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -P servlet -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /jetty COPY --from=maven /jetty/target/jetty-example-0.1-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/jetty/jetty.dockerfile b/frameworks/Java/jetty/jetty.dockerfile index 15c208ef4e8..996ee1627be 100644 --- a/frameworks/Java/jetty/jetty.dockerfile +++ b/frameworks/Java/jetty/jetty.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /jetty COPY --from=maven /jetty/target/jetty-example-0.1-jar-with-dependencies.jar app.jar From ab77d497ffff8241cce78007a7ec440afe5a4de0 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 6 Nov 2025 21:54:35 +0100 Subject: [PATCH 004/130] [ruby] Improve display names (#10246) Use square brackers for test variants names. --- frameworks/Ruby/agoo/benchmark_config.json | 2 +- frameworks/Ruby/grape/benchmark_config.json | 4 ++-- frameworks/Ruby/padrino/benchmark_config.json | 4 ++-- frameworks/Ruby/rack-sequel/benchmark_config.json | 4 ++-- frameworks/Ruby/rack/benchmark_config.json | 12 ++++++------ frameworks/Ruby/rails/benchmark_config.json | 10 +++++----- frameworks/Ruby/roda-sequel/benchmark_config.json | 6 +++--- frameworks/Ruby/sinatra-sequel/benchmark_config.json | 6 +++--- frameworks/Ruby/sinatra/benchmark_config.json | 6 +++--- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/frameworks/Ruby/agoo/benchmark_config.json b/frameworks/Ruby/agoo/benchmark_config.json index a4042facee3..29c8106d1e2 100644 --- a/frameworks/Ruby/agoo/benchmark_config.json +++ b/frameworks/Ruby/agoo/benchmark_config.json @@ -19,7 +19,7 @@ "webserver": "Agoo", "os": "Linux", "database_os": "Linux", - "display_name": "rack-agoo-mri", + "display_name": "rack [agoo]", "notes": "" } }] diff --git a/frameworks/Ruby/grape/benchmark_config.json b/frameworks/Ruby/grape/benchmark_config.json index f0afa34bc72..70e233c3cf6 100644 --- a/frameworks/Ruby/grape/benchmark_config.json +++ b/frameworks/Ruby/grape/benchmark_config.json @@ -18,7 +18,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "grape-puma-mri", + "display_name": "grape [puma]", "notes": "", "versus": "rack-puma-mri" }, @@ -39,7 +39,7 @@ "webserver": "Unicorn", "os": "Linux", "database_os": "Linux", - "display_name": "grape-unicorn-mri", + "display_name": "grape [unicorn]", "notes": "", "versus": "rack-unicorn-mri" } diff --git a/frameworks/Ruby/padrino/benchmark_config.json b/frameworks/Ruby/padrino/benchmark_config.json index 2fa32a70b47..1b467408cc2 100644 --- a/frameworks/Ruby/padrino/benchmark_config.json +++ b/frameworks/Ruby/padrino/benchmark_config.json @@ -19,7 +19,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "padrino-puma-mri", + "display_name": "padrino [puma]", "notes": "", "versus": "rack-puma-mri" }, @@ -41,7 +41,7 @@ "webserver": "Unicorn", "os": "Linux", "database_os": "Linux", - "display_name": "padrino-unicorn", + "display_name": "padrino [unicorn]", "notes": "", "versus": "rack-unicorn" } diff --git a/frameworks/Ruby/rack-sequel/benchmark_config.json b/frameworks/Ruby/rack-sequel/benchmark_config.json index 8c81927c69f..15763639c4c 100644 --- a/frameworks/Ruby/rack-sequel/benchmark_config.json +++ b/frameworks/Ruby/rack-sequel/benchmark_config.json @@ -18,7 +18,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-sequel-puma-mri", + "display_name": "rack-sequel [puma, mysql]", "versus": "rack-puma-mri", "notes": "" }, @@ -38,7 +38,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-sequel-postgres-puma-mri", + "display_name": "rack-sequel [puma, postgres]", "versus": null, "notes": "" } diff --git a/frameworks/Ruby/rack/benchmark_config.json b/frameworks/Ruby/rack/benchmark_config.json index dec94fec3a9..326c20b4f40 100644 --- a/frameworks/Ruby/rack/benchmark_config.json +++ b/frameworks/Ruby/rack/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-puma-mri-sequel-raw", + "display_name": "rack [puma]", "notes": "" }, "iodine": { @@ -41,7 +41,7 @@ "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "rack-iodine-mri-sequel-raw", + "display_name": "rack [iodine]", "notes": "" }, "falcon": { @@ -62,7 +62,7 @@ "webserver": "Falcon", "os": "Linux", "database_os": "Linux", - "display_name": "rack-falcon-mri-sequel-raw", + "display_name": "rack [falcon]", "notes": "" }, "jruby": { @@ -83,7 +83,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-puma-jruby-sequel-raw", + "display_name": "rack [jruby, puma]", "notes": "" }, "passenger": { @@ -104,7 +104,7 @@ "webserver": "Passenger", "os": "Linux", "database_os": "Linux", - "display_name": "rack-passenger-mri-sequel-raw", + "display_name": "rack [passenger]", "notes": "" }, "pitchfork": { @@ -125,7 +125,7 @@ "webserver": "Pitchfork", "os": "Linux", "database_os": "Linux", - "display_name": "rack-pitchfork-mri-sequel-raw", + "display_name": "rack [pitchfork]", "notes": "" } } diff --git a/frameworks/Ruby/rails/benchmark_config.json b/frameworks/Ruby/rails/benchmark_config.json index 232a4321e56..5f86a525145 100644 --- a/frameworks/Ruby/rails/benchmark_config.json +++ b/frameworks/Ruby/rails/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rails-postgresql", + "display_name": "rails [puma, postgres]", "notes": "", "versus": "" }, @@ -41,7 +41,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rails-mysql", + "display_name": "rails [puma, mysql]", "notes": "", "versus": "rack-puma-mri" }, @@ -64,7 +64,7 @@ "webserver": "Falcon", "os": "Linux", "database_os": "Linux", - "display_name": "rails-falcon", + "display_name": "rails [falcon]", "notes": "", "versus": "rack-falcon-mri-sequel-raw" }, @@ -87,7 +87,7 @@ "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "rails-iodine", + "display_name": "rails [iodine]", "notes": "", "versus": "rack-iodine-mri-sequel-raw" }, @@ -110,7 +110,7 @@ "webserver": "Pitchfork", "os": "Linux", "database_os": "Linux", - "display_name": "rails-pitchfork", + "display_name": "rails [pitchfork]", "notes": "", "versus": "rack-pitchfork-mri-sequel-raw" } diff --git a/frameworks/Ruby/roda-sequel/benchmark_config.json b/frameworks/Ruby/roda-sequel/benchmark_config.json index f51112ed0f9..c028cc7008c 100644 --- a/frameworks/Ruby/roda-sequel/benchmark_config.json +++ b/frameworks/Ruby/roda-sequel/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel-puma-mri", + "display_name": "roda-sequel [puma, mysql]", "versus": "rack-sequel-puma-mri", "notes": "" }, @@ -40,7 +40,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel-postgres-puma-mri", + "display_name": "roda-sequel [puma, postgres]", "versus": "rack-sequel-postgres-puma-mri", "notes": "" }, @@ -62,7 +62,7 @@ "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel-postgres-iodine-mri", + "display_name": "roda-sequel [iodine, postgres]", "versus": "rack-sequel-postgres-iodine-mri", "notes": "" } diff --git a/frameworks/Ruby/sinatra-sequel/benchmark_config.json b/frameworks/Ruby/sinatra-sequel/benchmark_config.json index 8b09aafbd54..008e63a8148 100644 --- a/frameworks/Ruby/sinatra-sequel/benchmark_config.json +++ b/frameworks/Ruby/sinatra-sequel/benchmark_config.json @@ -18,7 +18,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-sequel-puma-mri", + "display_name": "sinatra-sequel [puma, mysql]", "versus": "rack-sequel-puma-mri", "notes": "" }, @@ -38,7 +38,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-sequel-postgres-puma-mri", + "display_name": "sinatra-sequel [puma, postgres]", "versus": "rack-sequel-postgres-puma-mri", "notes": "" }, @@ -58,7 +58,7 @@ "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-sequel-postgres-iodine-mri", + "display_name": "sinatra-sequel [iodine, postgres]", "versus": "rack-sequel-postgres-iodine-mri", "notes": "" } diff --git a/frameworks/Ruby/sinatra/benchmark_config.json b/frameworks/Ruby/sinatra/benchmark_config.json index 0d14929dd67..7bdbb62e853 100644 --- a/frameworks/Ruby/sinatra/benchmark_config.json +++ b/frameworks/Ruby/sinatra/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-puma-mri", + "display_name": "sinatra [puma, mysql]", "versus": "rack-puma-mri", "notes": "" }, @@ -40,7 +40,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-postgres-puma-mri", + "display_name": "sinatra [puma, postgres]", "versus": "rack-postgres-puma-mri", "notes": "" }, @@ -62,7 +62,7 @@ "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-postgres-iodine-mri", + "display_name": "sinatra [iodine, postgres]", "versus": "rack-postgres-iodine-mri", "notes": "" } From d62d2941db9b663732ab9bb82ff0fdd631730445 Mon Sep 17 00:00:00 2001 From: Diogo Martins <165835485+MDA2AV@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:55:10 +0000 Subject: [PATCH 005/130] Add Unhinged adapter with genhttp (#10247) * Add Unhinged adapter with genhttp * Update Unhinged to 9.0.5 * Update dependencies, unhinged to micro, added http parsing and routing --- frameworks/CSharp/wiredio/UnhGHttp/Program.cs | 40 +++++++++++++++++++ .../CSharp/wiredio/UnhGHttp/UnhGHttp.csproj | 23 +++++++++++ .../CSharp/wiredio/benchmark_config.json | 25 ++++++++++-- frameworks/CSharp/wiredio/config.toml | 16 +++++++- .../wiredio/src/Platform/Platform.csproj | 2 +- .../CSharp/wiredio/src/Platform/Program.cs | 11 +++-- .../CSharp/wiredio/wiredio-gen.dockerfile | 24 +++++++++++ ...-plt.dockerfile => wiredio-mcr.dockerfile} | 0 8 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 frameworks/CSharp/wiredio/UnhGHttp/Program.cs create mode 100644 frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj create mode 100644 frameworks/CSharp/wiredio/wiredio-gen.dockerfile rename frameworks/CSharp/wiredio/{wiredio-plt.dockerfile => wiredio-mcr.dockerfile} (100%) diff --git a/frameworks/CSharp/wiredio/UnhGHttp/Program.cs b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs new file mode 100644 index 00000000000..82acdd926d6 --- /dev/null +++ b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs @@ -0,0 +1,40 @@ +using System.Text.Json; +using GenHTTP.Api.Protocol; +using GenHTTP.Modules.IO; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.Layouting.Provider; +using Unhinged; +using Unhinged.GenHttp.Experimental; + +internal class Program +{ + public static void Main(string[] args) + { + var builder = UnhingedEngine + .CreateBuilder() + .SetNWorkersSolver(() => Environment.ProcessorCount / 2) + .SetBacklog(16384) + .SetMaxEventsPerWake(512) + .SetMaxNumberConnectionsPerWorker(512) + .SetPort(8080) + .SetSlabSizes(32 * 1024, 16 * 1024) + .Map(CreateLayoutBuilder()); + + var engine = builder.Build(); + engine.Run(); + } + + private static LayoutBuilder CreateLayoutBuilder() => + Layout + .Create() + .Add("/plaintext", Content.From(Resource.FromString("Hello, World!"))) + + .Add("/json", Content.From( + Resource.FromString(JsonSerializer.Serialize(new JsonMessage { message = "Hello, World!" })) + .Type(new FlexibleContentType("application/json")))); +} + +public class JsonMessage +{ + public string message { get; set; } +} \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj b/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj new file mode 100644 index 00000000000..09308ff4747 --- /dev/null +++ b/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj @@ -0,0 +1,23 @@ + + + + Exe + net9.0 + enable + enable + + true + true + true + true + + linux-musl-x64 + + + + + + + + + diff --git a/frameworks/CSharp/wiredio/benchmark_config.json b/frameworks/CSharp/wiredio/benchmark_config.json index e74c7696415..50fcb4cd13f 100644 --- a/frameworks/CSharp/wiredio/benchmark_config.json +++ b/frameworks/CSharp/wiredio/benchmark_config.json @@ -20,12 +20,12 @@ "display_name": "Wired.IO", "notes": "Only plaintext and JSON benchmarks implemented yet" }, - "plt": { + "mcr": { "plaintext_url": "/plaintext", "json_url": "/json", "port": 8080, "approach": "Realistic", - "classification": "Platform", + "classification": "Micro", "database": "None", "framework": "Unhinged", "language": "C#", @@ -34,8 +34,25 @@ "webserver": "Unhinged", "os": "Linux", "database_os": "Linux", - "display_name": "Wired.IO [Unhinged]", - "notes": "Not a framework" + "display_name": "Unhinged", + "notes": "epoll" + }, + "gen": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "GenHttp", + "language": "C#", + "orm": "None", + "platform": ".NET", + "webserver": "Unhinged", + "os": "Linux", + "database_os": "Linux", + "display_name": "genhttp [Unhinged]", + "notes": "Adapter" } } ] diff --git a/frameworks/CSharp/wiredio/config.toml b/frameworks/CSharp/wiredio/config.toml index fe292c91330..b418d57d861 100644 --- a/frameworks/CSharp/wiredio/config.toml +++ b/frameworks/CSharp/wiredio/config.toml @@ -13,11 +13,23 @@ platform = ".NET" webserver = "Wired.IO" versus = "None" -[plt] +[mcr] urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" -classification = "Platform" +classification = "Micro" +os = "Linux" +database_os = "Linux" +orm = "None" +platform = ".NET" +webserver = "Unhinged" +versus = "None" + +[gen] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" os = "Linux" database_os = "Linux" orm = "None" diff --git a/frameworks/CSharp/wiredio/src/Platform/Platform.csproj b/frameworks/CSharp/wiredio/src/Platform/Platform.csproj index f560113a9f5..16ae7e90e4c 100644 --- a/frameworks/CSharp/wiredio/src/Platform/Platform.csproj +++ b/frameworks/CSharp/wiredio/src/Platform/Platform.csproj @@ -20,6 +20,6 @@ - + diff --git a/frameworks/CSharp/wiredio/src/Platform/Program.cs b/frameworks/CSharp/wiredio/src/Platform/Program.cs index a572a456ae9..24a76794d6e 100644 --- a/frameworks/CSharp/wiredio/src/Platform/Program.cs +++ b/frameworks/CSharp/wiredio/src/Platform/Program.cs @@ -58,14 +58,19 @@ public static void Main(string[] args) engine.Run(); } - private static void RequestHandler(Connection connection) + private const string Json = "/json"; + private const string PlainText = "/plaintext"; + + private static ValueTask RequestHandler(Connection connection) { // FNV-1a Hashed routes to avoid string allocations - if(connection.HashedRoute == 291830056) // /json + if(connection.H1HeaderData.Route == Json) // /json CommitJsonResponse(connection); - else if (connection.HashedRoute == 3454831873) // /plaintext + else if (connection.H1HeaderData.Route == PlainText) // /plaintext CommitPlainTextResponse(connection); + + return ValueTask.CompletedTask; } [ThreadStatic] private static Utf8JsonWriter? t_utf8JsonWriter; diff --git a/frameworks/CSharp/wiredio/wiredio-gen.dockerfile b/frameworks/CSharp/wiredio/wiredio-gen.dockerfile new file mode 100644 index 00000000000..5436527f964 --- /dev/null +++ b/frameworks/CSharp/wiredio/wiredio-gen.dockerfile @@ -0,0 +1,24 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY UnhGHttp/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY UnhGHttp/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine + +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 + +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["./UnhGHttp"] + +EXPOSE 8080 diff --git a/frameworks/CSharp/wiredio/wiredio-plt.dockerfile b/frameworks/CSharp/wiredio/wiredio-mcr.dockerfile similarity index 100% rename from frameworks/CSharp/wiredio/wiredio-plt.dockerfile rename to frameworks/CSharp/wiredio/wiredio-mcr.dockerfile From a06834659ae6b282b180a75f1db1c02d48316675 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 6 Nov 2025 21:55:45 +0100 Subject: [PATCH 006/130] [ruby/rack] Require ERB explicitly (#10248) Avoids the following warning when running just the fortune tests: \# Date: Thu, 6 Nov 2025 21:56:10 +0100 Subject: [PATCH 007/130] [ruby/rack] Remove unused method and option (#10249) select_random_numbers and sql_log_level don't seem to get used. --- frameworks/Ruby/rack/pg_db.rb | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/frameworks/Ruby/rack/pg_db.rb b/frameworks/Ruby/rack/pg_db.rb index bcaa1dad480..51a38cadc85 100644 --- a/frameworks/Ruby/rack/pg_db.rb +++ b/frameworks/Ruby/rack/pg_db.rb @@ -18,7 +18,7 @@ class PgDb attr_reader :connection def initialize(connection_string = nil, max_connections = 512) - @connection = Sequel.connect(connection_string, max_connections: max_connections, sql_log_level: :warning) + @connection = Sequel.connect(connection_string, max_connections: max_connections) Sequel.extension :fiber_concurrency if defined?(Falcon) prepare_statements @@ -53,13 +53,6 @@ def select_promises(count) end end - def select_random_numbers(count) - count = validate_count(count) - ALL_IDS.sample(count).map do |id| - @world_random_select.call(randomvalue: random_id, id: id).first - end - end - def select_worlds(count) count = validate_count(count) ALL_IDS.sample(count).map do |id| @@ -78,8 +71,7 @@ def update_worlds(count, async = false) else select_worlds(count) end - #values = [] - ids=[] + ids = [] sql = String.new("UPDATE world SET randomnumber = CASE id ") results.each do |r| r[:randomnumber] = random_id From f9b5e791c079b412f6a5e7ccb2ab56c830b44d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=88=80?= Date: Fri, 7 Nov 2025 04:56:32 +0800 Subject: [PATCH 008/130] update feat version (#10251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 适配最新版 * upgrade smart-socket * upgrade smart-socket * upgrade smart-socket * upgrade smart-socket * upgrade feat * upgrade feat * upgrade feat * upgrade feat * upgrade feat * upgrade feat * upgrade feat * upgrade feat --- frameworks/Java/smart-socket/feat-smart-servlet.dockerfile | 2 +- frameworks/Java/smart-socket/feat.dockerfile | 2 +- frameworks/Java/smart-socket/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile b/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile index 4209283ec42..7ec765572a8 100644 --- a/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile +++ b/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn install -q -FROM openjdk:21-jdk-slim +FROM amazoncorretto:25.0.1-alpine WORKDIR /smart-socket COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0.jar app.jar diff --git a/frameworks/Java/smart-socket/feat.dockerfile b/frameworks/Java/smart-socket/feat.dockerfile index f7eaec61f67..e21235baa58 100644 --- a/frameworks/Java/smart-socket/feat.dockerfile +++ b/frameworks/Java/smart-socket/feat.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn install -q -FROM openjdk:21-jdk-slim +FROM amazoncorretto:25.0.1-alpine WORKDIR /smart-socket COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0.jar app.jar diff --git a/frameworks/Java/smart-socket/pom.xml b/frameworks/Java/smart-socket/pom.xml index 7cf9b85b3e7..171f036e654 100644 --- a/frameworks/Java/smart-socket/pom.xml +++ b/frameworks/Java/smart-socket/pom.xml @@ -20,7 +20,7 @@ tech.smartboot.feat feat-cloud-starter - 1.1.0-SNAPSHOT + 1.3.2-SNAPSHOT From 65fc874dad60351b8634bba3d8442da12b0522db Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Fri, 7 Nov 2025 18:59:53 +0000 Subject: [PATCH 009/130] toolset: Reduce the packages installed by APT (#10253) Make sure that APT does not install anything unnecessary. Signed-off-by: Anton Kirilov --- Dockerfile | 5 +++-- entrypoint.sh | 2 +- toolset/__init__.py | 0 toolset/continuous/tfb-shutdown.sh | 0 toolset/continuous/tfb-startup.sh | 0 toolset/scaffolding/README.md | 0 toolset/scaffolding/benchmark_config.json | 0 toolset/utils/__init__.py | 0 toolset/utils/benchmark_config.py | 0 toolset/utils/output_helper.py | 0 toolset/utils/scaffolding.py | 0 toolset/wrk/concurrency.sh | 0 toolset/wrk/pipeline.sh | 0 toolset/wrk/query.sh | 0 toolset/wrk/wrk.dockerfile | 6 +----- 15 files changed, 5 insertions(+), 8 deletions(-) mode change 100755 => 100644 toolset/__init__.py mode change 100644 => 100755 toolset/continuous/tfb-shutdown.sh mode change 100644 => 100755 toolset/continuous/tfb-startup.sh mode change 100755 => 100644 toolset/scaffolding/README.md mode change 100755 => 100644 toolset/scaffolding/benchmark_config.json mode change 100755 => 100644 toolset/utils/__init__.py mode change 100755 => 100644 toolset/utils/benchmark_config.py mode change 100755 => 100644 toolset/utils/output_helper.py mode change 100755 => 100644 toolset/utils/scaffolding.py mode change 100644 => 100755 toolset/wrk/concurrency.sh mode change 100644 => 100755 toolset/wrk/pipeline.sh mode change 100644 => 100755 toolset/wrk/query.sh diff --git a/Dockerfile b/Dockerfile index 0e60a78d94c..c02bb66c087 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,10 +4,11 @@ ARG DEBIAN_FRONTEND=noninteractive # WARNING: DON'T PUT A SPACE AFTER ANY BACKSLASH OR APT WILL BREAK # One -q produces output suitable for logging (mostly hides # progress indicators) -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ -o Dpkg::Options::="--force-confdef" \ -o Dpkg::Options::="--force-confold" \ + -qqUy \ cloc \ curl \ gcc \ diff --git a/entrypoint.sh b/entrypoint.sh index 71ad543e960..eb22e6e75d7 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,4 +4,4 @@ set -eo pipefail -u chown -LR "$USER_ID" /var/run # Drop permissions of user to match those of the host system -gosu "$USER_ID" python3 "${FWROOT}/toolset/run-tests.py" "$@" +exec gosu "$USER_ID" python3 "${FWROOT}/toolset/run-tests.py" "$@" diff --git a/toolset/__init__.py b/toolset/__init__.py old mode 100755 new mode 100644 diff --git a/toolset/continuous/tfb-shutdown.sh b/toolset/continuous/tfb-shutdown.sh old mode 100644 new mode 100755 diff --git a/toolset/continuous/tfb-startup.sh b/toolset/continuous/tfb-startup.sh old mode 100644 new mode 100755 diff --git a/toolset/scaffolding/README.md b/toolset/scaffolding/README.md old mode 100755 new mode 100644 diff --git a/toolset/scaffolding/benchmark_config.json b/toolset/scaffolding/benchmark_config.json old mode 100755 new mode 100644 diff --git a/toolset/utils/__init__.py b/toolset/utils/__init__.py old mode 100755 new mode 100644 diff --git a/toolset/utils/benchmark_config.py b/toolset/utils/benchmark_config.py old mode 100755 new mode 100644 diff --git a/toolset/utils/output_helper.py b/toolset/utils/output_helper.py old mode 100755 new mode 100644 diff --git a/toolset/utils/scaffolding.py b/toolset/utils/scaffolding.py old mode 100755 new mode 100644 diff --git a/toolset/wrk/concurrency.sh b/toolset/wrk/concurrency.sh old mode 100644 new mode 100755 diff --git a/toolset/wrk/pipeline.sh b/toolset/wrk/pipeline.sh old mode 100644 new mode 100755 diff --git a/toolset/wrk/query.sh b/toolset/wrk/query.sh old mode 100644 new mode 100755 diff --git a/toolset/wrk/wrk.dockerfile b/toolset/wrk/wrk.dockerfile index 9bcf42f7b38..772fe3268fa 100644 --- a/toolset/wrk/wrk.dockerfile +++ b/toolset/wrk/wrk.dockerfile @@ -4,11 +4,7 @@ FROM ubuntu:24.04 COPY concurrency.sh pipeline.lua pipeline.sh query.sh ./ ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get -yqq update >/dev/null && \ - apt-get -yqq install >/dev/null \ - curl \ - wrk && \ - chmod 777 concurrency.sh pipeline.sh query.sh +RUN apt-get install --no-install-recommends -qqUy curl wrk > /dev/null # Environment vars required by the wrk scripts with nonsense defaults ENV accept=accept \ From eeda59f5331f1f59df71a40c0665ab55067776ce Mon Sep 17 00:00:00 2001 From: Hassan Sharara <167939195+HassanSharara@users.noreply.github.com> Date: Tue, 11 Nov 2025 19:47:21 +0300 Subject: [PATCH 010/130] Add water-http framework (#10255) * Add water-http framework * benchmark_config.json update --- frameworks/Rust/water-http/.gitignore | 3 + frameworks/Rust/water-http/Cargo.toml | 45 +++ frameworks/Rust/water-http/README | 39 +++ .../Rust/water-http/benchmark_config.json | 90 +++++ frameworks/Rust/water-http/src/cached.rs | 305 +++++++++++++++++ frameworks/Rust/water-http/src/db.rs | 320 ++++++++++++++++++ frameworks/Rust/water-http/src/json.rs | 55 +++ frameworks/Rust/water-http/src/main.rs | 7 + frameworks/Rust/water-http/src/models.rs | 25 ++ frameworks/Rust/water-http/src/plaintext.rs | 54 +++ frameworks/Rust/water-http/src/server.rs | 290 ++++++++++++++++ .../Rust/water-http/templates/fortune.hbs | 5 + .../Rust/water-http/templates/fortune.html | 12 + .../water-http/water-http-cached.dockerfile | 13 + .../Rust/water-http/water-http-db.dockerfile | 13 + .../water-http/water-http-json.dockerfile | 13 + .../water-http-plaintext.dockerfile | 13 + .../Rust/water-http/water-http.dockerfile | 13 + 18 files changed, 1315 insertions(+) create mode 100644 frameworks/Rust/water-http/.gitignore create mode 100644 frameworks/Rust/water-http/Cargo.toml create mode 100644 frameworks/Rust/water-http/README create mode 100644 frameworks/Rust/water-http/benchmark_config.json create mode 100644 frameworks/Rust/water-http/src/cached.rs create mode 100644 frameworks/Rust/water-http/src/db.rs create mode 100644 frameworks/Rust/water-http/src/json.rs create mode 100644 frameworks/Rust/water-http/src/main.rs create mode 100644 frameworks/Rust/water-http/src/models.rs create mode 100644 frameworks/Rust/water-http/src/plaintext.rs create mode 100644 frameworks/Rust/water-http/src/server.rs create mode 100644 frameworks/Rust/water-http/templates/fortune.hbs create mode 100644 frameworks/Rust/water-http/templates/fortune.html create mode 100644 frameworks/Rust/water-http/water-http-cached.dockerfile create mode 100644 frameworks/Rust/water-http/water-http-db.dockerfile create mode 100644 frameworks/Rust/water-http/water-http-json.dockerfile create mode 100644 frameworks/Rust/water-http/water-http-plaintext.dockerfile create mode 100644 frameworks/Rust/water-http/water-http.dockerfile diff --git a/frameworks/Rust/water-http/.gitignore b/frameworks/Rust/water-http/.gitignore new file mode 100644 index 00000000000..2da6cdebaac --- /dev/null +++ b/frameworks/Rust/water-http/.gitignore @@ -0,0 +1,3 @@ +target +Cargo.lock +.idea \ No newline at end of file diff --git a/frameworks/Rust/water-http/Cargo.toml b/frameworks/Rust/water-http/Cargo.toml new file mode 100644 index 00000000000..fe22c5a9a68 --- /dev/null +++ b/frameworks/Rust/water-http/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "water-http" +version = "0.1.0" +edition = "2018" + +[dependencies] +askama = "0.14.0" +tokio = { version = "1.47.1", features = ["full"] } +water_http = {git = "https://github.com/HassanSharara/water_http.git", branch = "beta", features = ["use_only_http1"],optional = true , version = "3.0.8-beta.5" } +smallvec = "1.15.1" +nanorand = "0.8.0" +tokio-postgres = "0.7.15" +sonic-rs = "0.5.5" +bytes = "1.10.1" +serde = { version = "1.0.228", features = ["derive","rc"] } +futures-util = "0.3.31" +num_cpus = "1.17.0" +httpdate = "1.0.3" +parking_lot = "0.12.5" +yarte = { version = "0.15.7" ,features = ["bytes-buf", "json"] } +itoa = {version = "1.0.15" ,optional = true} + + +[[bin]] +name = "plaintext" +path = "src/plaintext.rs" +required-features = ["json_plaintext"] + +[[bin]] +name = "json" +path = "src/json.rs" +required-features = ["json_plaintext"] + + +[[bin]] +name = "cache" +path = "src/cached.rs" +required-features = ["cache"] + + +[features] +json_plaintext = ["water_http"] +db = ["water_http/thread_shared_struct"] +cache = ["water_http/thread_shared_struct","itoa"] +all = ["water_http/thread_shared_struct"] diff --git a/frameworks/Rust/water-http/README b/frameworks/Rust/water-http/README new file mode 100644 index 00000000000..67e4ecc228a --- /dev/null +++ b/frameworks/Rust/water-http/README @@ -0,0 +1,39 @@ +🌊 Water HTTP — TechEmpower Benchmarks + +Water HTTP is a high-performance Rust web framework built and optimized for the TechEmpower Framework Benchmarks (TFB) +. It is designed to push the limits of speed, stability, and scalability using pure asynchronous Rust and Tokio’s runtime. Every part of the framework is hand-tuned to achieve predictable latency, minimal allocations, and efficient CPU utilization under extreme concurrency. + +This repository contains the official benchmark implementations for all test types, including Plaintext, JSON serialization, Single query, Multiple queries, Fortunes, Database updates, and Cached queries. + +⚡ Highlights + +🚀 One of the fastest and most stable frameworks in the TechEmpower Benchmarks + +🧵 Built entirely on Tokio’s asynchronous runtime — no io_uring or unsafe code + +💾 Zero-copy I/O, preallocated buffers, and predictable memory layout + +🔒 100% safe Rust with no hidden synchronization overhead + +🧱 Designed for consistent high performance at scale + + +🧠 Architecture + +Water HTTP is built around a fully asynchronous, event-driven architecture that leverages non-blocking I/O and efficient request processing. The system is designed to eliminate unnecessary locks and minimize latency even under heavy load. + +[ tokio::net::TcpListener ] + ↓ + [ connection handler ] + ↓ + [ water::http::parser ] + ↓ + [ application logic ] + ↓ + [ response encoder ] +This approach ensures optimal throughput and minimal per-request overhead while keeping code simple and safe. + + +🧭 Mission + +Water HTTP’s mission is to demonstrate how Rust’s async ecosystem can reach record-breaking performance without compromising simplicity, safety, or maintainability. It shows that carefully engineered async Rust can deliver unmatched speed and reliability in real-world workloads, setting a new standard for what modern web frameworks can achieve. diff --git a/frameworks/Rust/water-http/benchmark_config.json b/frameworks/Rust/water-http/benchmark_config.json new file mode 100644 index 00000000000..2b28f0476a3 --- /dev/null +++ b/frameworks/Rust/water-http/benchmark_config.json @@ -0,0 +1,90 @@ +{ + "framework": "water-http", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http" + }, + + "db": { + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http" + }, + + "cached": { + "cached_query_url": "/cached-queries?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http" + }, + "json": { + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http" + }, + "plaintext": { + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/cached.rs b/frameworks/Rust/water-http/src/cached.rs new file mode 100644 index 00000000000..6e1cea1a77f --- /dev/null +++ b/frameworks/Rust/water-http/src/cached.rs @@ -0,0 +1,305 @@ +#![allow(static_mut_refs)] +use std::io; +use std::fmt::Arguments; +use std::io::Write; +use std::mem::MaybeUninit; +use std::rc::Rc; +use std::cell::UnsafeCell; +use std::collections::HashMap; +use nanorand::{Rng, WyRand}; +use tokio_postgres::{connect, Client, NoTls}; +use tokio_postgres::types::private::BytesMut; +use sonic_rs::prelude::WriteExt; +use std::pin::Pin; +use tokio::task::LocalSet; +use water_http::{InitControllersRoot, RunServer, WaterController}; +use water_http::http::{HttpSender, ResponseData}; +use water_http::server::{HttpContext, ServerConfigurations}; +use water_http::http::HttpSenderTrait; + +pub struct DbConnectionPool { + pub connections: Vec>, + pub next: UnsafeCell, +} + +impl DbConnectionPool { + /// Get a connection from the pool (round-robin, relaxed ordering) + #[inline(always)] + pub fn get_connection(&self) -> &Rc { + let n = unsafe{&mut *self.next.get()}; + *n +=1; + let idx = *n % self.connections.len(); + unsafe { self.connections.get_unchecked(idx) } + } + + /// Fill the pool with connections + pub async fn fill_pool(&mut self, url: &'static str, size: usize) { + let mut tasks = Vec::with_capacity(size); + for _ in 0..size { + tasks.push(tokio::task::spawn_local(async move { + for attempt in 0..5 { + match PgConnection::connect(url).await { + Ok(conn) => { + + return Ok(conn); }, + Err(_) if attempt < 4 => { + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + } + Err(_) => return Err(()), + } + } + Err(()) + })); + } + for t in tasks { + if let Ok(Ok(conn)) = t.await { + self.connections.push(Rc::new(conn)); + } + } + } + + +} + + + + +pub struct PgConnection { + cl:Client, + _connection_task: tokio::task::JoinHandle<()>, +} + +// Safety: Only used within LocalSet, no cross-thread access +impl PgConnection { + /// Connect to the database + + pub async fn connect(db_url: &str) -> Result { + let (cl, c) = tokio::time::timeout( + std::time::Duration::from_secs(5), + connect(db_url, NoTls), + ) + .await + .map_err(|_| ())? + .map_err(|_| ())?; + + let connection_task = tokio::task::spawn_local(async move { + let _ = c.await; + }); + + Ok(PgConnection { + _connection_task: connection_task, + cl + }) + } +} + +/// Zero-copy writer for BytesMut +pub struct BytesMuteWriter<'a>(pub &'a mut BytesMut); + +impl BytesMuteWriter<'_> { + + #[inline(always)] + pub fn extend_from_slice(&mut self,data:&[u8]){ + self.0.extend_from_slice(data); + } +} + +impl Write for BytesMuteWriter<'_> { + #[inline(always)] + fn write(&mut self, src: &[u8]) -> Result { + self.0.extend_from_slice(src); + Ok(src.len()) + } + + #[inline(always)] + fn flush(&mut self) -> Result<(), io::Error> { + Ok(()) + } +} + +impl std::fmt::Write for BytesMuteWriter<'_> { + #[inline(always)] + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.0.extend_from_slice(s.as_bytes()); + Ok(()) + } + + #[inline(always)] + fn write_char(&mut self, c: char) -> std::fmt::Result { + let mut buf = [0u8; 4]; + self.0.extend_from_slice(c.encode_utf8(&mut buf).as_bytes()); + Ok(()) + } + + #[inline(always)] + fn write_fmt(&mut self, args: Arguments<'_>) -> std::fmt::Result { + std::fmt::write(self, args) + } +} + +impl WriteExt for BytesMuteWriter<'_> { + #[inline(always)] + fn reserve_with(&mut self, additional: usize) -> Result<&mut [MaybeUninit], io::Error> { + self.0.reserve(additional); + unsafe { + let ptr = self.0.as_mut_ptr().add(self.0.len()) as *mut MaybeUninit; + Ok(std::slice::from_raw_parts_mut(ptr, additional)) + } + } + + #[inline(always)] + unsafe fn flush_len(&mut self, additional: usize) -> io::Result<()> { + self.0.set_len(self.0.len() + additional); + Ok(()) + } +} + + +InitControllersRoot! { + name:ROOT, + holder_type:MainType, + shared_type:SH, +} + +pub struct ThreadSharedStruct{ + writing_buffer:UnsafeCell, + rng:WyRand, +} + + +impl ThreadSharedStruct { + + #[inline(always)] + pub fn get_value(id:i32)->&'static i32{ + let map = unsafe {CACHED_VALUES.as_ref().unwrap().get(&id)} ; + map.unwrap() + } + pub fn get_cached_queries(&self,num:usize)->&[u8]{ + let buf = unsafe{&mut *(self.writing_buffer.get())}; + buf.clear(); + buf.extend_from_slice(br#"["#); + let mut writer = BytesMuteWriter(buf); + let mut rn = self.rng.clone(); + for _ in 0..num { + let rd: i32 = (rn.generate::() & 0x3FFF) as i32 % 10_000 + 1; + let v = Self::get_value(rd); + writer.extend_from_slice(br"{"); + _ = write!(writer, r#""id":{},"randomnumber":{}"#, rd, v); + writer.extend_from_slice(br"},"); + } + if buf.len() >1 {buf.truncate(buf.len() - 1);} + buf.extend_from_slice(b"]"); + return &buf[..] + } +} + +pub type MainType = u8; +pub type SH = Rc; + + +static mut CACHED_VALUES:Option> = None; + +pub fn run_server(){ + + _= std::thread::spawn( + ||{ + let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(); + rt.block_on(async move { + const URL:&'static str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; + // const URL:&'static str = "postgres://postgres:root@localhost:5432/techmpower"; + + let mut pool = DbConnectionPool{ + connections:Vec::with_capacity( 1 + ), + next:0.into(), + // rt:tokio::runtime::Builder::new_multi_thread().enable_all().worker_threads(cpu_nums).build().unwrap() + }; + + let local_set = LocalSet::new(); + + _= local_set.run_until(async move { + tokio::task::spawn_local(async move { + pool.fill_pool(URL, 1).await; + let connection = pool.get_connection(); + let statement = connection.cl.prepare("SELECT id,randomnumber FROM World").await.unwrap(); + let res = connection.cl.query(&statement,&[]).await.unwrap(); + let mut map = HashMap::new(); + for row in res { + map.insert(row.get(0),row.get(1)); + } + unsafe { + let static_map = &mut CACHED_VALUES; + *static_map = Some(map); + } + }).await + }).await; + + }); + } + ).join(); + let cpu_nums = num_cpus::get(); + + + println!("start listening on port 8080 while workers count {cpu_nums}"); + let mut conf = ServerConfigurations::bind("0.0.0.0",8080); + conf.worker_threads_count = cpu_nums * 1 ; + + // let addresses = (0..cpu_nums).map(|_| { + // ("0.0.0.0".to_string(),8080) + // }).collect::>(); + // conf.addresses = addresses; + RunServer!( + conf, + ROOT, + EntryController, + shared_factory + ); +} + +fn shared_factory()->Pin>>{ + Box::pin(async { + + // const URL:&'static str = "postgres://postgres:root@localhost:5432/techmpower"; + + Rc::new(ThreadSharedStruct{ + writing_buffer:UnsafeCell::new(BytesMut::with_capacity(100_000)), + rng:WyRand::new() + }) + }) +} + +pub async fn handle_cached_queries(context:&mut HttpContext<'_,MainType,SH,HS,QS>){ + let q = context + .get_from_path_query("q") + .and_then(|v| v.parse::().ok()) // safely parse + .unwrap_or(1) // default to 1 if missing or invalid + .clamp(1, 500); + + let connection:SH = context.thread_shared_struct.clone().unwrap().clone(); + let data = connection.get_cached_queries(q); + let mut sender:HttpSender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + ResponseData::Slice(data) + ).await; +} + +WaterController! { + holder -> super::MainType, + shared -> super::SH, + name -> EntryController, + functions -> { + + GET -> "cached-queries" -> query (context) { + _=super::handle_cached_queries(context).await; + } + } +} + +fn main() { + run_server(); +} + diff --git a/frameworks/Rust/water-http/src/db.rs b/frameworks/Rust/water-http/src/db.rs new file mode 100644 index 00000000000..40640735f88 --- /dev/null +++ b/frameworks/Rust/water-http/src/db.rs @@ -0,0 +1,320 @@ +#![cfg(any(feature = "db",feature = "all"))] +use std::{borrow::Cow, io}; +use std::fmt::Arguments; +use std::io::Write; +use std::mem::MaybeUninit; +use std::rc::Rc; +use std::cell::UnsafeCell; +use bytes::Buf; +use nanorand::{Rng, WyRand}; +use tokio_postgres::{connect, Client, Statement, NoTls}; +use tokio_postgres::types::private::BytesMut; +use crate::models::{Fortune, FortuneTemplate, World}; +use sonic_rs::prelude::WriteExt; +use yarte::TemplateBytesTrait; + +/// Database connection pool with thread-local RNG +pub struct DbConnectionPool { + pub connections: Vec>, + pub next: UnsafeCell, +} + +impl DbConnectionPool { + /// Get a connection from the pool (round-robin, relaxed ordering) + #[inline(always)] + pub fn get_connection(&self) -> &Rc { + let n = unsafe{&mut *self.next.get()}; + *n +=1; + let idx = *n % self.connections.len(); + unsafe { self.connections.get_unchecked(idx) } + } + + /// Fill the pool with connections + pub async fn fill_pool(&mut self, url: &'static str, size: usize) { + let mut tasks = Vec::with_capacity(size); + for _ in 0..size { + tasks.push(tokio::task::spawn_local(async move { + for attempt in 0..5 { + match PgConnection::connect(url).await { + Ok(conn) => { + + return Ok(conn); }, + Err(_) if attempt < 4 => { + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + } + Err(_) => return Err(()), + } + } + Err(()) + })); + } + for t in tasks { + if let Ok(Ok(conn)) = t.await { + self.connections.push(Rc::new(conn)); + } + } + } +} + + +/// Reusable buffer pool per connection +struct BufferPool { + body: BytesMut, + worlds: Vec, + numbers: Vec, + fortunes: Vec, + fortune_output: Vec, +} + +impl BufferPool { + fn new() -> Self { + Self { + body: BytesMut::with_capacity(4096), + worlds: Vec::with_capacity(501), + numbers: Vec::with_capacity(501), + + fortunes: Vec::with_capacity(501), + fortune_output: Vec::with_capacity(4096), + } + } + +} + +/// PostgreSQL connection wrapper with pre-allocated buffers +pub struct PgConnection { + pub cl: Client, + pub fortune: Statement, + pub world: Statement, + pub updates: Vec, + rang:WyRand, + buffers: UnsafeCell, + _connection_task: tokio::task::JoinHandle<()>, +} + +// Safety: Only used within LocalSet, no cross-thread access +impl PgConnection { + /// Connect to the database + + pub async fn connect(db_url: &str) -> Result { + let (cl, conn) = tokio::time::timeout( + std::time::Duration::from_secs(5), + connect(db_url, NoTls), + ) + .await + .map_err(|_| ())? + .map_err(|_| ())?; + + let connection_task = tokio::task::spawn_local(async move { + let _ = conn.await; + }); + + let fortune = cl.prepare("SELECT * FROM fortune").await.map_err(|_| ())?; + let world = cl.prepare("SELECT id,randomnumber FROM world WHERE id=$1 LIMIT 1").await.map_err(|_| ())?; + + // Pre-compile update statements for batch sizes 1-500 + let mut updates = vec![]; + for num in 1..=500 { + let sql = Self::generate_update_values_stmt(num); + updates.push(cl.prepare(&sql).await.unwrap()); + } + + Ok(PgConnection { + cl, + fortune, + world, + updates, + buffers: UnsafeCell::new(BufferPool::new()), + _connection_task: connection_task, + rang: WyRand::new() + }) + } /// Connect to the database + + #[inline(always)] + pub fn generate_update_values_stmt(batch_size: usize) -> String { + + let mut sql = String::from("UPDATE world SET randomNumber = w.r FROM (VALUES "); + + for i in 0..batch_size { + let id_param = i * 2 + 1; + let val_param = id_param + 1; + sql.push_str(&format!("(${}::int, ${}::int),", id_param, val_param)); + } + + // Remove the trailing comma + sql.pop(); + + sql.push_str(") AS w(i, r) WHERE world.id = w.i"); + sql + } + + /// Get mutable access to buffers (safe because connection pool ensures single access) + #[inline(always)] + fn buffers(&self) -> &mut BufferPool { + unsafe { &mut *self.buffers.get() } + } + + /// Get a single random world - optimized with buffer reuse + #[inline] + pub async fn get_world(&self) -> &[u8] { + let rd = (self.rang.clone().generate::() % 10_000 + 1) as i32; + let row = self.cl.query_one(&self.world, &[&rd]).await.unwrap(); + + let buffers = self.buffers(); + buffers.body.clear(); + + sonic_rs::to_writer( + BytesMuteWriter(&mut buffers.body), + &World { + id: row.get(0), + randomnumber: row.get(1), + }, + ).unwrap(); + + buffers.body.chunk() + } + + /// Get multiple random worlds - optimized with buffer reuse + pub async fn get_worlds(&self, num: usize) -> &[u8] { + let buffers = self.buffers(); + buffers.worlds.clear(); + let mut rn = self.rang.clone(); + for _ in 0..num { + let id: i32 = (rn.generate::() & 0x3FFF) as i32 % 10_000 + 1; + let row = self.cl.query_one(&self.world, &[&id]).await.unwrap(); + buffers.worlds.push(World { + id: row.get(0), + randomnumber: row.get(1), + }); + } + buffers.body.clear(); + sonic_rs::to_writer(BytesMuteWriter(&mut buffers.body), &buffers.worlds).unwrap(); + buffers.body.chunk() + } + /// Update worlds in batch - optimized with buffer reuse + /// Update worlds in batch - optimized with buffer reuse + + /// Update worlds in batch - optimized with buffer reuse + + /// Update worlds in batch - optimized with buffer reuse + + /// Update worlds in batch - optimized with RETURNING clause to minimize reads + /// Update worlds - fetch and update each row to handle duplicates correctly + /// Update worlds in batch using CASE statement + pub async fn update(&self, num: usize) -> &[u8] { + + let buffers = self.buffers(); + let mut ids:Vec = Vec::with_capacity(num); + let mut rng = self.rang.clone(); + let mut params: Vec<&(dyn tokio_postgres::types::ToSql + Sync)> = + Vec::with_capacity(num * 2); + let mut futures =vec![]; + for _ in 0..num { + let w_id = (rng.generate::() % 10_000 + 1) as i32; + ids.push(w_id); + } + futures.extend(ids.iter().map(|x| async move {self.cl.query_one(&self.world,&[&x]).await})); + futures_util::future::join_all(futures).await; + ids.sort_unstable(); + buffers.worlds.clear(); + for index in 0..num { + let s_id = (rng.generate::() % 10_000 + 1 ) as i32; + buffers.worlds.push(World{ + id:ids[index], + randomnumber:s_id + }); + buffers.numbers.push(s_id); + } + buffers.body.clear(); + for index in 0..num { + params.push(&ids[index]); + params.push(&buffers.numbers[index]); + } + + _=self.cl.execute(&self.updates[num - 1], ¶ms).await.unwrap(); + sonic_rs::to_writer(BytesMuteWriter(&mut buffers.body), &buffers.worlds).unwrap(); + buffers.body.chunk() + } + + + /// Tell fortunes - optimized with buffer reuse + pub async fn tell_fortune(&self) -> Result<&[u8], ()> { + let res = self.cl.query(&self.fortune, &[]).await.map_err(|_| ())?; + + let buffers = self.buffers(); + buffers.fortunes.clear(); + buffers.fortune_output.clear(); + + buffers.fortunes.push(Fortune { + id: 0, + message: Cow::Borrowed("Additional fortune added at request time."), + }); + + for row in res { + buffers.fortunes.push(Fortune { + id: row.get(0), + message: Cow::Owned(row.get(1)), + }); + } + + buffers.fortunes.sort_unstable_by(|a, b| a.message.cmp(&b.message)); + + let template = FortuneTemplate { items: &buffers.fortunes }; + template.write_call(&mut buffers.fortune_output); + + // Return reference to buffer - zero-copy! + Ok(&buffers.fortune_output) + } +} + +/// Zero-copy writer for BytesMut +pub struct BytesMuteWriter<'a>(pub &'a mut BytesMut); + +impl Write for BytesMuteWriter<'_> { + #[inline(always)] + fn write(&mut self, src: &[u8]) -> Result { + self.0.extend_from_slice(src); + Ok(src.len()) + } + + #[inline(always)] + fn flush(&mut self) -> Result<(), io::Error> { + Ok(()) + } +} + +impl std::fmt::Write for BytesMuteWriter<'_> { + #[inline(always)] + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.0.extend_from_slice(s.as_bytes()); + Ok(()) + } + + #[inline(always)] + fn write_char(&mut self, c: char) -> std::fmt::Result { + let mut buf = [0u8; 4]; + self.0.extend_from_slice(c.encode_utf8(&mut buf).as_bytes()); + Ok(()) + } + + #[inline(always)] + fn write_fmt(&mut self, args: Arguments<'_>) -> std::fmt::Result { + std::fmt::write(self, args) + } +} + +impl WriteExt for BytesMuteWriter<'_> { + #[inline(always)] + fn reserve_with(&mut self, additional: usize) -> Result<&mut [MaybeUninit], io::Error> { + self.0.reserve(additional); + unsafe { + let ptr = self.0.as_mut_ptr().add(self.0.len()) as *mut MaybeUninit; + Ok(std::slice::from_raw_parts_mut(ptr, additional)) + } + } + + #[inline(always)] + unsafe fn flush_len(&mut self, additional: usize) -> io::Result<()> { + self.0.set_len(self.0.len() + additional); + Ok(()) + } +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/json.rs b/frameworks/Rust/water-http/src/json.rs new file mode 100644 index 00000000000..71f406b6051 --- /dev/null +++ b/frameworks/Rust/water-http/src/json.rs @@ -0,0 +1,55 @@ +use water_http::{InitControllersRoot, RunServer, WaterController}; +use water_http::server::ServerConfigurations; + +InitControllersRoot! { + name:ROOT, + holder_type:MainType, +} + + + +pub type MainType = u8; + + +fn main() { + run_server(); +} + + +pub fn run_server(){ + + let cpu_nums = num_cpus::get(); + + + println!("start listening on port 8080 while workers count {cpu_nums}"); + let mut conf = ServerConfigurations::bind("0.0.0.0",8080); + conf.worker_threads_count = cpu_nums * 2 ; + + RunServer!( + conf, + ROOT, + EntryController + ); +} + +const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; + + +WaterController! { + holder -> super::MainType, + name -> EntryController, + functions -> { + + + GET => json => j(cx){ + let mut sender = cx.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _=sender.send_data_as_final_response(http::ResponseData::Slice(super::JSON_RESPONSE)).await; + } + + } +} + diff --git a/frameworks/Rust/water-http/src/main.rs b/frameworks/Rust/water-http/src/main.rs new file mode 100644 index 00000000000..487409af1d6 --- /dev/null +++ b/frameworks/Rust/water-http/src/main.rs @@ -0,0 +1,7 @@ +mod server; +pub mod models; +mod db; + +fn main() { + server::run_server(); +} diff --git a/frameworks/Rust/water-http/src/models.rs b/frameworks/Rust/water-http/src/models.rs new file mode 100644 index 00000000000..1fee7283ba9 --- /dev/null +++ b/frameworks/Rust/water-http/src/models.rs @@ -0,0 +1,25 @@ +use std::borrow::Cow; +use sonic_rs::{Serialize}; +// use askama::Template; +#[derive(Serialize)] +pub struct World { + pub id: i32, + pub randomnumber: i32, +} +#[derive(Serialize,Debug)] +pub struct Fortune { + pub id: i32, + pub message: Cow<'static, str>, +} + +#[derive(yarte::TemplateBytes)] +#[template(path = "fortune.hbs")] +pub struct FortuneTemplate<'a>{ + pub items:&'a Vec +} + + + +// pub async fn to(model:FortuneTemplate<'_>){ +// model.r +// } \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/plaintext.rs b/frameworks/Rust/water-http/src/plaintext.rs new file mode 100644 index 00000000000..197da216e9c --- /dev/null +++ b/frameworks/Rust/water-http/src/plaintext.rs @@ -0,0 +1,54 @@ +use water_http::{InitControllersRoot, RunServer, WaterController}; +use water_http::server::ServerConfigurations; + +InitControllersRoot! { + name:ROOT, + holder_type:MainType, +} + + + +pub type MainType = u8; + + +fn main() { + run_server(); +} + + +pub fn run_server(){ + + let cpu_nums = num_cpus::get(); + + + println!("start listening on port 8080 while workers count {cpu_nums}"); + let mut conf = ServerConfigurations::bind("0.0.0.0",8080); + conf.worker_threads_count = cpu_nums * 1 ; + + RunServer!( + conf, + ROOT, + EntryController + ); +} + +const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; +const P:&'static [u8] = br#"Hello, World!"#; + + +WaterController! { + holder -> super::MainType, + name -> EntryController, + functions -> { + + GET => plaintext => p(cx) { + let mut sender = cx.sender(); + sender.set_header_ef("Content-Type","text/plain; charset=utf-8"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _=sender.send_data_as_final_response(http::ResponseData::Str("Hello, World!")).await; + } + } +} + diff --git a/frameworks/Rust/water-http/src/server.rs b/frameworks/Rust/water-http/src/server.rs new file mode 100644 index 00000000000..be464a0e3d6 --- /dev/null +++ b/frameworks/Rust/water-http/src/server.rs @@ -0,0 +1,290 @@ + +use std::pin::Pin; +use std::rc::Rc; +use water_http::{InitControllersRoot, RunServer, WaterController}; +use water_http::server::ServerConfigurations; +use crate::db::{DbConnectionPool}; +InitControllersRoot! { + name:ROOT, + holder_type:MainType, + shared_type:SharedType, +} + +pub struct ThreadSharedStruct{ + pg_connection: DbConnectionPool +} + +pub type MainType = u8; +pub type SharedType = Rc; + + + + +pub fn run_server(){ + + let cpu_nums = num_cpus::get(); + + + println!("start listening on port 8080 while workers count {cpu_nums}"); + let mut conf = ServerConfigurations::bind("0.0.0.0",8080); + #[cfg(feature = "json_plaintext")] + { + conf.worker_threads_count = cpu_nums * 2 ; + } + #[cfg(not(feature = "json_plaintext"))] + { + conf.worker_threads_count = cpu_nums * 1 ; + } + + // let addresses = (0..cpu_nums).map(|_| { + // ("0.0.0.0".to_string(),8080) + // }).collect::>(); + // conf.addresses = addresses; + RunServer!( + conf, + ROOT, + EntryController, + shared_factory + ); +} + +fn shared_factory()->Pin>>{ + Box::pin(async { + + // const URL:&'static str = "postgres://postgres:root@localhost:5432/techmpower"; + const URL:&'static str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; + let mut pool = DbConnectionPool{ + connections:Vec::with_capacity( 1 + ), + next:0.into(), + // rt:tokio::runtime::Builder::new_multi_thread().enable_all().worker_threads(cpu_nums).build().unwrap() + }; + pool.fill_pool(URL, 1).await; + Rc::new(ThreadSharedStruct{ + pg_connection:pool + }) + }) +} + +#[cfg(any(feature = "json_plaintext",feature = "all"))] +const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; +#[cfg(any(feature = "json_plaintext",feature = "all"))] +const P:&'static [u8] = br#"Hello, World!"#; + +#[cfg(feature = "all")] +WaterController! { + holder -> super::MainType, + shared -> super::SharedType, + name -> EntryController, + functions -> { + + + GET => json => j(cx){ + let mut sender = cx.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _=sender.send_data_as_final_response(http::ResponseData::Slice(super::JSON_RESPONSE)).await; + } + + GET => plaintext => p(cx){ + let mut sender = cx.sender(); + sender.set_header_ef("Content-Type","text/plain; charset=utf-8"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _=sender.send_data_as_final_response(http::ResponseData::Slice(super::P)).await; + } + + + GET -> db -> db (context){ + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = connection.get_world().await; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(data) + ).await; + } + GET -> queries -> query (context){ + let q = context + .get_from_path_query("q") + .and_then(|v| v.parse::().ok()) // safely parse + .unwrap_or(1) // default to 1 if missing or invalid + .clamp(1, 500); + + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = connection.get_worlds(q).await; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(data) + ).await; + } + + GET -> updates -> update (context){ + let q = context + .get_from_path_query("q") + .and_then(|v| v.parse::().ok()) // safely parse + .unwrap_or(1) // default to 1 if missing or invalid + .clamp(1, 500); + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = connection.update(q).await; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(data) + ).await; + } + + + GET -> fortunes -> ft (context){ + + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = match connection.tell_fortune().await { + Ok(r)=>{r}, + _=>{ + _= context.send_str("failed to connect").await; + return + } + }; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","text/html; charset=UTF-8"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(&data) + ).await; + } + + } +} + + + +#[cfg(all(not(feature = "all"),feature = "json_plaintext"))] +WaterController! { + holder -> super::MainType, + shared -> super::SharedType, + name -> EntryController, + functions -> { + + + GET => json => j(cx){ + let mut sender = cx.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _=sender.send_data_as_final_response(http::ResponseData::Slice(super::JSON_RESPONSE)).await; + } + + GET => plaintext => p(cx) { + let mut sender = cx.sender(); + sender.set_header_ef("Content-Type","text/plain; charset=utf-8"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _=sender.send_data_as_final_response(http::ResponseData::Slice(super::P)).await; + } + } +} + +#[cfg(all(not(feature = "all"),feature = "db"))] +WaterController! { + holder -> super::MainType, + shared -> super::SharedType, + name -> EntryController, + functions -> { + + + GET -> db -> db (context){ + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = connection.get_world().await; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(data) + ).await; + } + GET -> queries -> query (context){ + let q = context + .get_from_path_query("q") + .and_then(|v| v.parse::().ok()) // safely parse + .unwrap_or(1) // default to 1 if missing or invalid + .clamp(1, 500); + + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = connection.get_worlds(q).await; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(data) + ).await; + } + + GET -> updates -> update (context){ + let q = context + .get_from_path_query("q") + .and_then(|v| v.parse::().ok()) // safely parse + .unwrap_or(1) // default to 1 if missing or invalid + .clamp(1, 500); + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = connection.update(q).await; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","application/json"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(data) + ).await; + } + + + GET -> fortunes -> ft (context){ + + let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); + let connection = connection.pg_connection.get_connection(); + let data = match connection.tell_fortune().await { + Ok(r)=>{r}, + _=>{ + _= context.send_str("failed to connect").await; + return + } + }; + let mut sender = context.sender(); + sender.set_header_ef("Content-Type","text/html; charset=UTF-8"); + sender.set_header_ef("Server","water"); + let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",date); + _= sender.send_data_as_final_response( + http::ResponseData::Slice(&data) + ).await; + } + } +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/templates/fortune.hbs b/frameworks/Rust/water-http/templates/fortune.hbs new file mode 100644 index 00000000000..b219172a075 --- /dev/null +++ b/frameworks/Rust/water-http/templates/fortune.hbs @@ -0,0 +1,5 @@ +Fortunes +{{~# each items ~}} + +{{~/each ~}} +
idmessage
{{id}}{{message}}
diff --git a/frameworks/Rust/water-http/templates/fortune.html b/frameworks/Rust/water-http/templates/fortune.html new file mode 100644 index 00000000000..35923e04b21 --- /dev/null +++ b/frameworks/Rust/water-http/templates/fortune.html @@ -0,0 +1,12 @@ + + +Fortunes + + + + {% for item in items %} + + {% endfor %} +
idmessage
{{item.id}}{{item.message}}
+ + diff --git a/frameworks/Rust/water-http/water-http-cached.dockerfile b/frameworks/Rust/water-http/water-http-cached.dockerfile new file mode 100644 index 00000000000..3c873c71520 --- /dev/null +++ b/frameworks/Rust/water-http/water-http-cached.dockerfile @@ -0,0 +1,13 @@ +FROM rust:latest + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /water +WORKDIR /water + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin cache --features cache + +EXPOSE 8080 + +CMD ./target/release/cache \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-db.dockerfile b/frameworks/Rust/water-http/water-http-db.dockerfile new file mode 100644 index 00000000000..01d9507b35f --- /dev/null +++ b/frameworks/Rust/water-http/water-http-db.dockerfile @@ -0,0 +1,13 @@ +FROM rust:latest + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /water +WORKDIR /water + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin water-http --features db + +EXPOSE 8080 + +CMD ./target/release/water-http \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-json.dockerfile b/frameworks/Rust/water-http/water-http-json.dockerfile new file mode 100644 index 00000000000..4c457496cec --- /dev/null +++ b/frameworks/Rust/water-http/water-http-json.dockerfile @@ -0,0 +1,13 @@ +FROM rust:latest + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /water +WORKDIR /water + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin json --features json_plaintext + +EXPOSE 8080 + +CMD ./target/release/json \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-plaintext.dockerfile b/frameworks/Rust/water-http/water-http-plaintext.dockerfile new file mode 100644 index 00000000000..ab53eb54496 --- /dev/null +++ b/frameworks/Rust/water-http/water-http-plaintext.dockerfile @@ -0,0 +1,13 @@ +FROM rust:latest + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /water +WORKDIR /water + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin plaintext --features json_plaintext + +EXPOSE 8080 + +CMD ./target/release/plaintext \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http.dockerfile b/frameworks/Rust/water-http/water-http.dockerfile new file mode 100644 index 00000000000..5946c8b3821 --- /dev/null +++ b/frameworks/Rust/water-http/water-http.dockerfile @@ -0,0 +1,13 @@ +FROM rust:latest + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /water +WORKDIR /water + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin water-http --features all + +EXPOSE 8080 + +CMD ./target/release/water-http \ No newline at end of file From 5eb97c441a53a7cb21b55021114e5574d6318bfc Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 11 Nov 2025 17:48:01 +0100 Subject: [PATCH 011/130] [ruby] Add rack-app (#10257) rack-app is a minimalist web framework that focuses on simplicity and maintainability. The framework is meant to be used by seasoned web developers. --- frameworks/Ruby/rack-app/Gemfile | 13 ++++ frameworks/Ruby/rack-app/Gemfile.lock | 51 +++++++++++++ frameworks/Ruby/rack-app/README.md | 44 +++++++++++ frameworks/Ruby/rack-app/app.rb | 76 +++++++++++++++++++ .../Ruby/rack-app/app/fortunes.html.erb | 12 +++ .../Ruby/rack-app/benchmark_config.json | 27 +++++++ frameworks/Ruby/rack-app/boot.rb | 68 +++++++++++++++++ frameworks/Ruby/rack-app/config.ru | 5 ++ frameworks/Ruby/rack-app/config/auto_tune.rb | 43 +++++++++++ frameworks/Ruby/rack-app/config/puma.rb | 10 +++ frameworks/Ruby/rack-app/rack-app.dockerfile | 21 +++++ 11 files changed, 370 insertions(+) create mode 100644 frameworks/Ruby/rack-app/Gemfile create mode 100644 frameworks/Ruby/rack-app/Gemfile.lock create mode 100644 frameworks/Ruby/rack-app/README.md create mode 100644 frameworks/Ruby/rack-app/app.rb create mode 100644 frameworks/Ruby/rack-app/app/fortunes.html.erb create mode 100644 frameworks/Ruby/rack-app/benchmark_config.json create mode 100644 frameworks/Ruby/rack-app/boot.rb create mode 100644 frameworks/Ruby/rack-app/config.ru create mode 100644 frameworks/Ruby/rack-app/config/auto_tune.rb create mode 100644 frameworks/Ruby/rack-app/config/puma.rb create mode 100644 frameworks/Ruby/rack-app/rack-app.dockerfile diff --git a/frameworks/Ruby/rack-app/Gemfile b/frameworks/Ruby/rack-app/Gemfile new file mode 100644 index 00000000000..2ad03adfb21 --- /dev/null +++ b/frameworks/Ruby/rack-app/Gemfile @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rack-app' +gem 'rack-app-front_end' +gem 'iodine', '~> 0.7', platforms: %i[ruby windows] +gem 'irb' # for Ruby 3.5 +gem 'logger' # for Ruby 3.5 +gem 'json', '~> 2.10' +gem 'pg', '~> 1.5' +gem 'sequel', '~> 5.0' +gem 'sequel_pg', '~> 1.6', require: false diff --git a/frameworks/Ruby/rack-app/Gemfile.lock b/frameworks/Ruby/rack-app/Gemfile.lock new file mode 100644 index 00000000000..7da89e051ce --- /dev/null +++ b/frameworks/Ruby/rack-app/Gemfile.lock @@ -0,0 +1,51 @@ +GEM + remote: https://rubygems.org/ + specs: + concurrent-ruby (1.3.5) + date (3.5.0) + erb (5.1.3) + io-console (0.8.1) + irb (1.15.3) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (2.15.2) + logger (1.7.0) + nio4r (2.7.5) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + psych (5.2.6) + date + stringio + puma (7.1.0) + nio4r (~> 2.0) + rack (3.2.4) + rack-app (11.0.2) + rack (>= 3.0.0) + rackup + rackup (2.2.1) + rack (>= 3) + rdoc (6.15.1) + erb + psych (>= 4.0.0) + tsort + reline (0.6.2) + io-console (~> 0.5) + stringio (3.1.7) + tsort (0.2.0) + +PLATFORMS + arm64-darwin-24 + ruby + +DEPENDENCIES + concurrent-ruby + irb + json (~> 2.10) + logger + puma (~> 7.1) + rack-app + +BUNDLED WITH + 2.7.2 diff --git a/frameworks/Ruby/rack-app/README.md b/frameworks/Ruby/rack-app/README.md new file mode 100644 index 00000000000..585c970919e --- /dev/null +++ b/frameworks/Ruby/rack-app/README.md @@ -0,0 +1,44 @@ +# Rack-app Benchmarking Test + +rack-app is a minimalist web framework that focuses on simplicity and +maintainability. The framework is meant to be used by seasoned web developers. + +https://github.com/rack-app/rack-app + +### Test Type Implementation Source Code + +* [JSON Serialization](app.rb): "/json" +* [Single Database Query](app.rb): "/db" +* [Multiple Database Queries](app.rb): "/db?queries={#}" +* [Fortunes](app.rb): "/fortune" +* [Plaintext](app.rb): "/plaintext" + +## Important Libraries + +The tests were run with: + +* [Sequel](https://rubygems.org/gems/sequel) +* [PG](https://rubygems.org/gems/pg) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### FORTUNES + +http://localhost:8080/fortunes + diff --git a/frameworks/Ruby/rack-app/app.rb b/frameworks/Ruby/rack-app/app.rb new file mode 100644 index 00000000000..e5310fc012d --- /dev/null +++ b/frameworks/Ruby/rack-app/app.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'rack/app' +require 'rack/app/front_end' +require 'json' + +class App < Rack::App + MAX_PK = 10_000 + ID_RANGE = (1..10_000).freeze + ALL_IDS = ID_RANGE.to_a + QUERIES_MIN = 1 + QUERIES_MAX = 500 + JSON_TYPE = 'application/json' + HTML_TYPE = 'text/html; charset=utf-8' + PLAINTEXT_TYPE = 'text/plain' + + apply_extensions :front_end + + helpers do + def fortunes + fortunes = Fortune.all + fortunes << Fortune.new( + id: 0, + message: "Additional fortune added at request time." + ) + fortunes.sort_by!(&:message) + end + end + + get '/json' do + set_headers(JSON_TYPE) + { message: 'Hello, World!' }.to_json + end + + get '/db' do + set_headers(JSON_TYPE) + World.with_pk(rand1).values.to_json + end + + get '/queries' do + set_headers(JSON_TYPE) + ids = ALL_IDS.sample(bounded_queries) + DB.synchronize do + ids.map do |id| + World.with_pk(id).values + end + end.to_json + end + + get '/fortunes' do + set_headers(HTML_TYPE) + render 'fortunes.html.erb' + end + + get '/plaintext' do + set_headers(PLAINTEXT_TYPE) + 'Hello, World!' + end + + private + + # Return a random number between 1 and MAX_PK + def rand1 + rand(MAX_PK).succ + end + + def bounded_queries + queries = params['queries'].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end + + def set_headers(content_type) + response.headers[::Rack::CONTENT_TYPE] = content_type + response.headers['Server'] = 'rack-app' + end +end diff --git a/frameworks/Ruby/rack-app/app/fortunes.html.erb b/frameworks/Ruby/rack-app/app/fortunes.html.erb new file mode 100644 index 00000000000..56c5c540270 --- /dev/null +++ b/frameworks/Ruby/rack-app/app/fortunes.html.erb @@ -0,0 +1,12 @@ + + + Fortunes + + + + <% fortunes.each do |record| %> + + <% end %> +
idmessage
<%= record.id %><%= ERB::Escape.html_escape(record.message) %>
+ + diff --git a/frameworks/Ruby/rack-app/benchmark_config.json b/frameworks/Ruby/rack-app/benchmark_config.json new file mode 100644 index 00000000000..d25acd9a641 --- /dev/null +++ b/frameworks/Ruby/rack-app/benchmark_config.json @@ -0,0 +1,27 @@ +{ + "framework": "rack-app", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "orm": "Full", + "database": "Postgres", + "framework": "rack-app", + "language": "Ruby", + "platform": "Mri", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack-app", + "notes": "" + } + } + ] +} diff --git a/frameworks/Ruby/rack-app/boot.rb b/frameworks/Ruby/rack-app/boot.rb new file mode 100644 index 00000000000..7711f76a0a1 --- /dev/null +++ b/frameworks/Ruby/rack-app/boot.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true +require 'bundler/setup' +require 'time' + +MAX_PK = 10_000 +ID_RANGE = (1..MAX_PK).freeze +ALL_IDS = ID_RANGE.to_a +QUERIES_MIN = 1 +QUERIES_MAX = 500 +SEQUEL_NO_ASSOCIATIONS = true +#SERVER_STRING = "Sinatra" + +Bundler.require(:default) # Load core modules + +def connect(dbtype) + Bundler.require(dbtype) # Load database-specific modules + + opts = {} + + adapter = 'postgresql' + + # Determine threading/thread pool size and timeout + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 + opts[:max_connections] = threads + opts[:pool_timeout] = 10 + else + opts[:max_connections] = 512 + end + + Sequel.connect \ + '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { + adapter: adapter, + host: 'tfb-database', + database: 'hello_world', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' + }, opts +end + +DB = connect 'postgres' + +# Define ORM models +class World < Sequel::Model(:World) + def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql + + def self.batch_update(worlds) + if DB.database_type == :mysql + worlds.map(&:save_changes) + else + ids = [] + sql = String.new("UPDATE world SET randomnumber = CASE id ") + worlds.each do |world| + sql << "when #{world.id} then #{world.randomnumber} " + ids << world.id + end + sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" + DB.run(sql) + end + end +end + +class Fortune < Sequel::Model(:Fortune) + # Allow setting id to zero (0) per benchmark requirements + unrestrict_primary_key +end + +[World, Fortune].each(&:freeze) +DB.freeze diff --git a/frameworks/Ruby/rack-app/config.ru b/frameworks/Ruby/rack-app/config.ru new file mode 100644 index 00000000000..27540c2f4ee --- /dev/null +++ b/frameworks/Ruby/rack-app/config.ru @@ -0,0 +1,5 @@ +# frozen_string_literal: true +require_relative 'boot' +require_relative 'app' + +run App diff --git a/frameworks/Ruby/rack-app/config/auto_tune.rb b/frameworks/Ruby/rack-app/config/auto_tune.rb new file mode 100644 index 00000000000..1e075f56911 --- /dev/null +++ b/frameworks/Ruby/rack-app/config/auto_tune.rb @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Instantiate about one process per X MiB of available memory, scaling up to as +# close to MAX_THREADS as possible while observing an upper bound based on the +# number of virtual/logical CPUs. If there are fewer processes than +# MAX_THREADS, add threads per process to reach MAX_THREADS. +require 'etc' + +KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) +MIN_WORKERS = 2 +MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical +MIN_THREADS_PER_WORKER = 1 +MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) + +def meminfo(arg) + File.open('/proc/meminfo') do |f| + f.each_line do |line| + key, value = line.split(/:\s+/) + return value.split(/\s+/).first.to_i if key == arg + end + end + + raise "Unable to find `#{arg}' in /proc/meminfo!" +end + +def auto_tune + avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 + + workers = [ + [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, + [(Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil, MIN_WORKERS].max + ].min + + threads_per_worker = [ + workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, + MIN_THREADS_PER_WORKER + ].max + + [workers, threads_per_worker] +end + +p auto_tune if $PROGRAM_NAME == __FILE__ diff --git a/frameworks/Ruby/rack-app/config/puma.rb b/frameworks/Ruby/rack-app/config/puma.rb new file mode 100644 index 00000000000..1b6d05d8ac0 --- /dev/null +++ b/frameworks/Ruby/rack-app/config/puma.rb @@ -0,0 +1,10 @@ +require_relative 'auto_tune' + +# FWBM only... use the puma_auto_tune gem in production! +_num_workers, num_threads = auto_tune + +threads num_threads + +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/rack-app/rack-app.dockerfile b/frameworks/Ruby/rack-app/rack-app.dockerfile new file mode 100644 index 00000000000..2b24fcab8bd --- /dev/null +++ b/frameworks/Ruby/rack-app/rack-app.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:3.5-rc + +ENV RUBY_YJIT_ENABLE=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +WORKDIR /rack-app + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle install --jobs=8 + +COPY . . + +EXPOSE 8080 + +CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) From 2dafb0cb24a52f853a0f6339138997d3f48866f9 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 11 Nov 2025 17:48:45 +0100 Subject: [PATCH 012/130] [ruby/padrino] Only test with Iodine (#10258) Unicorn is no longer maintained. Replace Puma with Iodine, as it performs better than Puma in these benchmarks. --- frameworks/Ruby/padrino/Gemfile | 8 +- frameworks/Ruby/padrino/Gemfile.lock | 12 +- frameworks/Ruby/padrino/README.md | 9 +- frameworks/Ruby/padrino/benchmark_config.json | 28 +--- frameworks/Ruby/padrino/config.toml | 21 +-- frameworks/Ruby/padrino/config/nginx.conf | 158 ------------------ frameworks/Ruby/padrino/config/puma.rb | 9 - frameworks/Ruby/padrino/config/unicorn.rb | 15 -- .../Ruby/padrino/padrino-unicorn.dockerfile | 23 --- frameworks/Ruby/padrino/padrino.dockerfile | 5 +- 10 files changed, 14 insertions(+), 274 deletions(-) delete mode 100644 frameworks/Ruby/padrino/config/nginx.conf delete mode 100644 frameworks/Ruby/padrino/config/puma.rb delete mode 100644 frameworks/Ruby/padrino/config/unicorn.rb delete mode 100644 frameworks/Ruby/padrino/padrino-unicorn.dockerfile diff --git a/frameworks/Ruby/padrino/Gemfile b/frameworks/Ruby/padrino/Gemfile index 3e643448adb..8ccd7f58765 100644 --- a/frameworks/Ruby/padrino/Gemfile +++ b/frameworks/Ruby/padrino/Gemfile @@ -8,10 +8,6 @@ gem 'slim', '2.0.3' gem 'padrino', git: 'https://github.com/padrino/padrino-framework.git' gem 'rack' -group :puma, optional: true do - gem 'puma', '~> 7.1', require: false -end - -group :unicorn, optional: true do - gem 'unicorn', '~> 6.1', platforms: [:ruby, :windows], require: false +group :iodine, optional: true do + gem "iodine", "~> 0.7", require: false end diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock index 45c6deadd77..3636648c76e 100644 --- a/frameworks/Ruby/padrino/Gemfile.lock +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -66,8 +66,8 @@ GEM drb (2.2.1) i18n (1.14.7) concurrent-ruby (~> 1.0) + iodine (0.7.58) json (2.11.3) - kgio (2.11.4) logger (1.6.6) mail (2.8.1) mini_mime (>= 0.1.1) @@ -93,9 +93,6 @@ GEM timeout net-smtp (0.5.1) net-protocol - nio4r (2.7.4) - puma (7.1.0) - nio4r (~> 2.0) rack (3.1.18) rack-protection (4.1.1) base64 (>= 0.1.0) @@ -106,7 +103,6 @@ GEM rack (>= 3.0.0) rackup (2.2.1) rack (>= 3) - raindrops (0.20.1) ruby2_keywords (0.0.5) securerandom (0.4.1) sinatra (4.1.1) @@ -125,9 +121,6 @@ GEM timeout (0.4.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicorn (6.1.0) - kgio (~> 2.6) - raindrops (~> 0.7) uri (1.0.3) PLATFORMS @@ -137,13 +130,12 @@ PLATFORMS DEPENDENCIES activerecord (>= 7.1) + iodine (~> 0.7) json mysql2 (> 0.5) padrino! - puma (~> 7.1) rack slim (= 2.0.3) - unicorn (~> 6.1) BUNDLED WITH 2.7.0 diff --git a/frameworks/Ruby/padrino/README.md b/frameworks/Ruby/padrino/README.md index c0c1e7601fe..9d11b9ef5a4 100644 --- a/frameworks/Ruby/padrino/README.md +++ b/frameworks/Ruby/padrino/README.md @@ -11,14 +11,9 @@ comparing a variety of web servers. ## Infrastructure Software Versions The tests were run with: -* [Ruby 2.0.0-p0](http://www.ruby-lang.org/) -* [JRuby 1.7.8](http://jruby.org/) -* [Rubinius 2.2.10](http://rubini.us/) +* [Ruby 3.5](http://www.ruby-lang.org/) * [Padrino 0.12.3](http://www.padrinorb.com/) -* [Rack 1.5.2](http://rack.github.com/) -* [Unicorn 4.8.3](http://unicorn.bogomips.org/) -* [Puma 3.9](http://puma.io/) -* [Thin 1.6.2](http://code.macournoyer.com/thin/) +* [Iodine](https://github.com/boazsegev/iodine) ## Paths & Source for Tests diff --git a/frameworks/Ruby/padrino/benchmark_config.json b/frameworks/Ruby/padrino/benchmark_config.json index 1b467408cc2..0eaf86be1d9 100644 --- a/frameworks/Ruby/padrino/benchmark_config.json +++ b/frameworks/Ruby/padrino/benchmark_config.json @@ -2,28 +2,6 @@ "framework": "padrino", "tests": [{ "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "padrino", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Puma", - "os": "Linux", - "database_os": "Linux", - "display_name": "padrino [puma]", - "notes": "", - "versus": "rack-puma-mri" - }, - "unicorn": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -38,12 +16,12 @@ "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Unicorn", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "padrino [unicorn]", + "display_name": "padrino", "notes": "", - "versus": "rack-unicorn" + "versus": "rack-iodine" } }] } diff --git a/frameworks/Ruby/padrino/config.toml b/frameworks/Ruby/padrino/config.toml index 795c2789614..e5103e75fa5 100644 --- a/frameworks/Ruby/padrino/config.toml +++ b/frameworks/Ruby/padrino/config.toml @@ -15,22 +15,5 @@ database_os = "Linux" os = "Linux" orm = "Full" platform = "Rack" -webserver = "Puma" -versus = "rack-puma-mri" - -[unicorn] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-unicorn" +webserver = "Iodine" +versus = "rack-iodine" diff --git a/frameworks/Ruby/padrino/config/nginx.conf b/frameworks/Ruby/padrino/config/nginx.conf deleted file mode 100644 index 83d4479f28d..00000000000 --- a/frameworks/Ruby/padrino/config/nginx.conf +++ /dev/null @@ -1,158 +0,0 @@ -# This is example contains the bare mininum to get nginx going with -# Unicorn or Rainbows! servers. Generally these configuration settings -# are applicable to other HTTP application servers (and not just Ruby -# ones), so if you have one working well for proxying another app -# server, feel free to continue using it. -# -# The only setting we feel strongly about is the fail_timeout=0 -# directive in the "upstream" block. max_fails=0 also has the same -# effect as fail_timeout=0 for current versions of nginx and may be -# used in its place. -# -# Users are strongly encouraged to refer to nginx documentation for more -# details and search for other example configs. - -# you generally only need one nginx worker unless you're serving -# large amounts of static files which require blocking disk reads -worker_processes 8; - -# # drop privileges, root is needed on most systems for binding to port 80 -# # (or anything < 1024). Capability-based security may be available for -# # your system and worth checking out so you won't need to be root to -# # start nginx to bind on 80 -# user nobody nogroup; # for systems with a "nogroup" -#user nobody nobody; # for systems with "nobody" as a group instead - -# Feel free to change all paths to suite your needs here, of course -pid /tmp/nginx.pid; -#error_log /tmp/nginx.error.log; -error_log stderr error; - -events { - worker_connections 4096; # increase if you have lots of clients - accept_mutex off; # "on" if nginx worker_processes > 1 - use epoll; # enable for Linux 2.6+ - # use kqueue; # enable for FreeBSD, OSX -} - -http { - # nginx will find this file in the config directory set at nginx build time - include /etc/nginx/mime.types; - - # fallback in case we can't determine a type - default_type application/octet-stream; - - # click tracking! - #access_log /tmp/nginx.access.log combined; - access_log off; - - # you generally want to serve static files with nginx since neither - # Unicorn nor Rainbows! is optimized for it at the moment - sendfile on; - - tcp_nopush on; # off may be better for *some* Comet/long-poll stuff - tcp_nodelay off; # on may be better for some Comet/long-poll stuff - - # we haven't checked to see if Rack::Deflate on the app server is - # faster or not than doing compression via nginx. It's easier - # to configure it all in one place here for static files and also - # to disable gzip for clients who don't get gzip/deflate right. - # There are other gzip settings that may be needed used to deal with - # bad clients out there, see http://wiki.nginx.org/NginxHttpGzipModule - #gzip on; - #gzip_http_version 1.0; - #gzip_proxied any; - #gzip_min_length 500; - #gzip_disable "MSIE [1-6]\."; - #gzip_types text/plain text/html text/xml text/css - # text/comma-separated-values - # text/javascript application/x-javascript - # application/atom+xml; - - # this can be any application server, not just Unicorn/Rainbows! - upstream app_server { - # fail_timeout=0 means we always retry an upstream even if it failed - # to return a good HTTP response (in case the Unicorn master nukes a - # single worker for timing out). - - # for UNIX domain socket setups: - server unix:/tmp/.sock fail_timeout=0; - - # for TCP setups, point these to your backend servers - # server 192.168.0.7:8080 fail_timeout=0; - # server 192.168.0.8:8080 fail_timeout=0; - # server 192.168.0.9:8080 fail_timeout=0; - } - - server { - # enable one of the following if you're on Linux or FreeBSD - listen 8080 default deferred; # for Linux - # listen 80 default accept_filter=httpready; # for FreeBSD - - # If you have IPv6, you'll likely want to have two separate listeners. - # One on IPv4 only (the default), and another on IPv6 only instead - # of a single dual-stack listener. A dual-stack listener will make - # for ugly IPv4 addresses in $remote_addr (e.g ":ffff:10.0.0.1" - # instead of just "10.0.0.1") and potentially trigger bugs in - # some software. - # listen [::]:80 ipv6only=on; # deferred or accept_filter recommended - - client_max_body_size 4G; - server_name _; - - # ~2 seconds is often enough for most folks to parse HTML/CSS and - # retrieve needed images/icons/frames, connections are cheap in - # nginx so increasing this is generally safe... - keepalive_timeout 10; - - # path for static files - root /path/to/app/current/public; - - # Prefer to serve static files directly from nginx to avoid unnecessary - # data copies from the application server. - # - # try_files directive appeared in in nginx 0.7.27 and has stabilized - # over time. Older versions of nginx (e.g. 0.6.x) requires - # "if (!-f $request_filename)" which was less efficient: - # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127 - try_files $uri/index.html $uri.html $uri @app; - - location @app { - # an HTTP header important enough to have its own Wikipedia entry: - # http://en.wikipedia.org/wiki/X-Forwarded-For - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # enable this if you forward HTTPS traffic to unicorn, - # this helps Rack set the proper URL scheme for doing redirects: - # proxy_set_header X-Forwarded-Proto $scheme; - - # pass the Host: header from the client right along so redirects - # can be set properly within the Rack application - proxy_set_header Host $http_host; - - # we don't want nginx trying to do something clever with - # redirects, we set the Host: header above already. - proxy_redirect off; - - # set "proxy_buffering off" *only* for Rainbows! when doing - # Comet/long-poll/streaming. It's also safe to set if you're using - # only serving fast clients with Unicorn + nginx, but not slow - # clients. You normally want nginx to buffer responses to slow - # clients, even with Rails 3.1 streaming because otherwise a slow - # client can become a bottleneck of Unicorn. - # - # The Rack application may also set "X-Accel-Buffering (yes|no)" - # in the response headers do disable/enable buffering on a - # per-response basis. - # proxy_buffering off; - - proxy_pass http://app_server; - } - - # Rails error pages - error_page 500 502 503 504 /500.html; - location = /500.html { - root /path/to/app/current/public; - } - } -} diff --git a/frameworks/Ruby/padrino/config/puma.rb b/frameworks/Ruby/padrino/config/puma.rb deleted file mode 100644 index 8a42642fd61..00000000000 --- a/frameworks/Ruby/padrino/config/puma.rb +++ /dev/null @@ -1,9 +0,0 @@ -require_relative 'auto_tune' - -num_workers, num_threads = auto_tune - -workers num_workers -threads num_threads, num_threads - -environment 'production' -bind 'tcp://0.0.0.0:8080' diff --git a/frameworks/Ruby/padrino/config/unicorn.rb b/frameworks/Ruby/padrino/config/unicorn.rb deleted file mode 100644 index 9ca3171328b..00000000000 --- a/frameworks/Ruby/padrino/config/unicorn.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative 'auto_tune' - -num_workers, = auto_tune - -worker_processes num_workers -listen "/tmp/.sock", :backlog => 4096 - -preload_app true -GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true - -before_fork do |server, worker| -end - -after_fork do |server, worker| -end diff --git a/frameworks/Ruby/padrino/padrino-unicorn.dockerfile b/frameworks/Ruby/padrino/padrino-unicorn.dockerfile deleted file mode 100644 index 81a6e0fefda..00000000000 --- a/frameworks/Ruby/padrino/padrino-unicorn.dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM ruby:3.4 - -WORKDIR /padrino -COPY app app -COPY config config -COPY models models -COPY .components .components -COPY config.ru config.ru -COPY Gemfile Gemfile -COPY Gemfile.lock Gemfile.lock -COPY Rakefile Rakefile - -RUN bundle config set with 'unicorn' -RUN bundle install --jobs=4 --gemfile=/padrino/Gemfile - -RUN apt-get update -yqq && apt-get install -yqq nginx - -EXPOSE 8080 - -ENV RUBY_YJIT_ENABLE=1 - -CMD nginx -c /padrino/config/nginx.conf && \ - bundle exec unicorn -E production -c config/unicorn.rb diff --git a/frameworks/Ruby/padrino/padrino.dockerfile b/frameworks/Ruby/padrino/padrino.dockerfile index fc6ba9456d3..57fe29b1034 100644 --- a/frameworks/Ruby/padrino/padrino.dockerfile +++ b/frameworks/Ruby/padrino/padrino.dockerfile @@ -10,11 +10,12 @@ COPY Gemfile Gemfile COPY Gemfile.lock Gemfile.lock COPY Rakefile Rakefile -RUN bundle config set with 'puma' +RUN bundle config set with 'iodine' RUN bundle install --jobs=4 --gemfile=/padrino/Gemfile EXPOSE 8080 ENV RUBY_YJIT_ENABLE=1 +ENV RACK_ENV=production -CMD bundle exec puma -C config/puma.rb +CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) From 1231b12cf2346f5242965a5b20d765b39b4e1986 Mon Sep 17 00:00:00 2001 From: rio Date: Wed, 12 Nov 2025 01:49:27 +0900 Subject: [PATCH 013/130] [python/cherrypy] Update python 3.13 (#10259) increase queue_size for pass DB job --- frameworks/Python/cherrypy/app.py | 4 +-- .../Python/cherrypy/benchmark_config.json | 25 +------------------ .../Python/cherrypy/cherrypy-py3.dockerfile | 11 -------- .../Python/cherrypy/cherrypy.dockerfile | 6 ++--- frameworks/Python/cherrypy/requirements.txt | 14 ++++------- 5 files changed, 11 insertions(+), 49 deletions(-) delete mode 100644 frameworks/Python/cherrypy/cherrypy-py3.dockerfile diff --git a/frameworks/Python/cherrypy/app.py b/frameworks/Python/cherrypy/app.py index bf090cfd69b..d92177d379c 100755 --- a/frameworks/Python/cherrypy/app.py +++ b/frameworks/Python/cherrypy/app.py @@ -153,8 +153,8 @@ def fortunes(self): cherrypy.tools.db = SATool() cherrypy.server.socket_host = '0.0.0.0' cherrypy.server.socket_port = 8080 - cherrypy.server.thread_pool = workers - cherrypy.server.socket_queue_size = 25 + cherrypy.server.thread_pool = workers * 2 + cherrypy.server.socket_queue_size = 100 cherrypy.quickstart(CherryPyBenchmark(), '', { '/': { diff --git a/frameworks/Python/cherrypy/benchmark_config.json b/frameworks/Python/cherrypy/benchmark_config.json index 62e51834960..9d4f3c1c8ef 100644 --- a/frameworks/Python/cherrypy/benchmark_config.json +++ b/frameworks/Python/cherrypy/benchmark_config.json @@ -2,29 +2,6 @@ "framework": "cherrypy", "tests": [{ "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "None", - "language": "Python", - "flavor": "Python2", - "orm": "Full", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "CherryPy [py2]", - "notes": "CPython 2.7", - "tags": ["broken"] - }, - "py3": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -44,7 +21,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "CherryPy", - "notes": "CPython 3.9" + "notes": "CPython 3.13" } }] } diff --git a/frameworks/Python/cherrypy/cherrypy-py3.dockerfile b/frameworks/Python/cherrypy/cherrypy-py3.dockerfile deleted file mode 100644 index 8a8af2211d8..00000000000 --- a/frameworks/Python/cherrypy/cherrypy-py3.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.9-bullseye - -ADD ./ /cherrypy - -WORKDIR /cherrypy - -RUN pip3 install -r /cherrypy/requirements.txt - -EXPOSE 8080 - -CMD python3 app.py diff --git a/frameworks/Python/cherrypy/cherrypy.dockerfile b/frameworks/Python/cherrypy/cherrypy.dockerfile index ccf988da6a6..eae3768b5fe 100644 --- a/frameworks/Python/cherrypy/cherrypy.dockerfile +++ b/frameworks/Python/cherrypy/cherrypy.dockerfile @@ -1,11 +1,11 @@ -FROM python:2.7.15-stretch +FROM python:3.13-bullseye ADD ./ /cherrypy WORKDIR /cherrypy -RUN pip install -r /cherrypy/requirements.txt +RUN pip3 install -r /cherrypy/requirements.txt EXPOSE 8080 -CMD python app.py +CMD python3 app.py diff --git a/frameworks/Python/cherrypy/requirements.txt b/frameworks/Python/cherrypy/requirements.txt index fc63cbf2a2a..f71069db433 100644 --- a/frameworks/Python/cherrypy/requirements.txt +++ b/frameworks/Python/cherrypy/requirements.txt @@ -1,10 +1,6 @@ -cheroot==8.6.0 -CherryPy==17.4.2 ; python_version=='2.7' CherryPy==18.8.0 ; python_version>'3.5' -more-itertools==4.1.0 -mysqlclient==1.3.12 -portend==2.2 -pytz==2017.3 -six==1.11.0 -SQLAlchemy==1.4.47 -tempora==1.10 +mysqlclient==2.2.4 +pytz==2024.1 +SQLAlchemy==1.4.53 +six==1.17.0 +legacy-cgi==2.6.4 \ No newline at end of file From 4629cb33180037918ba4f29523fbbb809c7b1a27 Mon Sep 17 00:00:00 2001 From: Shyam <140629171+Shyam20001@users.noreply.github.com> Date: Tue, 11 Nov 2025 22:20:11 +0530 Subject: [PATCH 014/130] Updated brahma-firelight with CLUSTER mode (#10261) * brahma-firelight added * cluster mode enabled --- .../brahma-firelight/benchmark_config.json | 36 ++++++------ .../brahma-firelight.dockerfile | 22 ++++++-- .../TypeScript/brahma-firelight/bun.lock | 4 +- .../TypeScript/brahma-firelight/package.json | 2 +- .../TypeScript/brahma-firelight/src/main.ts | 55 +++++++++++++------ 5 files changed, 78 insertions(+), 41 deletions(-) diff --git a/frameworks/TypeScript/brahma-firelight/benchmark_config.json b/frameworks/TypeScript/brahma-firelight/benchmark_config.json index 5ebbb896e7e..60db94104a9 100644 --- a/frameworks/TypeScript/brahma-firelight/benchmark_config.json +++ b/frameworks/TypeScript/brahma-firelight/benchmark_config.json @@ -1,21 +1,23 @@ { "framework": "brahma-firelight", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "framework": "brahma-firelight", - "language": "TypeScript", - "flavor": "bun", - "platform": "bun", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "brahma-firelight", - "versus": "nodejs" + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "brahma-firelight", + "language": "TypeScript", + "flavor": "bun", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "brahma-firelight", + "versus": "nodejs" + } } - }] + ] } diff --git a/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile b/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile index dd682eba23f..4ae04a5efbf 100644 --- a/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile +++ b/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile @@ -1,13 +1,25 @@ -FROM oven/bun:1.3 - +FROM oven/bun:1.3 AS builder WORKDIR /app -COPY . . +COPY package.json bun.lock ./ -RUN bun install +RUN bun ci +COPY . . RUN bun run build +FROM oven/bun:1.3 AS runtime +WORKDIR /app + +ENV NODE_ENV=production +ENV PORT=8080 + +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./package.json + +ENV NODE_ENV=production + EXPOSE 8080 -CMD ["bun", "dist/main.js"] +ENTRYPOINT ["bun", "dist/main.js"] diff --git a/frameworks/TypeScript/brahma-firelight/bun.lock b/frameworks/TypeScript/brahma-firelight/bun.lock index a24e46c51c5..067ff9b71e3 100644 --- a/frameworks/TypeScript/brahma-firelight/bun.lock +++ b/frameworks/TypeScript/brahma-firelight/bun.lock @@ -4,7 +4,7 @@ "": { "name": "brahma-firelight", "dependencies": { - "brahma-firelight": "1.5.16", + "brahma-firelight": "^1.5.18", }, "devDependencies": { "@types/bun": "latest", @@ -21,7 +21,7 @@ "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], - "brahma-firelight": ["brahma-firelight@1.5.16", "", {}, "sha512-KwqrG3EHBcEYiOjjx7UvZ4TDxnKTP+DPjnQQqblKuHQcS/mw35NzIYf01YnBZLRM/9VZrb5+UrDaNmrAPZGYlw=="], + "brahma-firelight": ["brahma-firelight@1.5.18", "", {}, "sha512-/raDDeb6/AAHYPfvTi4vWA79BjsHwh5Eg63GWJPwWzyip3mvY0tIsNeMqHit4XBdyJZ9t0UgtsvNaHGx3zqFGw=="], "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], diff --git a/frameworks/TypeScript/brahma-firelight/package.json b/frameworks/TypeScript/brahma-firelight/package.json index dbe9f089100..c7b49a791fd 100644 --- a/frameworks/TypeScript/brahma-firelight/package.json +++ b/frameworks/TypeScript/brahma-firelight/package.json @@ -14,6 +14,6 @@ "typescript": "^5" }, "dependencies": { - "brahma-firelight": "1.5.16" + "brahma-firelight": "^1.5.18" } } \ No newline at end of file diff --git a/frameworks/TypeScript/brahma-firelight/src/main.ts b/frameworks/TypeScript/brahma-firelight/src/main.ts index 639d33f3085..3583f916605 100644 --- a/frameworks/TypeScript/brahma-firelight/src/main.ts +++ b/frameworks/TypeScript/brahma-firelight/src/main.ts @@ -1,10 +1,13 @@ import { createApp, type Response, type Request, type App, type NextFunction, type Handler } from "brahma-firelight"; +import cluster from "node:cluster"; +import os from "node:os"; const app: App = createApp(); // Server Config Middleware const serverInfo: Handler = (_req: Request, res: Response, next?: NextFunction) => { res.setHeader("Server", "brahma-firelight"); + res.setHeader("Connection", "keep-alive") next?.(); }; @@ -19,19 +22,39 @@ app.get("/plaintext", serverInfo, (_req: Request, res: Response) => { }); // Port & Host - -app.listen("0.0.0.0", 8080); - -// Enable built in Graceful Shutdown (optional for production use) - -process.on('SIGINT', async () => { - console.log('SIGINT → shutting down...'); - await app.close(2000); // wait up to 2s for requests - process.exit(0); -}); - -process.on('SIGTERM', async () => { - console.log('SIGTERM → shutting down...'); - await app.close(2000); - process.exit(0); -}); \ No newline at end of file +const PORT = process.env.PORT || 8080; +const HOST = process.env.HOST || "0.0.0.0"; + +// Single CORE +//app.listen(HOST, +PORT); + +// Multi CORE (cluster with max cpus available) +if (cluster.isPrimary) { + const cpuCount = os.cpus().length; + console.log(`Primary ${process.pid} running → forking ${cpuCount} workers...`); + + for (let i = 0; i < cpuCount; i++) { + cluster.fork(); + } + + cluster.on("exit", (worker) => { + console.log(`Worker ${worker.process.pid} died → restarting...`); + cluster.fork(); + }); +} else { + app.listen(HOST, +PORT); +} + +// // Enable built in Graceful Shutdown (optional for production use) + +// process.on('SIGINT', async () => { +// console.log('SIGINT → shutting down...'); +// await app.close(2000); // wait up to 2s for requests +// process.exit(0); +// }); + +// process.on('SIGTERM', async () => { +// console.log('SIGTERM → shutting down...'); +// await app.close(2000); +// process.exit(0); +// }); \ No newline at end of file From d2c875750e2d6d4ba257337f3767cd17adea643a Mon Sep 17 00:00:00 2001 From: ruroru <111705692+ruroru@users.noreply.github.com> Date: Tue, 11 Nov 2025 18:51:16 +0200 Subject: [PATCH 015/130] Fix some of the broken java base images (#10262) * fix broken java base images * Update Hikari CP settings in httpserver and ring-http-exchange * Add semeru to ring-http-exchange --------- Co-authored-by: jj --- .../ring-http-exchange/benchmark_config.json | 20 +++++++++++++++++++ ...ing-http-exchange-robaho-semeru.dockerfile | 14 +++++++++++++ .../src/ring_http_exchange/benchmark.clj | 9 ++++----- frameworks/Java/activej/activej.dockerfile | 8 ++++---- .../dropwizard-jdbi-postgres.dockerfile | 2 +- .../dropwizard/dropwizard-mongodb.dockerfile | 2 +- .../dropwizard/dropwizard-postgres.dockerfile | 2 +- .../Java/dropwizard/dropwizard.dockerfile | 2 +- frameworks/Java/httpserver/pom.xml | 12 +++++------ .../src/main/java/benchmarks/Server.java | 17 +++++++++++++--- frameworks/Java/voovan/voovan.dockerfile | 2 +- 11 files changed, 66 insertions(+), 24 deletions(-) create mode 100644 frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile diff --git a/frameworks/Clojure/ring-http-exchange/benchmark_config.json b/frameworks/Clojure/ring-http-exchange/benchmark_config.json index d8d2ba0ce3e..b0381b921ac 100755 --- a/frameworks/Clojure/ring-http-exchange/benchmark_config.json +++ b/frameworks/Clojure/ring-http-exchange/benchmark_config.json @@ -81,6 +81,26 @@ "display_name": "ring-http-exchange-robaho-graalvm", "notes": "", "versus": "ring-http-exchange-robaho" + }, + "robaho-semeru": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange-robaho-semeru", + "notes": "", + "versus": "ring-http-exchange-robaho" } } ] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile new file mode 100644 index 00000000000..64f06a3418a --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile @@ -0,0 +1,14 @@ +FROM clojure:lein as lein +WORKDIR /ring-http-exchange +COPY project.clj project.clj +COPY resources resources +COPY src src +RUN lein with-profile robaho uberjar + +FROM ibm-semeru-runtimes:open-25-jre-jammy +WORKDIR /ring-http-exchange +COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj index a5ee8a34384..fc6afa569b6 100644 --- a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj @@ -15,14 +15,13 @@ (def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "fortune.sql")) (def db-spec {:auto-commit true - :read-only false - :connection-timeout 30000 + :read-only true + :connection-timeout 10000 :validation-timeout 5000 :idle-timeout 600000 :max-lifetime 1800000 - :minimum-idle 10 - :maximum-pool-size 520 - :minimum-pool-size 512 + :minimum-idle 16 + :maximum-pool-size 64 :register-mbeans false :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass"}) diff --git a/frameworks/Java/activej/activej.dockerfile b/frameworks/Java/activej/activej.dockerfile index cea75f79e0d..da3ba92ee5a 100644 --- a/frameworks/Java/activej/activej.dockerfile +++ b/frameworks/Java/activej/activej.dockerfile @@ -1,11 +1,11 @@ -FROM maven:3.6.1-jdk-11-slim as maven - +FROM maven:3.9.0-eclipse-temurin-17 as maven WORKDIR /activej COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /activej COPY --from=maven /activej/target/activej-server-benchmark-0.0.1-SNAPSHOT-jar-with-dependencies.jar app.jar -CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-DHttpServerConnection.initialWriteBufferSize=4096", "-DHttpHeadersMultimap.initialSize=16", "-jar", "app.jar"] \ No newline at end of file +EXPOSE 8080 +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] \ No newline at end of file diff --git a/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile b/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile index 21a897236d7..13b5b94ce53 100644 --- a/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P postgres,jdbi -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-jdbi-postgres.yml hello-world-jdbi-postgres.yml diff --git a/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile b/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile index 1d13f4f9013..ce1fb9d4bbc 100644 --- a/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P mongo -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-mongo.yml hello-world-mongo.yml diff --git a/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile b/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile index b088d2df510..25cb2080922 100644 --- a/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P postgres -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-postgres.yml hello-world-postgres.yml diff --git a/frameworks/Java/dropwizard/dropwizard.dockerfile b/frameworks/Java/dropwizard/dropwizard.dockerfile index af3b49c8682..206455df590 100644 --- a/frameworks/Java/dropwizard/dropwizard.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P mysql -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-mysql.yml hello-world-mysql.yml diff --git a/frameworks/Java/httpserver/pom.xml b/frameworks/Java/httpserver/pom.xml index 26673413278..5b983699fe6 100644 --- a/frameworks/Java/httpserver/pom.xml +++ b/frameworks/Java/httpserver/pom.xml @@ -30,23 +30,21 @@ postgresql 42.7.2 - - com.zaxxer - HikariCP - 3.3.1 - - com.github.httl httl 1.0.11 - org.slf4j slf4j-simple 1.8.0-beta4 + + com.zaxxer + HikariCP + 7.0.2 + diff --git a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java index 2b4beb71889..80566641a9f 100755 --- a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java +++ b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java @@ -52,12 +52,23 @@ private static List queryFortunes(DataSource ds) throws SQLException { } private static DataSource createPostgresDataSource() throws ClassNotFoundException { - Class.forName("org.postgresql.Driver"); HikariConfig config = new HikariConfig(); + config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); config.setUsername("benchmarkdbuser"); config.setPassword("benchmarkdbpass"); - config.setMaximumPoolSize(512); + + config.setMaximumPoolSize(64); + config.setMinimumIdle(16); + + config.setConnectionTimeout(10000); + config.setIdleTimeout(600000); + config.setMaxLifetime(1800000); + + config.setAutoCommit(true); + + config.setPoolName("PostgreSQL-HikariCP-Pool"); + return new HikariDataSource(config); } @@ -145,4 +156,4 @@ static void main(String[] args) throws Exception { // start server server.start(); } -} +} \ No newline at end of file diff --git a/frameworks/Java/voovan/voovan.dockerfile b/frameworks/Java/voovan/voovan.dockerfile index 2ffcb0dbcfc..26ed65a1bdf 100644 --- a/frameworks/Java/voovan/voovan.dockerfile +++ b/frameworks/Java/voovan/voovan.dockerfile @@ -5,7 +5,7 @@ COPY src src COPY config/framework.properties config/framework.properties RUN mvn package -q -FROM openjdk:25-ea-slim-bullseye +FROM amazoncorretto:25 WORKDIR /voovan COPY --from=maven /voovan/target/voovan-bench-0.1-jar-with-dependencies.jar app.jar COPY --from=maven /voovan/config/framework.properties config/framework.properties From 45329a5d60f8a49a39912c484b4b2595d46a8ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Gajo?= <50725287+64J0@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:52:16 -0300 Subject: [PATCH 016/130] Minor code improvements and add Updates test (#10263) --- .../FSharp/giraffe/benchmark_config.json | 1 + frameworks/FSharp/giraffe/config.toml | 3 +- frameworks/FSharp/giraffe/src/App/App.fsproj | 2 +- frameworks/FSharp/giraffe/src/App/Program.fs | 147 +++++++++++++++--- 4 files changed, 130 insertions(+), 23 deletions(-) diff --git a/frameworks/FSharp/giraffe/benchmark_config.json b/frameworks/FSharp/giraffe/benchmark_config.json index 5552420b37f..cc2e70a748f 100644 --- a/frameworks/FSharp/giraffe/benchmark_config.json +++ b/frameworks/FSharp/giraffe/benchmark_config.json @@ -7,6 +7,7 @@ "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", + "update_url": "/updates?queries=", "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", diff --git a/frameworks/FSharp/giraffe/config.toml b/frameworks/FSharp/giraffe/config.toml index a44ef83d919..ada171349cb 100644 --- a/frameworks/FSharp/giraffe/config.toml +++ b/frameworks/FSharp/giraffe/config.toml @@ -2,11 +2,12 @@ name = "giraffe" [main] -urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" urls.query = "/queries?queries=" urls.fortune = "/fortunes" +urls.update = "/updates?queries=" +urls.plaintext = "/plaintext" approach = "Realistic" classification = "fullstack" database = "Postgres" diff --git a/frameworks/FSharp/giraffe/src/App/App.fsproj b/frameworks/FSharp/giraffe/src/App/App.fsproj index 215f3bfc001..ef58a0c3618 100644 --- a/frameworks/FSharp/giraffe/src/App/App.fsproj +++ b/frameworks/FSharp/giraffe/src/App/App.fsproj @@ -7,10 +7,10 @@ - + diff --git a/frameworks/FSharp/giraffe/src/App/Program.fs b/frameworks/FSharp/giraffe/src/App/Program.fs index b4e63e7333f..f7d62db7d33 100644 --- a/frameworks/FSharp/giraffe/src/App/Program.fs +++ b/frameworks/FSharp/giraffe/src/App/Program.fs @@ -18,15 +18,15 @@ module Common = Database=hello_world; User Id=benchmarkdbuser; Password=benchmarkdbpass; - SSL Mode=Disable; Maximum Pool Size=1024; NoResetOnClose=true; Enlist=false; - Max Auto Prepare=4; - Multiplexing=true; - Write Coalescing Buffer Threshold Bytes=1000 + Max Auto Prepare=4 """ + [] + let MultiplexedConnectionString = ConnectionString + ";Multiplexing=true" + [] type JsonMode = | System @@ -46,8 +46,43 @@ module Common = member _.Next () = rnd.Next (min, max) - [] - let MaxDegreeOfParallelism = 3 + // Cache SQL strings for bulk updates to avoid rebuilding on every request + // This module generates and caches SQL UPDATE statements that use PostgreSQL's + // VALUES clause to update multiple rows in a single statement. + module BatchUpdateSql = + let private cache = Array.zeroCreate 501 + + let get (count: int) = + match cache.[count] with + | null -> + let lastIndex = count - 1 + + // Build the VALUES clause: (@Id_0, @Rn_0), (@Id_1, @Rn_1), ... + // Each pair represents (id, new_randomnumber) for one row + let valueClauses = + List.init lastIndex (fun i -> sprintf "(@Id_%d, @Rn_%d), " i i) + |> String.concat "" + + // The final SQL uses a CTE-like VALUES construct to update multiple rows: + // UPDATE world SET randomnumber = temp.randomnumber + // FROM (VALUES ...) AS temp(id, randomnumber) + // WHERE temp.id = world.id + let sql = + sprintf + """ + UPDATE world + SET randomnumber = temp.randomnumber + FROM (VALUES %s(@Id_%d, @Rn_%d) ORDER BY 1) + AS temp(id, randomnumber) + WHERE temp.id = world.id + """ + valueClauses + lastIndex + lastIndex + + cache.[count] <- sql + sql + | sql -> sql [] module HtmlViews = @@ -87,10 +122,12 @@ module HttpHandlers = message = "Additional fortune added at request time." } - let private fortunes: HttpHandler = + let fortunes: HttpHandler = fun _ ctx -> task { - use conn = new NpgsqlConnection (ConnectionString) + let dataSource = ctx.GetService () + use conn = dataSource.CreateConnection () + do! conn.OpenAsync () let! data = conn.QueryAsync ("SELECT id, message FROM fortune") @@ -106,11 +143,13 @@ module HttpHandlers = return! ctx.WriteBytesAsync bytes } - let private db: HttpHandler = + let db: HttpHandler = fun _ ctx -> task { let rnd = ctx.GetService () - use conn = new NpgsqlConnection (ConnectionString) + let dataSource = ctx.GetService () + use conn = dataSource.CreateConnection () + do! conn.OpenAsync () let! data = conn.QuerySingleAsync ( @@ -121,7 +160,7 @@ module HttpHandlers = return! ctx.WriteJsonAsync data } - let private queries: HttpHandler = + let queries: HttpHandler = fun _ ctx -> task { let queryParam = @@ -137,30 +176,94 @@ module HttpHandlers = |> Option.defaultValue 1 let rnd = ctx.GetService () + let dataSource = ctx.GetService () + + use conn = dataSource.CreateConnection () + do! conn.OpenAsync () - let! res = - Array.init queryParam (fun _ -> rnd.Next ()) - |> Array.map (fun id -> - use conn = new NpgsqlConnection (ConnectionString) + // Read all rows sequentially + let results = Array.zeroCreate queryParam + for i in 0 .. queryParam - 1 do + let! world = conn.QuerySingleAsync ( "SELECT id, randomnumber FROM world WHERE id = @Id", - {| Id = id |} + {| Id = rnd.Next () |} ) - |> Async.AwaitTask + + results.[i] <- world + + return! ctx.WriteJsonAsync results + } + + let updates: HttpHandler = + fun _ ctx -> + task { + let queryParam = + ctx.TryGetQueryStringValue "queries" + |> Option.map (fun value -> + match System.Int32.TryParse value with + | true, intValue -> + if intValue < 1 then 1 + elif intValue > 500 then 500 + else intValue + | false, _ -> 1 ) - |> fun computations -> - Async.Parallel (computations, MaxDegreeOfParallelism) + |> Option.defaultValue 1 + + let rnd = ctx.GetService () + + // Use multiplexed connection for updates (more efficient for sequential ops) + use conn = new NpgsqlConnection (MultiplexedConnectionString) + do! conn.OpenAsync () + + // Read all rows sequentially + let readResults = Array.zeroCreate queryParam - return! ctx.WriteJsonAsync res + for i in 0 .. queryParam - 1 do + let! world = + conn.QuerySingleAsync ( + "SELECT id, randomnumber FROM world WHERE id = @Id", + {| Id = rnd.Next () |} + ) + + readResults.[i] <- world + + // Update random numbers functionally + let updatedData = + readResults + |> Array.map (fun data -> { data with randomNumber = rnd.Next () }) + + // Build bulk update parameters functionally + // We use a single UPDATE statement with a VALUES clause to update all rows at once. + // + // Example SQL for 2 rows: + // UPDATE world SET randomnumber = temp.randomnumber + // FROM (VALUES (@Id_0, @Rn_0), (@Id_1, @Rn_1) ORDER BY 1) AS temp(id, randomnumber) + // WHERE temp.id = world.id + let updateParams = + updatedData + |> Array.mapi (fun i data -> [ + sprintf "@Id_%d" i, box data.id // Parameter for the id + sprintf "@Rn_%d" i, box data.randomNumber // Parameter for the new random number + ]) + |> Array.collect List.toArray // Flatten the list of parameter pairs + |> dict // Convert to dictionary for Dapper + + // Execute bulk update using Dapper + let sql = BatchUpdateSql.get queryParam + let! _ = conn.ExecuteAsync (sql, updateParams) + + return! ctx.WriteJsonAsync updatedData } let endpoints: Endpoint list = [ - route "/plaintext" (text "Hello, World!") route "/json" (json {| message = "Hello, World!" |}) route "/db" db route "/queries" queries route "/fortunes" fortunes + route "/updates" updates + route "/plaintext" (text "Hello, World!") ] @@ -173,6 +276,7 @@ module Main = open Microsoft.Extensions.Logging open System.Text.Json open Newtonsoft.Json + open Npgsql [] let main args = @@ -202,6 +306,7 @@ module Main = builder.Services .AddSingleton(jsonSerializer) .AddSingleton(rnd) + .AddSingleton(NpgsqlDataSource.Create (ConnectionString)) .AddGiraffe () |> ignore From 24daeda25bf15cff2c49cdd501c9da676210daf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <76547834+RRQM@users.noreply.github.com> Date: Wed, 12 Nov 2025 00:52:42 +0800 Subject: [PATCH 017/130] update(touchsocket):version to 4.0.0-rc42 (#10265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update(touchsocket):version to 4.0.0-rc.2 * update(touchsocket):version to 4.0.0-rc.5 * optimize(touchsocket):scheduler * Performance (TouchSocketHttp, TouchSocketWebApi): Enable server garbage collection * update(touchsocket):version to 4.0.0-rc.15 * update(touchsocket):version to 4.0.0-rc42 * 重构(Program): 显式指定变量类型并优化配置 显式指定变量类型以提高代码可读性和类型安全性 修改命名空间为 `TouchSocketHttp` 将 `options.BufferOnDemand` 默认值从 `false` 修改为 `true` 调整 `SetTransportOption` 和 `ApiServer` 中的相关代码 * 优化(csproj): 升级TouchSocket包版本 在TouchSocketHttp.csproj和TouchSocketWebApi.csproj中,将TouchSocket.Hosting和TouchSocket.WebApi的包引用版本从4.0.0-rc.42升级到4.0.0-rc.44,以修复错误、提高性能或增加新功能 --- .../CSharp/touchsocket/src/TouchSocketHttp/Program.cs | 6 +++++- .../src/TouchSocketHttp/TouchSocketHttp.csproj | 4 ++-- .../CSharp/touchsocket/src/TouchSocketWebApi/Program.cs | 8 ++++++-- .../src/TouchSocketWebApi/TouchSocketWebApi.csproj | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs index 125284cd970..d77a1b3249d 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs @@ -10,12 +10,16 @@ public class Program { private static async Task Main(string[] args) { - var port = 8080; + int port = 8080; var service = new MyHttpService(); await service.SetupAsync(new TouchSocketConfig() .SetListenIPHosts(port) .SetMaxCount(1000000) + .SetTransportOption(options => + { + options.BufferOnDemand = true; + }) .ConfigureContainer(a => { a.AddConsoleLogger(); diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj index 74caaf7a658..ea6f43327a0 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs index 26cdfb935fd..a7c9e6dcafe 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs @@ -19,6 +19,10 @@ public static void Main(string[] args) { config.SetListenIPHosts(8080) .SetMaxCount(1000000) + .SetTransportOption(options => + { + options.BufferOnDemand = true; + }) .ConfigureContainer(a => { a.AddConsoleLogger(); @@ -45,7 +49,7 @@ public static void Main(string[] args) }); }); - var host = builder.Build(); + IHost host = builder.Build(); host.Run(); } } @@ -60,7 +64,7 @@ public partial class ApiServer : SingletonRpcServer [WebApi(Method = HttpMethodType.Get)] public async Task Plaintext(IWebApiCallContext callContext) { - var response = callContext.HttpContext.Response; + HttpResponse response = callContext.HttpContext.Response; response.SetStatus(200, "ok"); response.Content = m_contentPlaintext; await response.AnswerAsync().ConfigureAwait(false); diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj index 1319cf14650..d90651bb648 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj @@ -10,7 +10,7 @@ - - + + From 96a221905f4d209319110dd62cad7eea29fdb089 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 11 Nov 2025 17:53:19 +0100 Subject: [PATCH 018/130] [ruby/rack] Add Itsi webserver for Rack (#10266) --- frameworks/Ruby/rack/Gemfile | 4 ++++ frameworks/Ruby/rack/Gemfile.lock | 15 ++++++++++++++ frameworks/Ruby/rack/README.md | 9 ++++---- frameworks/Ruby/rack/benchmark_config.json | 21 +++++++++++++++++++ frameworks/Ruby/rack/config/itsi.rb | 13 ++++++++++++ frameworks/Ruby/rack/hello_world.rb | 4 ++++ frameworks/Ruby/rack/rack-itsi.dockerfile | 24 ++++++++++++++++++++++ 7 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 frameworks/Ruby/rack/config/itsi.rb create mode 100644 frameworks/Ruby/rack/rack-itsi.dockerfile diff --git a/frameworks/Ruby/rack/Gemfile b/frameworks/Ruby/rack/Gemfile index 091baa8d0e4..0512085a64f 100644 --- a/frameworks/Ruby/rack/Gemfile +++ b/frameworks/Ruby/rack/Gemfile @@ -22,6 +22,10 @@ group :iodine, optional: true do gem 'iodine', '~> 0.7', platforms: %i[ruby windows] end +group :itsi, optional: true do + gem 'itsi' +end + group :passenger, optional: true do gem 'logger' # required by passenger on Ruby 3.5 gem 'passenger', '~> 6.1', platforms: [:ruby, :windows], require: false diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index 0322d2109ed..4030d1e1ecb 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -60,6 +60,16 @@ GEM io-event (1.9.0) io-stream (0.6.1) iodine (0.7.58) + itsi (0.2.18) + itsi-scheduler (~> 0.2.18) + itsi-server (~> 0.2.18) + itsi-scheduler (0.2.18) + rb_sys (~> 0.9.91) + itsi-server (0.2.18) + json (~> 2) + prism (~> 1.4) + rack (>= 1.6) + rb_sys (~> 0.9.91) json (2.13.2) language_server-protocol (3.17.0.4) lint_roller (1.1.0) @@ -84,6 +94,7 @@ GEM pitchfork (0.17.0) logger rack (>= 2.0) + prism (1.4.0) protocol-hpack (1.5.1) protocol-http (0.54.0) protocol-http1 (0.35.2) @@ -104,6 +115,9 @@ GEM rack (>= 3) rainbow (3.1.1) rake (13.3.0) + rake-compiler-dock (1.9.1) + rb_sys (0.9.117) + rake-compiler-dock (= 1.9.1) regexp_parser (2.10.0) rubocop (1.73.2) json (~> 2.3) @@ -145,6 +159,7 @@ DEPENDENCIES connection_pool (~> 2.4) falcon (~> 0.47) iodine (~> 0.7) + itsi jdbc-postgres (~> 42.2) json (~> 2.10) logger diff --git a/frameworks/Ruby/rack/README.md b/frameworks/Ruby/rack/README.md index 53a5d5c5b09..4dd0a7d3954 100644 --- a/frameworks/Ruby/rack/README.md +++ b/frameworks/Ruby/rack/README.md @@ -13,12 +13,13 @@ The tests were run with: * [Ruby 3.4](http://www.ruby-lang.org/) * [JRuby 9.4](http://jruby.org/) -* [Rack 3.1](http://rack.github.com/) -* [Unicorn 6.1.0](http://unicorn.bogomips.org/) -* [Puma 7](http://puma.io/) -* [Iodine](https://github.com/boazsegev/iodine) +* [Rack 3](http://rack.github.com/) * [Falcon](https://github.com/socketry/falcon) +* [Iodine](https://github.com/boazsegev/iodine) +* [Itsi](https://github.com/wouterken/itsi) +* [Passenger](https://github.com/phusion/passenger) * [Pitchfork](https://github.com/Shopify/pitchfork) +* [Puma](http://puma.io/) * [Sequel 5](https://sequel.jeremyevans.net/) diff --git a/frameworks/Ruby/rack/benchmark_config.json b/frameworks/Ruby/rack/benchmark_config.json index 326c20b4f40..031e00dc5e9 100644 --- a/frameworks/Ruby/rack/benchmark_config.json +++ b/frameworks/Ruby/rack/benchmark_config.json @@ -65,6 +65,27 @@ "display_name": "rack [falcon]", "notes": "" }, + "itsi": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "orm": "raw", + "database": "Postgres", + "framework": "rack", + "language": "Ruby", + "platform": "Mri", + "webserver": "Itsi", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack [itsi]", + "notes": "" + }, "jruby": { "json_url": "/json", "plaintext_url": "/plaintext", diff --git a/frameworks/Ruby/rack/config/itsi.rb b/frameworks/Ruby/rack/config/itsi.rb new file mode 100644 index 00000000000..d0dd0992dc1 --- /dev/null +++ b/frameworks/Ruby/rack/config/itsi.rb @@ -0,0 +1,13 @@ +require_relative 'auto_tune' + +rackup_file './config.ru' + +ruby_thread_request_backlog_size 10_000 + +preload false + +num_workers, num_threads = auto_tune + +workers num_workers +threads num_threads +fiber_scheduler false diff --git a/frameworks/Ruby/rack/hello_world.rb b/frameworks/Ruby/rack/hello_world.rb index ca4c8f8671d..2a806461fa2 100644 --- a/frameworks/Ruby/rack/hello_world.rb +++ b/frameworks/Ruby/rack/hello_world.rb @@ -45,6 +45,10 @@ class HelloWorld def initialize if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 max_connections = threads + elsif defined?(Itsi) + require_relative 'config/auto_tune' + _num_workers, num_threads = auto_tune + max_connections = num_threads else max_connections = 512 end diff --git a/frameworks/Ruby/rack/rack-itsi.dockerfile b/frameworks/Ruby/rack/rack-itsi.dockerfile new file mode 100644 index 00000000000..952ac7ccdad --- /dev/null +++ b/frameworks/Ruby/rack/rack-itsi.dockerfile @@ -0,0 +1,24 @@ +FROM ruby:3.5-rc + +ENV RUBY_YJIT_ENABLE=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +RUN apt-get install -y build-essential libclang-dev + +WORKDIR /rack + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'itsi' +RUN bundle install --jobs=8 + +COPY . . + +EXPOSE 8080 + +CMD bundle exec itsi start -C config/itsi.rb --bind "http://tfb-server:8080" From 72bc54179fe18ccf1a8c141717db4c03d3a04eb5 Mon Sep 17 00:00:00 2001 From: Gabriel Scatolin <17441745+CypherPotato@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:54:11 -0300 Subject: [PATCH 019/130] updated sisk tests (#10267) * update sisk cadente * add missing dependencies to aot test * remove aot test * fix: plaintext strings * update cadente version * update cadente version * update sisk benchmarks --- .../CSharp/sisk/sisk-cadente/Program.cs | 70 ++++++++++--------- .../CSharp/sisk/sisk-cadente/sisk.csproj | 2 +- frameworks/CSharp/sisk/sisk.dockerfile | 4 ++ 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/frameworks/CSharp/sisk/sisk-cadente/Program.cs b/frameworks/CSharp/sisk/sisk-cadente/Program.cs index 267877ee584..f198260cbde 100644 --- a/frameworks/CSharp/sisk/sisk-cadente/Program.cs +++ b/frameworks/CSharp/sisk/sisk-cadente/Program.cs @@ -1,44 +1,50 @@ -using System.Net; +using System.Buffers.Text; +using System.Net; using System.Text; using System.Text.Json; using Sisk.Cadente; -HttpHost.QueueSize = 4096; - -var host = new HttpHost ( new IPEndPoint ( IPAddress.Any, 8080 ) ); -host.ContextCreated += Host_ContextCreated; +using var host = new HttpHost ( new IPEndPoint ( IPAddress.Any, 8080 ) ); +host.Handler = new DefaultHandler(); host.Start (); Thread.Sleep ( Timeout.Infinite ); -void Host_ContextCreated ( HttpHost sender, HttpHostContext 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; - } -} - -static void SerializePlainTextResponse ( HttpHostContext.HttpResponse response ) { - - var messageBytes = Encoding.UTF8.GetBytes ( "Hello, World!" ); - response.Headers.Add ( new HttpHeader ( "Content-Type", "text/plain; charset=UTF-8" ) ); - response.ResponseStream = new MemoryStream ( messageBytes ); -} +class DefaultHandler : HttpHostHandler +{ + public override async Task OnContextCreatedAsync(HttpHost host, HttpHostContext context) + { + var request = context.Request; + var response = context.Response; + + if (request.Path == "/plaintext") + { + var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); + + await SerializeResponseAsync(response, contentBytes, "text/plain; charset=utf-8"); + } + else if (request.Path == "/json") + { + var contentBytes = JsonSerializer.SerializeToUtf8Bytes(new + { + message = "Hello, World!" + }); + + await SerializeResponseAsync(response, contentBytes, "application/json; charset=utf-8"); + } + else + { + response.StatusCode = 404; + } + } -static void SerializeJsonResponse ( HttpHostContext.HttpResponse response ) { + static async ValueTask SerializeResponseAsync(HttpHostContext.HttpResponse response, Memory content, string contentType) + { + response.Headers.Add(new HttpHeader("Content-Type", contentType)); + response.Headers.Add(new HttpHeader("Content-Length", content.Length.ToString())); - var contentBytes = JsonSerializer.SerializeToUtf8Bytes ( new { - message = "Hello, World!" - } ); - - response.Headers.Add ( new HttpHeader ( "Content-Type", "application/json" ) ); - response.ResponseStream = new MemoryStream ( contentBytes ); + using var responseStream = await response.GetResponseStreamAsync(); + await responseStream.WriteAsync(content); + } } \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj b/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj index c72c3f1faee..12f1a5d7c2c 100644 --- a/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj +++ b/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj @@ -9,7 +9,7 @@ - + \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk.dockerfile b/frameworks/CSharp/sisk/sisk.dockerfile index 2a23e04743f..6509bffbd8a 100644 --- a/frameworks/CSharp/sisk/sisk.dockerfile +++ b/frameworks/CSharp/sisk/sisk.dockerfile @@ -9,6 +9,10 @@ RUN dotnet restore -r linux-musl-x64 COPY sisk/ . RUN dotnet publish -c release -o /app -r linux-musl-x64 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 + # final stage/image FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime WORKDIR /app From 195f7bc3f7235591e685c673aa6997c0f0189404 Mon Sep 17 00:00:00 2001 From: AkazawaYun <62974697+AkazawaYun@users.noreply.github.com> Date: Wed, 12 Nov 2025 00:54:31 +0800 Subject: [PATCH 020/130] update version for akazawayun.pro (#10269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add new test : CSharp/akazawayun.pro * modify config and code * add content-type * update url * update package version * add 3 new tests: db、queries、updates 1. add 3 new tests: db、queries、updates; 2. split code to multi files; * - * use generated sql instead const string. * update version * fix bug of db query * set port to 8080 * 升级 akazawayun.pro 框架版本到 14 * i forget to update the port change... * test self whether work fine.. * update nuget version * why pr failed... * 不小心多提交了别人的框架...改回 * akazawayun fix bug * remove db test there is some error in mysql * confirmed there is bug in mysql.data 9.5.0 还是用8080端口吧- -b, 都用8080, 改其他的对比测时不方便 * downgrade mysql.data back to 9.4.0 * fix bug of akazawayun.pro * update version of akazawayun.pro * update version * add platform test * update nupkg version * update version --- .../AkazawaYun.Benchmark.Platform.csproj | 2 +- .../AkazawaYun.Benchmark.WebApi.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj index f59eaf8f615..e43069a4338 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj @@ -15,7 +15,7 @@ - + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj index 547064216f4..452b23e493c 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj @@ -15,7 +15,7 @@ - + From ee7f5801edfa7658ac992b78ad78f09f1be3aeeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=A4=E9=9B=A8=E4=B8=9C?= Date: Wed, 12 Nov 2025 00:54:54 +0800 Subject: [PATCH 021/130] Upgrade hyperlane (#10270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: port * feat: port * feat: db * feat: db * feat: db * feat: lock * feat: lock * feat: v4.41.0 * feat: v4.42.0 * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * feat: inline * feat: dockerfile * feat: v4.52.1 * feat: remove key * remove: log * remove: log * feat: async * remove: empty loop * feat: utf8 * change: pool_size * remove: utf8 * feat: log * feat: log * feat: v3.14.1 * feat: 4.56.3 * feat: 4.56.4 * feat: 4.56.5 * feat: rename * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: speed * feat: speed * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * feat: runtime * feat: runtime * feat: runtime * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: hyperlane * feat: update * docs: readme * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: lock * feat: use super * feat: update lock * feat: update * feat: update lock * feat: update lock * feat: update lock * feat: lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * Merge remote-tracking branch 'upstream/master' * feat: update * feat: utf8 * feat: utf8 * feat: lock * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * update: code * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update version * feat: update version * update: code * Merge remote-tracking branch 'upstream/master' * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: error handle * feat: dep * feat: get_thread_count * update: code * feat: lock * feat: speed * feat: speed * update: code * feat: speed * update: code * feat: lock * fix: Framework hyperlane does not define a default test in benchmark_config.json * feat: hyperlane http version * feat: hyperlane http version * feat: toml * feat: toml * feat: toml * feat: toml * feat: v0.1.0 * feat: toml * feat: v6 * feat: v6 * feat: v6 * feat: v6 * feat: v6 * debug: test cache * debug: test cache * feat: v6 * feat: send unwrap * feat: v6 * feat: v6 * feat: v0.1.0 * feat: toml * feat: toml * feat: db * feat: toml * feat: toml * feat: toml * feat: toml * feat: dir update * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: 2025-10-24 12:22:32 * feat: v0.1.0 * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: v0.1.0 * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: 2025-11-09 18:38:22 --------- Co-authored-by: 尤雨东 <83822098+ltpp-universe@users.noreply.github.com> --- frameworks/Rust/hyperlane/Cargo.lock | 12 ++++++------ frameworks/Rust/hyperlane/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frameworks/Rust/hyperlane/Cargo.lock b/frameworks/Rust/hyperlane/Cargo.lock index 08387adbeb8..2f8ba49c1ee 100644 --- a/frameworks/Rust/hyperlane/Cargo.lock +++ b/frameworks/Rust/hyperlane/Cargo.lock @@ -525,15 +525,15 @@ dependencies = [ [[package]] name = "http-constant" -version = "1.68.0" +version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd414126bc050b1437bed5a52939854b2b7ef214e8e05aacca3663529514e3e" +checksum = "e1dd700ca01982ad65f60942687599f3ac04cf1010673b80af480f1f1f15592a" [[package]] name = "http-type" -version = "5.8.0" +version = "5.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb36d75dbf127e3bfa1c7f404ba69edd760a3a5a93687caaafdb07f73eff64f" +checksum = "60e700017e6818aca191fd8a2f8ba8f524954375b9525f3dd9aabc83c4f999ec" dependencies = [ "hex", "http-compress", @@ -549,9 +549,9 @@ dependencies = [ [[package]] name = "hyperlane" -version = "10.11.3" +version = "10.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c042df01c9d47727269228fa5bacbb25504a6785539c0e5942dd8b2541c33a0" +checksum = "8285c986ed79e5932f112dafb32ee32caf77b561bb782ac4b3b1af49cc27ff09" dependencies = [ "aho-corasick", "http-type", diff --git a/frameworks/Rust/hyperlane/Cargo.toml b/frameworks/Rust/hyperlane/Cargo.toml index 83196a7647b..88209c8ce36 100644 --- a/frameworks/Rust/hyperlane/Cargo.toml +++ b/frameworks/Rust/hyperlane/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ [dependencies] futures = "0.3.31" -hyperlane = "10.11.3" +hyperlane = "10.12.0" hyperlane-time = "0.7.12" num_cpus = "1.17.0" once_cell = "1.21.3" From a050d10624f81b7b44f2b7de05f24b2d69a65ec0 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Tue, 11 Nov 2025 16:56:55 +0000 Subject: [PATCH 022/130] Update the set of broken implementations (#10268) Signed-off-by: Anton Kirilov --- frameworks/C++/ffead-cpp/benchmark_config.json | 4 ++-- frameworks/CSharp/aspnetcore-mono/benchmark_config.json | 3 ++- frameworks/CSharp/revenj/benchmark_config.json | 1 + frameworks/Crystal/grip/benchmark_config.json | 1 + frameworks/Erlang/cowboy/benchmark_config.json | 1 + frameworks/Erlang/elli/benchmark_config.json | 1 + frameworks/Erlang/mochiweb/benchmark_config.json | 1 + frameworks/Go/goravel/benchmark_config.json | 1 + frameworks/Go/ronykit/benchmark_config.json | 4 +++- frameworks/Go/sprapp/benchmark_config.json | 1 + frameworks/Java/gemini/benchmark_config.json | 3 +++ frameworks/Java/officefloor/benchmark_config.json | 4 ++++ frameworks/Java/ratpack/benchmark_config.json | 3 +++ frameworks/Java/revenj-jvm/benchmark_config.json | 1 + frameworks/Java/servlet3/benchmark_config.json | 2 ++ frameworks/Java/wildfly-ee/benchmark_config.json | 3 ++- frameworks/JavaScript/elide/benchmark_config.json | 1 + frameworks/JavaScript/spliffy/benchmark_config.json | 4 ++++ .../vertx-web-kotlin-coroutines/benchmark_config.json | 1 + frameworks/Lua/openresty/benchmark_config.json | 1 + frameworks/Nim/basolato/benchmark_config.json | 1 + frameworks/Nim/httpbeast/benchmark_config.json | 1 + frameworks/Nim/jester/benchmark_config.json | 1 + frameworks/Nim/nim-stdlib/benchmark_config.json | 1 + frameworks/Nim/scorper/benchmark_config.json | 1 + frameworks/PHP/fomo/benchmark_config.json | 2 +- frameworks/PHP/fuel/benchmark_config.json | 1 + frameworks/Perl/plack/benchmark_config.json | 1 + frameworks/Python/eve/benchmark_config.json | 1 + frameworks/Python/flask/benchmark_config.json | 3 ++- frameworks/Python/klein/benchmark_config.json | 1 + frameworks/Python/turbogears/benchmark_config.json | 1 + frameworks/Python/web2py/benchmark_config.json | 2 ++ frameworks/Rust/gotham/benchmark_config.json | 1 + frameworks/Rust/pavex/benchmark_config.json | 1 + frameworks/Rust/rocket/benchmark_config.json | 1 + frameworks/Rust/salvo/benchmark_config.json | 8 ++++++++ frameworks/Rust/warp-rust/benchmark_config.json | 1 + 38 files changed, 63 insertions(+), 7 deletions(-) diff --git a/frameworks/C++/ffead-cpp/benchmark_config.json b/frameworks/C++/ffead-cpp/benchmark_config.json index 6ab98997f9d..0a61221fc46 100644 --- a/frameworks/C++/ffead-cpp/benchmark_config.json +++ b/frameworks/C++/ffead-cpp/benchmark_config.json @@ -198,7 +198,7 @@ "display_name": "ffead-cpp [pg-raw-async-prof-pool-m]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] }, "postgresql-raw-async-clibpqb-profiled": { "db_url": "/t4/d", @@ -301,7 +301,7 @@ "display_name": "ffead-cpp [pg-raw-async-qw-prof-pool-m]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] } }] } diff --git a/frameworks/CSharp/aspnetcore-mono/benchmark_config.json b/frameworks/CSharp/aspnetcore-mono/benchmark_config.json index e52c7d74b55..74fd85c0b83 100644 --- a/frameworks/CSharp/aspnetcore-mono/benchmark_config.json +++ b/frameworks/CSharp/aspnetcore-mono/benchmark_config.json @@ -40,6 +40,7 @@ "database_os": "Linux", "display_name": "ASP.NET Core [Platform, Mono, Pg]", "notes": "", + "tags": ["broken"], "versus": "aspcore-ado-pg" }, "mw": { @@ -123,4 +124,4 @@ "versus": "aspcore-mono-pg" } }] -} \ No newline at end of file +} diff --git a/frameworks/CSharp/revenj/benchmark_config.json b/frameworks/CSharp/revenj/benchmark_config.json index 8472ef41d12..402a5129f93 100644 --- a/frameworks/CSharp/revenj/benchmark_config.json +++ b/frameworks/CSharp/revenj/benchmark_config.json @@ -22,6 +22,7 @@ "os": "Linux", "display_name": "Revenj", "notes": "", + "tags": ["broken"], "versus": "Revenj" } }] diff --git a/frameworks/Crystal/grip/benchmark_config.json b/frameworks/Crystal/grip/benchmark_config.json index 56cd319dfc9..fbd828243a3 100644 --- a/frameworks/Crystal/grip/benchmark_config.json +++ b/frameworks/Crystal/grip/benchmark_config.json @@ -23,6 +23,7 @@ "database_os": "Linux", "display_name": "Grip", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Erlang/cowboy/benchmark_config.json b/frameworks/Erlang/cowboy/benchmark_config.json index 324b087d481..7c37a4a6864 100644 --- a/frameworks/Erlang/cowboy/benchmark_config.json +++ b/frameworks/Erlang/cowboy/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "Cowboy", "notes": "", + "tags": ["broken"], "versus": "" }}] } diff --git a/frameworks/Erlang/elli/benchmark_config.json b/frameworks/Erlang/elli/benchmark_config.json index 2910a94924c..ce58700f3e1 100644 --- a/frameworks/Erlang/elli/benchmark_config.json +++ b/frameworks/Erlang/elli/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "elli", "notes": "", + "tags": ["broken"], "versus": "" }}] } diff --git a/frameworks/Erlang/mochiweb/benchmark_config.json b/frameworks/Erlang/mochiweb/benchmark_config.json index 57f8dcbf8a8..e45bfbf83e7 100644 --- a/frameworks/Erlang/mochiweb/benchmark_config.json +++ b/frameworks/Erlang/mochiweb/benchmark_config.json @@ -21,6 +21,7 @@ "database_os": "Linux", "display_name": "mochiweb", "notes": "", + "tags": ["broken"], "versus": "" }}] } diff --git a/frameworks/Go/goravel/benchmark_config.json b/frameworks/Go/goravel/benchmark_config.json index bcb01875139..5be71f6fdbe 100644 --- a/frameworks/Go/goravel/benchmark_config.json +++ b/frameworks/Go/goravel/benchmark_config.json @@ -48,6 +48,7 @@ "database_os": "Linux", "display_name": "Goravel Fiber", "notes": "", + "tags": ["broken"], "versus": "go" } } diff --git a/frameworks/Go/ronykit/benchmark_config.json b/frameworks/Go/ronykit/benchmark_config.json index 69684f9bcef..dcff4ef38bd 100644 --- a/frameworks/Go/ronykit/benchmark_config.json +++ b/frameworks/Go/ronykit/benchmark_config.json @@ -18,6 +18,7 @@ "os": "Linux", "display_name": "RonyKIT", "notes": "", + "tags": ["broken"], "versus": "go" }, "prefork": { @@ -36,8 +37,9 @@ "os": "Linux", "display_name": "RonyKIT", "notes": "", + "tags": ["broken"], "versus": "go" } } ] -} \ No newline at end of file +} diff --git a/frameworks/Go/sprapp/benchmark_config.json b/frameworks/Go/sprapp/benchmark_config.json index a8764b2fe88..9074fd3c2db 100644 --- a/frameworks/Go/sprapp/benchmark_config.json +++ b/frameworks/Go/sprapp/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "SPRAPP", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Java/gemini/benchmark_config.json b/frameworks/Java/gemini/benchmark_config.json index e4049a488c6..0f051744dfa 100644 --- a/frameworks/Java/gemini/benchmark_config.json +++ b/frameworks/Java/gemini/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "Gemini", "notes": "", + "tags": ["broken"], "versus": "servlet" }, "mysql": { @@ -42,6 +43,7 @@ "database_os": "Linux", "display_name": "Gemini", "notes": "", + "tags": ["broken"], "versus": "servlet" }, "postgres": { @@ -64,6 +66,7 @@ "database_os": "Linux", "display_name": "Gemini", "notes": "", + "tags": ["broken"], "versus": "servlet" } } diff --git a/frameworks/Java/officefloor/benchmark_config.json b/frameworks/Java/officefloor/benchmark_config.json index 1a309d4ccbd..d90efc51b9d 100755 --- a/frameworks/Java/officefloor/benchmark_config.json +++ b/frameworks/Java/officefloor/benchmark_config.json @@ -47,6 +47,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-r2dbc", + "tags": ["broken"], "notes": "" }, "sqlclient": { @@ -69,6 +70,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-sqlclient", + "tags": ["broken"], "notes": "" }, "rawsqlclient": { @@ -91,6 +93,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-rawsqlclient", + "tags": ["broken"], "notes": "" }, "async": { @@ -162,6 +165,7 @@ "database_os": "Linux", "display_name": "OfficeFloor-thread_affinity", "notes": "", + "tags": ["broken"], "versus": "OfficeFloor-r2dbc" }, "netty": { diff --git a/frameworks/Java/ratpack/benchmark_config.json b/frameworks/Java/ratpack/benchmark_config.json index c3a755d87ab..85d054fed35 100755 --- a/frameworks/Java/ratpack/benchmark_config.json +++ b/frameworks/Java/ratpack/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Ratpack", "notes": "", + "tags": ["broken"], "versus": "Netty" }, "jdbc": { @@ -40,6 +41,7 @@ "database_os": "Linux", "display_name": "Ratpack-jdbc", "notes": "", + "tags": ["broken"], "versus": "Netty" }, "pgclient": { @@ -61,6 +63,7 @@ "database_os": "Linux", "display_name": "Ratpack-pgclient", "notes": "", + "tags": ["broken"], "versus": "Netty" } } diff --git a/frameworks/Java/revenj-jvm/benchmark_config.json b/frameworks/Java/revenj-jvm/benchmark_config.json index 4187598430b..ffc6b919ca6 100644 --- a/frameworks/Java/revenj-jvm/benchmark_config.json +++ b/frameworks/Java/revenj-jvm/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "Revenj.JVM", "notes": "", + "tags": ["broken"], "versus": "servlet" } }] diff --git a/frameworks/Java/servlet3/benchmark_config.json b/frameworks/Java/servlet3/benchmark_config.json index b6e4d1b5400..cd2a050e174 100644 --- a/frameworks/Java/servlet3/benchmark_config.json +++ b/frameworks/Java/servlet3/benchmark_config.json @@ -17,6 +17,7 @@ "database_os": "Linux", "display_name": "servlet3", "notes": "Servlet 3.1 Async I/O", + "tags": ["broken"], "versus": "servlet" }, "sync": { @@ -35,6 +36,7 @@ "database_os": "Linux", "display_name": "servlet3", "notes": "", + "tags": ["broken"], "versus": "servlet" } }] diff --git a/frameworks/Java/wildfly-ee/benchmark_config.json b/frameworks/Java/wildfly-ee/benchmark_config.json index 1628dc35eef..7fc9770b023 100644 --- a/frameworks/Java/wildfly-ee/benchmark_config.json +++ b/frameworks/Java/wildfly-ee/benchmark_config.json @@ -22,7 +22,8 @@ "database_os": "Linux", "display_name": "wildfly-ee", "notes": "", + "tags": ["broken"], "versus": "" - } + } }] } diff --git a/frameworks/JavaScript/elide/benchmark_config.json b/frameworks/JavaScript/elide/benchmark_config.json index 32c9d7e82aa..8b8e8599c57 100644 --- a/frameworks/JavaScript/elide/benchmark_config.json +++ b/frameworks/JavaScript/elide/benchmark_config.json @@ -14,6 +14,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "elide", + "tags": ["broken"], "versus": "nodejs" } }] diff --git a/frameworks/JavaScript/spliffy/benchmark_config.json b/frameworks/JavaScript/spliffy/benchmark_config.json index 750dc5bd0cc..40dcb1614bd 100644 --- a/frameworks/JavaScript/spliffy/benchmark_config.json +++ b/frameworks/JavaScript/spliffy/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" }, "mongodb": { @@ -41,6 +42,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" }, "mysql": { @@ -63,6 +65,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" }, "postgres": { @@ -85,6 +88,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json index 2b8ebd26c83..6697013773f 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json @@ -18,6 +18,7 @@ "database_os": "Linux", "display_name": "vertx-web-kotlin-coroutines", "notes": "", + "tags": ["broken"], "versus": "vertx-web" }, "postgres": { diff --git a/frameworks/Lua/openresty/benchmark_config.json b/frameworks/Lua/openresty/benchmark_config.json index 6b32f71f3de..7fa51aa4a95 100644 --- a/frameworks/Lua/openresty/benchmark_config.json +++ b/frameworks/Lua/openresty/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "openresty", "notes": "", + "tags": ["broken"], "versus": "openresty" } }] diff --git a/frameworks/Nim/basolato/benchmark_config.json b/frameworks/Nim/basolato/benchmark_config.json index 1bb2d11484e..e0f90c90dcc 100755 --- a/frameworks/Nim/basolato/benchmark_config.json +++ b/frameworks/Nim/basolato/benchmark_config.json @@ -23,6 +23,7 @@ "database_os": "Linux", "display_name": "Basolato", "notes": "", + "tags": ["broken"], "versus": "httpbeast, prologue" } } diff --git a/frameworks/Nim/httpbeast/benchmark_config.json b/frameworks/Nim/httpbeast/benchmark_config.json index be0ab4480b8..7aa8ac8fc19 100755 --- a/frameworks/Nim/httpbeast/benchmark_config.json +++ b/frameworks/Nim/httpbeast/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "HttpBeast", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Nim/jester/benchmark_config.json b/frameworks/Nim/jester/benchmark_config.json index b5795fba053..61499a79da1 100644 --- a/frameworks/Nim/jester/benchmark_config.json +++ b/frameworks/Nim/jester/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Jester", "notes": "", + "tags": ["broken"], "versus": "httpbeast" } } diff --git a/frameworks/Nim/nim-stdlib/benchmark_config.json b/frameworks/Nim/nim-stdlib/benchmark_config.json index acd5712689a..710cb9996ea 100644 --- a/frameworks/Nim/nim-stdlib/benchmark_config.json +++ b/frameworks/Nim/nim-stdlib/benchmark_config.json @@ -23,6 +23,7 @@ "database_os": "Linux", "display_name": "nim-stdlib", "notes": "", + "tags": ["broken"], "versus": "httpbeast" } } diff --git a/frameworks/Nim/scorper/benchmark_config.json b/frameworks/Nim/scorper/benchmark_config.json index 77669f6cad2..6a365398a14 100755 --- a/frameworks/Nim/scorper/benchmark_config.json +++ b/frameworks/Nim/scorper/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "scorper", "notes": "", + "tags": ["broken"], "versus": "httpbeast" } } diff --git a/frameworks/PHP/fomo/benchmark_config.json b/frameworks/PHP/fomo/benchmark_config.json index f79f7905e7e..817107d03d2 100755 --- a/frameworks/PHP/fomo/benchmark_config.json +++ b/frameworks/PHP/fomo/benchmark_config.json @@ -23,9 +23,9 @@ "database_os": "Linux", "display_name": "Fomo", "notes": "", + "tags": ["broken"], "versus": "swoole" } } ] } - \ No newline at end of file diff --git a/frameworks/PHP/fuel/benchmark_config.json b/frameworks/PHP/fuel/benchmark_config.json index d831c427cc3..98761b3a7a4 100644 --- a/frameworks/PHP/fuel/benchmark_config.json +++ b/frameworks/PHP/fuel/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "fuel", "notes": "", + "tags": ["broken"], "versus": "php" } }] diff --git a/frameworks/Perl/plack/benchmark_config.json b/frameworks/Perl/plack/benchmark_config.json index 6cf3d2a19ff..d3b26a6f800 100644 --- a/frameworks/Perl/plack/benchmark_config.json +++ b/frameworks/Perl/plack/benchmark_config.json @@ -39,6 +39,7 @@ "database_os": "Linux", "display_name": "plack-async", "notes": "", + "tags": ["broken"], "versus": "plack" } }] diff --git a/frameworks/Python/eve/benchmark_config.json b/frameworks/Python/eve/benchmark_config.json index 3e9e7cdc102..cb11c1586d1 100644 --- a/frameworks/Python/eve/benchmark_config.json +++ b/frameworks/Python/eve/benchmark_config.json @@ -18,6 +18,7 @@ "database_os": "Linux", "display_name": "Eve", "notes": "", + "tags": ["broken"], "versus": "" } }] diff --git a/frameworks/Python/flask/benchmark_config.json b/frameworks/Python/flask/benchmark_config.json index dad6b8ef11a..ee505a984c0 100644 --- a/frameworks/Python/flask/benchmark_config.json +++ b/frameworks/Python/flask/benchmark_config.json @@ -45,7 +45,7 @@ "display_name": "Flask [Meinheld] [Raw]", "notes": "", "versus": "wsgi", - "tags": [ ] + "tags": [ "broken" ] }, "socketify-wsgi": { "json_url": "/json-raw", @@ -83,6 +83,7 @@ "database_os": "Linux", "display_name": "Flask [socketify.py] [PyPy3]", "notes": "PyPy", + "tags": ["broken"], "versus": "wsgi" }, "pypy": { diff --git a/frameworks/Python/klein/benchmark_config.json b/frameworks/Python/klein/benchmark_config.json index e43ece59d8d..e00da480751 100644 --- a/frameworks/Python/klein/benchmark_config.json +++ b/frameworks/Python/klein/benchmark_config.json @@ -21,6 +21,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "Klein", + "tags": ["broken"], "notes": "CPython 2.7" } }] diff --git a/frameworks/Python/turbogears/benchmark_config.json b/frameworks/Python/turbogears/benchmark_config.json index cfd4c3efda7..162dbb38e64 100644 --- a/frameworks/Python/turbogears/benchmark_config.json +++ b/frameworks/Python/turbogears/benchmark_config.json @@ -21,6 +21,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "TurboGears", + "tags": ["broken"], "notes": "CPython 2.7" } }] diff --git a/frameworks/Python/web2py/benchmark_config.json b/frameworks/Python/web2py/benchmark_config.json index d1349f5633e..c8bf7c94bf0 100644 --- a/frameworks/Python/web2py/benchmark_config.json +++ b/frameworks/Python/web2py/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "web2py-standard", "notes": "CPython 2.7", + "tags": ["broken"], "versus": "wsgi" }, "optimized": { @@ -44,6 +45,7 @@ "database_os": "Linux", "display_name": "web2py-optimized", "notes": "CPython 2.7", + "tags": ["broken"], "versus": "wsgi" } }] diff --git a/frameworks/Rust/gotham/benchmark_config.json b/frameworks/Rust/gotham/benchmark_config.json index 2ee7db2a39f..8813ea15eed 100755 --- a/frameworks/Rust/gotham/benchmark_config.json +++ b/frameworks/Rust/gotham/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Gotham", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/pavex/benchmark_config.json b/frameworks/Rust/pavex/benchmark_config.json index e9decbdcdd9..1a4bc1856a7 100755 --- a/frameworks/Rust/pavex/benchmark_config.json +++ b/frameworks/Rust/pavex/benchmark_config.json @@ -18,6 +18,7 @@ "database_os": "Linux", "display_name": "pavex", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/rocket/benchmark_config.json b/frameworks/Rust/rocket/benchmark_config.json index 2569f14f9ef..fb37d7377e9 100755 --- a/frameworks/Rust/rocket/benchmark_config.json +++ b/frameworks/Rust/rocket/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "Rocket", "notes": "", + "tags": ["broken"], "versus": "None" }, "diesel": { diff --git a/frameworks/Rust/salvo/benchmark_config.json b/frameworks/Rust/salvo/benchmark_config.json index 2890085bf66..d5f4d1f91a0 100644 --- a/frameworks/Rust/salvo/benchmark_config.json +++ b/frameworks/Rust/salvo/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Salvo", "notes": "", + "tags": ["broken"], "versus": "None" }, "diesel": { @@ -39,6 +40,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres-diesel]", "notes": "", + "tags": ["broken"], "versus": "None" }, "pg": { @@ -59,6 +61,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres]", "notes": "", + "tags": ["broken"], "versus": "None" }, "pg-pool": { @@ -79,6 +82,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres-deadpool]", "notes": "", + "tags": ["broken"], "versus": "None" }, "mongo": { @@ -99,6 +103,7 @@ "database_os": "Linux", "display_name": "Salvo [mongodb]", "notes": "", + "tags": ["broken"], "versus": "None" }, "mongo-raw": { @@ -118,6 +123,7 @@ "database_os": "Linux", "display_name": "Salvo [mongodb-raw]", "notes": "", + "tags": ["broken"], "versus": "None" }, "sqlx": { @@ -136,6 +142,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres-sqlx]", "notes": "", + "tags": ["broken"], "versus": "None" }, "lru": { @@ -153,6 +160,7 @@ "database_os": "Linux", "display_name": "Salvo [lru]", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/warp-rust/benchmark_config.json b/frameworks/Rust/warp-rust/benchmark_config.json index 5d91146bef5..1f159f54957 100755 --- a/frameworks/Rust/warp-rust/benchmark_config.json +++ b/frameworks/Rust/warp-rust/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "warp-rust", "notes": "", + "tags": ["broken"], "versus": "None" } } From f4188f00397f0340b3a140f79773b313ba728aa9 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 11 Nov 2025 17:58:07 +0100 Subject: [PATCH 023/130] Warn if frameworks exceed the maximum number of test mutations (#9667) > The number of test mutations will be limited to 10. https://github.com/TechEmpower/FrameworkBenchmarks/issues/8420 This change shows a warning message for frameworks if the maximum is reached. --- toolset/utils/metadata.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/toolset/utils/metadata.py b/toolset/utils/metadata.py index 6e440fc23ab..6f7388828b8 100644 --- a/toolset/utils/metadata.py +++ b/toolset/utils/metadata.py @@ -191,6 +191,18 @@ def parse_config(self, config, directory): % config['framework'], color=Fore.YELLOW) + # Check that each framework does not have more than the maximum number of tests + maximum_tests = 10 + non_broken_tests_filter = lambda test: (not hasattr(test, "tags")) or ("broken" not in test.tags) + non_broken_tests_to_run = list(filter(non_broken_tests_filter, tests_to_run)) + if len(non_broken_tests_to_run) > maximum_tests: + message = [ + "Framework %s defines %s tests in benchmark_config.json (max is %s)." + % (config['framework'], len(non_broken_tests_to_run), maximum_tests), + "Contact maintainers and remove deprecated or discarded ones to make room." + ] + log("\n".join(message), color=Fore.YELLOW) + # Check that each test configuration is acceptable # Throw exceptions if a field is missing, or how to improve the field for test_name, test_keys in test.items(): From 140ebc97b22cffc2026d4505ec7877a2a94246ea Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Tue, 11 Nov 2025 09:03:56 -0800 Subject: [PATCH 024/130] Add --force-rm flag (#9727) * feat: add `--force-rm` flag to configure removing intermediate docker layers This commit makes it possible to turn off the removal of intermediate docker layers when building the tfb containers by adding a `--force-rm` flag to the tfb script. This is useful in situations where you want to inspect the intermediate layers for debugging purposes, or for caching builds of dependencies as a docker layer to speed up the build process. Note that the default behavior is to remove the intermediate layers to avoid filling up the disk with unused layers on the citrine server. Fixes: https://github.com/TechEmpower/FrameworkBenchmarks/issues/9718 * hyper: cache dependencies to reduce build time This change reduces the time it takes to build the hyper Docker image by caching the dependency builds. This is done by building a dummy binary before copying the source code into the image. * Change default for --force-rm to False --------- Co-authored-by: Mike Smith --- frameworks/Rust/hyper/hyper.dockerfile | 13 +++++++++++-- toolset/run-tests.py | 4 ++++ toolset/utils/benchmark_config.py | 1 + toolset/utils/docker_helper.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/frameworks/Rust/hyper/hyper.dockerfile b/frameworks/Rust/hyper/hyper.dockerfile index b2f6b8cb6b3..4816011104f 100644 --- a/frameworks/Rust/hyper/hyper.dockerfile +++ b/frameworks/Rust/hyper/hyper.dockerfile @@ -1,8 +1,17 @@ FROM rust:1.85 AS hyper WORKDIR /src -COPY . . -RUN RUSTFLAGS="-C target-cpu=native" cargo install --path . --locked +ENV RUSTFLAGS="-C target-cpu=native" + +# Cache dependency builds (requires passing --force-rm False to tfb command) +COPY Cargo.toml Cargo.lock /src/ +RUN mkdir src \ + && echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs \ + && cargo build --release \ + && rm -rfv src/ target/release/hyper-techempower* target/release/deps/hyper_techempower* + +COPY . /src/ +RUN cargo install --path . --locked EXPOSE 8080 CMD ["hyper-techempower"] HEALTHCHECK CMD curl --fail http://localhost:8080/ping || exit 1 \ No newline at end of file diff --git a/toolset/run-tests.py b/toolset/run-tests.py index a70fff3a490..ac24969c4e4 100644 --- a/toolset/run-tests.py +++ b/toolset/run-tests.py @@ -208,6 +208,10 @@ def main(argv=None): nargs='*', default=None, help='Extra docker arguments to be passed to the test container') + parser.add_argument( + '--force-rm', + default=False, + help='Remove intermediate docker containers after running.') # Network options parser.add_argument( diff --git a/toolset/utils/benchmark_config.py b/toolset/utils/benchmark_config.py index 04dcc2c6cc3..d73dcb4125c 100644 --- a/toolset/utils/benchmark_config.py +++ b/toolset/utils/benchmark_config.py @@ -57,6 +57,7 @@ def __init__(self, args): self.cpuset_cpus = args.cpuset_cpus self.test_container_memory = args.test_container_memory self.extra_docker_runtime_args = args.extra_docker_runtime_args + self.force_rm_intermediate_docker_layers = args.force_rm if self.network_mode is None: self.network = 'tfb' diff --git a/toolset/utils/docker_helper.py b/toolset/utils/docker_helper.py index e48a910e99d..f25a9d133a0 100644 --- a/toolset/utils/docker_helper.py +++ b/toolset/utils/docker_helper.py @@ -39,7 +39,7 @@ def __build(self, base_url, path, build_log_file, log_prefix, dockerfile, path=path, dockerfile=dockerfile, tag=tag, - forcerm=True, + forcerm=self.benchmarker.config.force_rm_intermediate_docker_layers, timeout=3600, pull=True, buildargs=buildargs, From fced31e613e5df4998e5b663636e1176bec40eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Tue, 11 Nov 2025 18:18:29 +0100 Subject: [PATCH 025/130] Update some CSharp frameworks to latest (#10184) --- .../embedio/Benchmarks/Benchmarks.csproj | 26 ++++++++--------- .../CSharp/embedio/Benchmarks/Program.cs | 14 ++++++---- frameworks/CSharp/embedio/README.md | 6 ++-- frameworks/CSharp/embedio/embedio.dockerfile | 6 ++-- .../genhttp/Benchmarks/Benchmarks.csproj | 8 +++--- .../Benchmarks/Benchmarks.csproj | 28 +++++++++---------- .../Benchmarks/HttpBenchmarkSession.cs | 2 +- .../netcoreserver/Benchmarks/Program.cs | 6 ++-- frameworks/CSharp/netcoreserver/README.md | 6 ++-- .../netcoreserver/netcoreserver.dockerfile | 6 ++-- 10 files changed, 55 insertions(+), 53 deletions(-) diff --git a/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj index 19e73c8b7c4..0015577d97e 100644 --- a/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj @@ -1,23 +1,23 @@  - + - - net5.0 - 9.0 - + + net9.0 + 13.0 + EmbedIO Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. - - Benchmarks.Program + + Benchmarks.Program Exe - + true false - + - + - + - - \ No newline at end of file + + diff --git a/frameworks/CSharp/embedio/Benchmarks/Program.cs b/frameworks/CSharp/embedio/Benchmarks/Program.cs index db1f8734c3e..f554daee530 100644 --- a/frameworks/CSharp/embedio/Benchmarks/Program.cs +++ b/frameworks/CSharp/embedio/Benchmarks/Program.cs @@ -1,10 +1,12 @@ -using EmbedIO; -using Swan.Logging; -using System; +using System; using System.Text; using System.Threading; using System.Threading.Tasks; +using EmbedIO; + +using Swan.Logging; + namespace Benchmarks { @@ -21,7 +23,7 @@ public class JsonResult public static class Program { - private static readonly ManualResetEvent _WaitEvent = new ManualResetEvent(false); + private static readonly ManualResetEvent WaitEvent = new(false); public static async Task Main(string[] args) { @@ -60,12 +62,12 @@ public static async Task Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += (_, __) => { - _WaitEvent.Set(); + WaitEvent.Set(); }; await server.RunAsync(); - _WaitEvent.WaitOne(); + WaitEvent.WaitOne(); return 0; } diff --git a/frameworks/CSharp/embedio/README.md b/frameworks/CSharp/embedio/README.md index f04d7d2ecd9..afa7412870f 100644 --- a/frameworks/CSharp/embedio/README.md +++ b/frameworks/CSharp/embedio/README.md @@ -6,17 +6,17 @@ See the [project website](https://github.com/unosquare/embedio) for more informa **Language** -* C# 9.0 +* C# 13.0 **Platforms** -* .NET 5 +* .NET 9 **Web Servers** * [EmbedIO](https://github.com/unosquare/embedio) -## Paths & Source for Tests +## Paths \& Source for Tests * [Plaintext](Benchmarks/Program.cs): "/plaintext" * [JSON](Benchmarks/Program.cs): "/json" diff --git a/frameworks/CSharp/embedio/embedio.dockerfile b/frameworks/CSharp/embedio/embedio.dockerfile index 675c16d8841..35e05ff1fc4 100644 --- a/frameworks/CSharp/embedio/embedio.dockerfile +++ b/frameworks/CSharp/embedio/embedio.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,10 +7,10 @@ RUN dotnet restore -r linux-musl-x64 # copy and publish app and libraries COPY Benchmarks/ . -RUN dotnet publish -c release -o /app -r linux-musl-x64 +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained # final stage/image -FROM mcr.microsoft.com/dotnet/runtime-deps:5.0-alpine +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine WORKDIR /app COPY --from=build /app . diff --git a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj index 529f7add6ca..1189d0c151c 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj @@ -26,11 +26,11 @@ - - + + - - + + diff --git a/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj index 6d372b01ee3..8315e4a6e83 100644 --- a/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj @@ -1,24 +1,24 @@  - + - - net5.0 - 9.0 - + + net9.0 + 13.0 + EmbedIO Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. - - Benchmarks.Program + + Benchmarks.Program Exe - + true false - + - + - - + + - - \ No newline at end of file + + diff --git a/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs b/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs index 25e58bd5aa1..bb99ce8f2c1 100644 --- a/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs +++ b/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs @@ -27,7 +27,7 @@ protected override void OnReceivedRequest(HttpRequest request) } else { - SendResponseAsync(Response.MakeErrorResponse("Not found", 404)); + SendResponseAsync(Response.MakeErrorResponse(404, "Not found")); } } diff --git a/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs b/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs index 411569ffb2f..3a821463b10 100644 --- a/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs +++ b/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs @@ -8,7 +8,7 @@ namespace Benchmarks public static class Program { - private static readonly ManualResetEvent _WaitEvent = new ManualResetEvent(false); + private static readonly ManualResetEvent WaitEvent = new(false); public static int Main(string[] args) { @@ -18,12 +18,12 @@ public static int Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += (_, __) => { - _WaitEvent.Set(); + WaitEvent.Set(); }; server.Start(); - _WaitEvent.WaitOne(); + WaitEvent.WaitOne(); return 0; } diff --git a/frameworks/CSharp/netcoreserver/README.md b/frameworks/CSharp/netcoreserver/README.md index 985758c2bc9..31c1e995dcd 100644 --- a/frameworks/CSharp/netcoreserver/README.md +++ b/frameworks/CSharp/netcoreserver/README.md @@ -6,17 +6,17 @@ See the [project website](https://github.com/chronoxor/NetCoreServer) for more i **Language** -* C# 9.0 +* C# 13.0 **Platforms** -* .NET 5 +* .NET 9 **Web Servers** * [NetCoreServer](https://github.com/chronoxor/NetCoreServer) -## Paths & Source for Tests +## Paths \& Source for Tests * [Plaintext](Benchmarks/HttpBenchmarkSession.cs): "/plaintext" * [JSON](Benchmarks/HttpBenchmarkSession.cs): "/json" diff --git a/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile b/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile index 675c16d8841..35e05ff1fc4 100644 --- a/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile +++ b/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,10 +7,10 @@ RUN dotnet restore -r linux-musl-x64 # copy and publish app and libraries COPY Benchmarks/ . -RUN dotnet publish -c release -o /app -r linux-musl-x64 +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained # final stage/image -FROM mcr.microsoft.com/dotnet/runtime-deps:5.0-alpine +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine WORKDIR /app COPY --from=build /app . From e6c7d05c1ea6978f15fa0926197bcdf8a98b48d1 Mon Sep 17 00:00:00 2001 From: cclilshy Date: Wed, 12 Nov 2025 02:34:12 +0800 Subject: [PATCH 026/130] [PHP/ripple] Sync the update of the Ripple (#10223) * Sync the update of the Ripple * Sync the update of the Ripple --- frameworks/PHP/ripple/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/PHP/ripple/server.php b/frameworks/PHP/ripple/server.php index 7d197c53a89..400e9fd574b 100644 --- a/frameworks/PHP/ripple/server.php +++ b/frameworks/PHP/ripple/server.php @@ -5,7 +5,7 @@ use Ripple\Database\Interface\AbstractResultSet; use Ripple\Database\MySQL\Client; use Ripple\Net\Http\Server; -use Ripple\Net\Http\Server\Request; +use Ripple\Net\Http\Request; use Ripple\Sync\Channel; use Ripple\Sync\WaitGroup; use Ripple\Worker; From d4197fad5f503884acead8a533980bb0df22a693 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 11 Nov 2025 22:24:51 +0100 Subject: [PATCH 027/130] [ruby/padrino] Cleanup for Iodine (#10271) Remove some unused code. --- frameworks/Ruby/padrino/app/controllers.rb | 4 ---- frameworks/Ruby/padrino/config/database.rb | 11 +++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/frameworks/Ruby/padrino/app/controllers.rb b/frameworks/Ruby/padrino/app/controllers.rb index c2a3291d797..e5a200c7f2c 100644 --- a/frameworks/Ruby/padrino/app/controllers.rb +++ b/frameworks/Ruby/padrino/app/controllers.rb @@ -7,10 +7,6 @@ response['Server'] = 'padrino' end - after do - response['Date'] = Time.now.httpdate - end if defined?(Puma) - get '/json', :provides => [:json] do {message: "Hello, World!"}.to_json end diff --git a/frameworks/Ruby/padrino/config/database.rb b/frameworks/Ruby/padrino/config/database.rb index 06324898cd9..c4bf9d564d2 100644 --- a/frameworks/Ruby/padrino/config/database.rb +++ b/frameworks/Ruby/padrino/config/database.rb @@ -8,14 +8,9 @@ } # Determine threading/thread pool size and timeout -if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:pool] = threads - opts[:checkout_timeout] = 10 -else - # TODO: ActiveRecord doesn't have a single-threaded mode? - opts[:pool] = 1 - opts[:checkout_timeout] = 0 -end +# TODO: ActiveRecord doesn't have a single-threaded mode? +opts[:pool] = 512 +opts[:checkout_timeout] = 5 # Setup our logger From 92bf758fd3771da4522f6954b5da69f6153b1bf5 Mon Sep 17 00:00:00 2001 From: rio Date: Thu, 13 Nov 2025 06:32:25 +0900 Subject: [PATCH 028/130] [PHP] remove unused extension, polyfill (#10272) * [PHP] remove unused extension, polyfill symfony, laravel * [PHP] add laravel, symfony workers intl extension --- frameworks/PHP/laravel/composer.json | 16 ++++++++++++++++ .../laravel/laravel-octane-frankenphp.dockerfile | 7 ++++--- frameworks/PHP/laravel/laravel-ripple.dockerfile | 3 ++- .../PHP/laravel/laravel-roadrunner.dockerfile | 7 +++++-- frameworks/PHP/laravel/laravel-swoole.dockerfile | 4 ++-- .../PHP/laravel/laravel-workerman.dockerfile | 2 +- frameworks/PHP/symfony/composer.json | 1 + frameworks/PHP/symfony/symfony-mysql.dockerfile | 2 +- frameworks/PHP/symfony/symfony.dockerfile | 2 +- 9 files changed, 33 insertions(+), 11 deletions(-) diff --git a/frameworks/PHP/laravel/composer.json b/frameworks/PHP/laravel/composer.json index 391fa9a1106..be731270c67 100644 --- a/frameworks/PHP/laravel/composer.json +++ b/frameworks/PHP/laravel/composer.json @@ -25,6 +25,22 @@ "App\\": "app/" } }, + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-mbstring":"*", + "symfony/polyfill-intl-idn": "*", + "symfony/polyfill-intl-normalizer": "*", + "symfony/polyfill-intl-grapheme": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php84": "*" + }, "minimum-stability": "stable", "prefer-stable": true, "scripts": { diff --git a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile index b483b396d10..da9fc1c16c5 100644 --- a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile +++ b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile @@ -1,12 +1,13 @@ FROM dunglas/frankenphp - + +RUN apt-get update -yqq && apt-get install libicu-dev unzip -y RUN install-php-extensions \ + intl \ pcntl \ pdo_mysql \ zip > /dev/null - -COPY --link . /app/ +COPY --link . /app/ COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer RUN mkdir -p bootstrap/cache \ diff --git a/frameworks/PHP/laravel/laravel-ripple.dockerfile b/frameworks/PHP/laravel/laravel-ripple.dockerfile index 2fc4a480716..0ce2de40016 100644 --- a/frameworks/PHP/laravel/laravel-ripple.dockerfile +++ b/frameworks/PHP/laravel/laravel-ripple.dockerfile @@ -4,6 +4,7 @@ RUN apt-get update -yqq >> /dev/null RUN apt-get install -y libevent-dev \ libssl-dev \ pkg-config \ + libicu-dev \ build-essential \ unzip >> /dev/null @@ -15,7 +16,7 @@ RUN docker-php-ext-install pdo_mysql \ RUN pecl install event >> /dev/null -RUN docker-php-ext-enable pdo_mysql opcache posix pcntl sockets +RUN docker-php-ext-enable intl pdo_mysql opcache posix pcntl sockets RUN docker-php-ext-enable --ini-name zz-event.ini event RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini diff --git a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile index 9a0c3aed98b..730df104fea 100644 --- a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile +++ b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile @@ -1,6 +1,7 @@ FROM php:8.4-cli - -RUN docker-php-ext-install pdo_mysql pcntl opcache sockets > /dev/null +RUN apt-get update -yqq && \ + apt-get install -yqq libpq-dev libicu-dev > /dev/null && \ +docker-php-ext-install intl pdo_mysql pcntl opcache sockets > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini @@ -26,6 +27,8 @@ RUN composer require laravel/octane --update-no-dev --no-scripts --quiet RUN php artisan octane:install --server="roadrunner" RUN php artisan optimize +RUN export WORKERS=$((1*$(nproc))) +RUN if [ $(nproc) > 2 ]; then export WORKERS=$((1*$(nproc) -1)) ; fi; EXPOSE 8080 # https://artisan.page/12.x/ diff --git a/frameworks/PHP/laravel/laravel-swoole.dockerfile b/frameworks/PHP/laravel/laravel-swoole.dockerfile index de27380656d..89dacff8abe 100644 --- a/frameworks/PHP/laravel/laravel-swoole.dockerfile +++ b/frameworks/PHP/laravel/laravel-swoole.dockerfile @@ -1,7 +1,7 @@ FROM phpswoole/swoole:php8.4 -RUN docker-php-ext-install pcntl opcache curl > /dev/null - +RUN apt-get update -yqq && apt-get install libicu-dev -y +RUN docker-php-ext-install intl pcntl opcache> /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini diff --git a/frameworks/PHP/laravel/laravel-workerman.dockerfile b/frameworks/PHP/laravel/laravel-workerman.dockerfile index 8b016a50626..d652fa11f84 100644 --- a/frameworks/PHP/laravel/laravel-workerman.dockerfile +++ b/frameworks/PHP/laravel/laravel-workerman.dockerfile @@ -6,7 +6,7 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 && \ apt-get install -yqq git unzip \ - php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-intl php8.4-curl > /dev/null COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer diff --git a/frameworks/PHP/symfony/composer.json b/frameworks/PHP/symfony/composer.json index f6bfbca31d6..9061d99d608 100644 --- a/frameworks/PHP/symfony/composer.json +++ b/frameworks/PHP/symfony/composer.json @@ -41,6 +41,7 @@ "replace": { "symfony/polyfill-ctype": "*", "symfony/polyfill-iconv": "*", + "symfony/polyfill-mbstring":"*", "symfony/polyfill-php72": "*", "symfony/polyfill-php73": "*", "symfony/polyfill-php74": "*", diff --git a/frameworks/PHP/symfony/symfony-mysql.dockerfile b/frameworks/PHP/symfony/symfony-mysql.dockerfile index 157a9179660..a09d877ade2 100644 --- a/frameworks/PHP/symfony/symfony-mysql.dockerfile +++ b/frameworks/PHP/symfony/symfony-mysql.dockerfile @@ -8,7 +8,7 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get install -yqq nginx git unzip curl \ php8.4-cli php8.4-fpm php8.4-mysql \ - php8.4-mbstring php8.4-xml php8.4-curl php8.4-dev > /dev/null + php8.4-mbstring php8.4-xml php8.4-curl > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer diff --git a/frameworks/PHP/symfony/symfony.dockerfile b/frameworks/PHP/symfony/symfony.dockerfile index 2ce94a53eb6..1d2fd84193f 100644 --- a/frameworks/PHP/symfony/symfony.dockerfile +++ b/frameworks/PHP/symfony/symfony.dockerfile @@ -8,7 +8,7 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get install -yqq nginx git unzip curl \ php8.4-bcmath php8.4-cli php8.4-fpm php8.4-pgsql \ - php8.4-mbstring php8.4-xml php8.4-curl php8.4-dev php8.4-intl > /dev/null + php8.4-mbstring php8.4-xml php8.4-curl php8.4-intl > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer From b648eb3d3f821e7f88d3ccd82a3c4077380d5ff6 Mon Sep 17 00:00:00 2001 From: AkazawaYun <62974697+AkazawaYun@users.noreply.github.com> Date: Thu, 13 Nov 2025 05:32:47 +0800 Subject: [PATCH 029/130] update test version (#10273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add new test : CSharp/akazawayun.pro * modify config and code * add content-type * update url * update package version * add 3 new tests: db、queries、updates 1. add 3 new tests: db、queries、updates; 2. split code to multi files; * - * use generated sql instead const string. * update version * fix bug of db query * set port to 8080 * 升级 akazawayun.pro 框架版本到 14 * i forget to update the port change... * test self whether work fine.. * update nuget version * why pr failed... * 不小心多提交了别人的框架...改回 * akazawayun fix bug * remove db test there is some error in mysql * confirmed there is bug in mysql.data 9.5.0 还是用8080端口吧- -b, 都用8080, 改其他的对比测时不方便 * downgrade mysql.data back to 9.4.0 * fix bug of akazawayun.pro * update version of akazawayun.pro * update version * add platform test * update nupkg version * update version * update version. * fix debug --- .../AkazawaYun.Benchmark.Platform.csproj | 2 +- .../MyBenchmarkReceptor.cs | 7 +------ .../AkazawaYun.Benchmark.Platform/Program.cs | 19 ++----------------- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj index e43069a4338..cdf987fdeb8 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj @@ -15,7 +15,7 @@ - + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs index e6ed8e9c5b7..e79ab493524 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs @@ -1,12 +1,10 @@ using AkazawaYun.PRO7; -using System.Text; namespace AkazawaYun.Benchmark.Platform; class MyBenchmarkReceptor : akzWebReceptorBenchmark { readonly JsonModel JsonModel; - readonly ReadOnlyMemory JsonContentLength; public MyBenchmarkReceptor() @@ -15,8 +13,6 @@ public MyBenchmarkReceptor() { message = "Hello, World!" }; - akzJson.Text2Json(JsonModel, out ReadOnlyMemory json); - JsonContentLength = Encoding.UTF8.GetBytes($"{json.Length}\r\n\r\n"); } @@ -26,8 +22,7 @@ public override ValueTask SendPlaintext(IHttpContext http) } public override async ValueTask SendJson(IHttpContext http) { - await http.Slient.Send(DataJson_OnlyHeaderExceptContentLength); - await http.Slient.Send(JsonContentLength); + await http.Slient.Send(DataJson_OnlyHeader); akzJson.Text2Json(JsonModel, out ReadOnlyMemory json); await http.Slient.Send(json); } diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs index 269c16f48be..e2acab53351 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs @@ -5,31 +5,16 @@ namespace AkazawaYun.Benchmark.Platform; class Program { static readonly akzWebBuilder builder; - const int port = 8080; static Program() { akzLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); - akzJson.Config(null, AotJsonContext.Default); - builder = akzWebBuilder.Shared.SetPort(port).SetDev(true) - .Add(() => null) - .Add(() => new MyBenchmarkReceptor()) - .Add(() => new(port)) - .Build(); + akzJson.Config(AotJsonContext.Default); + builder = akzWebBuilder.Shared.Build(new MyBenchmarkReceptor()); } static async Task Main() { await builder.Launch(); - - Console.WriteLine("[API SELF-TEST]"); - string url = $"http://localhost:{port}/plaintext"; - Console.WriteLine(" REQ URL :" + url); - string res = await akzHttpClient.Shared.Get(url).FetchString(); - Console.WriteLine(" RES LEN :" + res.Length); - Console.WriteLine(" RES BODY:" + res); - Console.WriteLine("[OK, I WORK FINE]"); - - akzLog.Default = akzLog.Output.NoneButWar; await Task.Delay(-1); } } From 8d81c9b0d6b54130968cfff3d0a037adbf23bd04 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Wed, 12 Nov 2025 21:33:10 +0000 Subject: [PATCH 030/130] H2O: Reduce the Docker image build time (#10275) Signed-off-by: Anton Kirilov --- frameworks/C/h2o/CMakeLists.txt | 11 +++++------ frameworks/C/h2o/h2o.dockerfile | 7 +------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/frameworks/C/h2o/CMakeLists.txt b/frameworks/C/h2o/CMakeLists.txt index 5126e991a82..d5062f2b26d 100644 --- a/frameworks/C/h2o/CMakeLists.txt +++ b/frameworks/C/h2o/CMakeLists.txt @@ -19,9 +19,8 @@ find_path(PQ_INCLUDE postgresql/libpq-fe.h REQUIRED) find_path(YAJL_INCLUDE yajl/yajl_gen.h REQUIRED) find_program(BPFTOOL_BIN bpftool REQUIRED) find_program(CLANG_BIN clang REQUIRED) -include_directories(src ${CMAKE_BINARY_DIR}/generated-headers ${BPF_INCLUDE} ${H2O_INCLUDE}) -include_directories(${MUSTACHE_C_INCLUDE} ${NUMA_INCLUDE} ${OPENSSL_INCLUDE} ${PQ_INCLUDE}) -include_directories(${YAJL_INCLUDE}) +include_directories(src ${CMAKE_BINARY_DIR} ${BPF_INCLUDE} ${H2O_INCLUDE} ${MUSTACHE_C_INCLUDE}) +include_directories(${NUMA_INCLUDE} ${OPENSSL_INCLUDE} ${PQ_INCLUDE} ${YAJL_INCLUDE}) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) add_compile_definitions(H2O_USE_LIBUV=0) @@ -32,7 +31,7 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_FORTIFY_SOURCE=2") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3") add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/generated-headers/socket_load_balancer.h + OUTPUT ${CMAKE_BINARY_DIR}/socket_load_balancer.h COMMAND ${CLANG_BIN} -c -DNDEBUG @@ -47,12 +46,12 @@ add_custom_command( ${WARNING_OPTIONS} ${CMAKE_CURRENT_SOURCE_DIR}/src/bpf/socket_load_balancer.c COMMAND ${BPFTOOL_BIN} gen skeleton ${CMAKE_BINARY_DIR}/socket_load_balancer.o > - ${CMAKE_BINARY_DIR}/generated-headers/socket_load_balancer.h + ${CMAKE_BINARY_DIR}/socket_load_balancer.h DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/bpf/socket_load_balancer.c VERBATIM) add_custom_target( generated_headers - DEPENDS ${CMAKE_BINARY_DIR}/generated-headers/socket_load_balancer.h) + DEPENDS ${CMAKE_BINARY_DIR}/socket_load_balancer.h) file(GLOB_RECURSE HANDLER_SOURCES "src/handlers/*.c") file(GLOB SOURCES "src/*.c") add_executable(${PROJECT_NAME} ${HANDLER_SOURCES} ${SOURCES}) diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index a86e36a7ebc..d6713a3e688 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -2,7 +2,7 @@ ARG UBUNTU_VERSION=25.10 ARG H2O_APP_PREFIX=/opt/h2o-app -FROM "ubuntu:${UBUNTU_VERSION}" AS compile +FROM "buildpack-deps:${UBUNTU_VERSION}" AS compile RUN echo "[timing] Installing system packages: $(date)" ARG DEBIAN_FRONTEND=noninteractive @@ -24,15 +24,12 @@ RUN apt-get install \ libnuma-dev \ libpq-dev \ libssl-dev \ - libstdc++-15-dev \ libtool \ liburing-dev \ libuv1-dev \ - libwslay-dev \ libyajl-dev \ libz-dev \ make \ - ninja-build \ pkg-config \ ruby \ systemtap-sdt-dev @@ -47,7 +44,6 @@ RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \ -B build \ -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ -DWITH_MRUBY=on \ - -G Ninja \ -S . && \ cmake --build build -j && \ cmake --install build @@ -72,7 +68,6 @@ RUN cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="-march=native -mtune=native" \ -DCMAKE_INSTALL_PREFIX="${H2O_APP_PREFIX}" \ - -G Ninja \ -S .. && \ cmake --build . -j && \ cmake --install . From 2bb509ea29679219254e782952965534ad366484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Thu, 13 Nov 2025 21:36:36 +0100 Subject: [PATCH 031/130] Update GenHTTP to version 10 and udpate to .NET 10 (#10274) * Switch to GenHTTP 10 & .NET 10 * Fix directories in the docker file * Fix DB tests, minor improvements * Align display names with unhinged --- .../genhttp/Benchmarks/Benchmarks.csproj | 15 +++++---- .../CSharp/genhttp/Benchmarks/Program.cs | 4 +++ .../genhttp/Benchmarks/Tests/JsonHandler.cs | 12 +++---- .../Utilities/FixedLengthJsonContent.cs | 31 +++++++++++++++++ .../CSharp/genhttp/benchmark_config.json | 33 ++++++++++++++++--- frameworks/CSharp/genhttp/config.toml | 18 ++++++++++ .../CSharp/genhttp/genhttp-kestrel.dockerfile | 33 +++++++++++++++++++ frameworks/CSharp/genhttp/genhttp.dockerfile | 19 ++++++++--- 8 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs create mode 100644 frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile diff --git a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj index 1189d0c151c..ae302d86dbb 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj @@ -2,14 +2,16 @@ - net9.0 - 13.0 + net10.0 + 14.0 true Exe GenHTTP Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. + $(DefineConstants);$(GENHTTP_ENGINE_NAME) + true true @@ -26,11 +28,12 @@ - - + + + - - + + diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.cs index dd55ad6b782..91323662c2d 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Program.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Program.cs @@ -1,7 +1,11 @@ using Benchmarks.Tests; using Benchmarks.Utilities; +#if INTERNAL using GenHTTP.Engine.Internal; +#else +using GenHTTP.Engine.Kestrel; +#endif using GenHTTP.Modules.IO; using GenHTTP.Modules.Layouting; diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs index 4944c669198..7fb89b926d7 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs @@ -1,10 +1,8 @@ -using System.Text.Json; +using Benchmarks.Utilities; using GenHTTP.Api.Content; using GenHTTP.Api.Protocol; -using GenHTTP.Modules.Conversion.Serializers.Json; - namespace Benchmarks.Tests; public sealed class JsonResult @@ -15,9 +13,7 @@ public sealed class JsonResult public sealed class JsonHandler : IHandler { - private static readonly FlexibleContentType _ContentType = new(ContentType.ApplicationJson, "utf-8"); - - private static readonly JsonSerializerOptions _Options = new(); + private static readonly FlexibleContentType ContentType = new(GenHTTP.Api.Protocol.ContentType.ApplicationJson, "utf-8"); public ValueTask PrepareAsync() => new(); @@ -29,8 +25,8 @@ public ValueTask HandleAsync(IRequest request) }; var response = request.Respond() - .Content(new JsonContent(result, _Options)) - .Type(_ContentType) + .Content(new FixedLengthJsonContent(result)) + .Type(ContentType) .Build(); return new(response); diff --git a/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs b/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs new file mode 100644 index 00000000000..7ef372c65f0 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs @@ -0,0 +1,31 @@ +using System.Text.Json; + +using GenHTTP.Api.Protocol; + +using Benchmarks.Tests; + +namespace Benchmarks.Utilities; + +public sealed class FixedLengthJsonContent : IResponseContent +{ + private readonly MemoryStream _buffer = new(); + + public ulong? Length => (ulong)_buffer.Length; + + public FixedLengthJsonContent(JsonResult result) + { + JsonSerializer.SerializeAsync(_buffer, result); + } + + public ValueTask CalculateChecksumAsync() => throw new NotImplementedException(); + + public ValueTask WriteAsync(Stream target, uint bufferSize) + { + _buffer.Seek(0, SeekOrigin.Begin); + + _buffer.CopyTo(target); + + return ValueTask.CompletedTask; + } + +} diff --git a/frameworks/CSharp/genhttp/benchmark_config.json b/frameworks/CSharp/genhttp/benchmark_config.json index bf1780e753a..2943457c204 100644 --- a/frameworks/CSharp/genhttp/benchmark_config.json +++ b/frameworks/CSharp/genhttp/benchmark_config.json @@ -1,5 +1,6 @@ { - "framework": "genhttp", + "framework": "genhttp", + "maintainers": ["Kaliumhexacyanoferrat"], "tests": [{ "default": { "plaintext_url": "/plaintext", @@ -17,11 +18,35 @@ "language": "C#", "orm": "Raw", "platform": ".NET", - "webserver": "Kestrel", + "webserver": "GenHTTP", "os": "Linux", "database_os": "Linux", - "display_name": "GenHTTP", + "display_name": "genhttp [internal]", "notes": "" } - }] + }, + { + "kestrel": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "update_url": "/updates/", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds/", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "GenHTTP", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "genhttp [kestrel]", + "notes": "" + } + }] } diff --git a/frameworks/CSharp/genhttp/config.toml b/frameworks/CSharp/genhttp/config.toml index f984318f53b..538213c05b4 100644 --- a/frameworks/CSharp/genhttp/config.toml +++ b/frameworks/CSharp/genhttp/config.toml @@ -16,5 +16,23 @@ database_os = "Linux" os = "Linux" orm = "Raw" platform = ".NET" +webserver = "GenHTTP" +versus = "None" + +[kestrel] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-worlds/" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" webserver = "Kestrel" versus = "None" diff --git a/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile b/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile new file mode 100644 index 00000000000..e345a538f34 --- /dev/null +++ b/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile @@ -0,0 +1,33 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build +WORKDIR /source + +ENV GENHTTP_ENGINE_NAME=KESTREL +ENV GENHTTP_ENGINE_PACKAGE=GenHTTP.Core.Kestrel + +# copy csproj and restore as distinct layers +COPY Benchmarks/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY Benchmarks/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine + +ENV DOTNET_GCDynamicAdaptationMode=0 \ + DOTNET_EnableDiagnostics=0 \ + COMPlus_EnableDiagnostics=0 \ + COMPlus_DbgEnableMiniDump=0 \ + COMPlus_DbgEnableMiniDumpCollection=0 \ + COMPlus_DbgMiniDumpType=0 \ + DOTNET_TieredPGO=0 \ + DOTNET_TC_QuickJitForLoops=1 \ + DOTNET_TC_QuickJit=1 + +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["./Benchmarks"] + +EXPOSE 8080 diff --git a/frameworks/CSharp/genhttp/genhttp.dockerfile b/frameworks/CSharp/genhttp/genhttp.dockerfile index 8c473477a61..9414123202e 100644 --- a/frameworks/CSharp/genhttp/genhttp.dockerfile +++ b/frameworks/CSharp/genhttp/genhttp.dockerfile @@ -1,6 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build WORKDIR /source +ENV GENHTTP_ENGINE_NAME=INTERNAL +ENV GENHTTP_ENGINE_PACKAGE=GenHTTP.Core + # copy csproj and restore as distinct layers COPY Benchmarks/*.csproj . RUN dotnet restore -r linux-musl-x64 @@ -10,11 +13,17 @@ COPY Benchmarks/ . RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained # final stage/image -FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine -ENV DOTNET_GCDynamicAdaptationMode=0 -ENV DOTNET_ReadyToRun=0 -ENV DOTNET_HillClimbing_Disable=1 +ENV DOTNET_GCDynamicAdaptationMode=0 \ + DOTNET_EnableDiagnostics=0 \ + COMPlus_EnableDiagnostics=0 \ + COMPlus_DbgEnableMiniDump=0 \ + COMPlus_DbgEnableMiniDumpCollection=0 \ + COMPlus_DbgMiniDumpType=0 \ + DOTNET_TieredPGO=0 \ + DOTNET_TC_QuickJitForLoops=1 \ + DOTNET_TC_QuickJit=1 WORKDIR /app COPY --from=build /app . From b7bca15e4642459862578b2423a8d4f5ffb3ab7b Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Thu, 13 Nov 2025 12:36:58 -0800 Subject: [PATCH 032/130] [F#/Oxpecker] Upgraded to .NET10 (#10276) --- frameworks/FSharp/oxpecker/README.md | 2 +- frameworks/FSharp/oxpecker/oxpecker.dockerfile | 4 ++-- frameworks/FSharp/oxpecker/src/App/App.fsproj | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frameworks/FSharp/oxpecker/README.md b/frameworks/FSharp/oxpecker/README.md index a35cbf08522..6ac388b2d50 100644 --- a/frameworks/FSharp/oxpecker/README.md +++ b/frameworks/FSharp/oxpecker/README.md @@ -5,7 +5,7 @@ This includes tests for plaintext, json, fortunes, single query, mutliple querie **Language** -* F# 8.0 +* F# 10.0 **Platforms** diff --git a/frameworks/FSharp/oxpecker/oxpecker.dockerfile b/frameworks/FSharp/oxpecker/oxpecker.dockerfile index 6424bcad50c..480ed2e3dd8 100644 --- a/frameworks/FSharp/oxpecker/oxpecker.dockerfile +++ b/frameworks/FSharp/oxpecker/oxpecker.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun 0 diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj index d54b0983e8b..c19d5d614ac 100644 --- a/frameworks/FSharp/oxpecker/src/App/App.fsproj +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 false @@ -13,10 +13,10 @@ - - - - + + + + \ No newline at end of file From 40ce2dba0b5c02703ec86116821be2455a9cbf9a Mon Sep 17 00:00:00 2001 From: rio Date: Fri, 14 Nov 2025 05:37:20 +0900 Subject: [PATCH 033/130] [PHP] Update PHP eloquent ORM (#10277) Update 8.x to 11.x Add php-curl extension --- frameworks/PHP/php/apc.php | 10 +++++----- .../PHP/php/deploy/eloquent/composer.json | 19 ++++++++++++++++--- frameworks/PHP/php/php-eloquent.dockerfile | 3 ++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/frameworks/PHP/php/apc.php b/frameworks/PHP/php/apc.php index 78e01fb4430..1ed4e7e4d1c 100644 --- a/frameworks/PHP/php/apc.php +++ b/frameworks/PHP/php/apc.php @@ -70,11 +70,11 @@ function defaults($d,$v) { } // operation constants -define('OB_HOST_STATS',1); -define('OB_SYS_CACHE',2); -define('OB_USER_CACHE',3); -define('OB_SYS_CACHE_DIR',4); -define('OB_VERSION_CHECK',9); +const OB_HOST_STATS = 1; +const OB_SYS_CACHE = 2; +const OB_USER_CACHE = 3; +const OB_SYS_CACHE_DIR = 4; +const OB_VERSION_CHECK = 9; // check validity of input variables $vardom=array( diff --git a/frameworks/PHP/php/deploy/eloquent/composer.json b/frameworks/PHP/php/deploy/eloquent/composer.json index e75de3f79ad..ebb6a48c6c9 100644 --- a/frameworks/PHP/php/deploy/eloquent/composer.json +++ b/frameworks/PHP/php/deploy/eloquent/composer.json @@ -1,7 +1,20 @@ { "require": { - "illuminate/database": "8.16.*", - "illuminate/events": "8.16.*", - "illuminate/container": "8.16.*" + "illuminate/database": "11.*", + "illuminate/events": "11.*", + "illuminate/container": "11.*" + }, + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-mbstring":"*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php84": "*" } } \ No newline at end of file diff --git a/frameworks/PHP/php/php-eloquent.dockerfile b/frameworks/PHP/php/php-eloquent.dockerfile index ea2e74e1c9a..5f9c0616938 100644 --- a/frameworks/PHP/php/php-eloquent.dockerfile +++ b/frameworks/PHP/php/php-eloquent.dockerfile @@ -5,7 +5,8 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null + apt-get install -yqq nginx git unzip \ + php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer From 5060bd2bee6ff77b293eefe4650d93538e495186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <76547834+RRQM@users.noreply.github.com> Date: Tue, 18 Nov 2025 01:28:59 +0800 Subject: [PATCH 034/130] Add touchsocket platform test (#10278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update(touchsocket):version to 4.0.0-rc.2 * update(touchsocket):version to 4.0.0-rc.5 * optimize(touchsocket):scheduler * Performance (TouchSocketHttp, TouchSocketWebApi): Enable server garbage collection * update(touchsocket):version to 4.0.0-rc.15 * update(touchsocket):version to 4.0.0-rc42 * 重构(Program): 显式指定变量类型并优化配置 显式指定变量类型以提高代码可读性和类型安全性 修改命名空间为 `TouchSocketHttp` 将 `options.BufferOnDemand` 默认值从 `false` 修改为 `true` 调整 `SetTransportOption` 和 `ApiServer` 中的相关代码 * 优化(csproj): 升级TouchSocket包版本 在TouchSocketHttp.csproj和TouchSocketWebApi.csproj中,将TouchSocket.Hosting和TouchSocket.WebApi的包引用版本从4.0.0-rc.42升级到4.0.0-rc.44,以修复错误、提高性能或增加新功能 * Add(TouchSocket):platform test * Add:Platform config * 优化(Program.cs): 替换 Console.ReadKey 为 Console.ReadLine 替换 Program.cs 文件中 Program 类的 Console.ReadKey 为 Console.ReadLine 更改目的是更方便地处理用户输入或与其他代码逻辑保持一致 * 优化: 移除不必要的 ServerGarbageCollection 属性并统一命名空间为 TouchSocketHttpPlatform * 优化(Program): 调整HTTP服务器启动逻辑 重构服务器启动流程以支持更灵活的配置: - 替换server.StartAsync(8080)为server.SetupAsync配置流程 - 配置监听端口、最大连接数及控制台日志记录器 - 删除server.SafeDispose,改为通过while(true)保持运行 - 删除直接调用Console.ReadLine的逻辑 * 重构(project): 更新项目依赖和SDK配置 更新 `TouchSocketHttp.csproj` 的项目 SDK 为 `Microsoft.NET.Sdk`,移除 `` 配置 移除 `Microsoft.Extensions.Hosting` 和 `TouchSocket.Hosting` 旧版本依赖,更新 `TouchSocket.WebApi` 至 `4.0.0-rc.46` 更新 `TouchSocketHttpPlatform.csproj` 中 `TouchSocket` 包版本至 `4.0.0-rc.46` 更新 `TouchSocketWebApi.csproj` 中 `TouchSocket.Hosting` 和 `TouchSocket.WebApi` 包版本至 `4.0.0-rc.46` * 新增(config): 添加 NuGet.Config 配置文件 添加新的 NuGet.Config 文件,包含以下更改: - 引入 XML 声明,版本为 1.0,编码为 UTF-8 - 在 `` 节点中定义 `` 节点 - 使用 `` 清除所有现有的包源配置 - 添加新的包源,键为 "NuGet",值为 "https://api.nuget.org/v3/index.json" --- frameworks/CSharp/touchsocket/Benchmarks.sln | 8 +- frameworks/CSharp/touchsocket/README.md | 35 +- .../CSharp/touchsocket/benchmark_config.json | 19 ++ frameworks/CSharp/touchsocket/config.toml | 13 + .../src/TouchSocketHttp/Program.cs | 3 +- .../TouchSocketHttp/TouchSocketHttp.csproj | 8 +- .../src/TouchSocketHttpPlatform/DateHeader.cs | 73 +++++ .../src/TouchSocketHttpPlatform/MyServer.cs | 24 ++ .../MyTcpSessionClientBase.cs | 299 ++++++++++++++++++ .../src/TouchSocketHttpPlatform/NuGet.Config | 7 + .../src/TouchSocketHttpPlatform/Program.cs | 39 +++ .../TouchSocketHttpPlatform.csproj | 13 + .../src/TouchSocketWebApi/Program.cs | 3 +- .../TouchSocketWebApi.csproj | 5 +- .../touchsocket-httpplatform.dockerfile | 13 + 15 files changed, 546 insertions(+), 16 deletions(-) create mode 100644 frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs create mode 100644 frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs create mode 100644 frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs create mode 100644 frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config create mode 100644 frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs create mode 100644 frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj create mode 100644 frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile diff --git a/frameworks/CSharp/touchsocket/Benchmarks.sln b/frameworks/CSharp/touchsocket/Benchmarks.sln index 6f164942105..8d41045e044 100644 --- a/frameworks/CSharp/touchsocket/Benchmarks.sln +++ b/frameworks/CSharp/touchsocket/Benchmarks.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.0.11109.219 d18.0-oob +VisualStudioVersion = 18.0.11109.219 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketWebApi", "src\TouchSocketWebApi\TouchSocketWebApi.csproj", "{6BD9363A-D77F-5D90-8444-2BC37495C920}" EndProject @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketHttp31", "src\To EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketWebApi31", "src\TouchSocketWebApi31\TouchSocketWebApi31.csproj", "{6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketHttpPlatform", "src\TouchSocketHttpPlatform\TouchSocketHttpPlatform.csproj", "{BC320C24-941D-2109-FBC8-92780569BBA4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Debug|Any CPU.Build.0 = Debug|Any CPU {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Release|Any CPU.Build.0 = Release|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/frameworks/CSharp/touchsocket/README.md b/frameworks/CSharp/touchsocket/README.md index 22524d6f70a..8a520d40eec 100644 --- a/frameworks/CSharp/touchsocket/README.md +++ b/frameworks/CSharp/touchsocket/README.md @@ -2,9 +2,40 @@ See [touchsocket](https://touchsocket.net/) for more information. +## Variants Included + +* `touchsocket.webapi` (`TouchSocketWebApi`) – WebApi style. +* `touchsocket.webapi31` (`TouchSocketWebApi31`) – WebApi targeting .NET 8. +* `touchsocket.http` (`TouchSocketHttp`) – Minimal HTTP implementation. +* `touchsocket.http31` (`TouchSocketHttp31`) – Minimal HTTP targeting .NET 8. +* `touchsocket.httpplatform` (`TouchSocketHttpPlatform`) – High-performance custom pipeline-based HTTP server focusing on low-level parsing and zero-allocation response writing. + ## Infrastructure Software Versions -**Language** +**Language / Runtime** + +* C# / .NET (8.0 & 9.0 depending on variant) + +## Endpoints + +All variants implement: + +* `/plaintext` – Returns a plain text "Hello, World!" response. +* `/json` – Returns a JSON object `{"message": "Hello, World!"}`. + +The `httpplatform` variant manually parses request lines and headers via `System.IO.Pipelines` for maximum throughput. + +## Dockerfiles + +Each variant has a dedicated Dockerfile named: + +* `touchsocket.dockerfile` (webapi) +* `touchsocket-webapi31.dockerfile` +* `touchsocket-http.dockerfile` +* `touchsocket-http31.dockerfile` +* `touchsocket-httpplatform.dockerfile` + +## Notes -* C# 8.0 +The `httpplatform` variant is intended for benchmarking raw server performance. It omits higher-level abstractions to reduce overhead. diff --git a/frameworks/CSharp/touchsocket/benchmark_config.json b/frameworks/CSharp/touchsocket/benchmark_config.json index 8aa1e953f59..86036458c9a 100644 --- a/frameworks/CSharp/touchsocket/benchmark_config.json +++ b/frameworks/CSharp/touchsocket/benchmark_config.json @@ -77,6 +77,25 @@ "display_name": "touchsocket.webapi31", "notes": "", "versus": "aspnetcore-mvc" + }, + "httpplatform": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "touchsocket.httpplatform", + "language": "C#", + "orm": "Micro", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "touchsocket", + "os": "Linux", + "database_os": "Linux", + "display_name": "touchsocket.httpplatform", + "notes": "High-performance custom pipeline-based implementation variant.", + "versus": "aspnetcore" } } ] diff --git a/frameworks/CSharp/touchsocket/config.toml b/frameworks/CSharp/touchsocket/config.toml index 9af10d4a486..0d06cb4e331 100644 --- a/frameworks/CSharp/touchsocket/config.toml +++ b/frameworks/CSharp/touchsocket/config.toml @@ -52,3 +52,16 @@ orm = "Raw" platform = ".NET" webserver = "touchsocket.webapi31" versus = "aspcore-mvc" + +[httpplatform] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "touchsocket.httpplatform" +versus = "aspcore" diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs index d77a1b3249d..baa00f9da87 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs @@ -1,7 +1,6 @@ using System.Text; using TouchSocket.Core; using TouchSocket.Http; -using TouchSocket.Sockets; using HttpContent = TouchSocket.Http.HttpContent; namespace TouchSocketHttp; @@ -18,7 +17,7 @@ await service.SetupAsync(new TouchSocketConfig() .SetMaxCount(1000000) .SetTransportOption(options => { - options.BufferOnDemand = true; + options.BufferOnDemand = false; }) .ConfigureContainer(a => { diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj index ea6f43327a0..073c2d99413 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj @@ -1,18 +1,14 @@ - + net9.0 enable Exe enable - true - dotnet-TouchSocketWebApi-987c185f-10b1-452b-beb6-47d798a5a131 - - - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs new file mode 100644 index 00000000000..9f0049fc54d --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using System.Buffers.Text; +using System.Diagnostics; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +internal static class DateHeader +{ + private const int dateTimeRLength = 29; + private const int prefixLength = 6; // "Date: ".Length is 6 in bytes for ASCII + private const int suffixIndex = dateTimeRLength + prefixLength; + + // Wed, 14 Mar 2018 14:20:00 GMT + private const int suffixLength = 2; // crlf + private static readonly Timer s_timer = new((s) => + { + SetDateValues(DateTimeOffset.UtcNow); + }, null, 1000, 1000); + + private static byte[] s_headerBytesMaster = new byte[prefixLength + dateTimeRLength + 2 * suffixLength]; + private static byte[] s_headerBytesScratch = new byte[prefixLength + dateTimeRLength + 2 * suffixLength]; + + static DateHeader() + { + var utf8 = "Date: "u8; + + utf8.CopyTo(s_headerBytesMaster); + utf8.CopyTo(s_headerBytesScratch); + s_headerBytesMaster[suffixIndex] = (byte)'\r'; + s_headerBytesMaster[suffixIndex + 1] = (byte)'\n'; + s_headerBytesMaster[suffixIndex + 2] = (byte)'\r'; + s_headerBytesMaster[suffixIndex + 3] = (byte)'\n'; + s_headerBytesScratch[suffixIndex] = (byte)'\r'; + s_headerBytesScratch[suffixIndex + 1] = (byte)'\n'; + s_headerBytesScratch[suffixIndex + 2] = (byte)'\r'; + s_headerBytesScratch[suffixIndex + 3] = (byte)'\n'; + + SetDateValues(DateTimeOffset.UtcNow); + SyncDateTimer(); + } + + public static ReadOnlySpan HeaderBytes => s_headerBytesMaster; + + public static void SyncDateTimer() + { + s_timer.Change(1000, 1000); + } + private static void SetDateValues(DateTimeOffset value) + { + lock (s_headerBytesScratch) + { + if (!Utf8Formatter.TryFormat(value, s_headerBytesScratch.AsSpan(prefixLength), out var written, 'R')) + { + throw new Exception("date time format failed"); + } + Debug.Assert(written == dateTimeRLength); + (s_headerBytesScratch, s_headerBytesMaster) = (s_headerBytesMaster, s_headerBytesScratch); + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs new file mode 100644 index 00000000000..714b8ff367b --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +internal sealed class MyServer : TcpService +{ + /// + protected override MyTcpSessionClientBase NewClient() + { + return new MyTcpSessionClientBase(); + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs new file mode 100644 index 00000000000..1b95c2ddd72 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs @@ -0,0 +1,299 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using System.Buffers; +using System.IO.Pipelines; +using System.Runtime.CompilerServices; +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +/// +/// 路由类型 +/// +internal enum RouteType +{ + /// + /// 未知路由 + /// + Unknown, + + /// + /// 纯文本路由 + /// + Plaintext, + + /// + /// JSON路由 + /// + Json +} + +internal sealed class MyTcpSessionClientBase : TcpSessionClient +{ + #region Paths + public static ReadOnlySpan Json => "/json"u8; + public static ReadOnlySpan Plaintext => "/plaintext"u8; + #endregion + + + private static ReadOnlySpan PlainTextBody => "Hello, World!"u8; + private static ReadOnlySpan JsonBody => "{\"message\":\"Hello, World!\"}"u8; + + private static ReadOnlySpan PlaintextPreamble => + "HTTP/1.1 200 OK\r\n"u8 + + "Server: T\r\n"u8 + + "Content-Type: text/plain\r\n"u8 + + "Content-Length: 13\r\n"u8; + + private static ReadOnlySpan JsonPreamble => + "HTTP/1.1 200 OK\r\n"u8 + + "Server: T\r\n"u8 + + "Content-Type: application/json\r\n"u8 + + "Content-Length: 27\r\n"u8; + + protected override async Task ReceiveLoopAsync(ITransport transport) + { + var pipeReader = transport.Reader; + var pipeWriter = transport.Writer; + + while (true) + { + var readResult = await pipeReader.ReadAsync(); + var bufferSequence = readResult.Buffer; + + var totalConsumed = ProcessRequests(bufferSequence, pipeWriter, out var responseCount); + + if (responseCount > 0) + { + await pipeWriter.FlushAsync(); + } + + if (totalConsumed > 0) + { + pipeReader.AdvanceTo(bufferSequence.GetPosition(totalConsumed)); + } + else + { + pipeReader.AdvanceTo(bufferSequence.Start, bufferSequence.End); + } + + if (readResult.IsCompleted) + { + break; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter writer, out int responseCount) + { + var seqReader = new SequenceReader(buffer); + var totalConsumed = 0L; + responseCount = 0; + + while (!seqReader.End) + { + var startConsumed = seqReader.Consumed; + + // 请求行 + if (!TryReadLine(ref seqReader, out var requestLineLength)) + { + // 请求行不完整,不消费任何数据 + break; + } + + var requestLineConsumed = requestLineLength + 2; + + // 读取Headers,直到空行;若不完整,回退并等待更多数据 + var headersStartConsumed = seqReader.Consumed; + bool headersComplete = false; + while (!seqReader.End) + { + if (!TryReadLine(ref seqReader, out var headerLength)) + { + // 回退到读取Headers前的位置,等待更多数据 + var rewind = seqReader.Consumed - headersStartConsumed; + if (rewind > 0) + { + seqReader.Rewind(rewind); + } + headersComplete = false; + break; + } + + if (headerLength == 0) + { + headersComplete = true; + break; // headers 结束 + } + } + + if (!headersComplete) + { + // 不完整,等待更多数据 + break; + } + + // 解析URL - 直接在原始位置解析,避免Slice + var routeType = ParseUrlFast(buffer.Slice(startConsumed), requestLineConsumed); + + // 计算本次消费的字节数 + var consumed = seqReader.Consumed - startConsumed; + totalConsumed += consumed; + + // 写入响应 + WriteResponseSync(writer, routeType); + responseCount++; + } + + return totalConsumed; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteResponseSync(PipeWriter writer, RouteType routeType) + { + switch (routeType) + { + case RouteType.Plaintext: + writer.Write(PlaintextPreamble); + writer.Write(DateHeader.HeaderBytes); + writer.Write(PlainTextBody); + break; + case RouteType.Json: + writer.Write(JsonPreamble); + writer.Write(DateHeader.HeaderBytes); + writer.Write(JsonBody); + break; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryReadLine(ref SequenceReader reader, out long length) + { + var start = reader.Consumed; + + while (!reader.End) + { + if (reader.TryRead(out var b)) + { + if (b == '\r') + { + // 查看是否有'\n',若暂不可用则回退并判定不完整 + if (!reader.TryPeek(out var next)) + { + // 回退已读取的'\r' + reader.Rewind(1); + length = 0; + return false; + } + if (next == '\n') + { + // 消费'\n'并返回本行长度(不含CRLF) + reader.Advance(1); + length = reader.Consumed - start - 2; + return true; + } + } + } + } + + length = 0; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static RouteType ParseUrlFast(ReadOnlySequence sequence, long requestLineLength) + { + var reader = new SequenceReader(sequence); + + // 跳过方法 + var spaceCount = 0; + var urlStart = 0L; + var urlEnd = 0L; + + while (reader.Consumed < requestLineLength && !reader.End) + { + if (reader.TryRead(out var b)) + { + if (b == ' ') + { + spaceCount++; + if (spaceCount == 1) + { + urlStart = reader.Consumed; + } + else if (spaceCount == 2) + { + urlEnd = reader.Consumed - 1; + break; + } + } + } + } + + if (spaceCount < 2) + { + return RouteType.Unknown; + } + + var urlLength = urlEnd - urlStart; + + // 截取URL片段 + var startPos = sequence.GetPosition(urlStart); + var urlSlice = sequence.Slice(startPos, urlLength); + + // "/plaintext" + if (urlLength == Plaintext.Length) + { + if (urlSlice.IsSingleSegment) + { + if (urlSlice.FirstSpan.SequenceEqual(Plaintext)) + { + return RouteType.Plaintext; + } + } + else + { + Span tmp = stackalloc byte[(int)urlLength]; + urlSlice.CopyTo(tmp); + if (tmp.SequenceEqual(Plaintext)) + { + return RouteType.Plaintext; + } + } + } + // "/json" + else if (urlLength == Json.Length) + { + if (urlSlice.IsSingleSegment) + { + if (urlSlice.FirstSpan.SequenceEqual(Json)) + { + return RouteType.Json; + } + } + else + { + Span tmp = stackalloc byte[(int)urlLength]; + urlSlice.CopyTo(tmp); + if (tmp.SequenceEqual(Json)) + { + return RouteType.Json; + } + } + } + + return RouteType.Unknown; + } +} + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config new file mode 100644 index 00000000000..f05d5867888 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs new file mode 100644 index 00000000000..95576ee70b5 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +internal class Program +{ + private static async Task Main(string[] args) + { + var server = new MyServer(); + await server.SetupAsync(new TouchSocketConfig() + .SetListenIPHosts(8080) + .SetMaxCount(1000000) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + })); + + await server.StartAsync(); + Console.WriteLine("HTTP服务器已启动,端口: 8080"); + + while (true) + { + Console.ReadLine(); + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj new file mode 100644 index 00000000000..8e9841293fc --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj @@ -0,0 +1,13 @@ + + + + Exe + net9.0 + enable + enable + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs index a7c9e6dcafe..4033ac03745 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs @@ -3,7 +3,6 @@ using TouchSocket.Core; using TouchSocket.Http; using TouchSocket.Rpc; -using TouchSocket.Sockets; using TouchSocket.WebApi; using HttpContent = TouchSocket.Http.HttpContent; @@ -21,7 +20,7 @@ public static void Main(string[] args) .SetMaxCount(1000000) .SetTransportOption(options => { - options.BufferOnDemand = true; + options.BufferOnDemand = false; }) .ConfigureContainer(a => { diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj index d90651bb648..909c2f984ee 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj @@ -4,13 +4,12 @@ net9.0 enable enable - true dotnet-WorkerService1-19b37b17-6043-4334-ad9a-9e0e3c670da3 - - + + diff --git a/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile new file mode 100644 index 00000000000..c20b0434e76 --- /dev/null +++ b/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /app +COPY src/TouchSocketHttpPlatform . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "TouchSocketHttpPlatform.dll"] From a14b2c9715223da6ec81e7f2ee47f657a8cba8df Mon Sep 17 00:00:00 2001 From: ruroru <111705692+ruroru@users.noreply.github.com> Date: Mon, 17 Nov 2025 19:30:02 +0200 Subject: [PATCH 035/130] Add minor improvements in clojure (#10279) * Revert executor service to VirtualThreadPerTaskExecutor * Fix retit base image marked async as broken * Add hiccup to kit --------- Co-authored-by: jj --- frameworks/Clojure/kit/benchmark_config.json | 18 +++++++++ frameworks/Clojure/kit/deps.edn | 1 + frameworks/Clojure/kit/kit-hiccup.dockerfile | 19 ++++++++++ .../te_bench/web/controllers/bench.clj | 31 +++++++++++++++- .../kit_clj/te_bench/web/routes/bench.clj | 4 +- .../Clojure/reitit/benchmark_config.json | 3 +- .../Clojure/reitit/reitit-async.dockerfile | 2 +- .../Clojure/reitit/reitit-jdbc.dockerfile | 2 +- frameworks/Clojure/reitit/reitit.dockerfile | 2 +- .../Clojure/reitit/src/hello/handler.clj | 2 +- .../Clojure/ring-http-exchange/project.clj | 3 +- .../src/ring_http_exchange/benchmark.clj | 37 +++++++++++-------- 12 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 frameworks/Clojure/kit/kit-hiccup.dockerfile diff --git a/frameworks/Clojure/kit/benchmark_config.json b/frameworks/Clojure/kit/benchmark_config.json index bbde2d31918..21581010726 100755 --- a/frameworks/Clojure/kit/benchmark_config.json +++ b/frameworks/Clojure/kit/benchmark_config.json @@ -43,6 +43,24 @@ "display_name": "kit-majavat", "notes": "", "versus": "kit" + }, + "hiccup": { + "fortune_url": "/hiccup-fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "kit-hiccup", + "notes": "", + "versus": "kit" } } ] diff --git a/frameworks/Clojure/kit/deps.edn b/frameworks/Clojure/kit/deps.edn index d517f976be1..972f7bb3d3f 100644 --- a/frameworks/Clojure/kit/deps.edn +++ b/frameworks/Clojure/kit/deps.edn @@ -16,6 +16,7 @@ ;; HTML templating selmer/selmer {:mvn/version "1.12.62"} org.clojars.jj/majavat {:mvn/version "1.12.3"} + hiccup/hiccup {:mvn/version "2.0.0"} ;; Database org.postgresql/postgresql {:mvn/version "42.7.8"} diff --git a/frameworks/Clojure/kit/kit-hiccup.dockerfile b/frameworks/Clojure/kit/kit-hiccup.dockerfile new file mode 100644 index 00000000000..c4b1990a3f8 --- /dev/null +++ b/frameworks/Clojure/kit/kit-hiccup.dockerfile @@ -0,0 +1,19 @@ +# syntax = docker/dockerfile:1.2 +FROM clojure:openjdk-17 AS build + +WORKDIR / +COPY . / + +RUN clj -Sforce -T:build all + +FROM amazoncorretto:25 + +COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone.jar + +EXPOSE 8080 + +ENV PORT=8080 +ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" +ENV JDBC_URL="jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass" + +ENTRYPOINT exec java $JAVA_OPTS -jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj index 2057a175140..c02f3621c49 100644 --- a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj +++ b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj @@ -5,6 +5,8 @@ [next.jdbc.result-set :as rs] [jj.majavat :as majavat] [jj.sql.boa :as boa] + [hiccup.page :as hp] + [hiccup.util :as hu] [jj.majavat.renderer :refer [->StringRenderer]] [jj.majavat.renderer.sanitizer :refer [->Html]] [ring.util.http-response :as http-response] @@ -20,6 +22,21 @@ (def ^:private render-fortune (majavat/build-renderer "html/fortunes.html" {:renderer (->StringRenderer {:sanitizer (->Html)})})) + +(defn render-hiccup-fortune [fortunes] + (hp/html5 + [:head + [:title "Fortunes"]] + [:body + [:table + [:tr + [:th "id"] + [:th "message"]] + (for [x fortunes] + [:tr + [:td (:id x)] + [:td (hu/escape-html (:message x))]])]])) + (def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "sql/fortunes.sql")) (def selmer-opts {:custom-resource-path (clojure.java.io/resource "html")}) @@ -35,6 +52,10 @@ (http-response/ok) (http-response/content-type "text/html; charset=utf-8"))) +(defn hiccup-html-response + [body] + (-> (http-response/ok body) + (http-response/content-type "text/html; charset=utf-8"))) (defn rand-id [n] @@ -148,4 +169,12 @@ (as-> (query-fortunes db-conn) fortunes (conj fortunes {:id 0 :message "Additional fortune added at request time."}) (sort-by :message fortunes) - (majavat-html-response {:messages fortunes}))) \ No newline at end of file + (majavat-html-response {:messages fortunes}))) + +(defn hiccup-fortune-handler + [db-conn _request] + (as-> (query-fortunes db-conn) fortunes + (conj fortunes {:id 0 :message "Additional fortune added at request time."}) + (sort-by :message fortunes) + (render-hiccup-fortune fortunes) + (hiccup-html-response fortunes))) diff --git a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj index 032ceb143f7..070fa899c17 100644 --- a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj +++ b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj @@ -18,7 +18,9 @@ ["/updates" {:get (partial bench/update-db-handler db-conn)}] ["/cached-queries" {:get (partial bench/cached-query-handler db-conn cache)}] ["/fortunes" {:get (partial bench/selmer-fortune-handler db-conn)}] - ["/majavat-fortunes" {:get (partial bench/majavat-fortune-handler db-conn)}]]) + ["/majavat-fortunes" {:get (partial bench/majavat-fortune-handler db-conn)}] + ["/hiccup-fortunes" {:get (partial bench/hiccup-fortune-handler db-conn)}] + ]) (defmethod ig/init-key :reitit.routes/bench [_ {:keys [base-path] diff --git a/frameworks/Clojure/reitit/benchmark_config.json b/frameworks/Clojure/reitit/benchmark_config.json index 713c812c206..e3793e46827 100755 --- a/frameworks/Clojure/reitit/benchmark_config.json +++ b/frameworks/Clojure/reitit/benchmark_config.json @@ -54,7 +54,8 @@ "database_os": "Linux", "display_name": "reitit-async", "notes": "", - "versus": "undertow" + "versus": "undertow", + "tags": ["broken"] } }] } diff --git a/frameworks/Clojure/reitit/reitit-async.dockerfile b/frameworks/Clojure/reitit/reitit-async.dockerfile index e24189d9adb..2d07ee7f7b7 100644 --- a/frameworks/Clojure/reitit/reitit-async.dockerfile +++ b/frameworks/Clojure/reitit/reitit-async.dockerfile @@ -4,7 +4,7 @@ COPY project.clj project.clj COPY src src RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /reitit COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar diff --git a/frameworks/Clojure/reitit/reitit-jdbc.dockerfile b/frameworks/Clojure/reitit/reitit-jdbc.dockerfile index ab746e5c464..e202481097a 100644 --- a/frameworks/Clojure/reitit/reitit-jdbc.dockerfile +++ b/frameworks/Clojure/reitit/reitit-jdbc.dockerfile @@ -4,7 +4,7 @@ COPY project.clj project.clj COPY src src RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /reitit COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar diff --git a/frameworks/Clojure/reitit/reitit.dockerfile b/frameworks/Clojure/reitit/reitit.dockerfile index 52fff78793a..2915a6efd2c 100644 --- a/frameworks/Clojure/reitit/reitit.dockerfile +++ b/frameworks/Clojure/reitit/reitit.dockerfile @@ -4,7 +4,7 @@ COPY project.clj project.clj COPY src src RUN lein uberjar -FROM openjdk:25-jdk-slim +FROM amazoncorretto:25 WORKDIR /reitit COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar diff --git a/frameworks/Clojure/reitit/src/hello/handler.clj b/frameworks/Clojure/reitit/src/hello/handler.clj index 7075cd4e5b6..97a8d8d1411 100644 --- a/frameworks/Clojure/reitit/src/hello/handler.clj +++ b/frameworks/Clojure/reitit/src/hello/handler.clj @@ -84,7 +84,7 @@ :else (constantly nil))] (-> (ring/ring-handler (ring/router - [["/plaintext" (exchange/constantly plain-text-handler)] + [["/plaintext" plain-text-handler] ["/json" json-handler] ["/db" db-handler]]) (ring/create-default-handler) diff --git a/frameworks/Clojure/ring-http-exchange/project.clj b/frameworks/Clojure/ring-http-exchange/project.clj index 2f61228d669..448d887f73e 100644 --- a/frameworks/Clojure/ring-http-exchange/project.clj +++ b/frameworks/Clojure/ring-http-exchange/project.clj @@ -11,11 +11,10 @@ [org.clojars.jj/majavat "1.12.3"] [hikari-cp "3.3.0"] [org.clojars.jj/boa-sql "1.0.0"] - [io.netty/netty-transport-native-epoll "4.2.7.Final" :classifier "linux-x86_64"] [org.postgresql/postgresql "42.7.8"] [metosin/jsonista "0.3.13"] ] - :profiles {:robaho {:dependencies [[io.github.robaho/httpserver "1.0.28"]]}} + :profiles {:robaho {:dependencies [[io.github.robaho/httpserver "1.0.29"]]}} :resource-paths ["resources"] :main ring-http-exchange.benchmark) diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj index fc6afa569b6..24063d085e6 100644 --- a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj @@ -10,20 +10,19 @@ [ring-http-exchange.core :as server]) (:import (com.zaxxer.hikari HikariDataSource) - (io.netty.channel.epoll EpollEventLoopGroup))) + (java.util.concurrent Executors))) (def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "fortune.sql")) -(def db-spec {:auto-commit true - :read-only true - :connection-timeout 10000 - :validation-timeout 5000 - :idle-timeout 600000 +(def db-spec {:auto-commit false + :connection-timeout 3000 + :validation-timeout 1000 + :idle-timeout 300000 :max-lifetime 1800000 - :minimum-idle 16 - :maximum-pool-size 64 + :minimum-idle 128 + :maximum-pool-size 1024 :register-mbeans false - :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass"}) + :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass&prepareThreshold=1"}) (def ^:private ^:const additional-message {:id 0 :message "Additional fortune added at request time."}) @@ -31,14 +30,18 @@ "Content-Type" "text/html; charset=UTF-8"}) (def ^:private ^:const json-headers {"Server" "ring-http-exchange" "Content-Type" "application/json"}) -(def ^:private ^:const plaintext-response {:status 200 - :headers {"Server" "ring-http-exchange" - "Content-Type" "text/plain"} - :body "Hello, World!"}) + (def ^:private render-fortune (majavat/build-renderer "fortune.html" {:renderer (->StringRenderer {:sanitizer (->Html)})})) + +(defn- plaintext-response [] + {:status 200 + :headers {"Server" "ring-http-exchange" + "Content-Type" "text/plain"} + :body "Hello, World!"}) + (defn- get-body [datasource] (let [context (as-> (query-fortunes datasource) fortunes (conj fortunes additional-message) @@ -47,11 +50,15 @@ (defn -main [& _] + (System/setProperty "jdk.virtualThreadScheduler.parallelism" + (str (* 4 (.availableProcessors (Runtime/getRuntime))))) + (println "Starting server on port 8080") (let [datasource (connection/->pool HikariDataSource db-spec)] (server/run-http-server (fn [req] (case (req :uri) + "/plaintext" (plaintext-response) "/json" {:status 200 :headers json-headers :body (json/write-value-as-bytes {:message "Hello, World!"})} @@ -59,7 +66,7 @@ {:status 200 :headers fortune-headers :body body}) - plaintext-response)) + (plaintext-response))) {:port 8080 :host "0.0.0.0" - :executor (EpollEventLoopGroup.)}))) \ No newline at end of file + :executor (Executors/newVirtualThreadPerTaskExecutor)}))) \ No newline at end of file From 13ff46a55a7a06c17db5d58d2ca2c4cd17982d71 Mon Sep 17 00:00:00 2001 From: Diogo Martins <165835485+MDA2AV@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:30:55 +0000 Subject: [PATCH 036/130] Unhinged - Add high worker variant (#10280) * Add high worker variant * bump unhinged to 9.0.7 --- .../CSharp/wiredio/benchmark_config.json | 17 ++++ frameworks/CSharp/wiredio/config.toml | 12 +++ .../wiredio/src/PlatformP/Platform.csproj | 25 +++++ .../CSharp/wiredio/src/PlatformP/Program.cs | 98 +++++++++++++++++++ .../CSharp/wiredio/wiredio-mcr-p.dockerfile | 22 +++++ 5 files changed, 174 insertions(+) create mode 100644 frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj create mode 100644 frameworks/CSharp/wiredio/src/PlatformP/Program.cs create mode 100644 frameworks/CSharp/wiredio/wiredio-mcr-p.dockerfile diff --git a/frameworks/CSharp/wiredio/benchmark_config.json b/frameworks/CSharp/wiredio/benchmark_config.json index 50fcb4cd13f..2d9ebf4896f 100644 --- a/frameworks/CSharp/wiredio/benchmark_config.json +++ b/frameworks/CSharp/wiredio/benchmark_config.json @@ -37,6 +37,23 @@ "display_name": "Unhinged", "notes": "epoll" }, + "mcr-p": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Unhinged", + "language": "C#", + "orm": "None", + "platform": ".NET", + "webserver": "Unhinged", + "os": "Linux", + "database_os": "Linux", + "display_name": "Unhinged [p]", + "notes": "epoll" + }, "gen": { "plaintext_url": "/plaintext", "json_url": "/json", diff --git a/frameworks/CSharp/wiredio/config.toml b/frameworks/CSharp/wiredio/config.toml index b418d57d861..0b973f1f1fb 100644 --- a/frameworks/CSharp/wiredio/config.toml +++ b/frameworks/CSharp/wiredio/config.toml @@ -25,6 +25,18 @@ platform = ".NET" webserver = "Unhinged" versus = "None" +[mcr-p] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +os = "Linux" +database_os = "Linux" +orm = "None" +platform = ".NET" +webserver = "Unhinged" +versus = "None" + [gen] urls.plaintext = "/plaintext" urls.json = "/json" diff --git a/frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj b/frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj new file mode 100644 index 00000000000..ea26e67a376 --- /dev/null +++ b/frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj @@ -0,0 +1,25 @@ + + + + Exe + net9.0 + enable + enable + true + true + true + true + + + linux-musl-x64 + true + + + + + + + + + + diff --git a/frameworks/CSharp/wiredio/src/PlatformP/Program.cs b/frameworks/CSharp/wiredio/src/PlatformP/Program.cs new file mode 100644 index 00000000000..46a7d69219c --- /dev/null +++ b/frameworks/CSharp/wiredio/src/PlatformP/Program.cs @@ -0,0 +1,98 @@ +// ReSharper disable always SuggestVarOrType_BuiltInTypes +// (var is avoided intentionally in this project so that concrete types are visible at call sites.) +// ReSharper disable always StackAllocInsideLoop + +using System.Runtime.CompilerServices; +using System.Text.Json; +using Unhinged; + +#pragma warning disable CA2014 + +/* (MDA2AV)Dev notes: + * + * Wired.IO Platform benchmark using [Unhinged - https://github.com/MDA2AV/Unhinged] epoll engine. + * + * This test was created purely for benchmark/comparison between .NET solutions. + * It should not be considered EVER as a go-to framework to build any kind of webserver! + * For such purpose please use the main Wired.IO framework [Wired.IO - https://github.com/MDA2AV/Wired.IO]. + * + * This benchmarks follows the JsonSerialization and PlainText rules imposed by the TechEmpower team. + * + * The Http parsing by the Unhinged engine is still naive(work in progress), yet it's development will not have any impact + * on these benchmarks results as the extra request parsing overhead is much smaller than the read/send syscalls'. + */ + +namespace Platform; + +[SkipLocalsInit] +internal static class Program +{ + public static void Main(string[] args) + { + var builder = UnhingedEngine + .CreateBuilder() + .SetPort(8080) + + .SetNWorkersSolver(() => Environment.ProcessorCount ) + + // Accept up to 16384 connections + .SetBacklog(16384) + + // Max 512 epoll events per wake (quite overkill) + .SetMaxEventsPerWake(512) + + // Max 1024 connection per thread + .SetMaxNumberConnectionsPerWorker(1024) + + // 32KB in and 16KB out slabs to handle 16 pipeline depth + .SetSlabSizes(32 * 1024, 16 * 1024) + .InjectRequestHandler(RequestHandler); + + var engine = builder.Build(); + engine.Run(); + } + + private const string Json = "/json"; + private const string PlainText = "/plaintext"; + + private static ValueTask RequestHandler(Connection connection) + { + // FNV-1a Hashed routes to avoid string allocations + if(connection.H1HeaderData.Route == Json) // /json + CommitJsonResponse(connection); + + else if (connection.H1HeaderData.Route == PlainText) // /plaintext + CommitPlainTextResponse(connection); + + return ValueTask.CompletedTask; + } + + [ThreadStatic] private static Utf8JsonWriter? t_utf8JsonWriter; + private static readonly JsonContext SerializerContext = JsonContext.Default; + private static void CommitJsonResponse(Connection connection) + { + connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 + + "Server: W\r\n"u8 + + "Content-Type: application/json; charset=UTF-8\r\n"u8 + + "Content-Length: 27\r\n"u8); + connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes); + + t_utf8JsonWriter ??= new Utf8JsonWriter(connection.WriteBuffer, new JsonWriterOptions { SkipValidation = true }); + t_utf8JsonWriter.Reset(connection.WriteBuffer); + + // Creating(Allocating) a new JsonMessage every request + var message = new JsonMessage { Message = "Hello, World!" }; + // Serializing it every request + JsonSerializer.Serialize(t_utf8JsonWriter, message, SerializerContext.JsonMessage); + } + + private static void CommitPlainTextResponse(Connection connection) + { + connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 + + "Server: W\r\n"u8 + + "Content-Type: text/plain\r\n"u8 + + "Content-Length: 13\r\n"u8); + connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes); + connection.WriteBuffer.WriteUnmanaged("Hello, World!"u8); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/wiredio-mcr-p.dockerfile b/frameworks/CSharp/wiredio/wiredio-mcr-p.dockerfile new file mode 100644 index 00000000000..1ef18f083c2 --- /dev/null +++ b/frameworks/CSharp/wiredio/wiredio-mcr-p.dockerfile @@ -0,0 +1,22 @@ +# Build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build +RUN apk add --no-cache clang build-base zlib-dev linux-headers +WORKDIR /src +COPY src/PlatformP/ ./PlatformP/ +WORKDIR /src/PlatformP +RUN dotnet publish -c Release \ + -r linux-musl-x64 \ + --self-contained true \ + -p:PublishAot=true \ + -p:OptimizationPreference=Speed \ + -p:GarbageCollectionAdaptationMode=0 \ + -o /app/out + +# Runtime (musl) +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine +ENV URLS=http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ +RUN chmod +x ./Platform +EXPOSE 8080 +ENTRYPOINT ["./Platform"] From fe1810bf707d54d4616001d879f38c013a4f59a6 Mon Sep 17 00:00:00 2001 From: Andrew McCloskey Date: Mon, 17 Nov 2025 12:34:43 -0500 Subject: [PATCH 037/130] Performance improvements to vertx-web-kotlin-dsljson (#10281) - Refactored core verticles and introduced ServerVerticle for improved request handling - Enhanced database repositories with optimized query patterns - Streamlined handlers to reduce overhead - Updated PeriodicResolver logic and added centralized Properties configuration - Removed unused profiling scripts and configuration files - Temporarily disabled fortunes endpoint in benchmark configuration - Updated Gradle build configuration and dependencies Verify was called to ensure operability. --- .../Kotlin/vertx-web-kotlin-dsljson/README.md | 10 +- .../benchmark_config.json | 1 - .../vertx-web-kotlin-dsljson/build.gradle.kts | 150 +++++++++------ .../buildSrc/build.gradle.kts | 7 + .../buildSrc/src/main/kotlin/Helper.kt | 58 ++++++ .../configuration/scripts/server.sh | 97 +++++++--- .../gradle/libs.versions.toml | 44 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 45457 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../Kotlin/vertx-web-kotlin-dsljson/gradlew | 12 +- .../vertx-web-kotlin-dsljson/gradlew.bat | 3 +- .../settings.gradle.kts | 14 ++ .../main/kotlin/com/example/starter/App.kt | 94 ++++++---- .../com/example/starter/BasicVerticle.kt | 64 +++---- .../com/example/starter/PostgresVerticle.kt | 108 +++++------ .../com/example/starter/ServerVerticle.kt | 91 ++++++++++ .../example/starter/db/FortuneRepository.kt | 28 ++- .../com/example/starter/db/WorldRepository.kt | 95 ++++++---- .../starter/handlers/AbstractHandler.kt | 79 ++++---- .../starter/handlers/DefaultHandler.kt | 16 +- .../starter/handlers/FortuneHandler.kt | 71 +++----- .../starter/handlers/MessageHandler.kt | 15 +- .../example/starter/handlers/WorldHandler.kt | 65 +++---- .../{io => helpers}/BufferOutputStream.kt | 162 ++++++++++------- .../starter/helpers/PeriodicResolver.kt | 61 +++++++ .../com/example/starter/helpers/Properties.kt | 171 ++++++++++++++++++ .../com/example/starter/io/JsonResource.kt | 15 -- .../com/example/starter/models/Fortune.kt | 4 +- .../com/example/starter/models/Message.kt | 2 +- .../com/example/starter/models/World.kt | 8 +- .../example/starter/utils/FutureExtensions.kt | 16 +- .../example/starter/utils/JsonExtensions.kt | 5 +- .../starter/utils/PeriodicDateResolver.kt | 19 -- .../example/starter/utils/RowSetExtensions.kt | 9 +- .../starter/utils/ThrowableExtensions.kt | 10 +- .../main/resources/http-server-options.json | 6 - .../main/resources/pg-connect-options.json | 12 -- ...x-web-kotlin-dsljson-postgresql.dockerfile | 73 +++++--- .../vertx-web-kotlin-dsljson.dockerfile | 73 +++++--- 39 files changed, 1165 insertions(+), 605 deletions(-) create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt mode change 100644 => 100755 frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml mode change 100644 => 100755 frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt rename frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/{io => helpers}/BufferOutputStream.kt (52%) create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt create mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt delete mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt delete mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt delete mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json delete mode 100644 frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md index b8ae3f33b30..2cb792746e2 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md @@ -31,6 +31,12 @@ http://localhost:8080/query?queries= http://localhost:8080/update?queries= -### FORTUNES -http://localhost:8080/fortunes +Testing: + +```shell +../../../tfb \ + --mode benchmark \ + --test vertx-web-kotlin-dsljson \ + --type json +``` \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json index 445d7e5f319..0625b6406be 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json @@ -24,7 +24,6 @@ "postgresql": { "db_url": "/db", "query_url": "/queries?queries=", - "fortune_url": "/fortunes", "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts index 5131d1b9ec7..03517f3a9a7 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts @@ -1,86 +1,116 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { - kotlin("jvm") version "1.9.22" - kotlin("kapt") version "1.9.22" + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.kotlin.kapt) + alias(libs.plugins.shadow) application - id("com.github.johnrengelman.shadow") version "7.1.2" } group = "com.example" version = "1.0.0-SNAPSHOT" -repositories { - mavenCentral() -} - java { toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + languageVersion.set(JavaLanguageVersion.of(25)) } } kotlin { compilerOptions { - jvmTarget = JvmTarget.JVM_21 + jvmTarget = JvmTarget.JVM_25 + apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3) + languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3) + freeCompilerArgs.addAll(listOf( + "-Xjvm-default=all", + "-Xlambdas=indy", + "-Xjdk-release=25" + )) } - jvmToolchain(21) + jvmToolchain(25) } -val mainClassName = "com.example.starter.App" - -val vertxVersion = "4.5.9" -val nettyVersion = "4.1.112.Final" -val scramVersion = "2.1" -val dslJsonVersion = "2.0.2" -val htmlFlowVersion = "4.6" -val log4jVersion = "2.23.1" - application { - mainClass = mainClassName + mainClass = "com.example.starter.AppKt" } dependencies { - listOfNotNull( - // Kotlin - kotlin("stdlib-jdk8"), - kotlin("reflect"), - - // Vertx - platform("io.vertx:vertx-stack-depchain:$vertxVersion"), - "io.vertx:vertx-core", - "io.vertx:vertx-web", - "io.vertx:vertx-pg-client", - "io.vertx:vertx-lang-kotlin", - "io.vertx:vertx-lang-kotlin-coroutines", - - // Netty - "io.netty:netty-transport-native-epoll:$nettyVersion:linux-x86_64", - - // Postgres - "com.ongres.scram:client:$scramVersion", - - // dsljson - "com.dslplatform:dsl-json:$dslJsonVersion", - - // HtmlFlow - "com.github.xmlet:htmlflow:$htmlFlowVersion", - - // Logging - "org.apache.logging.log4j:log4j-core:$log4jVersion", - "org.apache.logging.log4j:log4j-api:$log4jVersion", - "org.apache.logging.log4j:log4j-api-kotlin:1.4.0", - "com.lmax:disruptor:4.0.0", - ).map { implementation(it) } - - listOf( - "com.dslplatform:dsl-json:$dslJsonVersion", - "org.apache.logging.log4j:log4j-core:$log4jVersion", - ).map { kapt(it) } + // Kotlin + implementation(libs.kotlin.stdlib) + implementation(libs.kotlin.reflect) + + // Vert.x + implementation(platform(libs.vertx.bom)) + implementation(libs.vertx.core) + implementation(libs.vertx.web) + implementation(libs.vertx.pg.client) + implementation(libs.vertx.lang.kotlin) + implementation(libs.vertx.lang.kotlin.coroutines) + implementation(libs.vertx.micrometer) + + // Micrometer + implementation(libs.micrometer.registry.prometheus) + + // Netty + implementation(platform(libs.netty.bom)) + resolvePlatformSpecificNettyDependencies(libs.versions.netty.get()) + .forEach { implementation(it) } + + // DSL-JSON + implementation(libs.dsl.json) + kapt(libs.dsl.json) + + // Log4j + implementation(libs.log4j.core) + implementation(libs.log4j.api) + implementation(libs.log4j.api.kotlin) + implementation(libs.disruptor) } -tasks.withType { - archiveClassifier = "fat" - mergeServiceFiles() +tasks { + register("server") { + dependsOn(this@tasks.classes) + + mainClass.set(application.mainClass.get()) + classpath = sourceSets.main.get().runtimeClasspath + + jvmArgs = listOf( + "-server", + "--enable-native-access=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--sun-misc-unsafe-memory-access=allow", + "-Xms2G", + "-Xmx2G", + "-XX:+AlwaysPreTouch", + "-XX:+UseParallelGC", + "-XX:InitialCodeCacheSize=512m", + "-XX:ReservedCodeCacheSize=512m", + "-XX:MaxInlineLevel=20", + "-XX:+UseNUMA", + "-XX:-UseCodeCacheFlushing", + "-XX:AutoBoxCacheMax=10001", + "-XX:+UseCompactObjectHeaders", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+DebugNonSafepoints", + "-Djava.net.preferIPv4Stack=true", + "-Dvertx.disableMetrics=true", + "-Dvertx.disableWebsockets=true", + "-Dvertx.disableContextTimings=true", + "-Dvertx.cacheImmutableHttpResponseHeaders=true", + "-Dvertx.internCommonHttpRequestHeadersToLowerCase=true", + "-Dvertx.disableHttpHeadersValidation=true", + "-Dio.netty.noUnsafe=false", + "-Dio.netty.buffer.checkBounds=false", + "-Dio.netty.buffer.checkAccessible=false", + "-Dio.netty.leakDetection.level=disabled", + "-Dio.netty.iouring.ringSize=4096", + "-Dio.netty.iouring.cqSize=8192", + "-Dtfb.type=basic", + ) + } + + shadowJar { + archiveClassifier = "fat" + mergeServiceFiles() + } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts new file mode 100644 index 00000000000..4a87641372c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt new file mode 100644 index 00000000000..99d81bec357 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt @@ -0,0 +1,58 @@ +enum class SystemType { + LINUX_X86_64, + LINUX_AMD64, + LINUX_AARCH64, + OSX_X86_64, + OSX_AARCH64, + WINDOWS_AMD64, + WINDOWS_AARCH64, + UNKNOWN, +} + +data class SystemInfo( + val type: SystemType, + val os: OperatingSystem, +) { + data class OperatingSystem( + val name: String, + val arch: String, + ) +} + +val CURRENT_SYSTEM_INFO by lazy { + val os = System.getProperty("os.name").lowercase() + val arch = System.getProperty("os.arch").lowercase() + val type = when { + os.startsWith("linux") && arch == "x86_64" -> SystemType.LINUX_X86_64 + os.startsWith("linux") && arch == "amd64" -> SystemType.LINUX_AMD64 + os.startsWith("linux") && arch == "aarch64" -> SystemType.LINUX_AARCH64 + os.startsWith("mac") && arch == "x86_64" -> SystemType.OSX_X86_64 + os.startsWith("mac") && arch == "aarch64" -> SystemType.OSX_AARCH64 + os.startsWith("windows") && arch == "amd64" -> SystemType.WINDOWS_AMD64 + os.startsWith("windows") && arch == "aarch64" -> SystemType.WINDOWS_AARCH64 + else -> SystemType.UNKNOWN + } + + SystemInfo( + type = type, + os = SystemInfo.OperatingSystem( + name = os, + arch = arch, + ) + ) +} + +fun resolvePlatformSpecificNettyDependencies(version: String) = when (CURRENT_SYSTEM_INFO.type) { + SystemType.LINUX_X86_64, + SystemType.LINUX_AMD64 -> arrayOf( + "io.netty:netty-transport-native-io_uring:$version:linux-x86_64", + ) + SystemType.LINUX_AARCH64 -> arrayOf( + "io.netty:netty-transport-native-io_uring:$version:linux-aarch_64", + ) + SystemType.OSX_AARCH64 -> arrayOf( + "io.netty:netty-transport-native-kqueue:$version:osx-aarch_64", + "io.netty:netty-resolver-dns-native-macos:$version:osx-aarch_64", + ) + else -> throw IllegalStateException("Unsupported system: $CURRENT_SYSTEM_INFO") +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh old mode 100644 new mode 100755 index a5b03908062..6b8380b9308 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh @@ -1,45 +1,92 @@ #!/bin/bash -JVM_OPTS="-server \ +set -euo pipefail + +if [ -f /proc/cpuinfo ]; then + CPU_COUNT=$(grep --count ^processor /proc/cpuinfo) +else + CPU_COUNT=$(sysctl -n hw.ncpu 2>/dev/null || echo 1) +fi + +JAR_PATH="./build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar" +PG_DOCKER_PATH="../../../toolset/databases/postgres" + +HAS_DB=false +while [[ $# -gt 0 ]]; do + case $1 in + -db) + HAS_DB=true + ;; + esac + shift +done + +if [ "$HAS_DB" = true ]; then + docker image inspect tfb-postgres >/dev/null 2>&1 || \ + docker build -f "$PG_DOCKER_PATH/postgres.dockerfile" -t tfb-postgres "$PG_DOCKER_PATH" + + # ensure no old container blocks name reuse + docker rm -f tfb-postgres >/dev/null 2>&1 || true + + docker run --rm --name tfb-postgres -p 5432:5432 -d tfb-postgres + + until PGPASSWORD=benchmarkdbpass psql -h "0.0.0.0" -U benchmarkdbuser -d hello_world -c '\dt' > /dev/null 2>&1; do + sleep 1 + done +fi + +cleanup() { + echo "Caught termination signal. Cleaning up..." + if [ -n "${JAVA_PID:-}" ]; then + kill -SIGTERM "$JAVA_PID" 2>/dev/null || true + wait "$JAVA_PID" 2>/dev/null || true + fi + + if [ "$HAS_DB" = true ]; then + echo "Stopping postgres container..." + docker stop tfb-postgres >/dev/null 2>&1 || true + docker rm -f tfb-postgres >/dev/null 2>&1 || true + fi +} + +trap cleanup SIGINT SIGTERM EXIT + +java \ + -server \ + --enable-native-access=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ -Xms2G \ -Xmx2G \ -XX:+AlwaysPreTouch \ - -XX:+UseParallelGC \ - -XX:+PreserveFramePointer \ + -XX:+UseZGC \ + -XX:+ZUncommit \ + -XX:+DisableExplicitGC \ + -XX:+UseLargePages \ + -XX:+UseStringDeduplication \ -XX:+EnableDynamicAgentLoading \ -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ -XX:MaxInlineLevel=20 \ -XX:+UseNUMA \ - -Djava.lang.Integer.IntegerCache.high=10000 \ + -XX:-UseCodeCacheFlushing \ + -XX:AutoBoxCacheMax=10001 \ + -Djava.net.preferIPv4Stack=true \ -Dvertx.disableMetrics=true \ - -Dvertx.disableH2c=true \ + -Dvertx.disableDnsResolver=true \ -Dvertx.disableWebsockets=true \ - -Dvertx.flashPolicyHandler=false \ - -Dvertx.threadChecks=false \ -Dvertx.disableContextTimings=true \ - -Dvertx.disableTCCL=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ -Dvertx.disableHttpHeadersValidation=true \ - -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ - -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ + -Dio.netty.noUnsafe=false \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ - -Dtfb.hasDB=false" - -JAR_PATH="./build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar" - -cleanup() { - echo "Caught SIGINT signal. Stopping the Java program..." - if [ ! -z "$JAVA_PID" ]; then - kill -SIGTERM "$JAVA_PID" - wait "$JAVA_PID" - fi - exit 0 -} - -trap cleanup SIGINT + -Dio.netty.recycler.maxCapacity.default=0 \ + -Dio.netty.maxDirectMemory=0 \ + "-Dtfb.hasDB=$HAS_DB" \ + "-Dtfb.pgHostOverride=0.0.0.0" \ + -jar "$JAR_PATH" & -java $JVM_OPTS -jar $JAR_PATH & JAVA_PID=$! echo "Server PID: $JAVA_PID" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml new file mode 100644 index 00000000000..42556c390c6 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml @@ -0,0 +1,44 @@ +[versions] +kotlin = "2.3.0-Beta2" +shadow = "9.2.2" +vertx = "5.0.5" +micrometer = "1.16.0" +netty = "4.2.7.Final" +dsljson = "2.0.2" +log4j = "2.25.2" +log4j-kotlin = "1.5.0" +disruptor = "4.0.0" + +[libraries] +# Kotlin +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } + +# Vert.x +vertx-bom = { module = "io.vertx:vertx-stack-depchain", version.ref = "vertx" } +vertx-core = { module = "io.vertx:vertx-core" } +vertx-web = { module = "io.vertx:vertx-web" } +vertx-pg-client = { module = "io.vertx:vertx-pg-client" } +vertx-lang-kotlin = { module = "io.vertx:vertx-lang-kotlin" } +vertx-lang-kotlin-coroutines = { module = "io.vertx:vertx-lang-kotlin-coroutines" } +vertx-micrometer = { module = "io.vertx:vertx-micrometer-metrics" } + +# Prometheus +micrometer-registry-prometheus = { module = "io.micrometer:micrometer-registry-prometheus", version.ref = "micrometer" } + +# Netty +netty-bom = { module = "io.netty:netty-bom", version.ref = "netty" } + +# DSL-JSON +dsl-json = { module = "com.dslplatform:dsl-json", version.ref = "dsljson" } + +# Logging +log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } +log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } +log4j-api-kotlin = { module = "org.apache.logging.log4j:log4j-api-kotlin", version.ref = "log4j-kotlin" } +disruptor = { module = "com.lmax:disruptor", version.ref = "disruptor" } + +[plugins] +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } +shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..8bdaf60c75ab801e22807dde59e12a8735a34077 100644 GIT binary patch delta 37340 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 UX##k1IU5Uz9RMyC?XF1w2hzEis{jB1 delta 35347 zcmXVXRajdM({0fr!7X^9xVuXsxVsg1cZ!o@!QI`pcyTQRr?|VjOVI+S@AsdZTGNXNRtItN43NL7tgq8cm*=VdD4XPc^nV&aM5M-^|0ZqvP>{2 zClK@0y<$E3Rs!nMy<&zC0&0BRV*G2@Ygd>LD)JwZ9O^}czkK-cLG(is77OmD?bM{2Qf69Rnb}ME=PVb`2+N2gR=-HN)3)r@7TlxC4ilXK z9NgyQU;ltE@P}W7XPjQkj#eW$Mo4W^X*cX?@*9U7KihZ;r!u1KQz@^>&?3K6)kuWz zq3jDJ^ITo4rGNL&{V^OVG&2v-*Uv5kM`3yU->mj9#ZXXINpMv$DcOV_HL3SIPJLXF z^y2`cCDIL`fgRz@rZTKb(!9#hIF2j~2S%gjjG1C$X)~JoO4KvmcQtLM@mk`rZ%;1p zxqu|X;W6Pc&J4LJHBbK74RaO88EiG{u9H^o0mD zsk#IYY@ueLj3b6C3>R8*j)F@Ul-C;2R5CUiruXYn{O_lV1s&MlM~-#UX1LXLOHX+& zskg8<7^C@cc*W?+H*|2Ak7q%1NLm}G=Y;U#M8?bMWDEI+gSy{W0Zy0R$1z&F2eHn~ z4ziprjfIvzF{SQabi&$BUa9$=tR%f~Vrd>^;3G?ebV0EnSl04i*N`Pt?N)q(c|8bS z!dG^JG_z={jBFR3nn=R1#d1!6V)ZwbFov)iWHog3VaP?*BsxYIoS%OHf+|m% z{M3b#V~x{q{8sDy9r^p%NNuXTVh}y6IoLHbRez#j1E8yZX~gKB4n=CK_?G4Qd1BY5 zV2NLBda*FoDguLMWOF|#sXl95tX4yup-qd5iKEGaOpNFlutCMlSn1u--ax5#%y~8+ zB(cQi%ce|Xjw;T(&7>N@Ws-4?d_7aJGk?#-RMuGS51=>=0>bBFuS!M)GkSCOLemc; zRL{<-CUu|NFJ$F=sX(RKIue8LL{ z7taKyxq(>QjyaD_pLy|qV-dG7LF_Nw9f}*iuO^6jS}WLNX|0fF3tz`h5YTE_gK^pA z1L(Nkkj*KLY=$VIJLNlo0R?m70kTnmN%{h{faY|ZVPsq>Y8ER7+cW9%I9&9l*$yYm z#qQ1fZ3<}3oKBfs+{!C#1oqsLFu?R}gg^neXXj!ttfxm5rd|U%Y6zAvGTPKA(3pJJ z4xjNp|AG9!euSoBXE?%s`0x`3?tf#Pk0Sw|RlyBlfg5dS{{rtvz&Ol9hq@C6GYBuM zpn%U-n0`I5*6e9e&}HB#m<)WPctaGm4obA%!MKtpRBpk-Ol4{w5pFpYn&elW6n=Qf zBk%bjB$2Q^J3T#i^AWmp-yI)YZ@a{8)>{Y7-+mIh7q>wy_&i)2!sH$~by0=YX_4_SaF}R5B^%j2i|`i;@TOshy9?8Y+!V`iz!gwd zO1|Cf+?X!A_Xl3PAVrI9qGyfbPYM~ar5Cu$*X+cy$~9l6@brD!nyFAJCD4}?AFo<8 zEodf+xRL>hLdBKkR_%v`@QDx!Iqt!PA-(1LGE+fTlN6vj19mz#Dr@rEcFvVgX8;0s6=sF*-iM%5!NDt$RS~ z%?GU)m3>JG^=|LDLvf#nEv+Nx=a5}*H`$)?MmVJ|Q_$(8d0_sOhjLPQg{D;Z_`kf z(v4Bk^IylA7j}Kp``2;J@c(PLLkjAoD12J5@~jFl0R2;_UUHOIPjn=pIR#mrUY&OW3NAdpK{LBn}+{To21PlYZ_^&S6=97Lif72mooR0;kRqp5FX%}wOY%- z$9M&--rQsAwD@hu5y^VYcKEfnQd=P0p~>V(!kzZz&HE_sS*l+@oE@n0mn@+8ecWdp z1!H}GtXcbhLNm6jw6Moce)6y(@?XyB8|ZT?^s*ha?z=DVQ>zzy%*rSWrVgCX0KD7B z4U}77)lH{eBF=pRy0z@9gxlmrlihLj7d9t2e>bTGt8b2F z`Cto}93hh~`au;ow+t;(wcSwAx19yicaT7fr54CTz|65eE1(YRoz`{2l)v08jZ80c zzd4EYX0rfPNQO_gveia_@!^bmRkt3rW@e0vqGa+(1>Xu7r*MY&f|kSIU-$JLx>+d9 z>zNcprFK3iMijhMDV{)9NNf%EKMnb#I41LbLiuL1Imxlj5_z@fS%)A7HWVE z3iwRKAHiL?sNjl;+Chmgx<3%M%GTWb=xJnm>@^c!$2afq7j<>%w26Y28ic%O9=$6B zy2Ll^%V!-O-kMR8nj8n?dL?dq+yR!I@0uBvhhLPbb5q$v83D|*Tvy=ZXvDp?OikPi z14AwZDeC~)yA_ihgI>NOu%hw5-&1ZMfpE)bSh>P@zqnX)TRh)Q%18HtqyUOj1ifkT zhmR55cen?z3vZrBUSUNQ7%DvlJ!~(e84{#Kei0YkR48{`*?#Fd1H)O|<|xd0F3rwA zb;msOHp|I4mRx4e#d-k!gQs2{SfSs|XWq^pbf&ekf5$17Bl!lV{> ze6yzRMK=FjnQ({>O?;&AkcingSP%DDX%@g=B-N&~UsPOQ?{%)Ui8YxdI{}|1j5B8+ z1VFybUK|7vqUn%?gir&b82YJA2tk@jwM)Q$*Q)q>%s)-#gA9b+<#tWNvONJ z_jVjX9@*%GCXI82gjf&+PH@<3YK^Qlb>g#{ujgp17~Mc!gvs{)6t#W98u47wMV<7# zBO&ij>8Iu$%ja5Kq7((2{;uFKua$G_4OTPa6@(H}GBI4SiLF8&C+p15q#TaDv7c1^ z89`$y%u)19-c;kLBp!y?2^fmvywH0k_3h!Q(8nBBZVS|0il)q}Q zA7j8S1M#9D@mIULBtD9iD!Hc(EsD*L447&))Mf-1xC$5D(NNQQFN-$XaF%|;W_Kf) zxI*1ERfRE4{XcBl8g2qK;wzvCf}HXdM-0&&Y-vE^#TjnB?^ChRdW=7%vMeOaa$H{A zlceu}fWn&*FeEx90q#C&bGG>r3H%szG$ahq4P6)1v?|Tm5ni|)j_0WCfJP4HG*xh}P^v4$zsBMsaXK1&LAN?}EZ~c`+g0cA(kL5D~ zQERJHc)?&(B(a5y`Tz$ZgvA|Wn%Rx03md@Rj%0^#`J_Tm4E~Aj3RrxW5HK*4)QFPP zg0-;XD>y((Mk~X|2ujp2`o?4u5*d{^QdcnJOh+)n7gYaA>KZfSH{>TDEO|lX$nsjj z&XuGR{}L6!MBKJ2%so59o46N8E@p!ziB+rRV8|S`5cN%^O%9}YYDr_KZj}Qd&iF0W zI@{{Xo-}vR4a_A&`bxpFt8B`_GIZO-7pXaraH{*fdO!^!jp*Dy;X)}pT~U>48?W`b z?-a)?>R8h<7_-#Ts{&r8t|RbE{v|RbP}#^wVG&Kc!e}oPVgYHuHDQM;TlQ+a&oauk3Cl-FKJCMw?*01|0YU<*8tJLexKEXepW;BQPnS zXY`F;f#J1U6pR(kVeN`=bQXc>zkEz6gdBbi2EDR3GO5X|bG)oQYg4_9^T_I`Jn*A$1R|*S7SmB0|Jcx{>vSF6$(dcYi3oob z)0$6At)Z$9)7L;Ch@yi{Wp<};6lp>Ksw*7P4aSLQ%@@VX6+h9}`IYglBUv0XmfE%B zyM9$6*iKmd!OW=FBYGm_RI;R|&rs2>*Nxj>7c#`oRih=5Sc2pFo4{Z6 zjrd#KoqmY7lctKH*`0d7BQV~^y~Yl`(o}u9rH;;P0Y)Zv7;Vv!*?C=$MVHsXve~%{ z(P2@U;~_2v$|3IWO4hklB@+GG?T-drYGC(8vQJBt6LCuVe*?F`3>%XPx0fSN&lyaa zI=WgUh5RcK&jwV-W%s~RM0Pqw47K3B3gKAwU?IiKN%i1Psq<@^l5?t*WkTCH5xJWoaFHDl*Ao+PwQ=up)`vOSGGntCmY?P5a_iIu{P!CKvX}sH8fwt@@n^1;>gT}CbT$DG+N8> z`!0(gT@ow#?BSPp`e`KF=)Cx*5sjqu5?eA^oxYSv^aM}DxAM1WP;B3o7ZM<-VE+MD zUC2eh*Leuztew<(49{cMF)b>O#sms?UX{GLF{<^d$+(| zKG5{8(`rz$SYyTle+BR6m9U{_TjOap-Nm`Bcb3>RImE)OI}@rK`J!EDoJd6$XRQpv zQ>VjoCL;h2`aKZ@ydeF>LRMa^8b|_5)3++zZp$ZrGr*emTU&Vl{IcE2P-9y9ow2oa zhmvJLaRDgh-?ly0>r_iRKc7@0J6ddW<}EJ8;AqM+;T^^Exgr4bNk^}KVQAe{5HbO8oZeu`5D za*~`>5t4FE?lp18amck&lT5m)brpmaUYX&94Q45$*NDEBbF;dWNOhF%#Z_+GX5vpfN1>+75-6{wErlJSkf334OqkO{|F0latuXu z*7tH1G2Uhl$I(`#40tqTbXbWXqhVcNy3pp&Wu)TKe=)(qBfWYmkL#5N1gL~+CZW136rXUtnd4S+ zXuGCfLXJ`2NBo}k@+1GDh_iP@)zcaQN+003a)MXr1Pmm)d&foeI8ObAu-;0;Ij(Ye zsbl!=jBuah4C6cK$_!53RxA|g@_F3r02W$@=i@&B`yvKDgctCmAY21au#gq10psYR z3`h(b&-)PeM%vVGPcV~9Yuuc60nRM5BM$&M(+PQ7P=(JLZOlB;Urp-kN<1S`3|lRyrf0l6jy0UH?md2+RFdsyGCVDGgBxbSq@+Z0 zX5Cy-(%?v1th<7|f+kq8UUdj2Z}it3U6wPH^|Fcn_%9rhR>01zNz@FwS&QZA!RQn?fsk$D7*?x%kR?cc^`99n&t~nv%#c%Wdh$s_=NZBdm(8FVOD{B;mr$lv3 z*Bkf++Ydz&(oX?F|3Y!v2XYikNQh4k*Rsdw}%-4v}m z=GM|f)VJ(5^HY_@dIFPISEvqzmdCo%cFsfB;W8FCC=rNzZ@uF9G)%TZ-mv8nDS;o|S{dQ=i6bor&D1-zFR=DS;eYV4gtLbk&0jP5il!rs2W zl}EY|NjTw&JjQHhdFN(qf&<=Qzr!t=UY%cDxV;aedb@`*+@p6{@0@$7rXGm9GIH#f z=|=b4B@d$|^6d}Cl>!YiD7iPbL*#=6!G^hy^ppPELTrBTEa<+;KVC5YB#FyW{!V^* zVUeU3r?4%+Ha#pydzJJ9x3sK2m}UF6pcw-)i>juua*-nd=o~rl5eN1CpAsqg#%Gd$ zczsby(qjp49=ofR}+bWJXiWdba zK38?W!Z2>;Y<#;pQQM$lV%|SgqOrWPJr-kUZbPuE)8XOg_k$ru^*i<&WtcSxx)J`b zR32Y_L<^HP=*_|ZlaE1mUr%gpV1DEmGRl2z=L*Nbi^fQNln4nAOeWy$5L`z;)3$8! zXTK4>!+5MjPL{v{e-|C~YGJ-E;!gU#!S6Pi;XAoOF4`0D@d}6t9h#k89QSM=sm9q} zeJ*uu`qS=+U`S^`Huj6R^A~;y<2DKza{JlUaGgM(063!Eu-K`&jX0v6OaL+j0?`ol z`91gZ@X~2>vp${IoMK~owASYqKgQmLs?2yIog?E-e+}VXtBR^EmLdc1vf-K&?#3z57p=Li}zypn6L3tO& zl4~zaHG+cRBM1?yUm{QuL=PR_9yBU3;&D#`M3~m>9H|VFLY|OIG~>9KjM?M9wvMa3 zJ-kV3w>PWkuDxRTPxW>Qr8?&+Y?;Woi7kMYDz9Y# z`DD=q6~zB-);5^LJwf9&2=w5flXv3}HQgbR9O!R>=_{v+xz`k6rj$gbo71aC#nqZr zt;#dIM`g>O@-6BYE~bagY~sX~-xs;?`_;$G)MV={mIrYZeb5IamlAGJ)NZUx4(&XWH7Nt!OwGe#j+E40Y}sk^@0@QQ%rg%6-wp!VSMGa{Lo&-nFt)K zju8uRkY*Wa8@p3SpHF^I6X7#)F?Un#?Rac*vW(uE!B1>F_G@hYR5~z_E1++K-^k3azfS^( zbGb4B^SE*Mr5HP!Ei6p|FPm!v9~!6d{F!H{sgp8zGN%tv4T^vIU;W}oMk30R{8>D~ z_@gMPPI$Q5bItA@|8%5Z>7OE|m%d{Sd{Ov)eqo`z6nAie&n-pPZ*>($gMb5m{2-F- z;z&R9Nfw%y<7;)0&CmJspBSIl^WnD%FbL0IxPyv zkxZlWT58H|wFY9&ppo2Mpc1Mw-=xXkmNb||`MEU39pVbCtW#SB18cfmuxSwlmq;8;(H@ySTwn((dw$qNF zY!{ z3fu~Zq#0aW>-yZ^*)$+pP7}+SC?pJ~JcB6d=OffwhNVKLX)7bYE80iVet(*-Wz;bt z^NF+D9RK^b`;E=N*OULyC0jDbuqR`1%vpk<^;yMYgtJaub zKv*U*BDIf`B!tzf7v0UU#peI}1f9Qy=>?GCL@N@WpS z`qZtc`Wc8*F=I_qMg(X{(k>`{m9;&!mE{QBu0K++L7aPQ1T$ML(}TpCa$MWboY!$} z#<^y6JM{KbMHF(S+ICT-#p1!+TLvOS|3voDW545?DItUxAo{-a(8t@hV|`0=V;?R~ z5fQdjvv9PRt#+$)8|mZ$ai3)0T<59)0hh>*J@v#bLvDRTj?jr;j+`WQcHMtQO?#6F zF~23{ovu|!UuE9?Qk>20u^HF9?@V#ZHd*rQtpi+QgFa0MFb2W#0U_WZOUQwP2rdcA zE?eg3@U3c^vjJ7e6oOpW_SP?{Qr)B=O-wVsO4LQ?kX&8V?k$(vi|57l*e!#`5El|! zN+h!$_vO*4#Ps&Re>Bbm1{+W2KPH|2n7hj{_eHv7Cs_@pLAd0ki}_XnTY?QGrr>Tp zcG^tYK~mZcW>YF)4#EUynzNltC#^HubB?sYjtZB^~28QZYnXc zM`;ShQ`94h>Wb!~KP59VP&q(B9F6f65(F_mP0wj=& z@g@6EK?Ijt7AD2BFC#L$n5r{TBC@jY=-IVFxcd4%gE3nTOh;g9zdp>(R>vtW$&4(* zGW}YVF=Cym5ark)MnICTqi%DVtARGL`45M(b)J+ChL#1UOntqB!uHXU(Q&;{b?vF& zwv|%H&M}ooGYXXs6+G|k>kD{&nhe{~=PG`HF2O18HV}7n5oIexnYv`rlVUwDd$MoX zG`!#vY)Qo)zz?4HW+;o!f+aJt9(NKjpQ4z>(l^rZU~Cf*+1`flkcA?kZ64`}RhGTy*BNqXpbe|AZxLzwWSS2rvUsNkw+iFnyIQ|5RK? zzh*T_F9E1#yO$>=oRgG;ql~l+Z#~-+aGo6_4Cq&aBG5lZMkoF@|^dZ|_W@ z#8QF#>cQlnz!aT7V;u&_$bISBJqc-p<8sAf28}*l14a-Z*#)NBP~M_oSL7#CVzmk2 z(v%wg!fF#qX(#Rx@^*EYTB9-2oIm47=Nd>&V$XDYDpNbk$eg(Xt zliK4_VWskFjc@o%(XyF$E|N3d)yl|`A`VM?LSmAL;9ZqImN>b zUj2rn34HsO^lj!?$2wo-3zdZ2DhZMAhgqDZ1$ zHMg%)-)*s(vF9XcA!!jgZe9tmSF!Idwz zeHzu`rkpKf+{)tQQ1%Y01s82H3!&+hZHY=mCSOQKYel=DO;h79HXYa2F=nTq=$9cD zt+dAItSc}2UAF(BoGd&s-^)&mPou_uQ47*#kB;ZGD1O zD0k5SC~K<#80c>7$#QJESE0q;*OVV3_uNvQ< z9j*JjCE`cTXXL0x^$G<>sv$w%qiA=7TcR3N@l7+8Zl+Z-qvpHSW)pUWmPm8{!^A-@ zr+FU5(V~pi%K49!5jk&G_9gb|0<<(6Y4tSC=-pCt)}tBjo+7|sioGVvOt`-s)GGBD zri*@Il3$+9EVoXFG|N(enV;?1>gqpS#6yHSyiZrW9dXs22?!Hz5`yrmMvH~oKXS$} z3X&6fm=)Z=XvQ@eiDRK|;SdQq2}-5_Gfp`kgTZBc^AZo&Uk0(8EA;)*ApVstXqV6`&{S>D25kaQ7C5aYv>?YYP~+*!j~fF(B^|b z$M;T5&$MGZjPY0idT`ASL)UzI;cVK`LvI|#b!R*;6qXX(xpXG^r03z% z&ze;hi;S(?Mt*@`0mnK;>vL^7KlM(K_hg)3F|)olN?(DtB?hF||1gUPKMT8t$K}nh z0Fd{2R+y%q0~(M=1%EvqF6oK>qUNZ8)Bluo@q(=O%@<0bIPzGOv7tkg9wRzbHZGpG zeJfSKs8JqvCJ};Pw6P*D5d6nzn%G+lVe(lr!^4ORhe?92CurTsmRiSQgzWJR@xO!V zl*2Pd;2*4P|8rwWlj;No!13d9&@Z^5lR$?Rpo4?QDJ7~ZJESt|G58Y#FFr0p?><+X z;*e4zM-r~YotPgg0VUmkXFDH#tD9TfL$=dIPR3QLiLl%VdZob?wA+vmZz{TUS1vJs8QQJV8 z-hQ*9QUr6BJc5i&k9L+m&{Ea2= z2@E)w4&n&47@QXB8OG;gGZsuT(5;;|yUdPp#yg@s8=E($0uU@4Elxh1Gz_@P~Iwk}e zN^9y&Mes>q_n1*Adm{gXVcqlXxz}R!!{(DJK-)C^16t6-7Pu;;^BR?B-AtTVPE zWP5P%{Mkt<>!Y&diVJ>D{^@UivDCYw^iw){JJ|)S5P2-r8h8Y-ul{^cE>do#SYh@6 zOI%92+p`Jt_N!j9Tljrng_3WstHmqG-xG5PzMQN!XIOoPO)fNEl?c0?p}5d6WU`H6?W2d!DS)$KEv2eYA_O;<2}6u@%QQNg9HDXrh~uB@FQdK(bie;jXV$|le)zsNARA6@qK6XRD6-!M=6oal~C6s`Yy$p*dhc$ zs}Sc1D0lfk)!>Or8Tb7kb<2iNqL60%Hyh|l-~Y{rg^Hr`>K9D^uhGIyPZ%GuPX9*uU=`IUd;-vV>_3tYE`1IaZ#>;rv{$Sk=oySzCC zdeFlVL)TZe!CEKWbLCD_XGpkat}qqm4_?r}PpSD+H_OUgwHa!?7g^CyU?;i#z_ z?TZM3f%3aHjM)~dELI6M!gSs(c{ILN9z}<5E*1c|0Lr2qJyTAHi0o#qh-YZEAz`~ zx^gIKqqoni;g`8FXFurt_n%v9WE-YWrC9D$p!bM?7l~Q``4suvAY-7BwSR|6-9RCM zh#}{Qk-Z z41#p9SV1x}pnOfZKhv^~>Q1pZ{7OccFBE?xg*~v7yd-y|DY8A_xZ>-~bsrwHeJ|>J z-XCx9e&JMc_-$-%qKo=q#XZPSZ$Jnzx?%|qbt$NLDYXMqY0X^}6TM{bUHj!l$y7VF zwZOW^4uCeMie0>lyz4#!4~)oMVZ}m^vH9(a03BJIK-d1)A#TYMaV(nxwWwIxw1u%9 z6VEQt+ zg}LQ$3#BJK{K~t;5bD)Uz#@nalZO=S@AwEch;M zG)DX$0)*qe4cw2^mjt*`1>u`64*FFJ+}eZ}@1j%JUly~hw-KRLBMyKU$8%0G1C_PD z^Gx@!f_j^tmikCtzVfv3K<^I1i{;8FM9Z^dQWFz4uiGokG#Z^}NXh3$L<|8OeZl^5 z3^B6zUtx>>S6FFDDKPio7c#2Ae+w|S(=fxC4SAG8COas; zt{=w5=CXNl_xD7N<>0~h;jk+-{nqdOff!pwm|f^d@vRCrl|L$deY)QtpV5AS*3=)J zy`Nm~SaMaq_435U?b;JP>{c<@InW)A(paSYyoyCjvZ9|Drd^KyiP}Tw?vU1%z@%8F(=KiFAh;UST*sMBVaQ~ z%{uN!=-6WhPu0{9{RI42SLpFqX^(Lh;UAS-!TPyL&AVS%>U`Ov>uTz_%cx5r_6gnT zzxh$Ic<}DEt7>LwX4RI>qiDtDO>QHa1+u{mRUW>z0@k}y#8?7q`AoY4bZeKn@8_cY z@3UqknTy$XhKwZoXc<5~9o-ap#4smBH&b_WU4K>UP?WNN<*2ZALB|9^M z7nD#O&(BxFkL0-8 zuuX-ko~VX!qO^WRi{}k+&31RlLa?}*9T0kiWgCQSGm7UOD|b4HJWrZ<J~La_A%E3fBXkL$eoi z`6sx7#Ii`qQmbO?c%ZGsneq-7p{5IG{3R@xDf%g(#)+Kzuc#p@DJ_Sq^@pmT&aP%U zgC1i~Q7H^I3#^TX<6G$rGrp$(NVcEmy+jXWKZ^O3n%a8e6I4JXQ+6if=v&xH?OjW2 z{v=no?+eosXN2WI<~zOmr-cLTT#N*5Czk3XP=kH|Sq49NFYk7%8#*{3G0w0JvmGJC zex`zIyu!i%G5o*P;e&vm%EVQT{xzYr=Wsy8FdaLbu<~bfHX&(vp4*FB$>LWVTW~{TTIE%&P11 z&irDxskGtd=oX~Z*_7bKzc}^e;)*7y9B#Bcqj|Z_!?(ipg`XQ3}T#i9OZ|J8ORTg zv!zCh*-EKsoD`6=ttD>~*UL1Z0ndhon&@!2FoRL!m$|#YMjXHjbq*v74rVvHl-KE% z2WXGVfEm=k>BIq7z)b@1VDIMi?;}Fr=YWd} zhBFrfpw8^PUBQB=ljW22*hC|D{g%{x81`BM$O1i^37>7f!zQQ$SBD!^LlgP;}HKENWKEk_v-%WW(;VX+nhY>Cek4 z?}uF-W3P_xT=|{_lr=9367?}_Db*-D$kz%zo(JYdSq*)46@8Si&dMqczq>-fs`!Jb zwOZGW3JI&Z;db+Cg?&Ge8ILGX)RQbtg6cTBz8Y06^B{C`C`Th;mYMU5%Z$;hx=YH$ zwbJD(DN)TLt5;b&^%(<3K`k_B>`u!;6vv}#l~ipuQFE1h^Of-x{GRjm29B{zvJdks z3gfJ(LoI-d4vr9XNWr0BXc-B3yG+kD2Y}@?ek&QuP?6+>99Q7vf@*ZjEa;J^T}CKS zs~5X(WCfi1>N;%!`6k?6B_3G$DTEBq#NA{2!!s~8HKeCs*l9k+5{}y;$wViP%xHPktyczJH$D)KoFSj?!V~l0O?&f%@Qn`1Bp7L za03U!VbKnO=q;93cBu|10?VifkdQa0AK;G5IUHF)kysSpGOI3{{huWq zj%X^-l4naV0}G;@do-B+j%%4R1i1m>Jalkr_$B{J9~gjhsU$N%t$#5{RWtQlPcxKl zV5)=JY?0n1UU1mNr3B zisEQ$C@G2<6x;#Y*L}`sm!iR#Rt`~x2q`N&+*RdgE%@H?NPsUL+_g=g(C%Ubr1s!~ zeuy452J1?HTsdYj^8onwM|jc=-gsnJB)yAJG$0F$KHI}h3t+?1>zx4KgWQR`KPUCP z!>QM6P0iy^^(nif>l-cgj|-{(9zgbd@wbQb+;p-r`FiGH{rJ5RKiv;Yw-_P-W8n!75`M3`vgs!b*>Dl;UxST-JooN%!94^L8#FUVcQ%1FGV>MX>O^RR)`wbxR(ih*D zL6Uc4frL*%{KfE#5zKn}^L)G-%t~`uj_JiwM==Fx1%t-XaT;r9FlJYfKaE)Xf^+az zIu*p%kk*2JFm|WOoQfK~BbWWGbW=!8KUFJG?t$^M97ue62W=7k>`+x+92q1l9yin` z_Lmd^-hC-*yg!@cuC-V3Cy1N51{uPL%D%^?<+vLxCt$LFb-{loUd*qwDXT{zCBIJt zMIddCv5{Bga%Z4lY1G(VD0c)rRLa(rF(WPvI-6*K7l#?OymG&{p9moz;%D0340qtV z4PzPd#L@LCv$ToNYuKTJTs#zeFvjZpqAcjFbPQ#hL!y8}`ah$u*=XU$DsNM;Dwe~d z>Sv-pu$bs@*va9w27FM;QqGxi6MU-#(N%P(q;Q& z6ZySE{WkQJJ;z^CtW^3+z7btUvc+u}tgi4}i3#*rzXwmAXvWKM8#|E4DH*ics%i~C zxuN!VRhJs+Xk7$#h3f zM56X<3qq-rSA%VZ9GnwHc)GbA&{Q2OR68~wr|1)>V^~mHD*!hlpeF8>vSKxxqf?u) zC&n<2#~T-9VL%iejme3+EQ(xhxCYRlDzUu7efGwr1>{=~I$c1ctsR~@t(UGk8?OP= zEyQE6x_rBIGxayfBu-|E1d$l)DD;y;u$5=T{KEO&Pjo6yo+8{tlAGUS#;^VL>Bvo6 zAJ=@8GfA@dR)-3Os5_ZVL^Yx4p)0lu&F=gqK$^4>4>BsCEkSd;=kSztN+A5?$!sSO zqIAwJin#4Et~PjsyCIX~INYFCkPJrh$s0k#_^rF%=cr^8DX!0zF@}Px)XPCQuw)u- zobB@?-symm?-!;X-RdDt{t*|i`p3%L*^->#?zO03FN8mJ8Nm}K{&)sDG%XF>5@aLt ztGZtu0&54W4cCGevW3v}QEZ4dVRMHZ$j?TFgG^Ca?dtni!D`O1KYV4TuD z=mqMNodqkhyE?wIE4GK2l65AqSMQ0(xO9IC^v~pXha* z23AADThs~49Syv81^Wk~JBO}izxpFq8pYPbJOvQ$SrA)DT`?|bvL0h>G9`gpxT7TP ztQ%3jovm<}X009%3%NDTH926{JXyJYgRZXihI6p@w-4qy7sk5N=9-+|$wa9nIoEA; zSvov%=BA0BE9fa^bM$B)pP27M_8fg}vF%IcJ|@j_qChDyM1EmD#^q@Ag_Yx5f6H(y z?9_W_yZEz1Cn9b^1z1G;L$m6Laq$_I}-Y?*1RD_xfw zbpXM*u=alR%IqGKw%OxJ#l4Sk7NPAoIy39C|i0Jol>DnJrF8xjqPZrN7hjWhGUijnAv|v~%;IEW;miL29Y;!{fc2Jd2O9D)-wvy{ru>ctoq4~Tk{ZG4@DDBD500mp(;~F3p=If0^%uWtLww`&obLM zvA@&yvCO&_cCu|MTDru`9iG_Q^Q1!y&%4$+gZDDN>r~(7$%eRp#1?%HwxhMbkUSdn z(7pJIgd^Pvwk6sQkB=7v3l?=HOaL605_{#d^a&-h)(8PSDRT?+wJ5Ey7hguG=FHA# zfw7NCO-VAsrl`6KPH@3OYL*~Tt);r`4Qbe#ep}+v);Wmg9WH^2R{~_SN=$IXGuqhT z9M1aBSM}D4@PAL6vHq-|rOO)Z4bNBDNuj-3L0$!ao}8^EkSs60QO$Kqj|zi3PxKtYtw345fb=3V-46^0(@+Pmf-y+y6#< zWb6Fau*TA$*!q6R|ImVZmd0NNGVYl$$$@=wKtIJ^x||GE%m-(St(TB(qhj~8RQ&t< z_DlQk@=K(EG{_)~RsZX~YOk~VJQ@ZB zgc{|4McrLL%%lztO29uqy)ey|U%rN-f{KYMCCo<5zOblKpweyuedqapOqQTI8f~W_d{Al?*}okIL~A|U$?m*Z#>WF|JWRf?Cm%>a65?EPFoHK)!tdG z4(P7YE+A~nmDyxu{Fo&lM)xE&-k&IlhPRejrj+~C0PNsNFqF9RI{nla3(Y#p{~CaD z0|d2I+)DFH@WusrP{w#;lR0eqOSAvY){Zl+=Hz1tC$o_N!<%o_mqj z;ZTpbBscOh>(gM17EN|ZuEt1ShVeD^J0y$!D?^(h9%*Fe{=~b_2S}(X^)~kQ%Q?Gu zYFtIVr&2s~fP>dY4S z_UFD1h@c%gM|0x;pUN%hj0v-r)TgBbz&%O<*t<+xROzJR6AJ}8B#On-Wr2?t>>}w) zW{=8+8wWZe4bQJ)B(RE!qkx5k{DxRJ4G5VJZP-dBC`nGGNr0yhR>Fy$7oyq%EoPrk z@}i?FrfW3$-ibERZpNG6IZiVX+j-u8-}d#npL|E;mlByM(kt1h?Q}XHpQvmHG>z)< zVpqeeiF#F7RT7K+;m25EW+K6sz*59Nr{b-#w#3i!)#5?|E|7RHtckQ!uNDq1c-g7~ z?1>5CAE*Q4tVxyt90aS-2HJ=W zxh$8#Rr>I>B=KTRl|EK;YRU{VmXrXS(eU))U?W(OB(IWgYisD><9PLA^%=NJ48 zIb$c2=$dNVq}g@<-+6NCmISYnbL%D*MoxQ^axW5~Mk;6uBi0+TaFz*DaHqm`Qi#!& z@jatf7}+w?>Dh0^nlD%Yd0o6qYlHsW&>U5=1ecq%p|Q zUH&hlU$D$EVNli+r?e@l^J_9kNzbNQ2&v4WM+t>qKf*PBJV|M(iqTMN%u4%-mpEsb z>`4>tm$0S2oCGYl)tk`%H4F48)B~1?St*qVWYRU+%_(^?AC#y81oH!yHAT1^gRe^9 zmvJtRHdWmtQnkuv$vFgc0pkJ=CPrRb1#UMf^X~_l&=o2;TAG^sn<&}I%=>2R#H;|m zh5aNFqsRrS^i4C)PO?~q_$>N-RU>omBzv8F@qMON7vci4!e2!{iHaVRWel;F?B_Ph z=MmN+&aH1->w9PbZS0m8@^)942#B?Y9;2d-BM|9Px0UJzcB@mw1fzj!`7;u|-+yK^ z=j=ttA``KRS=rQ=EoUVVA7Sm@DB$nyhj!9H(FH49*~v zwSCHkKB32@|1$9wD!|gv!S)540s~yceLl^Pb%}) zKt9@+&IY8BV_-~q@^62v4@?VnX*j)f40OvDq|pMSRKXjZw{R)-1#yb=d6&Rbj+pTW zCQAG0en>jN7L=oDJA&p`gH^j_uMv7I3U#Q>%A4cn2oSYj^2-(Fm(9e3JyNdxr&n#)pJyD(#Q0t9#;SLctG(^@b zE}@~njb$TeCk^OU^7w_yQ619dMLbA)bo|;TTs#Aq1)wGVvFvD$&Yf=;b$XX4CnNVW zjZTiY>I_`JJ6D)F0Zuc&;rSK_6kF(*F#O6Y=sKN6G?}~+J4Kk+HGMFBgFO?O*P*YW z@Vs_hPzMtHcxEeEM_f#MJe{<_cJO2PU@L%kIe*C+x0&|#7&H0lc2x?c(jG@(k_h@E zB$g2X!FSU-OaPreBhCyT0m7k~!(TMd$osPz9F&{EYE`#zmi>mLz*IqJ!Oly?L0MQ_ z5odnw%4NHY=F^t!?;|_V@y92fi5`h2>1AvZ?GHlA3Q>n_KgWv}V7kIulFY=Hr%y(% z*zbwIG#`JMAYf)5^1vB}bbP{cRe{)V^kuJr8EN&C$2El(k%E)_c@5?Y!qrVMhM>Fk z%?DpE!P7IS{-3_^xbv5$o&KLRh?d%Xf%HvSGg&=-(I>6& zcA|04&2q9-j9X0C1^H@}XO^Nf9x;O!ffvyNe%4n@T7%{iCE{Jb;(6;oE~%o?CXg`z z3$G-;-I5hiVONq*#04r;QOoh+eMLn8AZ9-Zg}4;$|Aq$ML9m8sHc=4 z8s$6cBY~+(mi<$amDzqi&w%y;S|SSKu^l+$k~TZZU9wy-{MDK(czvTj(Fp*faGb=* z;9~*w#$V6vgrt1^z>YBqOSp#HbkPA=yzoH_vdD5lI5(0P+NFxfI}&b0YAgM98NV2H zr!SOU8VqD?{<}WKOhe7RMur9}n&-{D%|wM8-Gq4|rn+k>L&(L6mtjuyE0`SZ&?lfP z!o1CcJPi})#0VsVMx_R=EfW`w&onZd(kO&UV383LS_w-ysG6UV8@5nXl&WMl9(34`ANIftG4X*wPr=Jb!n`9+!DK9n0)A5Q!p~q|LQ!A<6dkrM zPOSbF#vFyIf&;Ur`u4pL!aw5eWFO2SH+2xd52S`=4CP1Y7q&WoB7}zgB|qAln{SMs zK}Jf)l_ON=nnQZ9a%9=nMic=&bT+9mPc>;g79hQ$ta*?_Vm@nDi|6zUrl?2wbMqpi zvpqC2Sek%z%RgI={eVM@hd&)J#Y^vqhx(m=4Uav%ZPPP}C34)@SYv$wYrFB+&)QhJ z%vE09{Ct@g_jgN6dmC~!e(h1o+;E#5>$I!c!6e;sbVkbzh|YbH5=b(jJ9Z^%brqxm zbw zgfovUR~SY|z+L%L@tah)e@o@&5au5;T1TtV(@XTQ3#4N6u%RRR6!$wjrdI+1ynf{8 z@S>I8bo~mc_)&eoMuJ%YiRPS`BfF12Y1R-~6El;zruiAQIM(9~%=2|b!7zqtF^o7{ z7UNp7SuxqwK|0)Ny7_UcfK?v{276=KKy{Ki^o?vS^P#K z@F%2l1_MK`G3@(3pFr}FNDI)0P|PBYb)zgPgF>(PE+x9a>KO)`FMvtP4&yeFABdAu zyBn8}95E~sw3gGPH4H?(3VI;|$fO@>VU_FcohP6%_L!|#b&pTw)kT7r(1_XfvyzoI z5p>a@8)xzlHBAC2fmttR1qMG=7nsG2&7HNiyA^k}r>xP2iA=5SImP$n`@o{?2i6~5 zw9c2bjk?+?EyJozOmWDl?AB7{a;l^jK=||axK+AynBX|uo2%ifR5YUbi8ff{k+<19 z(57-^?Y?++sFM8?&nBP56J7=Tdj3kPR59G9K}_`tO$h_ycGP#!&TXa5Tv!ARK%K;7 z5kyKD$9z++kvY;mv%h{P{k(9k9e2O?{S)S;)5%MOLvK$z=J9V0Bs?S!7@k&A6L)(r>R!#<= zkTUh#yD$qd-GhYwmWF@=Fk`K5LhgCdFnscFZ~2pn12d6$>`Q6f8L#w?{?#;YAD&qS ztNIAA94m@tb_@k<9@z|P$!7hY2oiAZIog3)++msG{#7=aPJbw4MFdVI+MW^FxC*t! zf0w7?7qw%i_4$3HoWWE$$!w32c_606udlN{1U1|MCdbY`2x9)b8gSH8{(4I!s3 zq6l$fD=N6jwbG`UNwDmx%~$moWqdywK#D`F!dfNs>?^INePbXyN&g*sj)X|Wk{|~J zEB_dXBIR1Ii`hUgi@F6{o)q6H&jd5>GR$}=-#)E{Py5=2^La^@86!@S079QUbjWU%%%QY^Z6 zd`M4ata}o~#G3S7RwWI-9;^bm?oWsY2i5n)gCUFPQZmg$$TYp4o#Em>R>6`ja{YeF zBtb#w_h>4?ZbOh(l!+-9p)G$W?%#S-?3H1-qfg~Y3%XwX|w~S zc+^CtvkE}MugNTZ+A~~@B?PkE=N+0Yc*EMM(JfrdN?6(owrAyFXZTLRQ#`gAK~X)H zzVRzm%tG8_r6%^*x-CCIDDwch0w&D%C_&DcFI1yij-V~s(r z{|F3(w&w#{mrVvr{B+%6mQQFU3@i*7inqlq(gHtMfcz%IaSH8mDg3Y&b{ZukSi16x zv^C`t9_NX_|9LJG7vQ2WJ+~+PK~}4ii)u7qg^UAPBY=<1^F<3-CLEhH4jYAI#UA(U zr@0=RQ|5frn`QF&Ah_VSzgmg-%z)?ga%=;s0zZwTos|mvG`hcx!28r7x`djSmm$p) zXow5&GCjdsO@%r=X<5Jn`JM-NLr_|S?!qAW^Ua3?f2-jl3az!@)w?k% zkn1)}majv;_)qqWMfPI3aJ{7ZzC`+@7q>q;wXJ_f3!a|SM@T3oDjOPpm-oIs*vcQM z*C|)&R9Ja;?*m#JJ}!b#GgD=+37C8|b_YE5?Hf`_Za1orOU7S<)HOQN?R!N^OEGum`DFBV;_(Jdt}m*YSR>Ai-EQ7E9U)|r zoqBrc#m=nqd3-?BQbnpat5OT$tob=^FCISy>3MSy#p>t~AbaftHxQj;G|IR|a`ZS1 zgl82A`n)(!Sv@tZdckZTbg z?%fbu5S#(H(_CUH#EnFWU>tfBho$~u?C{PbXdNt*=ulAlfOlW)1=2YSl7+i&Y6l0r&n<>OOP!LvPZvt#_rQC>n!-5Y zrGMUk@e2E_LF*&ii66$?q!0niu=gv$gg+E}!?*zm_pX6_)er*&Ummgc&lSfAeWCO7V_=Aq84Z@#K5q3$74t zg3|yHBhZ0KY=Y{&l^(i*N&-k+lRH?&WW>TqL2?jmD~5bH2o(@k^tB|UMJjNE7%N`7 zYzNT1dNP#XXL!Y)>2WbP%6svciC&jY3P5+KkL-+)flFdJ`pK|3svWVU!DsRMdi<-= z+o+a>dH*^J*?|LbGpXB{n+d}J?T(QFehfgt2tVEK=LMy^1CrrWC9EIa-rfqL6%8I< za@SqbVv2swW$PotI%B_m@YIXfUktnt@(}o-M8*hbvk+baRXZ`kwAD0hQw-&dVop3%ymf z4Nlsr8OiQnmVI@NSQJ5CL=<#GcA6X}_Y&r=UPXWFyHRME)lyxU{i@e;lW?vvy;#!N z*Q`L6J54mS7*u{ocwTX6%`!zFB&-8u4mxv_gb2!oHP%#%?#KcHo5kij&j{ighoqti zEYGnnDE+Nr{bfP>No=*5Np1PLVh^+&@aP?Q1QT;YTv4&pG4YFGU4Aa0x41A(6^9(A zwO>B3$BoWND!$i!roZ|ue?@w5(PTU4K!s;ZXG>3=z?#qc)Hv3#AU77!qoc zY07O6YJ^$MWMhEt}sb;*K_wnc7r-0?=DOZ#Qv z;a^>G^Ho0q)n<2#fGsh&OJ=%;nS8{x3CsE|c|UJD)s2}FvL|#EWBVel_YkzY>k=;S z;Im68pv*g_Ww~#B>e_Yj-;3JWwI}yeym#+LJd$VF5g{!g^epvA2AZ-<=ISoTi}cH2UI2XN*>Mi*n_?sTM_T>Ej)Iqo7~z`k}gI;m2>6 zkOcg<#L*|ff2}=iRUhkw=pZ1oRR0sv2OK#8S>E1Ryz4bv^Ih$BK{dAPyc%o$SkbYP z#mV({$#sTpvUUp{WNl>6W?KSC=*Y<6$cwh4(nWvD{B^Y`jd@IZ6&zqG!x8#^!Ip&w z5;M=dCRSOdO+7wK&+zUXbavl=&b&VPee4c^U_`2dZZLG%OeIQJbUe(GlMvJ(sD!lx zD$gs0)v8va&tffyKAC82WSJ!f4g{%h8r(Y1Aqy$U{p$Uu!$T(Xzq&D-S2hungY_zvwF;h!v z6-c039Vs%w(W+*PNanUJ^##SaN)pb*zT{0uy4x!JJ{U^%8eccnE6S%_{K|k?ME?-kl3sYup{` zmJBtLdkPq|`^-8^ZknlJ0nJqDbY02V#deX0*^<^h)*9^vp)4s6Y|G2vBxAvV=(66< zWu91#*+Zrcj%ytTDFv-y zp=9rZg7hA8?>$+-YbRFN?FZXZ6ioW4{sP1%TW9T07B<22xcLdmbV7LAss!RGrtmO`54JD{9v^!#^au_AkSbeb&K(0=rFsnk*Qy6<200T5 zR}ErD?rWIXd17HqgCGtD*(~NnP*bwz@!s6)p)rl=zoqeQB~wbB8VLjdE?EOm&W=A5 z&3`0EG^)9I^{QmN-P;9@5|oAdC{BgW3gQiw#imQMqZjemg1+)F#n*T!gtM?MDBb8@ zib7c&N_uZcS|$55O>DjPu+^eL9ez`o;Ht$1Mm$wF8xNvY6^vrTw67e6P3p<2ahX&W zjEn|0X{ZOgWlOtvYO@yt#)2I&h6Ljj#*>ew)9;Z?Y)?>?4w1_Yz{qqN5Jg~+$M1_# z@b5}z%lANaBu22vLEJ{8Y95$EDLqfIvI^U6lOh!*X`sfy!M1!lh+l(JubF8W$I^9F ztgq)V>FuoKhdWmX32ec)l&Uw36ng0y9Ifo`?~m5Np!_os7-#HXBhQ>u}6n zKH%9|)fUO~>5c2KiJ+olRV!=jQrwionuteI1SC-Jb)o}i3d@+HmcdI&gNd1*=Oada zWG}4e9jx9sO5>3tLTUTxK4Jq$(O`DGcm&RP*hu@@kDNZaE4qT5jO!Q>>hqrIv4Vz; zlo8Zonj4AO6x=m{{IxN~B*UU4L-P**>+nRhO__vW zDSDgz6Fni?RQtf-TZw4`GKhnND%|a+)8KKmshZl_{(=>Q)gzs`n8Sm zp>K&bpHZfD55lXH7=Ag-7*@Y4nT?D;^^n@zSm?roq(6n$rofSx#B0#kvi669u*|3s z6IwK@OUXI_9WlYkdd8;>db~0x$vM^$&*Ur)i8+3x+ULxWC$x$;8o5Dana!$(u#Ipt2z5$7R@+D@d!hN-rSIyhD zRnkbQQ)Sp-;>N~bD0<5`)*ogvoHKfFg{k*DcT=x9{uT|M_G-~vEohDFWmtvkG~T5TCV-)T=VtqKo$`qKg#!Cfqgstn70wGR8Y`KG zq*jn{S0874q-U&)kA=Kr@$B3ow{XNSDs49<@fQJ!uFbEp`NR#I9>CiYE_}>#18DHteFErP6a#A$ap~WD zVjSl1uD1|V4-F+|xqFRt*yqeB)|^7Y(jkiviYAI2^}##FAd2>(^V%{>UJ;T2DF${B zdM*7>$%lPCNgcY&XQUiO+|9Z^^*U5^S8k?aKMLwkZl)>qR#X;9rgOdf9=fiG5Xz+n<4pM!h$TRq-k)PH0E%#_l=Mbu{E|P$EzFO#c&dSh6t6H#4rgd)5&UqW(bWvs4P9 zlJ^GEO&kB!s%LL-%{x- z%RjxeHaqWc;&cEgb2MP955DtYZkLgO0uHLa^r2jkhb7!xc@=u9{ZRr)>zlxX(@#Tn!SMO{tEJ)I${ct;f546?8{w}sTa=2~M*s6S`W7+h(b-cR zcLS9`kEPNoFJ}Z1Yc2vL?2EtjH&1ZSW*ngC#tw(-%J_>)?5 z*6~4cj}YaNY7QVFNF?{j@_5}xt1tLlDkR6$s4so6thQP@0+s9V69$#DbP8}?X90U> ziiJjTb$tCWml{#*bp6HbsB~;&NdN}~IwWz(XUkN-ZzXOE$1p7X;2{DUFFr7BMVXWN zV!xC5!b6ezCapu25Gq}gNwKLVx!|QRl%yD?7A+Z-7Xc`u*b;|DYCTl5iRn?)CB2$j z)#lHK5G3s}gcJElpCsGmc^D8t{xR4S4-vy#(%Wksw@wKt)FiY>Gj+LjTBLHR?pxZf zl6jPm-*v$f&Bs6T&jrU=O#RZ%k^e1UOe?7WZ7SEOlg=c+e%7%6x3uV9{}*@N#upFx z7s&5|`S11i3dJ4bJ`qLU-;*ogL`((c1~yv~Wb+66a-o0jN65qU!>$zQ9&Y|VJ?K(g zegrxtdHiD}^l${$a7U_fpfw$NJH0>zO|X(WxM__v(^wbe(G{G+9)e**2bA(=)~>U* zQk*tu*ZcqO0qpld@P}|9Am8Z!znO*y@IPu)=(k3b)`(S??Pg4%8aIL-#$zC^AR3yW zphL!Vwp?Kb+*l*M2;pFh!>>R%!rm~H85L0xgv0Fn6K;Ue-Pi3Kqyd;SXdEKq$rN`B zSrD$2koySyy4?W$JcqK@F|}+b2YiI9aApzN_Jzbb1U{^t4SVyIoVJxTJUbw&Q^PEm zny0L(3%&Vw2HRBLtDCwthK;z_IYgoe^)F`X2#w2xdLNAQsivu>5=^C;F2Vq$GMyq_ z)Y*c0(z@i#(YWZJY_Bb1X4u%@9QAFBUbozYXqYs{3I=ytPerw+D6i(#*06WXp=;OH zACxg`wO;e)DrcBq9kh+b^SS`xQj_ZF^mMLQ*S6894Q95^Qk0ZyI9l3owim<|1_-H% zM`AJp=HS`NJEd#;Hs9x1%u z!SSUfICAworX`QzNz_?!Y2T=MivKQR72ruyR{v~DC;y)Rqnl>=b!eEiBiUHDJ6|tBw7_k! ziTX=-IS$#NthHJ>mg;)h?s}QKwQRDr+|_>dDFOWUNsP9cDB5_rU1-~R&bjtE;XVNn z26u9Ti*Y%g?s6!OTwQ#@YEcZ?o;0!*58<( zYK2w=S%UwK*cG%`G{MkVri=c=8~szs?!vnQu}snudQ09lfdiAl@t zA}+}tAB!HB*Si>0S8=MK;jITvswu(NhTPXOL-x(owxYgYF_}n zV#cR5=ZmW#i^>8?|kob6eY)YV;_H6>JZqvS{x(A~sx?tcC;X zwZ{SLp_0c6H5oaN6$I(=b$8Bc;>>IZVzinur&d!-v(!{thWpg!$5=OGPp?>vv9Q+4 z%*DfG|8Z)jPq7);3AQ+<*te1Y$1<* zjZp*!THn0HloFpZ*2eac66kVZIF|)zNjq$W>}VEm1C4P{QLhL@6(?-^YgY8p#^U$i z>Kpij2?8A+ojtZSqWv!62vO9DAWp{$;oIaK0o}H2(R0=t1dEF!PeS#A^6v5I%eFt~ z6#+4^Fvsg=>x1+6i8wrxjBE}cW!Wy-mNQu-60s}zZD*{hf7smiy15pdk`bLfIupO% z#+xE6rQwr1+faYJ_d$6lW;NTuBjdG7)whb3?51yfoahxXm~`qMhyM~}4(ttTL)WVM zxyruG@%JKZo!I~)T zPr!{YhIxMtT{msWs^aa}TiuPHNX765+-Y>biy-p_{aYCp5^pk8mS1ObcAlXY=*7d& zHn*BxY^8#MhbjpTY5p;uxA@-m$uhuiS}VjASpU;H1X7c0n`wImrZAw)FVf7-#8#tmVE$`8gj3I}3y#Q)i>Dznu3L*}$oA`fW< zz%0Wr&R<)g`-T=+XTWPm+zhxb)AY7G4#4h$c5~sgiA{M+o50acxIkj1l|O@4HWA}) z*q}ay7tcWCl9^Aw>0uStLzj-P0sZR%a?ylu>^?mzOilEqX^Frmyn-~F>NrfpFo}=| zgngKJpy~gr9Nlzo+=gcx33@o6#VV*rgdme)ke2X?)e}6O-uNSRg9mVO@sv0%{zFG~ z%sw~M_ErZ=moVhA@{IPOaMyBrkJBa9Lq|~9SL}8kA()|+rB$3|KPZ!=U zgy<`+nvKFkPwh#;hzUNFx`iLyWum!05nInYXEKODqZ%uP0eJRGD{ z!cO&Rj$~g?XUmN9mcziezY&HEvYZ6r7XYv-UqN4$?RZzUuz_^T0ra0VnDkfMNCCRV9m2p~Qk6^XjxL8s() zw{~z&yao&&ycg**EhA=@EY4WRA$ZFg2cmza);qiGRV5F|98egldECdDgEpZbdEamP zRF*`gqp0v&qXAiLcKb&xEyaO8xI~eM3{8X7yg~5_=9fKfkdic>DZ|KmF=+lLlC@Wv z8M&YpKTzzc(snNBXr6QAv4}(LPq+tBJi6IH^D=}GY^MxY9K6Jcm?r52AW~QQUzxL1 z7Jk`Pljd^@1$7eq(HYYBd(bm%+MhY9I~4DatGR`E z%I0t%KwXGMAVOZCnKKG=#lkKaON*OpO&h`Bm)Zb=Z2Z6YAQw}#+po&hom^Ql_Qi|4 zs^{?3#UG4O<~-nE@9eb0S!8atgCiq5C)Ztm1pVcPj7vUM zW)%U3D;sHf86~G~X&Q+gLx?ZcEtbe2^1QTUt);SFe%O?Q>86Kc0;fqtwEzK)R8j~s zv%V3;wlavFLawOn-RM11SqtTo?eFVyJ8FQxfT@4oYTFk($yW$y<>x$>5zu^Yc$_CE z5xBKvkoydC+Ue8Ei{F~CB~U(>K`~voR9*mwUFu88QVu>zZ;I1_T~N>u%*r*$le(B8 zUxv8^h*Q^PBR^ZNoJjT(3ZNmScdikP>sL-hrHc%j5BR~ze0iFs|x#>Cxam zQ?8<3Mxe_jh^#Agt(0cpTFm+=^`f|(FsTTa1p5B9nc_gB|fCwl7=EwzWgM(7k%s zL0x)7?p=*LrY=uLLs0E(H6JP9uMmz4TsvKrsI600w>CWWUZ{B7qG|LBz0ZLCHi+3z zR|h?x`ky+i(x$lfbmAk<>Od*3E=((os0YiwE!Vy+PM;4PFy=hzYt%7D-v)^uCQ*Hb z-q(FkE#kDdEs}qEz#%BUk)#fs=zmRV^e{{8#(|NUCqxHYZ+$_2(*k^xQ&m15*9T+l z$rns1x?;ak*|#~7MkH(X?Ewt)`g)0Z=iv(Qx9gR(jWToSXsV4NTIexzYN9O*a-!}F z1ft4~`g1`pGIPc*c*|t-mKt-44d`^U-e@WMd*1xMB6ErQtS?}zgJ+2{hy)vRHOM=fp1z=pUgt-vs=ZN7sNs#C(+^0D$T*c^vy!meJ=m zFy)*hYB!I|#C}X|M=-by6%!;svF*jlo2OdHlSt7-A1GqbF4z#3#PAUl5FlGIV6fU>jRI{J_=p@(I1Xg9d{B#PIlOZ#OAfj<95 z?(ylPsU4|R4i-BFN31VDExfVKoi3|az|Je6@W3AyQaAoU@Y0J38GnIz3&w#5+HwE!-_@3%uiU)s-_VYA-2Z6{776qK>;J&zp*zT@LR3O+ zFc@en+S(dwy@)9|s0)L^MT*AoV%@SWVVC`S<9dw4qlkOzWpkM?eT2Jl%((@k66>K` z7Z+C<&z#p8*%|x*z$auKjPmZo;h`)rNiS{r*DJiQcFWTv+ZJqR>cRLbjL!fZ&fsml zP9pNHiLzMe5-H%EQL0m7XFJVK#M*1(H_sX~UP{oJJOTTeb``wz$%o&5J6?F^{Hg-V zj+@V)*<0IK0%fdv%n|8x?Q^n1!I8HUMd$z*ItigDJq~&pTF3(1^#Yq#6F+FvO3{LU ze)%jR_yJI5s5_0!ng`o^)ldH_4PhyRC*rqkn4Vwf^p*fDbSzFOyhw<_T!FLl1MXXv zfV~erLv;g6{naU=pmR%$^hu(aTc&8D2^Kp8xXGhROi$~2Epbi9G^;Y-XrnvUNhVa% z3zikZ>|UR#w{)sRJvC38 zjl#mFN{_*`Q3e43pO&@8aEoScAATyZ)aZ= zG}S=WE2|Lqf?ksp_N|G*O63=|z17`ZDvTTRH(a}#X2*A()<9`)UBd#JNw?qw{Jk#sAqG4&jT5FJ z`#K53=Z;nC&{s$^uGQfF)YOg9=Rjd|1H(G~nwTcNXv80dM2Fc7-6io9_R8k7ra#e5C(mCaeEg zdOsMG_WUrAls%nYOl=jM>>W&vKf&0*>uIHIaJE?WIn}yi@iu-}N?5nh1f|+Jk zJvsUMS#HY!e36e1aoeOAQT3 z>qp+iB(-tasl(~ldfbrZXVX21Ww+p@SzHKZZ@<8T?Gm3d18x} z5XN}irvR(HbR0qe-3RAYqJ~vC<4=CTp>^l3LyMk91rM59zG1jwBYj|y+Ru}PdtTcO znlb~Hj7wwgx}1KzXI!{WwgHC^q%uKstahsow;QGb0WN2TSdLg=_#S+yM~^)GK#|q^ z#!&p(Cx;kg#Q}#LWA>_ZS6W(V64!7_>8+nUS<4c_cmP^w`5tSrE90vkiaih@v1=O| zesD`YP|jP-_nv#j%~9D;iVaCOaxaQUr78q^Lba!Q+e!#XqhRu z-n*C#AHxAy@$)ZJBo7rb$BTTx)o-bGQJuL0!^~gD*G@*vk(KYOf2(T($gAFeqy_XC zK{fIk0|)q)RQQL?x%m2ALsvfCh5#x38tpD72zkb8mODjy+>MyyObLZ(BY09$H)J{I zR-mZBfg^&o08iSodfLQa@RuDJSC^b9PdPel{9>~&d2PYGlIt+T{g2lKE3 z-(p?+4LQ~7eO|3vO)B0D9eZf@@>7X@6YI3&F`W7*Ej0aaX=!hl?pkAr9fhRD{SFa} z1OD}T1~}>?Zl78m9tA`kkEd`6-_e}Vhh^iBvt zgA|X2dn8hTP_CS>UL;9?|C9|TlXG_vyKuCv5#w`bl;eWV>8=VUj5Cvc`WnJ?FbC$o zQ24_?zUk(8cQ4w2vdqGW_|Idb@QeiOUv@lOZxi{~dm7;klR$}ZZGQXD3~u}})OL|T zq@xsb?Vh9D8Ghm9Iyi=oR%^F%0wTMw03kC$Yfi3uq1KN5_m zNC6*e3=D{mx9#X6(7Dd+u$E-K6a4tuJv%r&i0KEypX}J|URum+lk{&C&bPgryV>)~ zH6i~G1A=B4pZ4}~Grn+7tyTjoMIB@~GDk65iLev0B%rkv=6L3R5I89!|d(v#8eK3VGNzOWdq#DN4=_^sD zmow~kwK(!JWM|A0Mb$9*-~5qoP8u`y3}#G2ki)IolM`LER5Z?%N|&e?l&@(!s>{hV zD}YnH-hIME9&+cb#R{rY_=hu^eGftmKME*uOXyFmb;OD4c2vqIW$*!J&uR%)G4^`_ zFu~8?rsEktBbV*$i?pa%b~)oIz>j^U8ns`$z6|QsGMj%Jf9TvQEii14qn9knfSSbh zO5{*GC1l!^lFb#=7(4_ETxV8|A9DpMjKsdNzOAtpN!{?_?0@y(55TH1PZbA_(nxT>xT;b+}Ce3I@sI zUXwzP)}hDUO-1N5IZOmbU@K5nBB$D9l=qW7YF# zI^aiQnk7;id~R+SxwPJE_2;?uT+Nq(~3wcL))rBex({`wil3R=Qnp zBWhki5k6wU5!{0nX}92E6n<_?h&91P`PF4=#BQj;<` zSS;b7uV5qJrH0TU6jc<`)u``+PHut#$s_M(iR6~bh$n}K)85y9?ypzg&s~78u18FN z_|_>#w>KC2`>|esG{Su=;yOAcc}Ssv*3{|INR#nQ964(kxqB}4R)C3v7G83+gHQZO zShUSLw2ib>WS?+=40U!Yv!UkdE|@ku8RYN8n(gcniocOUsKfbadJHOy$yH7@6IPLC zVQqHt44L+J>#K`+ayNUuRP0zm6cwhA96Ka5*}w9E#l(SVOsl6f}1i6bb+q(a^WAhH$FT{kcGk zTGvQ`I&AoUn8!an#X2nn6gccmEa=DAjwRG&Ybp~HXEvW`5luw*5A(wFyF{qzgUd%9 z%{gQv40YFt(E#GvQIbbyhXVH8Luh?mh?#Y{h5>!jw9Jc(X;x9~wu9t~Aydf)eW=%sxj`RWp3^a#wVP<@3^z*b zI$od^G|EZmi!(!Qt+KKFsNWqTpa`Ha^KxF^z^{}~*Z~+-&Iwu$9MjF&tj8dPnl8x5 zS9{GJtzMh0ddVk0O!bfP^+__cF`NCrw$42qsx*${XT@4k<2Ix@VTPHpm~k(KLXXkn5 zpYwjs@ArG(_dI9L`#xvB->B=OG9Q2oSxS*4=X)HBAq)GaWWsC6#Pz`e*S!g*Ol24A zXJcu~<6GV?mdtJ>XP(r^ZL<)_NV^ev_&3z>v!RRqiQDg8FK1{xh&J%pq`bq}?odKw zE<3a}y(e`(h6^tbvP$c8O_TmMEZ6LnCemCTNtdFXZ})e8s^Z`y60YFuH1$$3N`1N5 zm!VLOJE%IVROGK?bHvN+=e&_Z)-gu&op#^MiXN}9#oW1}-TmT;`uTQ?LC@Y1Me1#b zVA-xv4b?GPHd9Yy%nl>$cKFoe>`7lpzN}jrdZ0IvM9p_&UCg6jspEym_f^-^`D`6_ zbF)0PCHT>B@uyQnV(+q6?e+OK7rAn2y-w%IOSOLW!Va5e;jgl!==ISp#e7G~ zupm6Xd#u*#7@1~r*Z|j0q^r=DlVYgl^#cD)Meoiux#`p*+)OSKvWI zEoD5=eCs=hhJH!)`hBAey!|B{TR&{hOb{4X zI@)$n<#Bu?<9%>=-NT1Yg%|g+Ih<0?$>tJ9jQNe2!H@dfr#IaP+KglwviE%rDXBi@ zv1pFnjdO+gAy0fk?mjhqe1Uci`+=S+{Yuvo)NWDedm*bRm5pK=M(?z&i4&*EF+f zt((M{b-f9y`teb!!h#tIeorj88Uh)<*rNl6H5FRz^WvoPvb@?qZou7F`7_8l{~IJNAX-Z{F`+RerhA3Kzk^?*cJ@F z(xmAJx7WkE@+PQuj1m&4S&6U`2oza?O9Ox<3KU>hL1`%Nsww!rZ>kjvj8qeW(^t(v zvFGL5h@F}uP>!IDq(|%m;X0jRQ9N|iWGw{lE3uUNW>kkM#Y)^KAqO|=kdd>+E@f+b zIi|A;Zh)Fgi6CN!1&?VToXQwgytkgHrfU7oD^aBo10%@23@Z^r5jCciZ3D&rA8QAF zpW!O_V?~d1(h&iXbUt{sR@4n?hHER zzp*gn2#R+g0YDQKr8W)*K5CeA< diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties index 09523c0e549..bad7c2462f5 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew old mode 100644 new mode 100755 index f5feea6d6b1..adff685a034 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -206,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat index 9d21a21834d..c4bdd3ab8e3 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts index a5d0428ce6f..a9e579940ea 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts @@ -1 +1,15 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + } +} + rootProject.name = "vertx-web-kotlin-dsljson-benchmark" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt index ee66a635231..21b08c43611 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt @@ -1,50 +1,80 @@ package com.example.starter -import com.example.starter.utils.PeriodicDateResolver +import com.example.starter.helpers.PeriodicResolver +import com.example.starter.helpers.Properties import com.example.starter.utils.block import io.vertx.core.Vertx import io.vertx.kotlin.core.deploymentOptionsOf import io.vertx.kotlin.core.vertxOptionsOf +import io.vertx.kotlin.coroutines.coAwait +import io.vertx.kotlin.micrometer.micrometerMetricsOptionsOf +import io.vertx.kotlin.micrometer.vertxPrometheusOptionsOf import kotlin.time.Duration.Companion.seconds -import org.apache.logging.log4j.kotlin.Logging +import kotlinx.coroutines.runBlocking +import org.apache.logging.log4j.kotlin.logger -object App : Logging { - private const val SERVER_NAME = "Vert.x-Web Benchmark" +private val LOGGER = logger("App") - @JvmStatic - fun main(args: Array?) { - val eventLoopPoolSize = System.getProperty("vertx.eventLoopPoolSize")?.toInt() - ?: Runtime.getRuntime().availableProcessors() +fun main(): Unit = runBlocking { + val vertx = Vertx.vertx( + vertxOptionsOf( + eventLoopPoolSize = Properties.EVENT_LOOP_POOL_SIZE, + preferNativeTransport = true, + disableTCCL = true, + blockedThreadCheckInterval = 60_000, + metricsOptions = if (Properties.METRICS_ENABLED) { + micrometerMetricsOptionsOf( + enabled = true, + jvmMetricsEnabled = true, + nettyMetricsEnabled = true, + prometheusOptions = vertxPrometheusOptionsOf( + enabled = true, + ), + ) + } else null + ) + ) - val vertx = Vertx.vertx( - vertxOptionsOf( - eventLoopPoolSize = eventLoopPoolSize, - preferNativeTransport = true, - ) + if (!vertx.isNativeTransportEnabled) { + throw IllegalStateException( + "Native transport not enabled; missing required dependencies", + vertx.unavailableNativeTransportCause(), ) - vertx.exceptionHandler { - logger.error(it) { "Vertx unexpected exception:" } - vertx.close().block(5.seconds) - } + } + + vertx.exceptionHandler { + LOGGER.error("Vertx unexpected exception", it) + } - // Add the SIGINT handler - Runtime.getRuntime().addShutdownHook(Thread { + Runtime.getRuntime().addShutdownHook( + Thread { vertx.close().block(5.seconds) - }) + } + ) - // Initialize the periodic date resolver - PeriodicDateResolver.init(vertx) + PeriodicResolver.init(vertx) - // Check the type of test that is being run - val hasDb = System.getProperty("tfb.hasDB")?.toBoolean() ?: false + val options = deploymentOptionsOf( + instances = Properties.EVENT_LOOP_POOL_SIZE, + ) - vertx.deployVerticle( - { if (hasDb) PostgresVerticle() else BasicVerticle() }, - deploymentOptionsOf( - instances = eventLoopPoolSize, - ) + val deployment = when (Properties.TYPE) { + "basic" -> vertx.deployVerticle( + BasicVerticle::class.java, + options ) - - logger.info("$SERVER_NAME started.") + "postgres" -> vertx.deployVerticle( + PostgresVerticle::class.java, + options + ) + "all" -> vertx.deployVerticle( + ServerVerticle::class.java, + options + ) + else -> throw IllegalStateException("Unknown deployment type: ${Properties.TYPE}") } -} \ No newline at end of file + + deployment.coAwait() + + LOGGER.info("${Properties.SERVER_NAME} started.") +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt index 7870a146c78..0a20956558e 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt @@ -2,55 +2,45 @@ package com.example.starter import com.example.starter.handlers.DefaultHandler import com.example.starter.handlers.MessageHandler -import com.example.starter.io.JsonResource +import com.example.starter.helpers.Properties import com.example.starter.utils.isConnectionReset -import io.vertx.core.AbstractVerticle -import io.vertx.core.Promise -import io.vertx.core.http.HttpServerOptions -import io.vertx.ext.web.Router +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.coAwait import org.apache.logging.log4j.kotlin.Logging -class BasicVerticle : AbstractVerticle() { - override fun start(startPromise: Promise) { +class BasicVerticle : CoroutineVerticle() { + override suspend fun start() { val defaultHandler = DefaultHandler() val messageHandler = MessageHandler() - val router = Router.router(vertx) - - router - .get("/plaintext") - .handler(defaultHandler::plaintext) - - router - .get("/json") - .handler(messageHandler::readDefaultMessage) - val server = vertx - .createHttpServer(HTTP_SERVER_OPTIONS) - .requestHandler(router) + .createHttpServer(Properties.HTTP) + .requestHandler { + val path = it.path() + val code = when (path.length) { + 10 -> if (path == PLAINTEXT_PATH) 1 else 0 + 5 -> if (path == JSON_PATH) 2 else 0 + else -> 0 + } + when (code) { + 1 -> defaultHandler.plaintext(it) + 2 -> messageHandler.readDefaultMessage(it) + else -> it.response().setStatusCode(404).end() + } + } .exceptionHandler { - if (it.isConnectionReset()) return@exceptionHandler - logger.error(it) { "Exception in HttpServer" } + if (!it.isConnectionReset()) { + logger.error("Exception in HttpServer", it) + } } - - server .listen() - .onSuccess { - logger.info { "HTTP server started on port 8080" } - startPromise.complete() - } - .onFailure { - logger.error(it.cause) { "Failed to start" } - startPromise.fail(it.cause) - } + .coAwait() + + logger.info("HTTP server started on port ${server.actualPort()}") } companion object : Logging { - private const val HTTP_SERVER_OPTIONS_RESOURCE = "http-server-options.json" - - private val HTTP_SERVER_OPTIONS: HttpServerOptions by lazy { - val json = JsonResource.of(HTTP_SERVER_OPTIONS_RESOURCE) - HttpServerOptions(json) - } + private const val PLAINTEXT_PATH = "/plaintext" + private const val JSON_PATH = "/json" } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt index 4caa057b488..5d31eb03bc4 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt @@ -4,78 +4,60 @@ import com.example.starter.db.FortuneRepository import com.example.starter.db.WorldRepository import com.example.starter.handlers.FortuneHandler import com.example.starter.handlers.WorldHandler -import com.example.starter.io.JsonResource +import com.example.starter.helpers.Properties import com.example.starter.utils.isConnectionReset -import io.vertx.core.AbstractVerticle -import io.vertx.core.Promise -import io.vertx.core.http.HttpServerOptions -import io.vertx.ext.web.Router -import io.vertx.pgclient.PgConnectOptions +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.coAwait import io.vertx.pgclient.PgConnection import org.apache.logging.log4j.kotlin.Logging -class PostgresVerticle : AbstractVerticle() { - override fun start(startPromise: Promise) { - PgConnection.connect(vertx, PG_CONNECT_OPTIONS) - .onSuccess { conn -> - val fortuneHandler = FortuneHandler(FortuneRepository(conn)) - val worldHandler = WorldHandler(WorldRepository(conn)) - - val router = Router.router(vertx) - - router - .get("/fortunes") - .handler(fortuneHandler::templateFortunes) - - router - .get("/db") - .handler(worldHandler::readRandomWorld) - - router - .get("/queries") - .handler(worldHandler::readRandomWorlds) - - router - .get("/updates") - .handler(worldHandler::updateRandomWorlds) - - val server = vertx - .createHttpServer(HTTP_SERVER_OPTIONS) - .requestHandler(router) - .exceptionHandler { - if (it.isConnectionReset()) return@exceptionHandler - logger.error(it) { "Exception in HttpServer" } - } - - server - .listen() - .onSuccess { - logger.info { "HTTP server started on port 8080" } - startPromise.complete() - } - .onFailure { - logger.error(it) { "Failed to start" } - startPromise.fail(it) +class PostgresVerticle : CoroutineVerticle() { + override suspend fun start() { + val conn = PgConnection.connect(vertx, Properties.PG_CONNECT).coAwait() + + val fortuneRepository = FortuneRepository.init(conn) + val worldRepository = WorldRepository.init(conn) + + val fortuneHandler = FortuneHandler(fortuneRepository.coAwait()) + val worldHandler = WorldHandler(worldRepository.coAwait()) + + val server = vertx + .createHttpServer(Properties.HTTP) + .requestHandler { + val path = it.path() + val code = when (path.length) { + 9 -> if (path == FORTUNES_PATH) 1 else 0 + 3 -> if (path == DB_PATH) 2 else 0 + 8 -> when (path) { + QUERIES_PATH -> 3 + UPDATES_PATH -> 4 + else -> 0 } + else -> 0 + } + when (code) { + 1 -> fortuneHandler.templateFortunes(it) + 2 -> worldHandler.readRandomWorld(it) + 3 -> worldHandler.readRandomWorlds(it) + 4 -> worldHandler.updateRandomWorlds(it) + else -> it.response().setStatusCode(404).end() + } } - .onFailure { - logger.error(it) { "Failed to start" } - startPromise.fail(it) + .exceptionHandler { + if (!it.isConnectionReset()) { + logger.error("Exception in HttpServer", it) + } } + .listen() + .coAwait() + + logger.info("HTTP server started on port ${server.actualPort()}") } companion object : Logging { - private const val HTTP_SERVER_OPTIONS_RESOURCE = "http-server-options.json" - private const val PG_CONNECT_OPTIONS_RESOURCE = "pg-connect-options.json" - - private val HTTP_SERVER_OPTIONS: HttpServerOptions by lazy { - val json = JsonResource.of(HTTP_SERVER_OPTIONS_RESOURCE) - HttpServerOptions(json) - } - - private val PG_CONNECT_OPTIONS: PgConnectOptions by lazy { - val json = JsonResource.of(PG_CONNECT_OPTIONS_RESOURCE) - PgConnectOptions(json) - } + private const val FORTUNES_PATH = "/fortunes" + private const val DB_PATH = "/db" + private const val QUERIES_PATH = "/queries" + private const val UPDATES_PATH = "/updates" } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt new file mode 100644 index 00000000000..c86ea244774 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt @@ -0,0 +1,91 @@ +package com.example.starter + +import com.example.starter.db.FortuneRepository +import com.example.starter.db.WorldRepository +import com.example.starter.handlers.DefaultHandler +import com.example.starter.handlers.FortuneHandler +import com.example.starter.handlers.MessageHandler +import com.example.starter.handlers.WorldHandler +import com.example.starter.helpers.Properties +import com.example.starter.utils.isConnectionReset +import io.micrometer.prometheusmetrics.PrometheusMeterRegistry +import io.vertx.core.Handler +import io.vertx.core.http.HttpHeaders.CONTENT_TYPE +import io.vertx.core.http.HttpServerRequest +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.coAwait +import io.vertx.micrometer.backends.BackendRegistries +import io.vertx.pgclient.PgConnection +import org.apache.logging.log4j.kotlin.Logging + +class ServerVerticle() : CoroutineVerticle() { + override suspend fun start() { + val conn = PgConnection.connect(vertx, Properties.PG_CONNECT).coAwait() + + val fortuneRepository = FortuneRepository.init(conn) + val worldRepository = WorldRepository.init(conn) + + val fortuneHandler = FortuneHandler(fortuneRepository.coAwait()) + val worldHandler = WorldHandler(worldRepository.coAwait()) + + val defaultHandler = DefaultHandler() + val messageHandler = MessageHandler() + + val metricsHandler = if (Properties.METRICS_ENABLED) { + val registry = BackendRegistries.getDefaultNow() as PrometheusMeterRegistry + Handler { + it.response() + .putHeader(CONTENT_TYPE, "text/plain; version=0.0.4; charset=utf-8") + .end(registry.scrape()) + } + } else null + + val server = vertx + .createHttpServer(Properties.HTTP) + .requestHandler { + val path = it.path() + val code = when (path.length) { + 10 -> if (path == PLAINTEXT_PATH) 1 else 0 + 5 -> if (path == JSON_PATH) 2 else 0 + 9 -> if (path == FORTUNES_PATH) 3 else 0 + 3 -> if (path == DB_PATH) 4 else 0 + 8 -> when (path) { + QUERIES_PATH -> 5 + UPDATES_PATH -> 6 + METRICS_PATH -> 7 + else -> 0 + } + else -> 0 + } + when (code) { + 1 -> defaultHandler.plaintext(it) + 2 -> messageHandler.readDefaultMessage(it) + 3 -> fortuneHandler.templateFortunes(it) + 4 -> worldHandler.readRandomWorld(it) + 5 -> worldHandler.readRandomWorlds(it) + 6 -> worldHandler.updateRandomWorlds(it) + 7 -> metricsHandler?.handle(it) ?: it.response().setStatusCode(404).end() + else -> it.response().setStatusCode(404).end() + } + } + .exceptionHandler { + if (!it.isConnectionReset()) { + logger.error("Exception in HttpServer", it) + } + } + .listen() + .coAwait() + + logger.info("HTTP server started on port ${server.actualPort()}") + } + + companion object : Logging { + private const val METRICS_PATH = "/metrics" + private const val PLAINTEXT_PATH = "/plaintext" + private const val JSON_PATH = "/json" + private const val FORTUNES_PATH = "/fortunes" + private const val DB_PATH = "/db" + private const val QUERIES_PATH = "/queries" + private const val UPDATES_PATH = "/updates" + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt index b9e4b9ab784..a3c0831f3aa 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt @@ -5,19 +5,35 @@ import com.example.starter.utils.mapToArray import io.vertx.core.Future import io.vertx.pgclient.PgConnection +import io.vertx.sqlclient.PreparedQuery import io.vertx.sqlclient.Row +import io.vertx.sqlclient.RowSet -class FortuneRepository(conn: PgConnection) : AbstractRepository(conn) { - private val selectFortuneQuery = this.conn.preparedQuery(SELECT_FORTUNE_SQL) +@Suppress("NOTHING_TO_INLINE") +class FortuneRepository( + conn: PgConnection, + private val selectFortunesQuery: PreparedQuery>, +) : AbstractRepository(conn) { - fun selectFortunes(): Future> = selectFortuneQuery + fun selectFortunes(): Future> = selectFortunesQuery .execute() .map { it.mapToArray(FortuneRepository::map) } companion object { - private const val SELECT_FORTUNE_SQL = "SELECT id, message FROM fortune" + private const val SELECT_FORTUNES_SQL = "SELECT id, message FROM fortune" - @Suppress("NOTHING_TO_INLINE") - private inline fun map(row: Row): Fortune = Fortune(row.getInteger(0), row.getString(1)) + private inline fun map(row: Row): Fortune = Fortune( + row.getInteger(0), + row.getString(1), + ) + + fun init(conn: PgConnection): Future = conn.let { conn -> + conn.prepare(SELECT_FORTUNES_SQL).map { ps -> + FortuneRepository( + conn, + ps.query(), + ) + } + } } } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt index 74823141453..e12717e7228 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt @@ -3,38 +3,48 @@ package com.example.starter.db import com.example.starter.models.World import io.vertx.core.Future import io.vertx.core.Promise +import io.vertx.core.impl.future.CompositeFutureImpl import io.vertx.pgclient.PgConnection import io.vertx.sqlclient.PreparedQuery import io.vertx.sqlclient.Row import io.vertx.sqlclient.RowSet import io.vertx.sqlclient.Tuple -import io.vertx.sqlclient.impl.ArrayTuple import io.vertx.sqlclient.impl.SqlClientInternal +import io.vertx.sqlclient.internal.ArrayTuple import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.atomic.AtomicInteger @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") -class WorldRepository(conn: PgConnection) : AbstractRepository(conn) { - private val selectWorldQuery = this.conn.preparedQuery(SELECT_WORLD_SQL) - private val updateWorldQueries = generateQueries(this.conn) - +class WorldRepository private constructor( + conn: PgConnection, + private val selectWorldQuery: PreparedQuery>, + private val updateWorldQueries: Array>>, +) : AbstractRepository(conn) { fun selectRandomWorld(): Future = selectWorldQuery .execute(Tuple.of(randomWorld())) - .map { map(it.iterator().next()) } + .map { map(it.first()) } fun selectRandomWorlds(numWorlds: Int): Future> { val promise = Promise.promise>() val arr = arrayOfNulls(numWorlds) val count = AtomicInteger(0) (this.conn as SqlClientInternal).group { c -> - repeat(numWorlds) { - c.preparedQuery(SELECT_WORLD_SQL).execute(Tuple.of(randomWorld())) { ar -> - val index = count.getAndIncrement() - arr[index] = map(ar.result().iterator().next()) - if (index == numWorlds - 1) { - promise.complete(arr as Array) + val query = c.preparedQuery(SELECT_WORLD_SQL) + repeat(numWorlds) { _ -> + query.execute(Tuple.of(randomWorld())) + .onComplete { ar -> + when { + ar.succeeded() -> { + val result = ar.result() + val index = count.getAndIncrement() + arr[index] = map(result.iterator().next()) + if (index == numWorlds - 1) { + promise.complete(arr as Array) + } + } + else -> promise.fail(ar.cause()) + } } - } } } return promise.future() @@ -57,28 +67,49 @@ class WorldRepository(conn: PgConnection) : AbstractRepository(conn) { companion object { private const val SELECT_WORLD_SQL = "SELECT id, randomnumber FROM world WHERE id = $1" - private inline fun randomWorld(): Int = 1 + ThreadLocalRandom.current().nextInt(10000) - private inline fun map(row: Row): World = World(row.getInteger(0), row.getInteger(1)) + private inline fun randomWorld(): Int = 1 + ThreadLocalRandom.current().nextInt(10_000) + private inline fun map(row: Row): World = World( + row.getInteger(0), + row.getInteger(1), + ) - private fun generateQueries(conn: PgConnection): Array>> { - val arr = arrayOfNulls>>(500) - for (num in 1..500) { - var paramIndex = 1 - val sb = StringBuilder() - sb.append("UPDATE world SET randomnumber = CASE id ") - for (i in 1..num) { - sb.append("WHEN \$$paramIndex THEN \$${paramIndex + 1} ") - paramIndex += 2 - } - sb.append("ELSE randomnumber END WHERE id IN (") - for (i in 1..num) { - sb.append("\$$paramIndex,") - paramIndex += 1 + fun init(conn: PgConnection): Future = conn.let { conn -> + val selectWorldQuery = conn.prepare(SELECT_WORLD_SQL).map { ps -> ps.query() } + val updateWorldQueries = run { + val queries = arrayOfNulls>>(500) + Array(500) { num -> + val count = num + 1 + var paramIndex = 1 + val sb = StringBuilder() + sb.append("UPDATE world SET randomnumber = CASE id ") + repeat(count) { + sb.append("WHEN $${paramIndex++} THEN $${paramIndex++} ") + } + sb.append("ELSE randomnumber END WHERE id IN (") + repeat(count) { + sb.append("$${paramIndex++},") + } + sb[sb.length - 1] = ')' + + conn + .prepare(sb.toString()) + .map { ps -> + queries[num] = ps.query() + } + }.let { + CompositeFutureImpl.all(*it).map { + queries as Array>> + } } - sb[sb.length - 1] = ')' - arr[num - 1] = conn.preparedQuery(sb.toString()) } - return arr as Array>> + + CompositeFutureImpl.all(selectWorldQuery, updateWorldQueries).map { + WorldRepository( + conn, + selectWorldQuery.result(), + updateWorldQueries.result(), + ) + } } } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt index cb29d630167..d34e72b5598 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt @@ -1,57 +1,52 @@ package com.example.starter.handlers -import com.example.starter.utils.PeriodicDateResolver -import io.vertx.core.AsyncResult -import io.vertx.core.Handler +import com.example.starter.helpers.PeriodicResolver +import com.example.starter.helpers.Properties +import io.netty.handler.codec.http.HttpHeaderNames +import io.netty.handler.codec.http.HttpHeaderValues +import io.vertx.core.Future import io.vertx.core.MultiMap +import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpHeaders +import io.vertx.core.http.HttpServerRequest import io.vertx.core.http.HttpServerResponse -import io.vertx.ext.web.RoutingContext +import io.vertx.core.internal.buffer.BufferInternal @Suppress("NOTHING_TO_INLINE") abstract class AbstractHandler { protected companion object { - val NULL_HANDLER: Handler>? = null - - const val SOMETHING_WENT_WRONG = "Something went wrong" + val SOMETHING_WENT_WRONG: Buffer = BufferInternal.buffer("Something went wrong") // Headers - val SERVER: CharSequence = HttpHeaders.createOptimized("Vert.x-Web") - val APPLICATION_JSON: CharSequence = HttpHeaders.createOptimized("application/json") - val TEXT_PLAIN: CharSequence = HttpHeaders.createOptimized("text/plain") - val TEXT_HTML: CharSequence = HttpHeaders.createOptimized("text/html; charset=utf-8") + val SERVER: CharSequence = HttpHeaders.createOptimized(Properties.SERVER_NAME) inline fun MultiMap.common(): MultiMap = this - .add(HttpHeaders.SERVER, SERVER) - .add(HttpHeaders.DATE, PeriodicDateResolver.current) - - inline fun RoutingContext.json(): HttpServerResponse { - val response = this.response() - val headers = response.headers() - headers - .common() - .add(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON) - return response - } - - inline fun RoutingContext.text(): HttpServerResponse { - val response = this.response() - val headers = response.headers() - headers - .common() - .add(HttpHeaders.CONTENT_TYPE, TEXT_PLAIN) - return response - } - - inline fun RoutingContext.html(): HttpServerResponse { - val response = this.response() - val headers = response.headers() - headers - .common() - .add(HttpHeaders.CONTENT_TYPE, TEXT_HTML) - return response - } - - inline fun RoutingContext.error(): Unit = this.text().end(SOMETHING_WENT_WRONG, NULL_HANDLER) + .add(HttpHeaderNames.SERVER, SERVER) + .add(HttpHeaderNames.DATE, PeriodicResolver.current) + + inline fun HttpServerRequest.json(): HttpServerResponse = response() + .apply { + headers() + .common() + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + } + + inline fun HttpServerRequest.plaintext(): HttpServerResponse = response() + .apply { + headers() + .common() + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + } + + inline fun HttpServerRequest.html(): HttpServerResponse = response() + .apply { + headers() + .common() + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_HTML) + } + + inline fun HttpServerRequest.error(): Future = plaintext() + .setStatusCode(500) + .end(SOMETHING_WENT_WRONG) } } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt index 8311474177e..7f981320192 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt @@ -1,15 +1,19 @@ package com.example.starter.handlers +import com.example.starter.helpers.PeriodicResolver +import io.vertx.core.Future import io.vertx.core.buffer.Buffer -import io.vertx.ext.web.RoutingContext +import io.vertx.core.http.HttpServerRequest class DefaultHandler : AbstractHandler() { - fun plaintext(ctx: RoutingContext) { - ctx.text().end(MESSAGE_BUFFER, NULL_HANDLER) - } + fun plaintext(req: HttpServerRequest): Future = req + .response().apply { + headers().setAll(PeriodicResolver.plaintext) + } + .end(MESSAGE_BUFFER) companion object { - private const val MESSAGE = "Hello, World!" - private val MESSAGE_BUFFER = Buffer.buffer(MESSAGE, "UTF-8") + const val MESSAGE: String = "Hello, World!" + val MESSAGE_BUFFER: Buffer = Buffer.buffer(MESSAGE, "UTF-8") } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt index 5e60c04cfeb..029026dab4c 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt @@ -2,56 +2,39 @@ package com.example.starter.handlers import com.example.starter.db.FortuneRepository import com.example.starter.models.Fortune -import htmlflow.HtmlFlow -import htmlflow.HtmlView -import io.vertx.ext.web.RoutingContext +import io.vertx.core.http.HttpServerRequest +import java.lang.Exception import org.apache.logging.log4j.kotlin.Logging class FortuneHandler(private val repository: FortuneRepository) : AbstractHandler() { - fun templateFortunes(ctx: RoutingContext) { + fun templateFortunes(req: HttpServerRequest) { repository .selectFortunes() - .onSuccess { - val updatedFortunes = it.plus(Fortune(0, "Additional fortune added at request time.")) - updatedFortunes.sort() - ctx.html().end(TEMPLATE.render(updatedFortunes), NULL_HANDLER) - } - .onFailure { - logger.error(it) { SOMETHING_WENT_WRONG } - ctx.error() + .onComplete { ar -> + when { + ar.succeeded() -> { + try { + val updatedFortunes = ar.result().plus(Fortune(0, "Additional fortune added at request time.")) + updatedFortunes.sort() + + val html = renderFortunes(updatedFortunes) + req.html().end(html) + } catch (ex: Exception) { + logger.error(SOMETHING_WENT_WRONG, ex) + req.error() + } + } + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } } } - companion object : Logging { - private val TEMPLATE: HtmlView = HtmlFlow - .view { page -> - page - .html() - .head() - .title() - .text("Fortunes") - .`__`() // title - .`__`() // head - .body() - .table() - .tr() - .th().text("id").`__`() - .th().text("message").`__`() - .`__`() // tr - .dynamic> { container, fortunes -> - fortunes.forEach { - container - .tr() - .td().text(it.id.toString()).`__`() - .td().text(it.message).`__`() - .`__`() // tr - } - } - .`__`() // table - .`__`() // body - .`__`() // html - } - .setIndented(false) - .threadSafe() + private companion object : Logging { + private fun renderFortunes(fortunes: Array): String { + throw NotImplementedError("Not implemented") + } } -} \ No newline at end of file +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt index 1fa432ef313..0a91afea21e 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt @@ -1,15 +1,20 @@ package com.example.starter.handlers +import com.example.starter.helpers.PeriodicResolver import com.example.starter.models.Message import com.example.starter.utils.serialize -import io.vertx.ext.web.RoutingContext +import io.vertx.core.Future +import io.vertx.core.http.HttpServerRequest class MessageHandler : AbstractHandler() { - fun readDefaultMessage(ctx: RoutingContext) { - ctx.json().end(DEFAULT_MESSAGE.serialize(), NULL_HANDLER) - } + fun readDefaultMessage(req: HttpServerRequest): Future = req + .response().apply { + headers().setAll(PeriodicResolver.json) + } + .end(Message(MESSAGE).serialize()) companion object { - private val DEFAULT_MESSAGE = Message("Hello, World!") + const val MESSAGE: String = "Hello, World!" + val DEFAULT_MESSAGE = Message(MESSAGE) } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt index 1226361d71b..c8152dda51f 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt @@ -2,55 +2,58 @@ package com.example.starter.handlers import com.example.starter.db.WorldRepository import com.example.starter.utils.serialize -import io.vertx.ext.web.RoutingContext +import io.vertx.core.http.HttpServerRequest import org.apache.logging.log4j.kotlin.Logging class WorldHandler(private val repository: WorldRepository) : AbstractHandler() { - fun readRandomWorld(ctx: RoutingContext) { + fun readRandomWorld(req: HttpServerRequest) { repository .selectRandomWorld() - .onSuccess { - ctx.json().end(it.serialize(), NULL_HANDLER) - } - .onFailure { - logger.error(it) { SOMETHING_WENT_WRONG } - ctx.error() + .onComplete { ar -> + when { + ar.succeeded() -> req.json().end(ar.result().serialize()) + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } } } - fun readRandomWorlds(ctx: RoutingContext) { - val queries = ctx.queries() + fun readRandomWorlds(req: HttpServerRequest) { repository - .selectRandomWorlds(queries) - .onSuccess { - ctx.json().end(it.serialize(), NULL_HANDLER) - } - .onFailure { - logger.error(it) { SOMETHING_WENT_WRONG } - ctx.error() + .selectRandomWorlds(req.queries()) + .onComplete { ar -> + when { + ar.succeeded() -> req.json().end(ar.result().serialize()) + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } } } - fun updateRandomWorlds(ctx: RoutingContext) { - val queries = ctx.queries() + fun updateRandomWorlds(req: HttpServerRequest) { repository - .updateRandomWorlds(queries) - .onSuccess { - ctx.json().end(it.serialize(), NULL_HANDLER) - } - .onFailure { - logger.error(it) { SOMETHING_WENT_WRONG } - ctx.error() + .updateRandomWorlds(req.queries()) + .onComplete { ar -> + when { + ar.succeeded() -> req.json().end(ar.result().serialize()) + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } } } - companion object : Logging { + private companion object : Logging { private const val QUERIES_PARAM_NAME = "queries" @Suppress("NOTHING_TO_INLINE") - private inline fun RoutingContext.queries(): Int { - val queriesParam = this.request().getParam(QUERIES_PARAM_NAME) - return queriesParam?.toIntOrNull()?.coerceIn(1, 500) ?: 1 - } + private inline fun HttpServerRequest.queries(): Int = getParam(QUERIES_PARAM_NAME) + ?.toIntOrNull() + ?.coerceIn(1, 500) ?: 1 } } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferOutputStream.kt similarity index 52% rename from frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt rename to frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferOutputStream.kt index d82b31fb6ee..162feef9cd6 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferOutputStream.kt @@ -1,7 +1,8 @@ -package com.example.starter.io +package com.example.starter.helpers import io.netty.buffer.ByteBuf import io.vertx.core.buffer.Buffer +import io.vertx.core.internal.buffer.BufferInternal import io.vertx.core.json.JsonArray import io.vertx.core.json.JsonObject import java.io.IOException @@ -9,8 +10,8 @@ import java.io.OutputStream import java.nio.ByteBuffer import java.nio.charset.Charset -class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { - private val buffer: Buffer = Buffer.buffer(initialSizeHint) +class BufferOutputStream(initialSizeHint: Int = 256) : BufferInternal, OutputStream() { + private val buffer: BufferInternal = BufferInternal.buffer(initialSizeHint) @Throws(IOException::class) override fun write(b: Int) { @@ -27,23 +28,15 @@ class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { buffer.appendBytes(bytes, offset, len) } - override fun toString(enc: String?): String { + override fun toString(enc: String): String { return buffer.toString(enc) } - override fun toString(enc: Charset?): String { + override fun toString(enc: Charset): String { return buffer.toString(enc) } - override fun writeToBuffer(other: Buffer?) { - buffer.writeToBuffer(other) - } - - override fun readFromBuffer(pos: Int, other: Buffer?): Int { - return buffer.readFromBuffer(pos, other) - } - - override fun copy(): Buffer { + override fun copy(): BufferInternal { return buffer.copy() } @@ -91,10 +84,18 @@ class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { return buffer.getDouble(pos) } + override fun getDoubleLE(pos: Int): Double { + return buffer.getDoubleLE(pos) + } + override fun getFloat(pos: Int): Float { return buffer.getFloat(pos) } + override fun getFloatLE(pos: Int): Float { + return buffer.getFloatLE(pos) + } + override fun getShort(pos: Int): Short { return buffer.getShort(pos) } @@ -135,19 +136,19 @@ class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { return buffer.getBytes(start, end) } - override fun getBytes(dst: ByteArray?): Buffer { + override fun getBytes(dst: ByteArray): Buffer { return buffer.getBytes(dst) } - override fun getBytes(dst: ByteArray?, dstIndex: Int): Buffer { + override fun getBytes(dst: ByteArray, dstIndex: Int): Buffer { return buffer.getBytes(dst, dstIndex) } - override fun getBytes(start: Int, end: Int, dst: ByteArray?): Buffer { + override fun getBytes(start: Int, end: Int, dst: ByteArray): Buffer { return buffer.getBytes(start, end, dst) } - override fun getBytes(start: Int, end: Int, dst: ByteArray?, dstIndex: Int): Buffer { + override fun getBytes(start: Int, end: Int, dst: ByteArray, dstIndex: Int): Buffer { return buffer.getBytes(start, end, dst, dstIndex) } @@ -155,7 +156,7 @@ class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { return buffer.getBuffer(start, end) } - override fun getString(start: Int, end: Int, enc: String?): String { + override fun getString(start: Int, end: Int, enc: String): String { return buffer.getString(start, end, enc) } @@ -163,183 +164,199 @@ class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { return buffer.getString(start, end) } - override fun appendBuffer(buff: Buffer?): Buffer { - return buffer.appendBuffer(buff) + override fun appendBuffer(b: Buffer): BufferInternal { + return buffer.appendBuffer(b) } - override fun appendBuffer(buff: Buffer?, offset: Int, len: Int): Buffer { - return buffer.appendBuffer(buff, offset, len) + override fun appendBuffer(b: Buffer, offset: Int, len: Int): BufferInternal { + return buffer.appendBuffer(b, offset, len) } - override fun appendBytes(bytes: ByteArray?): Buffer { + override fun appendBytes(bytes: ByteArray): BufferInternal { return buffer.appendBytes(bytes) } - override fun appendBytes(bytes: ByteArray?, offset: Int, len: Int): Buffer { + override fun appendBytes(bytes: ByteArray, offset: Int, len: Int): BufferInternal { return buffer.appendBytes(bytes, offset, len) } - override fun appendByte(b: Byte): Buffer { + override fun appendByte(b: Byte): BufferInternal { return buffer.appendByte(b) } - override fun appendUnsignedByte(b: Short): Buffer { + override fun appendUnsignedByte(b: Short): BufferInternal { return buffer.appendUnsignedByte(b) } - override fun appendInt(i: Int): Buffer { + override fun appendInt(i: Int): BufferInternal { return buffer.appendInt(i) } - override fun appendIntLE(i: Int): Buffer { + override fun appendIntLE(i: Int): BufferInternal { return buffer.appendIntLE(i) } - override fun appendUnsignedInt(i: Long): Buffer { + override fun appendUnsignedInt(i: Long): BufferInternal { return buffer.appendUnsignedInt(i) } - override fun appendUnsignedIntLE(i: Long): Buffer { + override fun appendUnsignedIntLE(i: Long): BufferInternal { return buffer.appendUnsignedIntLE(i) } - override fun appendMedium(i: Int): Buffer { + override fun appendMedium(i: Int): BufferInternal { return buffer.appendMedium(i) } - override fun appendMediumLE(i: Int): Buffer { + override fun appendMediumLE(i: Int): BufferInternal { return buffer.appendMediumLE(i) } - override fun appendLong(l: Long): Buffer { + override fun appendLong(l: Long): BufferInternal { return buffer.appendLong(l) } - override fun appendLongLE(l: Long): Buffer { + override fun appendLongLE(l: Long): BufferInternal { return buffer.appendLongLE(l) } - override fun appendShort(s: Short): Buffer { + override fun appendShort(s: Short): BufferInternal { return buffer.appendShort(s) } - override fun appendShortLE(s: Short): Buffer { + override fun appendShortLE(s: Short): BufferInternal { return buffer.appendShortLE(s) } - override fun appendUnsignedShort(s: Int): Buffer { + override fun appendUnsignedShort(s: Int): BufferInternal { return buffer.appendUnsignedShort(s) } - override fun appendUnsignedShortLE(s: Int): Buffer { + override fun appendUnsignedShortLE(s: Int): BufferInternal { return buffer.appendUnsignedShortLE(s) } - override fun appendFloat(f: Float): Buffer { + override fun appendFloat(f: Float): BufferInternal { return buffer.appendFloat(f) } - override fun appendDouble(d: Double): Buffer { + override fun appendFloatLE(f: Float): BufferInternal { + return buffer.appendFloatLE(f) + } + + override fun appendDouble(d: Double): BufferInternal { return buffer.appendDouble(d) } - override fun appendString(str: String?, enc: String?): Buffer { + override fun appendDoubleLE(d: Double): BufferInternal { + return buffer.appendDoubleLE(d) + } + + override fun appendString(str: String, enc: String): BufferInternal { return buffer.appendString(str, enc) } - override fun appendString(str: String?): Buffer { + override fun appendString(str: String): BufferInternal { return buffer.appendString(str) } - override fun setByte(pos: Int, b: Byte): Buffer { + override fun setByte(pos: Int, b: Byte): BufferInternal { return buffer.setByte(pos, b) } - override fun setUnsignedByte(pos: Int, b: Short): Buffer { + override fun setUnsignedByte(pos: Int, b: Short): BufferInternal { return buffer.setUnsignedByte(pos, b) } - override fun setInt(pos: Int, i: Int): Buffer { + override fun setInt(pos: Int, i: Int): BufferInternal { return buffer.setInt(pos, i) } - override fun setIntLE(pos: Int, i: Int): Buffer { + override fun setIntLE(pos: Int, i: Int): BufferInternal { return buffer.setIntLE(pos, i) } - override fun setUnsignedInt(pos: Int, i: Long): Buffer { + override fun setUnsignedInt(pos: Int, i: Long): BufferInternal { return buffer.setUnsignedInt(pos, i) } - override fun setUnsignedIntLE(pos: Int, i: Long): Buffer { + override fun setUnsignedIntLE(pos: Int, i: Long): BufferInternal { return buffer.setUnsignedIntLE(pos, i) } - override fun setMedium(pos: Int, i: Int): Buffer { + override fun setMedium(pos: Int, i: Int): BufferInternal { return buffer.setMedium(pos, i) } - override fun setMediumLE(pos: Int, i: Int): Buffer { + override fun setMediumLE(pos: Int, i: Int): BufferInternal { return buffer.setMediumLE(pos, i) } - override fun setLong(pos: Int, l: Long): Buffer { + override fun setLong(pos: Int, l: Long): BufferInternal { return buffer.setLong(pos, l) } - override fun setLongLE(pos: Int, l: Long): Buffer { + override fun setLongLE(pos: Int, l: Long): BufferInternal { return buffer.setLongLE(pos, l) } - override fun setDouble(pos: Int, d: Double): Buffer { + override fun setDouble(pos: Int, d: Double): BufferInternal { return buffer.setDouble(pos, d) } - override fun setFloat(pos: Int, f: Float): Buffer { + override fun setDoubleLE(pos: Int, d: Double): BufferInternal { + return buffer.setDoubleLE(pos, d) + } + + override fun setFloat(pos: Int, f: Float): BufferInternal { return buffer.setFloat(pos, f) } - override fun setShort(pos: Int, s: Short): Buffer { + override fun setFloatLE(pos: Int, f: Float): BufferInternal { + return buffer.setFloatLE(pos, f) + } + + override fun setShort(pos: Int, s: Short): BufferInternal { return buffer.setShort(pos, s) } - override fun setShortLE(pos: Int, s: Short): Buffer { + override fun setShortLE(pos: Int, s: Short): BufferInternal { return buffer.setShortLE(pos, s) } - override fun setUnsignedShort(pos: Int, s: Int): Buffer { + override fun setUnsignedShort(pos: Int, s: Int): BufferInternal { return buffer.setUnsignedShort(pos, s) } - override fun setUnsignedShortLE(pos: Int, s: Int): Buffer { + override fun setUnsignedShortLE(pos: Int, s: Int): BufferInternal { return buffer.setUnsignedShortLE(pos, s) } - override fun setBuffer(pos: Int, b: Buffer?): Buffer { + override fun setBuffer(pos: Int, b: Buffer): BufferInternal { return buffer.setBuffer(pos, b) } - override fun setBuffer(pos: Int, b: Buffer?, offset: Int, len: Int): Buffer { + override fun setBuffer(pos: Int, b: Buffer, offset: Int, len: Int): BufferInternal { return buffer.setBuffer(pos, b, offset, len) } - override fun setBytes(pos: Int, b: ByteBuffer?): Buffer { + override fun setBytes(pos: Int, b: ByteBuffer): BufferInternal { return buffer.setBytes(pos, b) } - override fun setBytes(pos: Int, b: ByteArray?): Buffer { + override fun setBytes(pos: Int, b: ByteArray): BufferInternal { return buffer.setBytes(pos, b) } - override fun setBytes(pos: Int, b: ByteArray?, offset: Int, len: Int): Buffer { + override fun setBytes(pos: Int, b: ByteArray, offset: Int, len: Int): BufferInternal { return buffer.setBytes(pos, b, offset, len) } - override fun setString(pos: Int, str: String?): Buffer { + override fun setString(pos: Int, str: String): BufferInternal { return buffer.setString(pos, str) } - override fun setString(pos: Int, str: String?, enc: String?): Buffer { + override fun setString(pos: Int, str: String, enc: String): BufferInternal { return buffer.setString(pos, str, enc) } @@ -347,16 +364,23 @@ class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() { return buffer.length() } - override fun slice(): Buffer { + override fun slice(): BufferInternal { return buffer.slice() } - override fun slice(start: Int, end: Int): Buffer { + override fun slice(start: Int, end: Int): BufferInternal { return buffer.slice(start, end) } - @Deprecated("Deprecated in Java") override fun getByteBuf(): ByteBuf { return buffer.byteBuf } + + override fun writeToBuffer(b: Buffer) { + return buffer.writeToBuffer(b) + } + + override fun readFromBuffer(pos: Int, b: Buffer): Int { + return buffer.readFromBuffer(pos, b) + } } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt new file mode 100644 index 00000000000..4e08f883e23 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt @@ -0,0 +1,61 @@ +package com.example.starter.helpers + +import com.example.starter.handlers.DefaultHandler +import com.example.starter.handlers.MessageHandler +import com.example.starter.utils.serialize +import io.vertx.core.MultiMap +import io.vertx.core.Vertx +import io.vertx.core.http.HttpHeaders +import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter + +private val FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC) +private val SERVER: CharSequence = HttpHeaders.createOptimized(Properties.SERVER_NAME) +private val CONTENT_TYPE_TEXT_PLAIN: CharSequence = HttpHeaders.createOptimized("text/plain") +private val CONTENT_TYPE_APPLICATION_JSON: CharSequence = HttpHeaders.createOptimized("application/json") +private val PLAINTEXT_CONTENT_LENGTH: CharSequence= HttpHeaders.createOptimized(DefaultHandler.MESSAGE.length.toString()) +private val JSON_CONTENT_LENGTH: CharSequence = HttpHeaders.createOptimized(MessageHandler.DEFAULT_MESSAGE.serialize().length().toString()) + +@Suppress("NOTHING_TO_INLINE") +object PeriodicResolver { + @Volatile + var current: CharSequence = next() + private set + + @Volatile + var plaintext: MultiMap = nextPlaintext() + private set + + @Volatile + var json: MultiMap = nextJson() + private set + + fun init(vertx: Vertx) { + vertx.setPeriodic(1_000L) { + current = next() + plaintext = nextPlaintext() + json = nextJson() + } + } + + private fun next(): CharSequence = HttpHeaders.createOptimized( + FORMATTER.format(Instant.now()) + ) + + private fun nextPlaintext(): MultiMap = HttpHeaders + .headers() + .add(HttpHeaders.SERVER, SERVER) + .add(HttpHeaders.DATE, current) + .add(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN) + .add(HttpHeaders.CONTENT_LENGTH, PLAINTEXT_CONTENT_LENGTH) + .copy(false) + + private fun nextJson(): MultiMap = HttpHeaders + .headers() + .add(HttpHeaders.SERVER, SERVER) + .add(HttpHeaders.DATE, current) + .add(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON) + .add(HttpHeaders.CONTENT_LENGTH, JSON_CONTENT_LENGTH) + .copy(false) +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt new file mode 100644 index 00000000000..ca72dd8a61c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt @@ -0,0 +1,171 @@ +package com.example.starter.helpers + +import io.netty.util.internal.SystemPropertyUtil +import io.vertx.core.impl.cpu.CpuCoreSensor +import io.vertx.core.tracing.TracingPolicy +import io.vertx.kotlin.core.http.httpServerOptionsOf +import io.vertx.kotlin.pgclient.pgConnectOptionsOf + +object Properties { + + /** + * The server name (used in headers and logging). + * Default: `Vert.x-Web` + */ + val SERVER_NAME: String = SystemPropertyUtil.get("tfb.serverName", "Vert.x-Web") + + /** + * Type of verticle to deploy. + * Default: all ([com.example.starter.ServerVerticle]) + */ + val TYPE: String = SystemPropertyUtil.get("tfb.type", "all") + + /** + * Number of event loop threads. + * Default: [io.vertx.core.impl.cpu.CpuCoreSensor.availableProcessors] + */ + val EVENT_LOOP_POOL_SIZE: Int = SystemPropertyUtil.getInt("tfb.eventLoopPoolSize", CpuCoreSensor.availableProcessors()) + + /** + * Whether metrics are enabled. + * Default: Reverse of `vertx.disableMetrics` (defaults to false) + */ + val METRICS_ENABLED: Boolean = SystemPropertyUtil.getBoolean("vertx.disableMetrics", false).not() + + /** + * Port the HTTP server listens on. + * Default: 8080 (tfb.http.port) + */ + val HTTP_PORT: Int = SystemPropertyUtil.getInt("tfb.http.port", 8080) + + /** + * Size of TCP send buffer for HTTP connections, in bytes. + * Default: 32768 (tfb.http.sendBufferSize) + */ + val HTTP_SEND_BUFFER_SIZE: Int = SystemPropertyUtil.getInt("tfb.http.sendBufferSize", 16 * 1024) + + /** + * Size of TCP receive buffer for HTTP connections, in bytes. + * Default: 32768 (tfb.http.receiveBufferSize) + */ + val HTTP_RECEIVE_BUFFER_SIZE: Int = SystemPropertyUtil.getInt("tfb.http.receiveBufferSize", 16 * 1024) + + /** + * Enables TCP Fast Open on the HTTP server. + * Default: true (tfb.http.tcpFastOpen) + */ + val HTTP_TCP_FASTOPEN: Boolean = SystemPropertyUtil.getBoolean("tfb.http.tcpFastOpen", true) + + /** + * Enables TCP_NODELAY (disables Nagle) on HTTP connections. + * Default: true (tfb.http.tcpNoDelay) + */ + val HTTP_TCP_NODELAY: Boolean = SystemPropertyUtil.getBoolean("tfb.http.tcpNoDelay", true) + + /** + * Idle timeout for HTTP connections in seconds. + * 0 disables idle timeout. + * Default: 0 (tfb.http.idleTimeout) + */ + val HTTP_IDLE_TIMEOUT: Int = SystemPropertyUtil.getInt("tfb.http.idleTimeout", 0) + + /** + * Enables SO_REUSEADDR on the HTTP server socket. + * Default: true (tfb.http.reuseAddress) + */ + val HTTP_REUSE_ADDRESS: Boolean = SystemPropertyUtil.getBoolean("tfb.http.reuseAddress", true) + + /** + * Enables SO_REUSEPORT on the HTTP server socket. + * Default: true (tfb.http.reusePort) + */ + val HTTP_REUSE_PORT: Boolean = SystemPropertyUtil.getBoolean("tfb.http.reusePort", true) + + /** + * Size of the TCP accept backlog for the HTTP server. + * Default: 8192 (tfb.http.acceptBacklog) + */ + val HTTP_ACCEPT_BACKLOG: Int = SystemPropertyUtil.getInt("tfb.http.acceptBacklog", 8192) + + /** + * PostgreSQL username used for connections. + * Default: benchmarkdbuser (tfb.pg.user) + */ + val PG_USER: String = SystemPropertyUtil.get("tfb.pg.user", "benchmarkdbuser") + + /** + * PostgreSQL password used for connections. + * Default: benchmarkdbpass (tfb.pg.password) + */ + val PG_PASSWORD: String = SystemPropertyUtil.get("tfb.pg.password", "benchmarkdbpass") + + /** + * PostgreSQL host used for connections. + * Default: tfb.pgHostOverride system property, otherwise "tfb-database". + * Property: tfb.pg.host + */ + val PG_HOST: String = SystemPropertyUtil.get("tfb.pg.host", System.getProperty("tfb.pgHostOverride") ?: "tfb-database") + + /** + * PostgreSQL port used for connections. + * Default: 5432 (tfb.pg.port) + */ + val PG_PORT: Int = SystemPropertyUtil.getInt("tfb.pg.port", 5432) + + /** + * PostgreSQL database name used for connections. + * Default: hello_world (tfb.pg.database) + */ + val PG_DATABASE: String = SystemPropertyUtil.get("tfb.pg.database", "hello_world") + + /** + * Enables prepared statement caching on the PostgreSQL client. + * Default: true (tfb.pg.cachePreparedStatements) + */ + val PG_CACHE_PREPARED_STATEMENTS: Boolean = SystemPropertyUtil.getBoolean("tfb.pg.cachePreparedStatements", true) + + /** + * Maximum size of the prepared statement cache. + * Default: 1024 (tfb.pg.preparedStatementCacheMaxSize) + */ + val PG_PREPARED_STATEMENT_CACHE_MAX_SIZE: Int = + SystemPropertyUtil.getInt("tfb.pg.preparedStatementCacheMaxSize", 1024) + + /** + * Max number of in-flight pipelined requests per connection. + * Default: 1024 (tfb.pg.pipeliningLimit) + */ + val PG_PIPELINING_LIMIT: Int = SystemPropertyUtil.getInt("tfb.pg.pipeliningLimit", 1024) + + val HTTP by lazy { + httpServerOptionsOf( + port = HTTP_PORT, + sendBufferSize = HTTP_SEND_BUFFER_SIZE, + receiveBufferSize = HTTP_RECEIVE_BUFFER_SIZE, + tcpFastOpen = HTTP_TCP_FASTOPEN, + tcpNoDelay = HTTP_TCP_NODELAY, + idleTimeout = HTTP_IDLE_TIMEOUT, + reuseAddress = HTTP_REUSE_ADDRESS, + reusePort = HTTP_REUSE_PORT, + acceptBacklog = HTTP_ACCEPT_BACKLOG, + compressionSupported = false, + tracingPolicy = TracingPolicy.IGNORE, + http2ClearTextEnabled = false, + strictThreadMode = true, + ) + } + + val PG_CONNECT by lazy { + pgConnectOptionsOf( + user = PG_USER, + password = PG_PASSWORD, + host = PG_HOST, + port = PG_PORT, + database = PG_DATABASE, + cachePreparedStatements = PG_CACHE_PREPARED_STATEMENTS, + preparedStatementCacheMaxSize = PG_PREPARED_STATEMENT_CACHE_MAX_SIZE, + tracingPolicy = TracingPolicy.IGNORE, + pipeliningLimit = PG_PIPELINING_LIMIT + ) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt deleted file mode 100644 index fbf355e66a9..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.example.starter.io - -import io.vertx.core.json.JsonObject - -object JsonResource { - fun of(resource: String): JsonObject { - val classLoader = ClassLoader.getSystemClassLoader() - classLoader.getResourceAsStream(resource)?.use { input -> - val output = BufferOutputStream() - output.write(input.readAllBytes()) - return output.toJsonObject() - } - throw IllegalStateException("$resource not found") - } -} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt index 4b832526750..f9293258ed9 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt @@ -5,8 +5,8 @@ import com.dslplatform.json.JsonAttribute @CompiledJson class Fortune( - @JsonAttribute(nullable = false) val id: Int, - @JsonAttribute(nullable = false) val message: String + @field:JsonAttribute(nullable = false) val id: Int, + @field:JsonAttribute(nullable = false) val message: String, ) : Comparable { override fun compareTo(other: Fortune): Int { return message.compareTo(other.message) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt index eb7fc6250a3..1953c10cfcb 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt @@ -4,4 +4,4 @@ import com.dslplatform.json.CompiledJson import com.dslplatform.json.JsonAttribute @CompiledJson -class Message(@JsonAttribute(nullable = false) val message: String) +class Message(@field:JsonAttribute(nullable = false) val message: String) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt index 5011a2bb2e0..030f96ed314 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt @@ -5,10 +5,8 @@ import com.dslplatform.json.JsonAttribute @CompiledJson class World( - @JsonAttribute(nullable = false) val id: Int, - @JsonAttribute(nullable = false) var randomNumber: Int + @field:JsonAttribute(nullable = false) val id: Int, + @field:JsonAttribute(nullable = false) var randomNumber: Int, ) : Comparable { - override fun compareTo(other: World): Int { - return id.compareTo(other.id) - } + override fun compareTo(other: World): Int = id - other.id } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt index 03d5a018575..1b9ce713000 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt @@ -1,14 +1,14 @@ package com.example.starter.utils -import io.vertx.core.CompositeFuture import io.vertx.core.Future -import java.util.concurrent.TimeUnit +import io.vertx.kotlin.coroutines.coAwait import kotlin.time.Duration - -inline fun CompositeFuture.array(): Array = Array(this.size()) { this.resultAt(it) } +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout @Suppress("NOTHING_TO_INLINE") -inline fun > T.block(duration: Duration): R = this - .toCompletionStage() - .toCompletableFuture() - .get(duration.inWholeMilliseconds, TimeUnit.MILLISECONDS) \ No newline at end of file +inline fun > T.block(duration: Duration): R = runBlocking { + withTimeout(duration) { + coAwait() + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt index 264be5a7323..f7793af1509 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt @@ -2,17 +2,16 @@ package com.example.starter.utils import com.dslplatform.json.DslJson import com.dslplatform.json.runtime.Settings -import com.example.starter.io.BufferOutputStream +import com.example.starter.helpers.BufferOutputStream import io.vertx.core.buffer.Buffer val DSL_JSON: DslJson = DslJson( Settings.withRuntime() .includeServiceLoader() - .useStringValuesCache(DslJson.SimpleStringCache()) ) @Suppress("NOTHING_TO_INLINE") -inline fun T.serialize(initialSizeHint: Int = 0): Buffer { +inline fun T.serialize(initialSizeHint: Int = 128): Buffer { val output = BufferOutputStream(initialSizeHint) DSL_JSON.serialize(this, output) return output diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt deleted file mode 100644 index 23786587569..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.example.starter.utils - -import io.vertx.core.Vertx -import io.vertx.core.http.HttpHeaders -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter - -object PeriodicDateResolver { - var current: CharSequence = next() - - fun init(vertx: Vertx) { - vertx.setPeriodic(1000L) { current = next() } - } - - @Suppress("NOTHING_TO_INLINE") - private inline fun next(): CharSequence = HttpHeaders.createOptimized( - DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()) - ) -} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt index 3959ba8d9a0..7f7fcc84ab4 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt @@ -5,11 +5,8 @@ import io.vertx.sqlclient.RowSet // This extension relies on the assumption the mapper never returns null, as it is defined. Otherwise, // we prevent the overhead from having to do another iteration over the loop for a `filterNotNull` check. -@Suppress("UNCHECKED_CAST") +@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") inline fun RowSet.mapToArray(mapper: (Row) -> U): Array { - val arr = arrayOfNulls(this.size()) - val iterator = this.iterator() - var index = 0 - while (iterator.hasNext()) arr[index++] = mapper(iterator.next()) - return arr as Array + val iterator = iterator() + return Array(size()) { mapper(iterator.next()) } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt index 00cf1463297..3f31f9720a9 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt @@ -7,10 +7,8 @@ import java.net.SocketException const val CONNECTION_RESET_MESSAGE = "Connection reset" @Suppress("NOTHING_TO_INLINE") -inline fun Throwable.isConnectionReset(): Boolean { - return when { - this is NativeIoException && this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE -> true - this is SocketException && this.message == CONNECTION_RESET_MESSAGE -> true - else -> false - } +inline fun Throwable.isConnectionReset(): Boolean = when (this) { + is NativeIoException if this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE -> true + is SocketException if this.message == CONNECTION_RESET_MESSAGE -> true + else -> false } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json deleted file mode 100644 index a790bc93043..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "port": 8080, - "tcpFastOpen": true, - "receiveBufferSize": 262144, - "sendBufferSize": 262144 -} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json deleted file mode 100644 index 3cf43317687..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "user": "benchmarkdbuser", - "password": "benchmarkdbpass", - "host": "tfb-database", - "port": 5432, - "database": "hello_world", - "cachePreparedStatements": true, - "preparedStatementCacheMaxSize": 1024, - "pipeliningLimit": 100000, - "receiveBufferSize": 262144, - "sendBufferSize": 262144 -} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile index 50152d8df30..b7157b37da2 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile @@ -1,39 +1,56 @@ -FROM gradle:8.9-jdk21 as gradle +# --- Build stage with JDK 25 --- +FROM gradle:9.2-jdk25-corretto AS builder WORKDIR /vertx-web-kotlin-dsljson COPY src src +COPY buildSrc buildSrc COPY build.gradle.kts build.gradle.kts -COPY gradle.properties gradle.properties COPY settings.gradle.kts settings.gradle.kts +COPY gradle.properties gradle.properties +COPY gradle/libs.versions.toml gradle/libs.versions.toml + +RUN gradle shadowJar --no-daemon + +# --- Runtime stage using Amazon Corretto 25 --- +FROM amazoncorretto:25 + +WORKDIR /app -RUN gradle shadowJar +COPY --from=builder \ + /vertx-web-kotlin-dsljson/build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar \ + vertx-web-kotlin-dsljson.jar EXPOSE 8080 CMD java \ - -server \ - -Xms2G \ - -Xmx2G \ - -XX:+AlwaysPreTouch \ - -XX:+UseParallelGC \ - -XX:InitialCodeCacheSize=512m \ - -XX:ReservedCodeCacheSize=512m \ - -XX:MaxInlineLevel=20 \ - -XX:+UseNUMA \ - -Djava.lang.Integer.IntegerCache.high=10000 \ - -Dvertx.disableMetrics=true \ - -Dvertx.disableH2c=true \ - -Dvertx.disableWebsockets=true \ - -Dvertx.flashPolicyHandler=false \ - -Dvertx.threadChecks=false \ - -Dvertx.disableContextTimings=true \ - -Dvertx.disableTCCL=true \ - -Dvertx.disableHttpHeadersValidation=true \ - -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ - -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ - -Dio.netty.buffer.checkBounds=false \ - -Dio.netty.buffer.checkAccessible=false \ - -Dtfb.hasDB=true \ - -jar \ - build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar + -server \ + --enable-native-access=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -XX:-UseCodeCacheFlushing \ + -XX:AutoBoxCacheMax=10001 \ + -XX:+UseCompactObjectHeaders \ + -Djava.net.preferIPv4Stack=true \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.leakDetection.level=disabled \ + -Dio.netty.iouring.ringSize=4096 \ + -Dio.netty.iouring.cqSize=8192 \ + -Dtfb.type=postgres \ + -jar /app/vertx-web-kotlin-dsljson.jar diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile index 568f19f79dd..c69e49fbbfd 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile @@ -1,39 +1,56 @@ -FROM gradle:8.9-jdk21 as gradle +# --- Build stage with JDK 25 --- +FROM gradle:9.2-jdk25-corretto AS builder WORKDIR /vertx-web-kotlin-dsljson COPY src src +COPY buildSrc buildSrc COPY build.gradle.kts build.gradle.kts -COPY gradle.properties gradle.properties COPY settings.gradle.kts settings.gradle.kts +COPY gradle.properties gradle.properties +COPY gradle/libs.versions.toml gradle/libs.versions.toml + +RUN gradle shadowJar --no-daemon + +# --- Runtime stage using Amazon Corretto 25 --- +FROM amazoncorretto:25 + +WORKDIR /app -RUN gradle shadowJar +COPY --from=builder \ + /vertx-web-kotlin-dsljson/build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar \ + vertx-web-kotlin-dsljson.jar EXPOSE 8080 CMD java \ - -server \ - -Xms2G \ - -Xmx2G \ - -XX:+AlwaysPreTouch \ - -XX:+UseParallelGC \ - -XX:InitialCodeCacheSize=512m \ - -XX:ReservedCodeCacheSize=512m \ - -XX:MaxInlineLevel=20 \ - -XX:+UseNUMA \ - -Djava.lang.Integer.IntegerCache.high=10000 \ - -Dvertx.disableMetrics=true \ - -Dvertx.disableH2c=true \ - -Dvertx.disableWebsockets=true \ - -Dvertx.flashPolicyHandler=false \ - -Dvertx.threadChecks=false \ - -Dvertx.disableContextTimings=true \ - -Dvertx.disableTCCL=true \ - -Dvertx.disableHttpHeadersValidation=true \ - -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ - -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ - -Dio.netty.buffer.checkBounds=false \ - -Dio.netty.buffer.checkAccessible=false \ - -Dtfb.hasDB=false \ - -jar \ - build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar + -server \ + --enable-native-access=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -XX:-UseCodeCacheFlushing \ + -XX:AutoBoxCacheMax=10001 \ + -XX:+UseCompactObjectHeaders \ + -Djava.net.preferIPv4Stack=true \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.leakDetection.level=disabled \ + -Dio.netty.iouring.ringSize=4096 \ + -Dio.netty.iouring.cqSize=8192 \ + -Dtfb.type=basic \ + -jar /app/vertx-web-kotlin-dsljson.jar From dd562f589f954f91ef576162bdd61a2452ab3bf7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 23:11:39 +0000 Subject: [PATCH 038/130] Build(deps): bump golang.org/x/crypto in /frameworks/Go/fiber/src Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/fiber/src/go.mod | 10 +++++----- frameworks/Go/fiber/src/go.sum | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frameworks/Go/fiber/src/go.mod b/frameworks/Go/fiber/src/go.mod index 6980da19018..6e1dcc6247f 100644 --- a/frameworks/Go/fiber/src/go.mod +++ b/frameworks/Go/fiber/src/go.mod @@ -1,6 +1,6 @@ module fiber/app -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -24,8 +24,8 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.60.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect ) diff --git a/frameworks/Go/fiber/src/go.sum b/frameworks/Go/fiber/src/go.sum index 386b9e79452..bbb70d60f3f 100644 --- a/frameworks/Go/fiber/src/go.sum +++ b/frameworks/Go/fiber/src/go.sum @@ -43,15 +43,15 @@ github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdq github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 895d00e622da7220089298d920cc8399a57dd441 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 23:17:56 +0000 Subject: [PATCH 039/130] Build(deps): bump golang.org/x/crypto in /frameworks/Go/hertz Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/hertz/go.mod | 10 +++++----- frameworks/Go/hertz/go.sum | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frameworks/Go/hertz/go.mod b/frameworks/Go/hertz/go.mod index 4119d421b62..741b2016451 100644 --- a/frameworks/Go/hertz/go.mod +++ b/frameworks/Go/hertz/go.mod @@ -1,6 +1,6 @@ module hertz -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -28,10 +28,10 @@ require ( github.com/tidwall/pretty v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect golang.org/x/arch v0.15.0 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/frameworks/Go/hertz/go.sum b/frameworks/Go/hertz/go.sum index 7c4f93bbbfe..9159cda26d4 100644 --- a/frameworks/Go/hertz/go.sum +++ b/frameworks/Go/hertz/go.sum @@ -84,8 +84,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -101,8 +101,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -112,8 +112,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -126,8 +126,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From 118f90427a0d6d772219f9a630eaa1dd0d70ca38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 23:24:34 +0000 Subject: [PATCH 040/130] Build(deps): bump golang.org/x/crypto in /frameworks/Go/gin/gin-gorm Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/gin/gin-gorm/go.mod | 12 ++++++------ frameworks/Go/gin/gin-gorm/go.sum | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/frameworks/Go/gin/gin-gorm/go.mod b/frameworks/Go/gin/gin-gorm/go.mod index 4e73bd0d4e2..1660edbccf5 100644 --- a/frameworks/Go/gin/gin-gorm/go.mod +++ b/frameworks/Go/gin/gin-gorm/go.mod @@ -1,6 +1,6 @@ module gin-gorm/app -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -39,11 +39,11 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.15.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/frameworks/Go/gin/gin-gorm/go.sum b/frameworks/Go/gin/gin-gorm/go.sum index 8d103d7745f..79a5ba8e1a4 100644 --- a/frameworks/Go/gin/gin-gorm/go.sum +++ b/frameworks/Go/gin/gin-gorm/go.sum @@ -84,17 +84,17 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 563b3d7e31c04848dc6615966ed4fcc70d8371ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 01:38:24 +0000 Subject: [PATCH 041/130] Build(deps): bump golang.org/x/crypto Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.35.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.35.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/goravel/src/fiber/go.mod | 14 +++++------ frameworks/Go/goravel/src/fiber/go.sum | 32 +++++++++++++------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/frameworks/Go/goravel/src/fiber/go.mod b/frameworks/Go/goravel/src/fiber/go.mod index 6fd142f91bf..e0ee741ee37 100644 --- a/frameworks/Go/goravel/src/fiber/go.mod +++ b/frameworks/Go/goravel/src/fiber/go.mod @@ -1,6 +1,6 @@ module goravel -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -162,14 +162,14 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.35.0 // indirect + golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/net v0.47.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.29.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.171.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/frameworks/Go/goravel/src/fiber/go.sum b/frameworks/Go/goravel/src/fiber/go.sum index bc5125921ca..5e100bb5998 100644 --- a/frameworks/Go/goravel/src/fiber/go.sum +++ b/frameworks/Go/goravel/src/fiber/go.sum @@ -723,8 +723,8 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -764,8 +764,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -812,8 +812,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -840,8 +840,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -905,8 +905,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -917,8 +917,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -935,8 +935,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1002,8 +1002,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 58e20ba817177415cf02f6f75c6a0cf775d03b6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 02:02:49 +0000 Subject: [PATCH 042/130] Build(deps): bump golang.org/x/crypto in /frameworks/Go/atreugo/src Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/atreugo/src/go.mod | 10 +++++----- frameworks/Go/atreugo/src/go.sum | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frameworks/Go/atreugo/src/go.mod b/frameworks/Go/atreugo/src/go.mod index 46944099dc5..01fb51e3d5c 100644 --- a/frameworks/Go/atreugo/src/go.mod +++ b/frameworks/Go/atreugo/src/go.mod @@ -1,6 +1,6 @@ module atreugo/src -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -20,8 +20,8 @@ require ( github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.60.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect ) diff --git a/frameworks/Go/atreugo/src/go.sum b/frameworks/Go/atreugo/src/go.sum index 0850edc3bd7..87b06ac2495 100644 --- a/frameworks/Go/atreugo/src/go.sum +++ b/frameworks/Go/atreugo/src/go.sum @@ -36,14 +36,14 @@ github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdq github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 47360255070785407b064ed01dd8c85ae08c371c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 02:45:26 +0000 Subject: [PATCH 043/130] Build(deps): bump golang.org/x/crypto in /frameworks/Go/indigo/src Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.41.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.41.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frameworks/Go/indigo/src/go.mod | 8 ++++---- frameworks/Go/indigo/src/go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/frameworks/Go/indigo/src/go.mod b/frameworks/Go/indigo/src/go.mod index cf0eeb1cb9e..874efeac4de 100644 --- a/frameworks/Go/indigo/src/go.mod +++ b/frameworks/Go/indigo/src/go.mod @@ -18,8 +18,8 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/text v0.28.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/text v0.31.0 // indirect ) diff --git a/frameworks/Go/indigo/src/go.sum b/frameworks/Go/indigo/src/go.sum index 2207dda2ca6..99170600d2b 100644 --- a/frameworks/Go/indigo/src/go.sum +++ b/frameworks/Go/indigo/src/go.sum @@ -36,14 +36,14 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From a0209169314c83d091abb839539a157f75f1ae50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Tue, 25 Nov 2025 17:54:41 +0100 Subject: [PATCH 044/130] [genhttp] update to version 10.1 (#10297) * Update GenHTTP to version 10.1 * Fix structure of benchmark_config.json * Update postgres driver to latest --- frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj | 6 +++--- frameworks/CSharp/genhttp/benchmark_config.json | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj index ae302d86dbb..66a7a9301d9 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj @@ -28,12 +28,12 @@ - + - + - + diff --git a/frameworks/CSharp/genhttp/benchmark_config.json b/frameworks/CSharp/genhttp/benchmark_config.json index 2943457c204..f2376bf64fc 100644 --- a/frameworks/CSharp/genhttp/benchmark_config.json +++ b/frameworks/CSharp/genhttp/benchmark_config.json @@ -23,10 +23,8 @@ "database_os": "Linux", "display_name": "genhttp [internal]", "notes": "" - } - }, - { - "kestrel": { + }, + "kestrel": { "plaintext_url": "/plaintext", "json_url": "/json", "db_url": "/db", @@ -47,6 +45,6 @@ "database_os": "Linux", "display_name": "genhttp [kestrel]", "notes": "" - } - }] + } + }] } From 238234b07a750f105ac2b929dd7a910115081422 Mon Sep 17 00:00:00 2001 From: Kayden <143221653+Kayden1412@users.noreply.github.com> Date: Tue, 25 Nov 2025 23:54:50 +0700 Subject: [PATCH 045/130] Update httpz to Zig 0.15.2 (#10299) * update httpz to zig 0.15.2 * Update Zig installation method in Dockerfile Replace curl with wget for downloading Zig and adjust installation paths. * Replace curl with wget in Dockerfile * Fix tar extraction and move commands in Dockerfile * Fix URL format for Zig download in Dockerfile * fix compile error --- frameworks/Zig/httpz/build.zig | 12 ++++++--- frameworks/Zig/httpz/build.zig.zon | 35 ++++++++++++++++---------- frameworks/Zig/httpz/httpz.dockerfile | 16 ++++++------ frameworks/Zig/httpz/src/endpoints.zig | 16 +++--------- frameworks/Zig/httpz/src/main.zig | 32 ++++++++++++----------- frameworks/Zig/httpz/src/pool.zig | 3 --- 6 files changed, 59 insertions(+), 55 deletions(-) diff --git a/frameworks/Zig/httpz/build.zig b/frameworks/Zig/httpz/build.zig index 16a4bb64845..420e696ae8c 100644 --- a/frameworks/Zig/httpz/build.zig +++ b/frameworks/Zig/httpz/build.zig @@ -6,16 +6,20 @@ pub fn build(b: *std.Build) !void { const dep_opts = .{ .target = target, .optimize = optimize }; - const exe = b.addExecutable(.{ - .name = "httpz", - .root_source_file = b.path("src/main.zig"), + const root_module = b.addModule("root_mod", .{ .target = target, .optimize = optimize, + .root_source_file = b.path("src/main.zig"), }); const httpz_module = b.dependency("httpz", dep_opts).module("httpz"); const pg_module = b.dependency("pg", dep_opts).module("pg"); - const datetimez_module = b.dependency("datetimez", dep_opts).module("zig-datetime"); + const datetimez_module = b.dependency("datetimez", dep_opts).module("datetime"); + + const exe = b.addExecutable(.{ + .name = "httpz", + .root_module = root_module, + }); exe.root_module.addImport("httpz", httpz_module); exe.root_module.addImport("pg", pg_module); diff --git a/frameworks/Zig/httpz/build.zig.zon b/frameworks/Zig/httpz/build.zig.zon index 83c29e48929..ed67e4a7d99 100644 --- a/frameworks/Zig/httpz/build.zig.zon +++ b/frameworks/Zig/httpz/build.zig.zon @@ -1,15 +1,24 @@ -.{ .name = "Zap testing", .version = "0.1.1", .paths = .{ - "build.zig", - "build.zig.zon", - "src", -}, .dependencies = .{ - .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, - .httpz = .{ - .url = "git+https://github.com/karlseguin/http.zig?ref=zig-0.13#7d2ddae87af9b110783085c0ea6b03985faa4584", - .hash = "12208c1f2c5f730c4c03aabeb0632ade7e21914af03e6510311b449458198d0835d6", +.{ + .name = .httpz_testing, + .fingerprint = 0x586e7c8a23a7e7c2, + .version = "0.1.1", + .paths = .{ + "build.zig", + "build.zig.zon", + "src", }, - .datetimez = .{ - .url = "git+https://github.com/frmdstryr/zig-datetime#70aebf28fb3e137cd84123a9349d157a74708721", - .hash = "122077215ce36e125a490e59ec1748ffd4f6ba00d4d14f7308978e5360711d72d77f", + .dependencies = .{ + .pg = .{ + .url = "git+https://github.com/karlseguin/pg.zig.git#f8d4892387fbad2abdf775783e101e50a7114335", + .hash = "pg-0.0.0-Wp_7gag6BgD_QAZrPhNNEGpnUZR_LEkKT40Ura3p-4yX", + }, + .httpz = .{ + .url = "git+https://github.com/karlseguin/http.zig.git#a4477b1dbdc5b820fd4ad301797ca6399f7eb6e4", + .hash = "httpz-0.0.0-PNVzrBgtBwCVkSJyophIX6WHwDR0r8XhBGQr96Kk-1El", + }, + .datetimez = .{ + .url = "git+https://github.com/frmdstryr/zig-datetime.git#3a39a21e6e34dcb0ade0ff828d0914d40ba535f3", + .hash = "datetime-0.8.0-cJNXzP_YAQBxQ5hkNNP6ScnG5XsqciJmeP5RVV4xwCBA", + }, }, -} } +} diff --git a/frameworks/Zig/httpz/httpz.dockerfile b/frameworks/Zig/httpz/httpz.dockerfile index ea4f9a7f76d..c2d0776025f 100644 --- a/frameworks/Zig/httpz/httpz.dockerfile +++ b/frameworks/Zig/httpz/httpz.dockerfile @@ -12,17 +12,19 @@ COPY src src COPY build.zig.zon build.zig.zon COPY build.zig build.zig -ARG ZIG_VER=0.13.0 +ARG ZIG_VER=0.15.2 -RUN apt-get update && apt-get install -y curl xz-utils ca-certificates +RUN apt-get update && apt-get install -y wget xz-utils ca-certificates -RUN curl https://ziglang.org/download/${ZIG_VER}/zig-linux-$(uname -m)-${ZIG_VER}.tar.xz -o zig-linux.tar.xz && \ - tar xf zig-linux.tar.xz && \ - mv zig-linux-$(uname -m)-${ZIG_VER}/ /opt/zig +RUN wget https://ziglang.org/download/${ZIG_VER}/zig-$(uname -m)-linux-${ZIG_VER}.tar.xz -RUN /opt/zig/zig build -Doptimize=ReleaseFast +RUN tar -xvf zig-$(uname -m)-linux-${ZIG_VER}.tar.xz + +RUN mv zig-$(uname -m)-linux-${ZIG_VER} /usr/local/zig + +ENV PATH="/usr/local/zig:$PATH" +RUN zig build -Doptimize=ReleaseFast EXPOSE 3000 -RUN ls CMD ["zig-out/bin/httpz"] diff --git a/frameworks/Zig/httpz/src/endpoints.zig b/frameworks/Zig/httpz/src/endpoints.zig index b8cfe9757fb..62b9c8be39f 100644 --- a/frameworks/Zig/httpz/src/endpoints.zig +++ b/frameworks/Zig/httpz/src/endpoints.zig @@ -3,11 +3,11 @@ const httpz = @import("httpz"); const pg = @import("pg"); const datetimez = @import("datetimez"); -pub var date_str: []u8 = ""; +pub var date_str: [29]u8 = undefined; pub const Global = struct { pool: *pg.Pool, - rand: *std.rand.Random, + rand: *std.Random, }; const World = struct { @@ -70,17 +70,7 @@ fn getWorld(pool: *pg.Pool, random_number: u32) !World { fn setHeaders(allocator: std.mem.Allocator, res: *httpz.Response) !void { res.header("Server", "Httpz"); - //const now = datetimez.datetime.Date.now(); - //const time = datetimez.datetime.Time.now(); - - // Wed, 17 Apr 2013 12:00:00 GMT - // Return date in ISO format YYYY-MM-DD - //const TB_DATE_FMT = "{s:0>3}, {d:0>2} {s:0>3} {d:0>4} {d:0>2}:{d:0>2}:{d:0>2} GMT"; - //const now_str = try std.fmt.allocPrint(allocator, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); - - //defer allocator.free(now_str); - - res.header("Date", try allocator.dupe(u8, date_str)); + res.header("Date", try allocator.dupe(u8, &date_str)); } fn getFortunesHtml(allocator: std.mem.Allocator, pool: *pg.Pool) ![]const u8 { diff --git a/frameworks/Zig/httpz/src/main.zig b/frameworks/Zig/httpz/src/main.zig index dd5b3966b2f..0089c1f2ef2 100644 --- a/frameworks/Zig/httpz/src/main.zig +++ b/frameworks/Zig/httpz/src/main.zig @@ -7,22 +7,24 @@ const pool = @import("pool.zig"); const endpoints = @import("endpoints.zig"); -var server: httpz.ServerCtx(*endpoints.Global, *endpoints.Global) = undefined; +var server: httpz.Server(*endpoints.Global) = undefined; pub fn main() !void { const cpu_count = try std.Thread.getCpuCount(); var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true, }){}; + defer { + if (builtin.mode == .Debug) _ = gpa.deinit(); + } - const allocator = gpa.allocator(); + const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.smp_allocator; var pg_pool = try pool.initPool(allocator); defer pg_pool.deinit(); const date_thread = try std.Thread.spawn(.{}, struct { fn update() !void { - const ally = std.heap.page_allocator; while (true) { const now = datetimez.datetime.Date.now(); const time = datetimez.datetime.Time.now(); @@ -30,15 +32,15 @@ pub fn main() !void { // Wed, 17 Apr 2013 12:00:00 GMT // Return date in ISO format YYYY-MM-DD const TB_DATE_FMT = "{s:0>3}, {d:0>2} {s:0>3} {d:0>4} {d:0>2}:{d:0>2}:{d:0>2} GMT"; - endpoints.date_str = try std.fmt.allocPrint(ally, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); - std.time.sleep(std.time.ns_per_ms * 980); + _ = try std.fmt.bufPrint(&endpoints.date_str, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); + std.Thread.sleep(std.time.ns_per_ms * 980); } } }.update, .{}); date_thread.detach(); - var prng = std.rand.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp()))); + var prng: std.Random.DefaultPrng = .init(@as(u64, @bitCast(std.time.milliTimestamp()))); var rand = prng.random(); @@ -50,7 +52,7 @@ pub fn main() !void { const port: u16 = 3000; const workers = @as(u16, @intCast(16 * cpu_count)); - server = try httpz.ServerApp(*endpoints.Global).init(allocator, .{ + server = try httpz.Server(*endpoints.Global).init(allocator, .{ .port = port, .address = "0.0.0.0", .workers = .{ @@ -118,24 +120,24 @@ pub fn main() !void { defer server.deinit(); // now that our server is up, we register our intent to handle SIGINT - try std.posix.sigaction(std.posix.SIG.INT, &.{ + std.posix.sigaction(std.posix.SIG.INT, &.{ .handler = .{ .handler = shutdown }, - .mask = std.posix.empty_sigset, + .mask = std.posix.sigemptyset(), .flags = 0, }, null); - var router = server.router(); - router.get("/json", endpoints.json); - router.get("/plaintext", endpoints.plaintext); - router.get("/db", endpoints.db); - router.get("/fortunes", endpoints.fortune); + var router = try server.router(.{}); + router.get("/json", endpoints.json, .{}); + router.get("/plaintext", endpoints.plaintext, .{}); + router.get("/db", endpoints.db, .{}); + router.get("/fortunes", endpoints.fortune, .{}); std.debug.print("Httpz using {d} workers listening at 0.0.0.0:{d}\n", .{ workers, port }); try server.listen(); } -fn shutdown(_: c_int) callconv(.C) void { +fn shutdown(_: c_int) callconv(.c) void { server.stop(); } diff --git a/frameworks/Zig/httpz/src/pool.zig b/frameworks/Zig/httpz/src/pool.zig index 91867be7906..b8944b547db 100644 --- a/frameworks/Zig/httpz/src/pool.zig +++ b/frameworks/Zig/httpz/src/pool.zig @@ -1,14 +1,11 @@ const std = @import("std"); -const regex = @import("regex"); const pg = @import("pg"); const Allocator = std.mem.Allocator; const Pool = pg.Pool; -const ArrayList = std.ArrayList; pub fn initPool(allocator: Allocator) !*pg.Pool { const info = try parsePostgresConnStr(allocator); - //std.debug.print("Connection: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); const pg_pool = try Pool.init(allocator, .{ .size = 56, From 416ff2309e9f4dce44e7d23dd865747fa376501e Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:54:59 +0100 Subject: [PATCH 046/130] [php] Update plain PHP to 8.5 (#10304) * [php] Update plain PHP to 8.5 * Fix php * FrankenPHP force PHP 8.5 * Fix Frankenphp --- frameworks/PHP/php/php-caddy.dockerfile | 8 ++++---- frameworks/PHP/php/php-eloquent.dockerfile | 8 ++++---- frameworks/PHP/php/php-franken.dockerfile | 5 ++--- frameworks/PHP/php/php-h2o.dockerfile | 4 ++-- .../PHP/php/php-laravel-query-builder.dockerfile | 8 ++++---- frameworks/PHP/php/php-pgsql-raw.dockerfile | 8 ++++---- frameworks/PHP/php/php-pools.dockerfile | 10 +++++----- frameworks/PHP/php/php-raw7-tcp.dockerfile | 10 +++++----- frameworks/PHP/php/php-workerman.dockerfile | 8 ++++---- frameworks/PHP/php/php.dockerfile | 9 ++++----- 10 files changed, 38 insertions(+), 40 deletions(-) diff --git a/frameworks/PHP/php/php-caddy.dockerfile b/frameworks/PHP/php/php-caddy.dockerfile index 3be7ccf8b61..34b48756849 100644 --- a/frameworks/PHP/php/php-caddy.dockerfile +++ b/frameworks/PHP/php/php-caddy.dockerfile @@ -7,9 +7,9 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq RUN apt-get install -yqq git unzip curl \ - php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ # Install Caddyserver RUN apt-get install -y debian-keyring debian-archive-keyring apt-transport-https > /dev/null \ @@ -20,11 +20,11 @@ RUN apt-get install -y debian-keyring debian-archive-keyring apt-transport-https ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ caddy run --config deploy/caddy/Caddyfile diff --git a/frameworks/PHP/php/php-eloquent.dockerfile b/frameworks/PHP/php/php-eloquent.dockerfile index 5f9c0616938..b912febd2a1 100644 --- a/frameworks/PHP/php/php-eloquent.dockerfile +++ b/frameworks/PHP/php/php-eloquent.dockerfile @@ -6,16 +6,16 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq nginx git unzip \ - php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-curl > /dev/null + php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; COPY deploy/eloquent/composer* ./ RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-franken.dockerfile b/frameworks/PHP/php/php-franken.dockerfile index 747a3722169..26157202e87 100644 --- a/frameworks/PHP/php/php-franken.dockerfile +++ b/frameworks/PHP/php/php-franken.dockerfile @@ -1,10 +1,9 @@ -FROM dunglas/frankenphp +FROM dunglas/frankenphp:php8.5 # add additional extensions here: RUN install-php-extensions \ pdo_mysql \ - zip \ - opcache > /dev/null + zip > /dev/null COPY --link deploy/franken/Caddyfile /etc/frankenphp/Caddyfile diff --git a/frameworks/PHP/php/php-h2o.dockerfile b/frameworks/PHP/php/php-h2o.dockerfile index a722b660011..013c6de55c0 100644 --- a/frameworks/PHP/php/php-h2o.dockerfile +++ b/frameworks/PHP/php/php-h2o.dockerfile @@ -41,7 +41,7 @@ RUN apt-get install \ FROM "ubuntu:${UBUNTU_VERSION}" -ARG PHP_VERSION=8.4 +ARG PHP_VERSION=8.5 ENV TZ=America/Los_Angeles @@ -75,5 +75,5 @@ ARG TFB_TEST_DATABASE ARG TFB_TEST_NAME CMD sed -i "s/num-threads: x/num-threads: $((2 * $(nproc)))/g" /opt/h2o/etc/h2o.conf && \ - service php8.4-fpm start && \ + service php8.5-fpm start && \ /opt/h2o/bin/h2o -c /opt/h2o/etc/h2o.conf diff --git a/frameworks/PHP/php/php-laravel-query-builder.dockerfile b/frameworks/PHP/php/php-laravel-query-builder.dockerfile index ea2e74e1c9a..0edff7f49e0 100644 --- a/frameworks/PHP/php/php-laravel-query-builder.dockerfile +++ b/frameworks/PHP/php/php-laravel-query-builder.dockerfile @@ -5,16 +5,16 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; COPY deploy/eloquent/composer* ./ RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -23,5 +23,5 @@ RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-pgsql-raw.dockerfile b/frameworks/PHP/php/php-pgsql-raw.dockerfile index c3d3c922718..2f149f52fb0 100644 --- a/frameworks/PHP/php/php-pgsql-raw.dockerfile +++ b/frameworks/PHP/php/php-pgsql-raw.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-pgsql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-pgsql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /php WORKDIR /php @@ -17,11 +17,11 @@ RUN sed -i "s|PDO('mysql:|PDO('pgsql:|g" dbquery.php RUN sed -i "s|PDO('mysql:|PDO('pgsql:|g" fortune.php RUN sed -i "s|PDO('mysql:|PDO('pgsql:|g" updateraw.php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-pools.dockerfile b/frameworks/PHP/php/php-pools.dockerfile index e217f448e88..4da9000d414 100644 --- a/frameworks/PHP/php/php-pools.dockerfile +++ b/frameworks/PHP/php/php-pools.dockerfile @@ -5,19 +5,19 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /php WORKDIR /php -COPY deploy/conf/php-fpm-pools.conf /etc/php/8.4/fpm/php-fpm.conf -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 512|pm.max_children = 256|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +COPY deploy/conf/php-fpm-pools.conf /etc/php/8.5/fpm/php-fpm.conf +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 512|pm.max_children = 256|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /php/deploy/nginx-pools.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-raw7-tcp.dockerfile b/frameworks/PHP/php/php-raw7-tcp.dockerfile index 2dde7c65ee0..989a6a27e24 100644 --- a/frameworks/PHP/php/php-raw7-tcp.dockerfile +++ b/frameworks/PHP/php/php-raw7-tcp.dockerfile @@ -5,21 +5,21 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /php WORKDIR /php -RUN sed -i "s|listen = /run/php/php-fpm.sock|listen = 127.0.0.1:9001|g" /etc/php/8.4/fpm/php-fpm.conf +RUN sed -i "s|listen = /run/php/php-fpm.sock|listen = 127.0.0.1:9001|g" /etc/php/8.5/fpm/php-fpm.conf RUN sed -i "s|server unix:/var/run/php/php-fpm.sock;|server 127.0.0.1:9001;|g" deploy/nginx7.conf -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-workerman.dockerfile b/frameworks/PHP/php/php-workerman.dockerfile index 40ce5e187af..ac049780535 100644 --- a/frameworks/PHP/php/php-workerman.dockerfile +++ b/frameworks/PHP/php/php-workerman.dockerfile @@ -7,12 +7,12 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq RUN apt-get install -yqq git unzip \ - php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -RUN apt-get install -y php-pear php8.4-dev php8.4-xml libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev php8.5-xml libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY deploy/workerman/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY deploy/workerman/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer diff --git a/frameworks/PHP/php/php.dockerfile b/frameworks/PHP/php/php.dockerfile index 495e54b5631..cdf703dddfd 100644 --- a/frameworks/PHP/php/php.dockerfile +++ b/frameworks/PHP/php/php.dockerfile @@ -6,19 +6,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq RUN apt-get install -yqq nginx git unzip \ - php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; -RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.4/fpm/conf.d/10-opcache.ini +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" From 0a9a48403f5b52775dc00a84b7adcc6bf9dbe31d Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:55:08 +0100 Subject: [PATCH 047/130] [php] KumbiaPHP update to 8.5 (#10305) * [php] KumbiaPHP update to 8.5 * Less verbose --- frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile | 8 ++++---- .../PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile | 8 ++++---- .../PHP/kumbiaphp/kumbiaphp-workerman.dockerfile | 10 +++++----- frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile index f97c728e4c9..1814858f0bf 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile @@ -7,17 +7,17 @@ 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 nginx git unzip \ - php8.4-fpm php8.4-mysql > /dev/null + php8.5-fpm php8.5-mysql > /dev/null -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /kumbiaphp COPY --link . . RUN git clone -b v1.2.1 --single-branch --depth 1 -q https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /kumbiaphp/deploy/nginx.conf diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile index 775a825d187..6389a637c2c 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile @@ -6,14 +6,14 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 git php8.4-cli php8.4-mysql php8.4-xml > /dev/null +RUN apt-get install -yqq git php8.5-cli php8.5-mysql php8.5-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY deploy/conf/cliphp.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY deploy/conf/cliphp.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini ADD ./ /kumbiaphp WORKDIR /kumbiaphp diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile index 9342ce03dbc..a5eb7d5e0af 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile @@ -3,16 +3,16 @@ 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 +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 php8.4-cli php8.4-pgsql php8.4-xml > /dev/null + apt-get install -yqq git php8.5-cli php8.5-pgsql php8.5-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY deploy/conf/cliphp.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY deploy/conf/cliphp.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini ADD ./ /kumbiaphp WORKDIR /kumbiaphp diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile index 960100a6347..db4eee13b45 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile @@ -7,18 +7,18 @@ 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 nginx git unzip \ - php8.4-fpm php8.4-mysql > /dev/null + php8.5-fpm php8.5-mysql > /dev/null -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /kumbiaphp COPY --link . . RUN git clone -b v1.2.1 --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia RUN git clone -b master --single-branch --depth 1 https://github.com/KumbiaPHP/ActiveRecord.git vendor/Kumbia/ActiveRecord -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /kumbiaphp/deploy/nginx.conf From 1a2496b27c8dcff8e0494b6991636acd2d3fc9cc Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:55:17 +0100 Subject: [PATCH 048/130] [php] Workerman update to PHP 8.5 (#10306) --- frameworks/PHP/workerman/workerman-jit.dockerfile | 8 ++++---- frameworks/PHP/workerman/workerman-mysql-jit.dockerfile | 8 ++++---- frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile | 8 ++++---- frameworks/PHP/workerman/workerman-pgsql.dockerfile | 8 ++++---- frameworks/PHP/workerman/workerman.dockerfile | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/frameworks/PHP/workerman/workerman-jit.dockerfile b/frameworks/PHP/workerman/workerman-jit.dockerfile index 47ae11800d2..5f9aa99ee81 100644 --- a/frameworks/PHP/workerman/workerman-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-jit.dockerfile @@ -10,18 +10,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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-mysql php8.4-xml > /dev/null +RUN apt-get install -yqq php8.5-cli php8.5-mysql php8.5-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -COPY php-jit.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY php-jit.ini /etc/php/8.5/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile index 8992f918a0d..913e46733f5 100644 --- a/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile @@ -10,18 +10,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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-mysql php8.4-xml > /dev/null +RUN apt-get install -yqq php8.5-cli php8.5-mysql php8.5-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -COPY php-jit.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY php-jit.ini /etc/php/8.5/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile index f1e84f54011..0eda40a8b81 100644 --- a/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile @@ -10,18 +10,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 +RUN apt-get install -yqq php8.5-cli php8.5-pgsql php8.5-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -COPY php-jit.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY php-jit.ini /etc/php/8.5/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman-pgsql.dockerfile b/frameworks/PHP/workerman/workerman-pgsql.dockerfile index f8209fb7d00..b96cc229d4e 100644 --- a/frameworks/PHP/workerman/workerman-pgsql.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql.dockerfile @@ -10,18 +10,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 +RUN apt-get install -yqq php8.5-cli php8.5-pgsql php8.5-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -COPY php.ini /etc/php/8.4/cli/php.ini +COPY php.ini /etc/php/8.5/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman.dockerfile b/frameworks/PHP/workerman/workerman.dockerfile index 8d93101166f..4ddb640e323 100644 --- a/frameworks/PHP/workerman/workerman.dockerfile +++ b/frameworks/PHP/workerman/workerman.dockerfile @@ -10,18 +10,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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-mysql php8.4-xml > /dev/null +RUN apt-get install -yqq php8.5-cli php8.5-mysql php8.5-xml > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ - pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /workerman COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -COPY php.ini /etc/php/8.4/cli/php.ini +COPY php.ini /etc/php/8.5/cli/php.ini EXPOSE 8080 From d129b2bedf83568f1e5f0735dd4eaedabce420ae Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:55:37 +0100 Subject: [PATCH 049/130] [php] Amp update to PHP 8.5 (#10307) --- frameworks/PHP/amp/amp.dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/PHP/amp/amp.dockerfile b/frameworks/PHP/amp/amp.dockerfile index 240db763cec..ced0e578009 100644 --- a/frameworks/PHP/amp/amp.dockerfile +++ b/frameworks/PHP/amp/amp.dockerfile @@ -6,19 +6,19 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php 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 php8.4-curl > /dev/null + php8.5-cli php8.5-mbstring php8.5-dev php8.5-xml php8.5-curl > /dev/null # An extension is required! # We deal with concurrencies over 1k, which stream_select doesn't support. RUN wget http://pear.php.net/go-pear.phar --quiet && php go-pear.phar #RUN apt-get install -y libuv1-dev > /dev/null RUN apt-get install -y libevent-dev > /dev/null -#RUN pecl install uv-0.2.4 > /dev/null && echo "extension=uv.so" > /etc/php/8.4/cli/conf.d/uv.ini -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +#RUN pecl install uv-0.2.4 > /dev/null && echo "extension=uv.so" > /etc/php/8.5/cli/conf.d/uv.ini +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini WORKDIR /amp COPY --link . . -COPY deploy/conf/* /etc/php/8.4/cli/conf.d/ +COPY deploy/conf/* /etc/php/8.5/cli/conf.d/ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer From 0dedb6f51c774ccbad0faf04d5302eb45581767e Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:56:33 +0100 Subject: [PATCH 050/130] [php] Webman update to PHP 8.5 (#10308) --- frameworks/PHP/webman/support/bootstrap/Date.php | 4 ++-- frameworks/PHP/webman/webman-pgsql.dockerfile | 8 ++++---- frameworks/PHP/webman/webman.dockerfile | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/PHP/webman/support/bootstrap/Date.php b/frameworks/PHP/webman/support/bootstrap/Date.php index 0101c5ad44f..31bfccbdaff 100644 --- a/frameworks/PHP/webman/support/bootstrap/Date.php +++ b/frameworks/PHP/webman/support/bootstrap/Date.php @@ -30,9 +30,9 @@ class Date implements Bootstrap { */ public static function start($worker) { - self::$date = gmdate(DATE_RFC7231); + self::$date = gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, function() { - self::$date = gmdate(DATE_RFC7231); + self::$date = gmdate('D, d M Y H:i:s \G\M\T'); }); } diff --git a/frameworks/PHP/webman/webman-pgsql.dockerfile b/frameworks/PHP/webman/webman-pgsql.dockerfile index 2fe12ba3529..3db45c4aed2 100644 --- a/frameworks/PHP/webman/webman-pgsql.dockerfile +++ b/frameworks/PHP/webman/webman-pgsql.dockerfile @@ -8,18 +8,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 +RUN apt-get install -yqq php8.5-cli php8.5-pgsql php8.5-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 +RUN apt-get update -yqq && apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /webman 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 +COPY php.ini /etc/php/8.5/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/webman/webman.dockerfile b/frameworks/PHP/webman/webman.dockerfile index 6020fed75ed..83ff704032d 100644 --- a/frameworks/PHP/webman/webman.dockerfile +++ b/frameworks/PHP/webman/webman.dockerfile @@ -8,18 +8,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 +RUN apt-get install -yqq php8.5-cli php8.5-pgsql php8.5-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 +RUN apt-get update -yqq && apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/30-event.ini WORKDIR /webman 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 +COPY php.ini /etc/php/8.5/cli/conf.d/10-opcache.ini EXPOSE 8080 From 4f48c6f5ebed85e4418b7211fc2917db777f6bec Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:56:54 +0100 Subject: [PATCH 051/130] [php] Comet update to PHP 8.5 (#10309) --- frameworks/PHP/comet/app.php | 4 ++-- frameworks/PHP/comet/comet-mysql.dockerfile | 8 ++++---- frameworks/PHP/comet/comet.dockerfile | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/PHP/comet/app.php b/frameworks/PHP/comet/app.php index 857853bc9ec..f0ef91fbece 100644 --- a/frameworks/PHP/comet/app.php +++ b/frameworks/PHP/comet/app.php @@ -24,9 +24,9 @@ $app->init( function() { ORM::init(); - Storage::$date = gmdate(DATE_RFC7231); + Storage::$date = gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, function() { - Storage::$date = gmdate(DATE_RFC7231); + Storage::$date = gmdate('D, d M Y H:i:s \G\M\T'); }); }); diff --git a/frameworks/PHP/comet/comet-mysql.dockerfile b/frameworks/PHP/comet/comet-mysql.dockerfile index 2adc4d70f81..778b6d3c276 100644 --- a/frameworks/PHP/comet/comet-mysql.dockerfile +++ b/frameworks/PHP/comet/comet-mysql.dockerfile @@ -6,14 +6,14 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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.3-cli php8.3-xml php8.3-mysql php8.3-mbstring > /dev/null +RUN apt-get install -yqq php8.5-cli php8.5-xml php8.5-mysql php8.5-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY php.ini /etc/php/8.3/cli/php.ini +COPY php.ini /etc/php/8.5/cli/php.ini ADD ./ /comet WORKDIR /comet diff --git a/frameworks/PHP/comet/comet.dockerfile b/frameworks/PHP/comet/comet.dockerfile index 2cfbc0935c6..f7a98ab36aa 100644 --- a/frameworks/PHP/comet/comet.dockerfile +++ b/frameworks/PHP/comet/comet.dockerfile @@ -6,14 +6,14 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 php8.4-mbstring > /dev/null +RUN apt-get install -yqq php8.5-cli php8.5-pgsql php8.5-xml php8.5-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null -RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY php.ini /etc/php/8.4/cli/php.ini +COPY php.ini /etc/php/8.5/cli/php.ini ADD ./ /comet WORKDIR /comet From 14508660aacba242d9d10fe191de090a71a8fac5 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:57:02 +0100 Subject: [PATCH 052/130] [php] Mark update to PHP 8.5 (#10310) --- frameworks/PHP/mark/mark.dockerfile | 10 +++++----- frameworks/PHP/mark/start.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frameworks/PHP/mark/mark.dockerfile b/frameworks/PHP/mark/mark.dockerfile index 7f6b8180969..05400be1cfa 100644 --- a/frameworks/PHP/mark/mark.dockerfile +++ b/frameworks/PHP/mark/mark.dockerfile @@ -5,20 +5,20 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null + apt-get install -yqq php8.5-cli php8.5-pgsql php8.5-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null -RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY php.ini /etc/php/8.4/cli/php.ini +COPY php.ini /etc/php/8.5/cli/php.ini ADD ./ /mark WORKDIR /mark RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN sed -i "s|opcache.jit=off|opcache.jit=tracing|g" /etc/php/8.4/cli/conf.d/10-opcache.ini +#RUN sed -i "s|opcache.jit=off|opcache.jit=tracing|g" /etc/php/8.5/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/mark/start.php b/frameworks/PHP/mark/start.php index b1f96ce9ffd..b785005e679 100644 --- a/frameworks/PHP/mark/start.php +++ b/frameworks/PHP/mark/start.php @@ -27,12 +27,12 @@ ], \json_encode(['message' => 'Hello, World!'])); }); -$date = gmdate(DATE_RFC7231); +$date = gmdate('D, d M Y H:i:s \G\M\T'); $api->onWorkerStart = static function () { Timer::add(1, function () { global $date; - $date = gmdate(DATE_RFC7231); + $date = gmdate('D, d M Y H:i:s \G\M\T'); }); }; From 95038a3736903ea7b81ef014ee9d39b0cabe97cc Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:57:19 +0100 Subject: [PATCH 053/130] [php] CodeIgniter update to PHP 8.5 (#10311) --- frameworks/PHP/codeigniter/codeigniter.dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/PHP/codeigniter/codeigniter.dockerfile b/frameworks/PHP/codeigniter/codeigniter.dockerfile index 097ea60514d..0737e1eeed9 100644 --- a/frameworks/PHP/codeigniter/codeigniter.dockerfile +++ b/frameworks/PHP/codeigniter/codeigniter.dockerfile @@ -7,16 +7,16 @@ 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 update > /dev/null && apt-get install -yqq nginx git unzip \ - php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-intl php8.4-curl > /dev/null + php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-intl php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /codeigniter WORKDIR /codeigniter -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev #--quiet @@ -25,5 +25,5 @@ RUN chmod -R 777 writable EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /codeigniter/deploy/nginx.conf From 7ba41171a54e54b44b28bd3e19e4f3bfa4e7ebf0 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:57:42 +0100 Subject: [PATCH 054/130] [php] Flight update to PHP 8.5 (#10312) * [php] Flight update to PHP 8.5 * Fix deprecated constant --- frameworks/PHP/flight/flight-workerman.dockerfile | 8 ++++---- frameworks/PHP/flight/flight.dockerfile | 8 ++++---- frameworks/PHP/flight/server.php | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/PHP/flight/flight-workerman.dockerfile b/frameworks/PHP/flight/flight-workerman.dockerfile index ebaa2098243..ec9f644e16f 100644 --- a/frameworks/PHP/flight/flight-workerman.dockerfile +++ b/frameworks/PHP/flight/flight-workerman.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /flight COPY . . @@ -16,8 +16,8 @@ ENV FLIGHT_DIR="/flight/src" COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev php8.4-xml > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev php8.5-xml > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini RUN composer require joanhey/adapterman:^0.7 RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet diff --git a/frameworks/PHP/flight/flight.dockerfile b/frameworks/PHP/flight/flight.dockerfile index 60b2b3ebc7a..51f64fb97b5 100644 --- a/frameworks/PHP/flight/flight.dockerfile +++ b/frameworks/PHP/flight/flight.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /flight COPY --link . . @@ -18,11 +18,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /flight EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /flight/deploy/nginx.conf diff --git a/frameworks/PHP/flight/server.php b/frameworks/PHP/flight/server.php index 826e74e38ec..06f562cd98a 100644 --- a/frameworks/PHP/flight/server.php +++ b/frameworks/PHP/flight/server.php @@ -37,9 +37,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, static function () { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); }); } } From 48dfc638a1c3fb1a75aa9ba7451dda3df72ddb18 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:57:55 +0100 Subject: [PATCH 055/130] [php] Leaf update to PHP 8.5 (#10313) --- frameworks/PHP/leaf/leaf-workerman.dockerfile | 8 ++++---- frameworks/PHP/leaf/leaf.dockerfile | 8 ++++---- frameworks/PHP/leaf/server.php | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/PHP/leaf/leaf-workerman.dockerfile b/frameworks/PHP/leaf/leaf-workerman.dockerfile index c98f11f5c84..ec7038b780d 100644 --- a/frameworks/PHP/leaf/leaf-workerman.dockerfile +++ b/frameworks/PHP/leaf/leaf-workerman.dockerfile @@ -7,15 +7,15 @@ 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 update -yqq > /dev/null && apt-get install -yqq git \ - php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl php8.4-zip > /dev/null + php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml php8.5-curl php8.5-zip > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y libevent-dev php8.4-dev > /dev/null \ +RUN apt-get install -y libevent-dev php8.5-dev > /dev/null \ && pecl install event-3.1.4 > /dev/null \ - && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini + && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini WORKDIR /leaf COPY --link . . diff --git a/frameworks/PHP/leaf/leaf.dockerfile b/frameworks/PHP/leaf/leaf.dockerfile index 1ebe23e5735..c9d1d8a88e5 100644 --- a/frameworks/PHP/leaf/leaf.dockerfile +++ b/frameworks/PHP/leaf/leaf.dockerfile @@ -7,16 +7,16 @@ 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 nginx git unzip \ - php8.4-cli php8.4-fpm php8.4-mysql php8.4-xml php8.4-curl php8.4-zip > /dev/null + php8.5-cli php8.5-fpm php8.5-mysql php8.5-xml php8.5-curl php8.5-zip > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /leaf COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 /leaf EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /leaf/deploy/nginx.conf diff --git a/frameworks/PHP/leaf/server.php b/frameworks/PHP/leaf/server.php index 4e931b07e33..91ac664aabb 100644 --- a/frameworks/PHP/leaf/server.php +++ b/frameworks/PHP/leaf/server.php @@ -39,9 +39,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, static function() { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); }); } } \ No newline at end of file From dbe23a602426678060e507529681cd044c89b334 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:58:07 +0100 Subject: [PATCH 056/130] [php] Nette update to PHP 8.5 (#10314) --- frameworks/PHP/nette/nette.dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/PHP/nette/nette.dockerfile b/frameworks/PHP/nette/nette.dockerfile index 0e66d630510..dde675a0e1e 100644 --- a/frameworks/PHP/nette/nette.dockerfile +++ b/frameworks/PHP/nette/nette.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get install -yqq nginx git unzip \ - php8.4-fpm php8.4-mysql php8.4-xml php8.4-mbstring php8.4-intl php8.4-dev php8.4-curl > /dev/null + php8.5-fpm php8.5-mysql php8.5-xml php8.5-mbstring php8.5-intl php8.5-dev php8.5-curl > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /nette COPY --link . . @@ -17,11 +17,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /nette EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /nette/deploy/nginx.conf 2>&1 > /dev/stderr From aaf150ff68d38c530bf206f03b48fc47d2758893 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:58:25 +0100 Subject: [PATCH 057/130] [php] ReactPHP update to PHP 8.5 (#10316) --- frameworks/PHP/reactphp/reactphp-libuv.dockerfile | 8 ++++---- frameworks/PHP/reactphp/reactphp.dockerfile | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frameworks/PHP/reactphp/reactphp-libuv.dockerfile b/frameworks/PHP/reactphp/reactphp-libuv.dockerfile index 48126b5c59c..96040a738ca 100644 --- a/frameworks/PHP/reactphp/reactphp-libuv.dockerfile +++ b/frameworks/PHP/reactphp/reactphp-libuv.dockerfile @@ -6,23 +6,23 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 + php8.5-cli php8.5-mbstring php8.5-dev php8.5-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 + && echo "extension=uv.so" > /etc/php/8.5/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 +# && echo "extension=event.so" > /etc/php/8.5/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/ +COPY --link deploy/conf/* /etc/php/8.5/cli/conf.d/ WORKDIR /reactphp COPY --link . . diff --git a/frameworks/PHP/reactphp/reactphp.dockerfile b/frameworks/PHP/reactphp/reactphp.dockerfile index 0ecb546a1c3..f6f3cacbd6f 100644 --- a/frameworks/PHP/reactphp/reactphp.dockerfile +++ b/frameworks/PHP/reactphp/reactphp.dockerfile @@ -6,23 +6,23 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 + php8.5-cli php8.5-mbstring php8.5-dev php8.5-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 +# && echo "extension=uv.so" > /etc/php/8.5/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 + && echo "extension=event.so" > /etc/php/8.5/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/ +COPY --link deploy/conf/* /etc/php/8.5/cli/conf.d/ WORKDIR /reactphp COPY --link . . From 76190d70387ef59a21fef0b575051711fb659824 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:58:32 +0100 Subject: [PATCH 058/130] [php] Slim update to PHP 8.5 (#10317) --- frameworks/PHP/slim/server.php | 4 ++-- frameworks/PHP/slim/slim-workerman-pgsql.dockerfile | 8 ++++---- frameworks/PHP/slim/slim-workerman.dockerfile | 8 ++++---- frameworks/PHP/slim/slim.dockerfile | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frameworks/PHP/slim/server.php b/frameworks/PHP/slim/server.php index 7eafd061037..1fb5665fe0d 100644 --- a/frameworks/PHP/slim/server.php +++ b/frameworks/PHP/slim/server.php @@ -39,9 +39,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, static function() { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); }); } } \ No newline at end of file diff --git a/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile b/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile index 8a06648dd86..aedf38ca656 100644 --- a/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile +++ b/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile @@ -8,14 +8,14 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq git \ - php8.4-cli php8.4-pgsql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-pgsql php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY deploy/conf/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini WORKDIR /slim COPY --link . . diff --git a/frameworks/PHP/slim/slim-workerman.dockerfile b/frameworks/PHP/slim/slim-workerman.dockerfile index a8c535bb05c..1795da7a5b7 100644 --- a/frameworks/PHP/slim/slim-workerman.dockerfile +++ b/frameworks/PHP/slim/slim-workerman.dockerfile @@ -7,14 +7,14 @@ 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 update -yqq > /dev/null && apt-get install -yqq git \ - php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY deploy/conf/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini WORKDIR /slim COPY --link . . diff --git a/frameworks/PHP/slim/slim.dockerfile b/frameworks/PHP/slim/slim.dockerfile index c81bf1e051f..496497d65ee 100644 --- a/frameworks/PHP/slim/slim.dockerfile +++ b/frameworks/PHP/slim/slim.dockerfile @@ -7,16 +7,16 @@ 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 nginx git unzip \ - php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-xml php8.4-curl > /dev/null + php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql php8.5-xml php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /slim COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 /slim EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /slim/deploy/nginx.conf From 2cf7b9d7f465e61b480e9d30fc86a74efcd9387a Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:58:52 +0100 Subject: [PATCH 059/130] [php] Wolff update to PHP 8.5 (#10319) --- frameworks/PHP/wolff/server.php | 4 ++-- frameworks/PHP/wolff/wolff-workerman.dockerfile | 8 ++++---- frameworks/PHP/wolff/wolff.dockerfile | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/PHP/wolff/server.php b/frameworks/PHP/wolff/server.php index 507f3df619f..af725b39df4 100644 --- a/frameworks/PHP/wolff/server.php +++ b/frameworks/PHP/wolff/server.php @@ -39,9 +39,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, static function() { - self::$date = self::NAME . gmdate(DATE_RFC7231); + self::$date = self::NAME . gmdate('D, d M Y H:i:s \G\M\T'); }); } } \ No newline at end of file diff --git a/frameworks/PHP/wolff/wolff-workerman.dockerfile b/frameworks/PHP/wolff/wolff-workerman.dockerfile index 920de95b389..0895fe91c11 100644 --- a/frameworks/PHP/wolff/wolff-workerman.dockerfile +++ b/frameworks/PHP/wolff/wolff-workerman.dockerfile @@ -7,14 +7,14 @@ 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 update -yqq > /dev/null && apt-get install -yqq git \ - php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY deploy/conf/adapterman-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY deploy/conf/adapterman-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini WORKDIR /wolff/bench COPY --link . . diff --git a/frameworks/PHP/wolff/wolff.dockerfile b/frameworks/PHP/wolff/wolff.dockerfile index d3dfc84bfad..a722286902e 100644 --- a/frameworks/PHP/wolff/wolff.dockerfile +++ b/frameworks/PHP/wolff/wolff.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get install -yqq nginx git unzip \ - php8.4-fpm php8.4-mysql php8.4-xml php8.4-mbstring php8.4-intl php8.4-dev php8.4-curl > /dev/null + php8.5-fpm php8.5-mysql php8.5-xml php8.5-mbstring php8.5-intl php8.5-dev php8.5-curl > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /wolff COPY --link . . @@ -16,11 +16,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /wolff EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /wolff/deploy/nginx.conf 2>&1 > /dev/stderr From 60effe1cf47ad97721d59a570c99679f236b2faa Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:59:02 +0100 Subject: [PATCH 060/130] [php] Yii2 update to PHP 8.5 (#10320) --- frameworks/PHP/yii2/server.php | 4 ++-- frameworks/PHP/yii2/yii2-raw.dockerfile | 8 ++++---- frameworks/PHP/yii2/yii2-workerman.dockerfile | 8 ++++---- frameworks/PHP/yii2/yii2.dockerfile | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frameworks/PHP/yii2/server.php b/frameworks/PHP/yii2/server.php index 59fe04b19f1..932124b2775 100644 --- a/frameworks/PHP/yii2/server.php +++ b/frameworks/PHP/yii2/server.php @@ -34,9 +34,9 @@ class WorkerTimer public static function init() { - self::$date = 'Date: ' . gmdate(DATE_RFC7231); + self::$date = 'Date: ' . gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, function() { - WorkerTimer::$date = 'Date: ' . gmdate(DATE_RFC7231); + WorkerTimer::$date = 'Date: ' . gmdate('D, d M Y H:i:s \G\M\T'); }); } } diff --git a/frameworks/PHP/yii2/yii2-raw.dockerfile b/frameworks/PHP/yii2/yii2-raw.dockerfile index cfb0bf78a38..d826e74f4e1 100644 --- a/frameworks/PHP/yii2/yii2-raw.dockerfile +++ b/frameworks/PHP/yii2/yii2-raw.dockerfile @@ -5,20 +5,20 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /yii2 COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /yii2/deploy/nginx.conf diff --git a/frameworks/PHP/yii2/yii2-workerman.dockerfile b/frameworks/PHP/yii2/yii2-workerman.dockerfile index 204aeaf58a8..ec889ad9d97 100644 --- a/frameworks/PHP/yii2/yii2-workerman.dockerfile +++ b/frameworks/PHP/yii2/yii2-workerman.dockerfile @@ -5,14 +5,14 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml > /dev/null + apt-get install -yqq git php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini WORKDIR /yii2 COPY --link . . diff --git a/frameworks/PHP/yii2/yii2.dockerfile b/frameworks/PHP/yii2/yii2.dockerfile index cfb0bf78a38..d826e74f4e1 100644 --- a/frameworks/PHP/yii2/yii2.dockerfile +++ b/frameworks/PHP/yii2/yii2.dockerfile @@ -5,20 +5,20 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /yii2 COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /yii2/deploy/nginx.conf From 2c4a992d464ec6d3e8c04660d4cd58e21179d266 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:59:17 +0100 Subject: [PATCH 061/130] [php] Spiral update to PHP 8.5 (#10325) --- frameworks/PHP/spiral/spiral.dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frameworks/PHP/spiral/spiral.dockerfile b/frameworks/PHP/spiral/spiral.dockerfile index 22f390d0e49..5dc788a4e1d 100644 --- a/frameworks/PHP/spiral/spiral.dockerfile +++ b/frameworks/PHP/spiral/spiral.dockerfile @@ -1,10 +1,9 @@ -FROM php:8.4-cli +FROM php:8.5-cli RUN apt-get update -yqq > /dev/null && apt-get install -yqq git unzip > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer RUN docker-php-ext-install \ - opcache \ pdo_mysql \ sockets > /dev/null From 2219f26b77b85402fe532aa8ee711215f12b6bd5 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 17:59:41 +0100 Subject: [PATCH 062/130] [php] Ripple update to PHP 8.5 (#10326) * [php] Ripple update to PHP 8.5 * Add posix --- frameworks/PHP/ripple/ripple.dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frameworks/PHP/ripple/ripple.dockerfile b/frameworks/PHP/ripple/ripple.dockerfile index 138d91d0918..796dce5165f 100644 --- a/frameworks/PHP/ripple/ripple.dockerfile +++ b/frameworks/PHP/ripple/ripple.dockerfile @@ -1,4 +1,4 @@ -FROM php:8.3-cli +FROM php:8.5-cli RUN apt-get update -yqq >> /dev/null RUN apt-get install -y libevent-dev \ @@ -10,7 +10,6 @@ RUN apt-get install -y libevent-dev \ RUN docker-php-ext-install pdo_mysql \ ffi \ - opcache \ posix \ pcntl \ sockets >> /dev/null From 7c714bec9053cf529889c3ad41027711ef759071 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 18:04:47 +0100 Subject: [PATCH 063/130] [php] Laravel update to PHP 8.5 (#10323) * [php] Laravel update to PHP 8.5 * [php] Laravel update to PHP 8.5 * Fix Laravel-s * Small changes * Enable OPCache in Laravel-S --- .../PHP/laravel/laravel-octane-frankenphp.dockerfile | 6 ++++-- frameworks/PHP/laravel/laravel-ripple.dockerfile | 8 +++++--- frameworks/PHP/laravel/laravel-roadrunner.dockerfile | 9 ++++++--- frameworks/PHP/laravel/laravel-swoole.dockerfile | 4 ++-- frameworks/PHP/laravel/laravel-workerman.dockerfile | 8 ++++---- frameworks/PHP/laravel/laravel.dockerfile | 10 +++++----- frameworks/PHP/laravel/server-man.php | 4 ++-- 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile index da9fc1c16c5..dc2e4724395 100644 --- a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile +++ b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile @@ -1,6 +1,8 @@ -FROM dunglas/frankenphp +FROM dunglas/frankenphp:php8.5 -RUN apt-get update -yqq && apt-get install libicu-dev unzip -y +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -yqq && apt-get install libicu-dev unzip -y > /dev/null RUN install-php-extensions \ intl \ pcntl \ diff --git a/frameworks/PHP/laravel/laravel-ripple.dockerfile b/frameworks/PHP/laravel/laravel-ripple.dockerfile index 0ce2de40016..101b458a051 100644 --- a/frameworks/PHP/laravel/laravel-ripple.dockerfile +++ b/frameworks/PHP/laravel/laravel-ripple.dockerfile @@ -1,4 +1,6 @@ -FROM php:8.3-cli +FROM php:8.5-cli + +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq >> /dev/null RUN apt-get install -y libevent-dev \ @@ -9,14 +11,14 @@ RUN apt-get install -y libevent-dev \ unzip >> /dev/null RUN docker-php-ext-install pdo_mysql \ - opcache \ + intl \ posix \ pcntl \ sockets >> /dev/null RUN pecl install event >> /dev/null -RUN docker-php-ext-enable intl pdo_mysql opcache posix pcntl sockets +RUN docker-php-ext-enable intl pdo_mysql posix pcntl sockets RUN docker-php-ext-enable --ini-name zz-event.ini event RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini diff --git a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile index 730df104fea..44c97267c12 100644 --- a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile +++ b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile @@ -1,7 +1,10 @@ -FROM php:8.4-cli +FROM php:8.5-cli + +ARG DEBIAN_FRONTEND=noninteractive + RUN apt-get update -yqq && \ apt-get install -yqq libpq-dev libicu-dev > /dev/null && \ -docker-php-ext-install intl pdo_mysql pcntl opcache sockets > /dev/null +docker-php-ext-install intl pdo_mysql pcntl sockets > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini @@ -24,7 +27,7 @@ RUN pecl install protobuf > /dev/null && echo "extension=protobuf.so" > /usr/loc COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer RUN composer require laravel/octane --update-no-dev --no-scripts --quiet -RUN php artisan octane:install --server="roadrunner" +RUN php artisan octane:install --server="roadrunner" > /dev/null RUN php artisan optimize RUN export WORKERS=$((1*$(nproc))) diff --git a/frameworks/PHP/laravel/laravel-swoole.dockerfile b/frameworks/PHP/laravel/laravel-swoole.dockerfile index 89dacff8abe..ae51b9d0ad1 100644 --- a/frameworks/PHP/laravel/laravel-swoole.dockerfile +++ b/frameworks/PHP/laravel/laravel-swoole.dockerfile @@ -1,7 +1,7 @@ FROM phpswoole/swoole:php8.4 -RUN apt-get update -yqq && apt-get install libicu-dev -y -RUN docker-php-ext-install intl pcntl opcache> /dev/null +RUN apt-get update -yqq && apt-get install libicu-dev -y > /dev/null +RUN docker-php-ext-install intl pcntl opcache > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini diff --git a/frameworks/PHP/laravel/laravel-workerman.dockerfile b/frameworks/PHP/laravel/laravel-workerman.dockerfile index d652fa11f84..a9cd1313cc7 100644 --- a/frameworks/PHP/laravel/laravel-workerman.dockerfile +++ b/frameworks/PHP/laravel/laravel-workerman.dockerfile @@ -6,12 +6,12 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 && \ apt-get install -yqq git unzip \ - php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-intl php8.4-curl > /dev/null + php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml php8.5-intl php8.5-curl > /dev/null COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini WORKDIR /laravel COPY --link . . @@ -25,7 +25,7 @@ RUN mkdir -p bootstrap/cache \ RUN composer require joanhey/adapterman --update-no-dev --no-scripts --quiet RUN php artisan optimize -COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini EXPOSE 8080 diff --git a/frameworks/PHP/laravel/laravel.dockerfile b/frameworks/PHP/laravel/laravel.dockerfile index 13ca827c6d3..46d5aca59cc 100644 --- a/frameworks/PHP/laravel/laravel.dockerfile +++ b/frameworks/PHP/laravel/laravel.dockerfile @@ -7,15 +7,15 @@ 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 nginx git unzip \ - php8.4-bcmath php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl php8.4-intl > /dev/null + php8.5-bcmath php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-xml php8.5-curl php8.5-intl > /dev/null COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /laravel COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN mkdir -p bootstrap/cache \ storage/logs \ @@ -29,7 +29,7 @@ RUN php artisan optimize EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.5/fpm/php-fpm.conf -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /laravel/deploy/nginx.conf diff --git a/frameworks/PHP/laravel/server-man.php b/frameworks/PHP/laravel/server-man.php index 6aa249cce8f..1816cd90c29 100644 --- a/frameworks/PHP/laravel/server-man.php +++ b/frameworks/PHP/laravel/server-man.php @@ -13,9 +13,9 @@ $http_worker->reusePort = true; $http_worker->name = 'AdapterMan-Laravel'; $http_worker->onWorkerStart = static function () { - Header::$date = gmdate(DATE_RFC7231); + Header::$date = gmdate('D, d M Y H:i:s \G\M\T'); Timer::add(1, function() { - Header::$date = gmdate(DATE_RFC7231); + Header::$date = gmdate('D, d M Y H:i:s \G\M\T'); }); //init(); require __DIR__.'/start.php'; From 844f0c8d5789544e6d9caabc1725742a1be866dd Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 18:05:05 +0100 Subject: [PATCH 064/130] [php] Symfony update to PHP 8.5 (#10322) * [php] Symfony update to PHP 8.5 * Update and fix DbRawController --- .../PHP/symfony/config/packages/doctrine.yaml | 1 - .../symfony/config/packages/prod/doctrine.yaml | 1 - .../symfony/src/Controller/DbRawController.php | 18 +++++++++--------- .../PHP/symfony/symfony-franken.dockerfile | 3 +-- .../PHP/symfony/symfony-mysql.dockerfile | 14 +++++++------- frameworks/PHP/symfony/symfony-raw.dockerfile | 14 +++++++------- .../PHP/symfony/symfony-react.dockerfile | 4 ++-- .../PHP/symfony/symfony-roadrunner.dockerfile | 3 +-- .../PHP/symfony/symfony-workerman.dockerfile | 8 ++++---- frameworks/PHP/symfony/symfony.dockerfile | 14 +++++++------- 10 files changed, 38 insertions(+), 42 deletions(-) diff --git a/frameworks/PHP/symfony/config/packages/doctrine.yaml b/frameworks/PHP/symfony/config/packages/doctrine.yaml index 6d22e583379..4aea981408f 100644 --- a/frameworks/PHP/symfony/config/packages/doctrine.yaml +++ b/frameworks/PHP/symfony/config/packages/doctrine.yaml @@ -11,7 +11,6 @@ doctrine: !php/const \PDO::ATTR_PERSISTENT: true url: '%env(resolve:DATABASE_URL)%' orm: - auto_generate_proxy_classes: true naming_strategy: doctrine.orm.naming_strategy.default auto_mapping: true mappings: diff --git a/frameworks/PHP/symfony/config/packages/prod/doctrine.yaml b/frameworks/PHP/symfony/config/packages/prod/doctrine.yaml index 93d4ec59e8d..b9ce62903f1 100644 --- a/frameworks/PHP/symfony/config/packages/prod/doctrine.yaml +++ b/frameworks/PHP/symfony/config/packages/prod/doctrine.yaml @@ -1,6 +1,5 @@ doctrine: orm: - auto_generate_proxy_classes: false metadata_cache_driver: type: pool pool: doctrine.system_cache_pool diff --git a/frameworks/PHP/symfony/src/Controller/DbRawController.php b/frameworks/PHP/symfony/src/Controller/DbRawController.php index 098de3246ef..616d0218da4 100644 --- a/frameworks/PHP/symfony/src/Controller/DbRawController.php +++ b/frameworks/PHP/symfony/src/Controller/DbRawController.php @@ -3,7 +3,6 @@ namespace App\Controller; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\FetchMode; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; @@ -22,8 +21,7 @@ public function __construct(Connection $connection) public function db(): JsonResponse { - $statement = $this->connection->prepare('SELECT id,randomNumber FROM World WHERE id = ?'); - $world = $statement->execute([mt_rand(1, 10000)]); + $world = $this->connection->executeQuery('SELECT id,randomNumber FROM World WHERE id = ?', [mt_rand(1, 10000)]); return new JsonResponse($world->fetchAssociative()); } @@ -40,7 +38,8 @@ public function queries(Request $request): JsonResponse $statement = $this->connection->prepare('SELECT id,randomNumber FROM World WHERE id = ?'); for ($i = 0; $i < $queries; ++$i) { - $world = $statement->execute([mt_rand(1, 10000)]); + $statement->bindValue(1, mt_rand(1, 10000)); + $world = $statement->executeQuery(); $worlds[] = $world->fetchAssociative(); } @@ -61,11 +60,12 @@ public function updates(Request $request): JsonResponse for ($i = 0; $i < $queries; ++$i) { $id = mt_rand(1, 10000); - $world = $readStatement->execute([$id]); - $world = $world->fetchAssociative(); - $writeStatement->execute( - [$world['randomNumber'] = mt_rand(1, 10000), $id] - ); + $readStatement->bindValue(1, $id); + $world = $readStatement->executeQuery(); + $world = $world->fetchAssociative(); + $writeStatement->bindValue(1, mt_rand(1, 10000)); + $writeStatement->bindValue(2, $id); + $writeStatement->executeStatement(); $worlds[] = $world; } diff --git a/frameworks/PHP/symfony/symfony-franken.dockerfile b/frameworks/PHP/symfony/symfony-franken.dockerfile index a985294ab58..e20064e6a95 100644 --- a/frameworks/PHP/symfony/symfony-franken.dockerfile +++ b/frameworks/PHP/symfony/symfony-franken.dockerfile @@ -1,8 +1,7 @@ -FROM dunglas/frankenphp:php8.4 +FROM dunglas/frankenphp:php8.5 # add additional extensions here: RUN install-php-extensions \ - opcache \ pdo_pgsql \ zip > /dev/null diff --git a/frameworks/PHP/symfony/symfony-mysql.dockerfile b/frameworks/PHP/symfony/symfony-mysql.dockerfile index a09d877ade2..6fa2403d108 100644 --- a/frameworks/PHP/symfony/symfony-mysql.dockerfile +++ b/frameworks/PHP/symfony/symfony-mysql.dockerfile @@ -7,27 +7,27 @@ 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 nginx git unzip curl \ - php8.4-cli php8.4-fpm php8.4-mysql \ - php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-fpm php8.5-mysql \ + php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /symfony COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/mysql/.env . && composer dump-env prod && bin/console cache:clear -RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.4/fpm/php.ini +RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.5/fpm/php.ini EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.5/fpm/php-fpm.conf RUN mkdir -p /run/php -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /symfony/deploy/nginx.conf \ No newline at end of file diff --git a/frameworks/PHP/symfony/symfony-raw.dockerfile b/frameworks/PHP/symfony/symfony-raw.dockerfile index a2622d5a397..130fe781d15 100644 --- a/frameworks/PHP/symfony/symfony-raw.dockerfile +++ b/frameworks/PHP/symfony/symfony-raw.dockerfile @@ -7,27 +7,27 @@ 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 nginx git unzip curl \ - php8.4-cli php8.4-fpm php8.4-pgsql \ - php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-fpm php8.5-pgsql \ + php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /symfony COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.4/fpm/php.ini +RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.5/fpm/php.ini EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.5/fpm/php-fpm.conf RUN mkdir -p /run/php -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /symfony/deploy/nginx.conf diff --git a/frameworks/PHP/symfony/symfony-react.dockerfile b/frameworks/PHP/symfony/symfony-react.dockerfile index e2a47c08f73..3b57b331e76 100644 --- a/frameworks/PHP/symfony/symfony-react.dockerfile +++ b/frameworks/PHP/symfony/symfony-react.dockerfile @@ -1,8 +1,8 @@ -FROM php:8.4-cli +FROM php:8.5-cli RUN apt-get update -yqq && \ apt-get install -yqq libpq-dev libicu-dev git > /dev/null && \ - docker-php-ext-install pdo_pgsql opcache intl pcntl > /dev/null + docker-php-ext-install pdo_pgsql intl pcntl > /dev/null COPY --link deploy/swoole/php.ini /usr/local/etc/php/ WORKDIR /symfony diff --git a/frameworks/PHP/symfony/symfony-roadrunner.dockerfile b/frameworks/PHP/symfony/symfony-roadrunner.dockerfile index a388570c60f..7fae6298c8b 100644 --- a/frameworks/PHP/symfony/symfony-roadrunner.dockerfile +++ b/frameworks/PHP/symfony/symfony-roadrunner.dockerfile @@ -1,4 +1,4 @@ -FROM php:8.4-cli +FROM php:8.5-cli COPY --from=ghcr.io/roadrunner-server/roadrunner:2025.1 --link /usr/bin/rr /usr/local/bin/rr COPY --from=mlocati/php-extension-installer --link /usr/bin/install-php-extensions /usr/local/bin/ @@ -6,7 +6,6 @@ COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/compose RUN install-php-extensions \ intl \ - opcache \ pdo_pgsql \ sockets \ zip > /dev/null diff --git a/frameworks/PHP/symfony/symfony-workerman.dockerfile b/frameworks/PHP/symfony/symfony-workerman.dockerfile index 480b734100a..fe5d5ce9ba6 100644 --- a/frameworks/PHP/symfony/symfony-workerman.dockerfile +++ b/frameworks/PHP/symfony/symfony-workerman.dockerfile @@ -7,12 +7,12 @@ 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 unzip \ - php8.4-cli php8.4-pgsql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-pgsql php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev 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 +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini WORKDIR /symfony COPY --link . . @@ -20,7 +20,7 @@ COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.5/cli/conf.d/20-adapterman.ini EXPOSE 8080 diff --git a/frameworks/PHP/symfony/symfony.dockerfile b/frameworks/PHP/symfony/symfony.dockerfile index 1d2fd84193f..6d685dfb987 100644 --- a/frameworks/PHP/symfony/symfony.dockerfile +++ b/frameworks/PHP/symfony/symfony.dockerfile @@ -7,28 +7,28 @@ 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 nginx git unzip curl \ - php8.4-bcmath php8.4-cli php8.4-fpm php8.4-pgsql \ - php8.4-mbstring php8.4-xml php8.4-curl php8.4-intl > /dev/null + php8.5-bcmath php8.5-cli php8.5-fpm php8.5-pgsql \ + php8.5-mbstring php8.5-xml php8.5-curl php8.5-intl > /dev/null COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY --link deploy/conf/* /etc/php/8.4/fpm/ +COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /symfony COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.4/fpm/php.ini +RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.5/fpm/php.ini EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.5/fpm/php-fpm.conf RUN mkdir -p /run/php -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /symfony/deploy/nginx.conf \ No newline at end of file From 9ec43b9f3dfc5ecb77d10f2d2c5ee0c2b1bdc367 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 25 Nov 2025 18:05:13 +0100 Subject: [PATCH 065/130] [php] Piko update to PHP 8.5 (#10315) --- frameworks/PHP/piko/piko-postgres.dockerfile | 8 ++++---- frameworks/PHP/piko/piko.dockerfile | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frameworks/PHP/piko/piko-postgres.dockerfile b/frameworks/PHP/piko/piko-postgres.dockerfile index 6f9b970d864..a274ebaea63 100644 --- a/frameworks/PHP/piko/piko-postgres.dockerfile +++ b/frameworks/PHP/piko/piko-postgres.dockerfile @@ -6,9 +6,9 @@ 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 -RUN apt-get install -yqq nginx git unzip php8.4-fpm php8.4-pgsql > /dev/null +RUN apt-get install -yqq nginx git unzip php8.5-fpm php8.5-pgsql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /piko COPY --link . . @@ -17,7 +17,7 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /piko @@ -25,4 +25,4 @@ EXPOSE 8080 CMD set -e; \ /usr/sbin/nginx -c /piko/deploy/nginx.conf 2>&1 > /dev/stderr & \ - exec /usr/sbin/php-fpm8.4 --nodaemonize --fpm-config /etc/php/8.4/fpm/php-fpm.conf + exec /usr/sbin/php-fpm8.5 --nodaemonize --fpm-config /etc/php/8.5/fpm/php-fpm.conf diff --git a/frameworks/PHP/piko/piko.dockerfile b/frameworks/PHP/piko/piko.dockerfile index e525d2b64d7..88bcfac4682 100644 --- a/frameworks/PHP/piko/piko.dockerfile +++ b/frameworks/PHP/piko/piko.dockerfile @@ -4,9 +4,9 @@ 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 -RUN apt-get install -yqq nginx git unzip php8.4-fpm php8.4-mysql > /dev/null +RUN apt-get install -yqq nginx git unzip php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /piko COPY --link . . @@ -15,11 +15,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /piko EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /piko/deploy/nginx.conf 2>&1 > /dev/stderr From 86decfabadf2ba017c68bd496abe3192911ac5f1 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 25 Nov 2025 18:05:33 +0100 Subject: [PATCH 066/130] [ruby] Use Ruby 4.0 rc (#10296) --- frameworks/Ruby/agoo/agoo.dockerfile | 2 +- frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile | 2 +- frameworks/Ruby/rack-sequel/rack-sequel.dockerfile | 2 +- frameworks/Ruby/rack/rack-iodine.dockerfile | 2 +- frameworks/Ruby/rack/rack-jruby.dockerfile | 2 +- frameworks/Ruby/rack/rack-passenger.dockerfile | 2 +- frameworks/Ruby/rack/rack-pitchfork.dockerfile | 2 +- frameworks/Ruby/rack/rack.dockerfile | 2 +- frameworks/Ruby/rage-sequel/rage-sequel.dockerfile | 2 +- frameworks/Ruby/rage/rage.dockerfile | 2 +- frameworks/Ruby/rails/rails-falcon.dockerfile | 2 +- frameworks/Ruby/rails/rails-iodine.dockerfile | 2 +- frameworks/Ruby/rails/rails-mysql.dockerfile | 2 +- frameworks/Ruby/rails/rails-pitchfork.dockerfile | 2 +- frameworks/Ruby/rails/rails.dockerfile | 2 +- .../Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile | 2 +- frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile | 2 +- frameworks/Ruby/roda-sequel/roda-sequel.dockerfile | 2 +- .../sinatra-sequel-postgres-iodine-mri.dockerfile | 2 +- .../Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile | 2 +- frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/frameworks/Ruby/agoo/agoo.dockerfile b/frameworks/Ruby/agoo/agoo.dockerfile index 548fb50341b..3f0e73a6f74 100644 --- a/frameworks/Ruby/agoo/agoo.dockerfile +++ b/frameworks/Ruby/agoo/agoo.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc RUN apt-get update -q \ && apt-get install --no-install-recommends -q -y \ diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile index 65728878595..2e973cf9ecc 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ADD ./ /rack-sequel diff --git a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile index a7e0c901daa..748cfc05b9e 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ADD ./ /rack-sequel diff --git a/frameworks/Ruby/rack/rack-iodine.dockerfile b/frameworks/Ruby/rack/rack-iodine.dockerfile index 0c4f7aafc6d..26f65700e15 100644 --- a/frameworks/Ruby/rack/rack-iodine.dockerfile +++ b/frameworks/Ruby/rack/rack-iodine.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/rack/rack-jruby.dockerfile b/frameworks/Ruby/rack/rack-jruby.dockerfile index 062547508ca..16d2781a114 100644 --- a/frameworks/Ruby/rack/rack-jruby.dockerfile +++ b/frameworks/Ruby/rack/rack-jruby.dockerfile @@ -1,4 +1,4 @@ -FROM jruby:10.0 +FROM ruby:4.0-rc RUN apt-get update -y && apt-get install netbase -y diff --git a/frameworks/Ruby/rack/rack-passenger.dockerfile b/frameworks/Ruby/rack/rack-passenger.dockerfile index bde26ea58bc..115f5740f1c 100644 --- a/frameworks/Ruby/rack/rack-passenger.dockerfile +++ b/frameworks/Ruby/rack/rack-passenger.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/rack/rack-pitchfork.dockerfile b/frameworks/Ruby/rack/rack-pitchfork.dockerfile index bebaf61bcb4..1546e882b4e 100644 --- a/frameworks/Ruby/rack/rack-pitchfork.dockerfile +++ b/frameworks/Ruby/rack/rack-pitchfork.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index ce1c639ea11..4efbac15571 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 ENV RUBY_THREAD_TIMESLICE=10 diff --git a/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile b/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile index 41bfd349920..68a57f4b52a 100644 --- a/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile +++ b/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc EXPOSE 8080 WORKDIR /rage-sequel diff --git a/frameworks/Ruby/rage/rage.dockerfile b/frameworks/Ruby/rage/rage.dockerfile index e73bb58f8c9..d70e975a853 100644 --- a/frameworks/Ruby/rage/rage.dockerfile +++ b/frameworks/Ruby/rage/rage.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc EXPOSE 8080 WORKDIR /rage diff --git a/frameworks/Ruby/rails/rails-falcon.dockerfile b/frameworks/Ruby/rails/rails-falcon.dockerfile index 6ede5622c05..c92590a0f19 100644 --- a/frameworks/Ruby/rails/rails-falcon.dockerfile +++ b/frameworks/Ruby/rails/rails-falcon.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/rails/rails-iodine.dockerfile b/frameworks/Ruby/rails/rails-iodine.dockerfile index ceab1c1ba4f..90020e652fa 100644 --- a/frameworks/Ruby/rails/rails-iodine.dockerfile +++ b/frameworks/Ruby/rails/rails-iodine.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/rails/rails-mysql.dockerfile b/frameworks/Ruby/rails/rails-mysql.dockerfile index 1009954ca6e..998294d1ec6 100644 --- a/frameworks/Ruby/rails/rails-mysql.dockerfile +++ b/frameworks/Ruby/rails/rails-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/rails/rails-pitchfork.dockerfile b/frameworks/Ruby/rails/rails-pitchfork.dockerfile index 190f30a4926..53f8c66b4cc 100644 --- a/frameworks/Ruby/rails/rails-pitchfork.dockerfile +++ b/frameworks/Ruby/rails/rails-pitchfork.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index a1095428571..2e901b62062 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile index 2ab0b2de6cc..db7fbc995f1 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ADD ./ /roda-sequel WORKDIR /roda-sequel diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile index 46cff7f1b39..80a1934282c 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ADD ./ /roda-sequel WORKDIR /roda-sequel diff --git a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile index 1506324b59c..ceadc12af5d 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ADD ./ /roda-sequel WORKDIR /roda-sequel diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile index 83d1de64132..98e42167f64 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile index afbbc915d22..058c6f6de73 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile index 7f622501ddf..6804394c054 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 From 67f4481c3c869eba621fb12f92e4da947db87745 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Wed, 26 Nov 2025 01:05:44 +0800 Subject: [PATCH 067/130] [xitca-web] add toasty as orm (#10294) * [xitca-web] add toasty as orm * dep update * reduce dep * use sync pipeline for multiple queries * reduce usage of explicty vector size hint * remove unnecssary iterator method * simplify pipelined update query * dedup main functions * prevent pg server from deadlocking itself --- frameworks/Rust/xitca-web/.cargo/config.toml | 3 - frameworks/Rust/xitca-web/Cargo.lock | 886 +++++++++++++----- frameworks/Rust/xitca-web/Cargo.toml | 43 +- .../Rust/xitca-web/benchmark_config.json | 14 +- frameworks/Rust/xitca-web/src/db.rs | 52 +- frameworks/Rust/xitca-web/src/db_diesel.rs | 143 +-- .../Rust/xitca-web/src/db_diesel_async.rs | 122 --- frameworks/Rust/xitca-web/src/db_toasty.rs | 97 ++ .../Rust/xitca-web/src/db_unrealistic.rs | 56 +- frameworks/Rust/xitca-web/src/db_util.rs | 93 +- frameworks/Rust/xitca-web/src/main_orm.rs | 26 +- frameworks/Rust/xitca-web/src/main_sync.rs | 61 -- frameworks/Rust/xitca-web/src/ser.rs | 35 +- .../xitca-web/xitca-web-diesel.dockerfile | 10 + .../Rust/xitca-web/xitca-web-orm.dockerfile | 10 - .../Rust/xitca-web/xitca-web-sync.dockerfile | 10 - .../xitca-web/xitca-web-toasty.dockerfile | 10 + .../xitca-web-unrealistic.dockerfile | 2 +- .../Rust/xitca-web/xitca-web.dockerfile | 2 +- 19 files changed, 1006 insertions(+), 669 deletions(-) mode change 100644 => 100755 frameworks/Rust/xitca-web/Cargo.lock mode change 100644 => 100755 frameworks/Rust/xitca-web/Cargo.toml mode change 100644 => 100755 frameworks/Rust/xitca-web/src/db.rs mode change 100644 => 100755 frameworks/Rust/xitca-web/src/db_diesel.rs delete mode 100644 frameworks/Rust/xitca-web/src/db_diesel_async.rs create mode 100755 frameworks/Rust/xitca-web/src/db_toasty.rs mode change 100644 => 100755 frameworks/Rust/xitca-web/src/db_unrealistic.rs mode change 100644 => 100755 frameworks/Rust/xitca-web/src/db_util.rs mode change 100644 => 100755 frameworks/Rust/xitca-web/src/main_orm.rs delete mode 100644 frameworks/Rust/xitca-web/src/main_sync.rs mode change 100644 => 100755 frameworks/Rust/xitca-web/src/ser.rs create mode 100755 frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile delete mode 100644 frameworks/Rust/xitca-web/xitca-web-orm.dockerfile delete mode 100644 frameworks/Rust/xitca-web/xitca-web-sync.dockerfile create mode 100755 frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile diff --git a/frameworks/Rust/xitca-web/.cargo/config.toml b/frameworks/Rust/xitca-web/.cargo/config.toml index df736010a76..d56cb43d3f5 100644 --- a/frameworks/Rust/xitca-web/.cargo/config.toml +++ b/frameworks/Rust/xitca-web/.cargo/config.toml @@ -1,6 +1,3 @@ [build] rustflags = ["-C", "target-cpu=native", "--cfg", "tokio_unstable"] incremental = false - -[target.wasm32-wasip1-threads] -rustflags = ["-C", "target-feature=+simd128", "--cfg", "tokio_unstable"] diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock old mode 100644 new mode 100755 index 4eb82962d66..dddca17e554 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -3,26 +3,48 @@ version = 4 [[package]] -name = "addr2line" -version = "0.25.1" +name = "aho-corasick" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ - "gimli", + "memchr", ] -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -49,21 +71,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - [[package]] name = "base64" version = "0.22.1" @@ -72,15 +79,31 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bb8" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d8b8e1a22743d9241575c6ba822cf9c8fef34771c86ab7e477a4fbfd254e5" +checksum = "457d7ed3f888dfd2c7af56d4975cade43c622f74bdcddfed6d4352f57acc6310" dependencies = [ "futures-util", "parking_lot", + "portable-atomic", "tokio", ] +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -89,9 +112,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block-buffer" @@ -108,6 +131,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + [[package]] name = "byteorder" version = "1.5.0" @@ -116,15 +145,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.40" +version = "1.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" dependencies = [ "find-msvc-tools", "shlex", @@ -132,9 +161,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "core_affinity" @@ -158,9 +187,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -203,24 +232,23 @@ dependencies = [ [[package]] name = "diesel" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8496eeb328dce26ee9d9b73275d396d9bddb433fa30106cf6056dd8c3c2764c" +checksum = "5e7624a3bb9fffd82fff016be9a7f163d20e5a89eb8d28f9daaa6b30fff37500" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "diesel_derives", "downcast-rs", "itoa", "pq-sys", - "r2d2", ] [[package]] name = "diesel-async" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69eded9cb72c7e112505caec23da00149d4dd49f4c96b3c83b2b63f0aa3da5f" +checksum = "13096fb8dae53f2d411c4b523bec85f45552ed3044a2ab4d85fb2092d9cb4f34" dependencies = [ "bb8", "diesel", @@ -233,9 +261,9 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09af0e983035368439f1383011cd87c46f41da81d0f21dc3727e2857d5a43c8e" +checksum = "9daac6489a36e42570da165a10c424f3edcefdff70c5fd55e1847c23f3dd7562" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -264,6 +292,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "downcast-rs" version = "2.0.2" @@ -304,9 +343,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "float-cmp" @@ -392,21 +431,26 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasi", ] [[package]] -name = "gimli" -version = "0.32.3" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] [[package]] name = "halfbrown" @@ -420,9 +464,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", @@ -452,12 +496,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -473,6 +516,87 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -480,23 +604,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "io-uring" -version = "0.6.4" +name = "idna" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "bitflags 1.3.2", - "libc", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "index_vec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44faf5bb8861a9c72e20d3fb0fdbd59233e43056e2b80475ab0aacdc2e781355" + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown", ] [[package]] name = "io-uring" -version = "0.7.10" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5" dependencies = [ - "bitflags 2.9.4", - "cfg-if", + "bitflags 1.3.2", "libc", ] @@ -514,19 +664,25 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libmimalloc-sys" @@ -544,11 +700,17 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "redox_syscall", ] +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + [[package]] name = "lock_api" version = "0.4.14" @@ -589,24 +751,15 @@ dependencies = [ "libmimalloc-sys", ] -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -628,15 +781,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -709,6 +853,22 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "pluralizer" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4616e94b67b8b61846ea69d4bf041a62147d569d16f437689229e2677d38c" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + [[package]] name = "postgres-protocol" version = "0.6.9" @@ -722,22 +882,31 @@ dependencies = [ "hmac", "md-5", "memchr", - "rand", + "rand 0.9.2", "sha2", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a120daaabfcb0e324d5bf6e411e9222994cb3795c79943a0ef28ed27ea76e4" +checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" dependencies = [ "bytes", "fallible-iterator", "postgres-protocol", ] +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -749,9 +918,9 @@ dependencies = [ [[package]] name = "pq-sys" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "412a4cb9e93795c0594dab7c1c4ec1c8b42b514e1baf6e9f63d14aa376e5bd04" +checksum = "574ddd6a267294433f140b02a726b0640c43cf7c6f717084684aaa3b285aba61" dependencies = [ "libc", "pkg-config", @@ -760,18 +929,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -783,14 +952,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "r2d2" -version = "0.8.10" +name = "rand" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", ] [[package]] @@ -799,8 +968,18 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -810,7 +989,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -819,7 +1007,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom", + "getrandom 0.3.4", ] [[package]] @@ -828,7 +1016,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -852,10 +1040,33 @@ dependencies = [ ] [[package]] -name = "rustc-demangle" -version = "0.1.26" +name = "regex" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustversion" @@ -880,15 +1091,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "scoped-futures" version = "0.1.4" @@ -978,9 +1180,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -1062,12 +1264,28 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "std-util" +version = "0.1.0" +source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +dependencies = [ + "heck", + "pluralizer", + "rand 0.8.5", ] [[package]] @@ -1095,15 +1313,26 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thiserror" version = "2.0.17" @@ -1124,6 +1353,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.10.0" @@ -1139,30 +1378,103 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "toasty" +version = "0.1.0" +source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +dependencies = [ + "anyhow", + "async-stream", + "by_address", + "index_vec", + "indexmap", + "toasty-core", + "toasty-macros", + "tokio", + "tokio-stream", + "url", + "uuid", +] + +[[package]] +name = "toasty-codegen" +version = "0.1.0" +source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +dependencies = [ + "proc-macro2", + "quote", + "std-util", + "syn", +] + +[[package]] +name = "toasty-core" +version = "0.1.0" +source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +dependencies = [ + "anyhow", + "async-trait", + "bit-set", + "indexmap", + "std-util", + "tokio-stream", + "uuid", +] + +[[package]] +name = "toasty-macros" +version = "0.1.0" +source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "toasty-codegen", + "toasty-core", +] + +[[package]] +name = "toasty-sql" +version = "0.1.0" +source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +dependencies = [ + "anyhow", + "toasty-core", +] + [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring 0.7.10", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", - "windows-sys", + "socket2 0.6.1", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "tokio-postgres" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156efe7fff213168257853e1dfde202eed5f487522cbbbf7d219941d753d853" +checksum = "2b40d66d9b2cfe04b628173409368e58247e8eddbbd3b0e6c6ba1d09f20f6c9e" dependencies = [ "async-trait", "byteorder", @@ -1177,13 +1489,24 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand", - "socket2 0.6.0", + "rand 0.9.2", + "socket2 0.6.1", "tokio", "tokio-util", "whoami", ] +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-uring" version = "0.5.0" @@ -1192,7 +1515,7 @@ checksum = "748482e3e13584a34664a710168ad5068e8cb1d968aa4ffa887e83ca6dd27967" dependencies = [ "bytes", "futures-util", - "io-uring 0.6.4", + "io-uring", "libc", "slab", "socket2 0.4.10", @@ -1201,9 +1524,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -1242,30 +1565,60 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "rand 0.9.2", + "wasm-bindgen", +] [[package]] name = "value-trait" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d93718a3c9696765926b8acd98588727b285ae969901f76fcf1b6cad5d5d9" +checksum = "8e80f0c733af0720a501b3905d22e2f97662d8eacfe082a75ed7ffb5ab08cb59" dependencies = [ "float-cmp", "halfbrown", @@ -1291,15 +1644,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -1317,9 +1661,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -1328,25 +1672,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1354,31 +1684,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -1425,19 +1755,29 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ + "windows-link", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", @@ -1450,51 +1790,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" @@ -1502,10 +1842,16 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + [[package]] name = "xitca-codegen" version = "0.4.0" -source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" dependencies = [ "quote", "syn", @@ -1514,7 +1860,7 @@ dependencies = [ [[package]] name = "xitca-http" version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" dependencies = [ "futures-core", "http", @@ -1522,7 +1868,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "tokio", "tokio-uring", "tracing", @@ -1547,7 +1893,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" dependencies = [ "fallible-iterator", "futures-core", @@ -1573,6 +1919,21 @@ dependencies = [ "xitca-postgres", ] +[[package]] +name = "xitca-postgres-toasty" +version = "0.1.0" +source = "git+https://github.com/fakeshadow/xitca-postgres-toasty?rev=04bedb8#04bedb8641a13b61f13c85a1fd0b8318dd5454a8" +dependencies = [ + "anyhow", + "futures-core", + "pin-project-lite", + "postgres-types", + "toasty-core", + "toasty-sql", + "tokio", + "xitca-postgres", +] + [[package]] name = "xitca-router" version = "0.3.0" @@ -1585,9 +1946,9 @@ dependencies = [ [[package]] name = "xitca-server" version = "0.5.0" -source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" dependencies = [ - "socket2 0.6.0", + "socket2 0.6.1", "tokio", "tokio-uring", "tracing", @@ -1599,7 +1960,7 @@ dependencies = [ [[package]] name = "xitca-service" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" [[package]] name = "xitca-unsafe-collection" @@ -1622,18 +1983,20 @@ dependencies = [ "futures-util", "httparse", "mimalloc", - "rand", + "rand 0.9.2", "sailfish", "serde", "serde_json", "simd-json", "simd-json-derive", + "toasty", "tokio", "tokio-uring", "xitca-http", "xitca-io", "xitca-postgres", "xitca-postgres-diesel", + "xitca-postgres-toasty", "xitca-server", "xitca-service", "xitca-unsafe-collection", @@ -1643,7 +2006,7 @@ dependencies = [ [[package]] name = "xitca-web" version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" dependencies = [ "futures-core", "pin-project-lite", @@ -1658,20 +2021,97 @@ dependencies = [ "xitca-unsafe-collection", ] +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml old mode 100644 new mode 100755 index dd95fc7b92a..87158075f2e --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -14,22 +14,22 @@ path = "./src/main_unrealistic.rs" required-features = ["perf", "pg", "template"] [[bin]] -name = "xitca-web-orm" +name = "xitca-web-diesel" path = "./src/main_orm.rs" -required-features = ["pg-orm-async", "template", "web-codegen"] +required-features = ["diesel", "template", "web-codegen"] [[bin]] -name = "xitca-web-sync" -path = "./src/main_sync.rs" -required-features = ["pg-orm", "template", "web-codegen"] +name = "xitca-web-toasty" +path = "./src/main_orm.rs" +required-features = ["toasty", "template", "web-codegen"] [features] # pg client optional pg = ["dep:xitca-postgres"] # diesel orm optional -pg-orm = ["diesel/r2d2"] -# diesel async orm optional -pg-orm-async = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"] +diesel = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"] +# toasty orm optional +toasty = ["dep:toasty", "dep:xitca-postgres-toasty"] # http router optional router = ["xitca-http/router"] # web optional @@ -61,14 +61,16 @@ xitca-web = { version = "0.7", features = ["json"], optional = true } # raw-pg optional xitca-postgres = { version = "0.3", optional = true } -# orm optional +# diesel orm optional diesel = { version = "2", features = ["postgres"], optional = true } - -# orm async optional diesel-async = { version = "0.7", features = ["bb8", "postgres"], optional = true } xitca-postgres-diesel = { version = "0.2", optional = true } futures-util = { version = "0.3", default-features = false, optional = true } +# toasty orm optional +xitca-postgres-toasty = { version = "0.1", optional = true } +toasty = { version = "0.1", optional = true } + # template optional sailfish = { version = "0.10", default-features = false, features = ["perf-inline"], optional = true } @@ -93,10 +95,15 @@ panic = "abort" [patch.crates-io] xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "8ce4e5b" } - -xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } -xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } -xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } -xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } -xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } -xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } +xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "04bedb8" } + +toasty = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" } +toasty-core = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" } +toasty-sql = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" } + +xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } +xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } +xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } +xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } +xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index c60cf0bc3b2..4481eae03b2 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -46,9 +46,7 @@ "notes": "", "versus": "" }, - "orm": { - "json_url": "/json", - "plaintext_url": "/plaintext", + "diesel": { "db_url": "/db", "fortune_url": "/fortunes", "query_url": "/queries?q=", @@ -64,20 +62,18 @@ "webserver": "xitca-server", "os": "linux", "database_os": "linux", - "display_name": "xitca-web [orm]", + "display_name": "xitca-web [diesel]", "notes": "", "versus": "" }, - "sync": { - "json_url": "/json", - "plaintext_url": "/plaintext", + "toasty": { "db_url": "/db", "fortune_url": "/fortunes", "query_url": "/queries?q=", "update_url": "/updates?q=", "port": 8080, "approach": "realistic", - "classification": "micro", + "classification": "fullstack", "database": "postgres", "framework": "xitca-web", "language": "rust", @@ -86,7 +82,7 @@ "webserver": "xitca-server", "os": "linux", "database_os": "linux", - "display_name": "xitca-web [sync]", + "display_name": "xitca-web [toasty]", "notes": "", "versus": "" } diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs old mode 100644 new mode 100755 index b35affdc61b..4a9761e7bb1 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -3,28 +3,24 @@ mod db_util; use core::cell::RefCell; -use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement}; +use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool}; use super::{ ser::{Fortune, Fortunes, World}, util::{DB_URL, HandleResult}, }; -use db_util::{FORTUNE_STMT, Shared, WORLD_STMT, not_found, sort_update_params, update_query_from_num}; +use db_util::{FORTUNE_STMT, Shared, UPDATE_BATCH_STMT, WORLD_STMT, not_found}; pub struct Client { pool: Pool, shared: RefCell, - updates: Box<[Box]>, } pub async fn create() -> HandleResult { Ok(Client { pool: Pool::builder(DB_URL).capacity(1).build()?, shared: Default::default(), - updates: core::iter::once(Box::from("")) - .chain((1..=500).map(update_query_from_num)) - .collect(), }) } @@ -64,34 +60,33 @@ impl Client { pub async fn update(&self, num: u16) -> HandleResult> { let len = num as usize; - let update = self.updates.get(len).ok_or("request num is out of range")?; let mut conn = self.pool.get().await?; let world_stmt = WORLD_STMT.execute(&mut conn).await?; - let update_stmt = Statement::named(update, &[]).execute(&mut conn).await?; + let update_stmt = UPDATE_BATCH_STMT.execute(&mut conn).await?; - let mut params = Vec::with_capacity(len); - - let mut res = { + let (mut res, worlds) = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); - (0..num).try_for_each(|_| { - let w_id = rng.gen_id(); - let r_id = rng.gen_id(); - params.push([w_id, r_id]); - world_stmt.bind([w_id]).query(&mut pipe) - })?; - update_stmt.bind(sort_update_params(¶ms)).query(&mut pipe)?; - pipe.query(&conn.consume())? - }; - let mut worlds = Vec::with_capacity(len); + let (mut params, worlds) = core::iter::repeat_with(|| { + let id = rng.gen_id(); + let rand = rng.gen_id(); + world_stmt.bind([id]).query(&mut pipe)?; + HandleResult::Ok(((id, rand), World::new(id, rand))) + }) + .take(len) + .collect::, Vec<_>), _>>()?; + + params.sort(); + let (ids, rngs) = params.into_iter().collect::<(Vec<_>, Vec<_>)>(); - let mut r_ids = params.into_iter(); + update_stmt.bind([&ids, &rngs]).query(&mut pipe)?; + (pipe.query(&conn.consume())?, worlds) + }; while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { - let r_id = r_ids.next().unwrap()[1]; - worlds.push(World::new(row.get(0), r_id)) + let _rand = row.get::(1); } } @@ -99,19 +94,16 @@ impl Client { } pub async fn tell_fortune(&self) -> HandleResult { - let mut items = Vec::with_capacity(32); - items.push(Fortune::new(0, "Additional fortune added at request time.")); + let mut fortunes = Vec::with_capacity(16); let mut conn = self.pool.get().await?; let stmt = FORTUNE_STMT.execute(&mut conn).await?; let mut res = stmt.query(&conn.consume()).await?; while let Some(row) = res.try_next().await? { - items.push(Fortune::new(row.get(0), row.get::(1))); + fortunes.push(Fortune::new(row.get(0), row.get::(1))); } - items.sort_by(|it, next| it.message.cmp(&next.message)); - - Ok(Fortunes::new(items)) + Ok(Fortunes::new(fortunes)) } } diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs old mode 100644 new mode 100755 index f187afc54e1..454a3779eab --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -1,104 +1,113 @@ #[path = "./db_util.rs"] mod db_util; -use std::{ - io, - sync::{Arc, Mutex}, -}; +use core::cell::RefCell; + +use std::io; -use diesel::{prelude::*, r2d2}; +use diesel::prelude::*; +use diesel_async::{ + RunQueryDsl, + pooled_connection::{AsyncDieselConnectionManager, bb8}, +}; +use futures_util::future::{TryFutureExt, try_join, try_join_all}; +use xitca_postgres_diesel::AsyncPgConnection; use crate::{ ser::{Fortune, Fortunes, World}, util::{DB_URL, HandleResult, Rand}, }; -use db_util::{not_found, update_query_from_ids}; - -pub type Pool = Arc<_Pool>; +use db_util::update_query_from_ids; -pub struct _Pool { - pool: r2d2::Pool>, - rng: Mutex, +pub struct Pool { + pool: bb8::Pool, + rng: RefCell, } -pub fn create() -> io::Result> { - r2d2::Builder::new() - .max_size(100) - .min_idle(Some(100)) +pub async fn create() -> io::Result { + bb8::Pool::builder() + .max_size(1) + .min_idle(Some(1)) .test_on_check_out(false) - .idle_timeout(None) - .max_lifetime(None) - .build(r2d2::ConnectionManager::new(DB_URL)) + .build(AsyncDieselConnectionManager::new(DB_URL)) + .await .map_err(io::Error::other) - .map(|pool| { - Arc::new(_Pool { - pool, - rng: Mutex::new(Rand::default()), - }) + .map(|pool| Pool { + pool, + rng: RefCell::new(Rand::default()), }) } -impl _Pool { - pub fn get_world(&self) -> HandleResult { - use crate::schema::world::dsl::*; +impl Pool { + pub async fn get_world(&self) -> HandleResult { + { + use crate::schema::world::dsl::*; - let w_id = self.rng.lock().unwrap().gen_id(); - let mut conn = self.pool.get()?; - world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found) + let w_id = self.rng.borrow_mut().gen_id(); + let mut conn = self.pool.get().await?; + world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into) + } + .await } - pub fn get_worlds(&self, num: u16) -> HandleResult> { - use crate::schema::world::dsl::*; + pub async fn get_worlds(&self, num: u16) -> HandleResult> { + try_join_all({ + use crate::schema::world::dsl::*; + + let mut conn = self.pool.get().await?; + let mut rng = self.rng.borrow_mut(); - let mut conn = self.pool.get()?; - core::iter::repeat_with(|| { - let w_id = self.rng.lock().unwrap().gen_id(); - world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found) + core::iter::repeat_with(|| { + let w_id = rng.gen_id(); + world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into) + }) + .take(num as _) + .collect::>() }) - .take(num as _) - .collect() + .await } - pub fn update(&self, num: u16) -> HandleResult> { - use crate::schema::world::dsl::*; + pub async fn update(&self, num: u16) -> HandleResult> { + let (get, update) = { + use crate::schema::world::dsl::*; - let mut rngs = { - let mut rng = self.rng.lock().unwrap(); - (0..num).map(|_| (rng.gen_id(), rng.gen_id())).collect::>() - }; - - rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); + let mut conn = self.pool.get().await?; + let mut rng = self.rng.borrow_mut(); - let update_sql = update_query_from_ids(&rngs); + let (rngs, get) = core::iter::repeat_with(|| { + let w_id = rng.gen_id(); + let rng = rng.gen_id(); - let mut conn = self.pool.get()?; + let get = world.filter(id.eq(w_id)).first::(&mut conn); - let worlds = rngs - .into_iter() - .map(|(w_id, num)| { - let mut w: World = world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found)?; - w.randomnumber = num; - Ok(w) + ((w_id, rng), async move { + let mut w = get.await?; + w.randomnumber = rng; + HandleResult::Ok(w) + }) }) - .collect::>>()?; + .take(num as _) + .collect::<(Vec<_>, Vec<_>)>(); - diesel::sql_query(update_sql).execute(&mut conn)?; - - Ok(worlds) - } + let update = diesel::sql_query(update_query_from_ids(rngs)) + .execute(&mut conn) + .map_err(Into::into); - pub fn tell_fortune(&self) -> HandleResult { - use crate::schema::fortune::dsl::*; - - let mut items = { - let mut conn = self.pool.get()?; - fortune.load(&mut conn)? + (try_join_all(get), update) }; - items.push(Fortune::new(0, "Additional fortune added at request time.")); - items.sort_by(|it, next| it.message.cmp(&next.message)); + try_join(get, update).await.map(|(worlds, _)| worlds) + } + + pub async fn tell_fortune(&self) -> HandleResult { + { + use crate::schema::fortune::dsl::*; - Ok(Fortunes::new(items)) + let mut conn = self.pool.get().await?; + fortune.load(&mut conn).map_err(Into::into) + } + .await + .map(Fortunes::new) } } diff --git a/frameworks/Rust/xitca-web/src/db_diesel_async.rs b/frameworks/Rust/xitca-web/src/db_diesel_async.rs deleted file mode 100644 index edae0afec03..00000000000 --- a/frameworks/Rust/xitca-web/src/db_diesel_async.rs +++ /dev/null @@ -1,122 +0,0 @@ -#[path = "./db_util.rs"] -mod db_util; - -use std::{io, sync::Mutex}; - -use diesel::prelude::*; -use diesel_async::{ - RunQueryDsl, - pooled_connection::{AsyncDieselConnectionManager, bb8}, -}; -use futures_util::{ - future::join, - stream::{FuturesUnordered, TryStreamExt}, -}; -use xitca_postgres_diesel::AsyncPgConnection; - -use crate::{ - ser::{Fortune, Fortunes, World}, - util::{DB_URL, HandleResult, Rand}, -}; - -use db_util::{not_found, update_query_from_ids}; - -pub struct Pool { - pool: bb8::Pool, - rng: Mutex, -} - -pub async fn create() -> io::Result { - bb8::Pool::builder() - .max_size(1) - .min_idle(Some(1)) - .test_on_check_out(false) - .build(AsyncDieselConnectionManager::new(DB_URL)) - .await - .map_err(io::Error::other) - .map(|pool| Pool { - pool, - rng: Mutex::new(Rand::default()), - }) -} - -impl Pool { - pub async fn get_world(&self) -> HandleResult { - use crate::schema::world::dsl::*; - { - let w_id = self.rng.lock().unwrap().gen_id(); - let mut conn = self.pool.get().await?; - world.filter(id.eq(w_id)).load(&mut conn) - } - .await? - .pop() - .ok_or_else(not_found) - } - - pub async fn get_worlds(&self, num: u16) -> HandleResult> { - use crate::schema::world::dsl::*; - { - let mut conn = self.pool.get().await?; - let mut rng = self.rng.lock().unwrap(); - core::iter::repeat_with(|| { - let w_id = rng.gen_id(); - let fut = world.filter(id.eq(w_id)).load(&mut conn); - async { fut.await?.pop().ok_or_else(not_found) } - }) - .take(num as _) - .collect::>() - } - .try_collect() - .await - } - - pub async fn update(&self, num: u16) -> HandleResult> { - use crate::schema::world::dsl::*; - - let (select_res, update_res) = { - let mut conn = self.pool.get().await?; - let mut rng = self.rng.lock().unwrap(); - - let (select, mut rngs) = core::iter::repeat_with(|| { - let w_id = rng.gen_id(); - let num = rng.gen_id(); - - let fut = world.filter(id.eq(w_id)).load::(&mut conn); - let select = async move { - let mut w = fut.await?.pop().ok_or_else(not_found)?; - w.randomnumber = num; - HandleResult::Ok(w) - }; - - (select, (w_id, num)) - }) - .take(num as _) - .collect::<(FuturesUnordered<_>, Vec<_>)>(); - - rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); - - let update = diesel::sql_query(update_query_from_ids(&rngs)).execute(&mut conn); - - join(select.try_collect::>(), update) - } - .await; - - update_res?; - select_res - } - - pub async fn tell_fortune(&self) -> HandleResult { - use crate::schema::fortune::dsl::*; - - let mut items = { - let mut conn = self.pool.get().await?; - fortune.load(&mut conn) - } - .await?; - - items.push(Fortune::new(0, "Additional fortune added at request time.")); - items.sort_by(|it, next| it.message.cmp(&next.message)); - - Ok(Fortunes::new(items)) - } -} diff --git a/frameworks/Rust/xitca-web/src/db_toasty.rs b/frameworks/Rust/xitca-web/src/db_toasty.rs new file mode 100755 index 00000000000..e74f115f459 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_toasty.rs @@ -0,0 +1,97 @@ +use core::cell::RefCell; + +use std::io; + +use toasty::Db; +use xitca_postgres_toasty::PostgreSQL; + +use crate::{ + ser::{Fortune, Fortunes, World}, + util::{DB_URL, HandleResult, Rand}, +}; + +// this is not a realistic connection pool. +pub struct Pool { + db: Db, + rng: RefCell, +} + +pub async fn create() -> io::Result { + let conn = PostgreSQL::connect(DB_URL).await.unwrap(); + + let db = Db::builder() + .register::() + .register::() + .build(conn) + .await + .unwrap(); + + Ok(Pool { + db, + rng: Default::default(), + }) +} + +impl Pool { + pub async fn get_world(&self) -> HandleResult { + let id = self.rng.borrow_mut().gen_id(); + World::get_by_id(&self.db, id).await.map_err(Into::into) + } + + pub async fn get_worlds(&self, num: u16) -> HandleResult> { + let res = { + let mut rng = self.rng.borrow_mut(); + core::iter::repeat_with(|| { + let id = rng.gen_id(); + World::get_by_id(&self.db, id) + }) + .take(num as _) + .collect::>() + }; + + let mut worlds = Vec::with_capacity(num as _); + + for fut in res { + let world = fut.await?; + worlds.push(world); + } + + Ok(worlds) + } + + pub async fn update(&self, num: u16) -> HandleResult> { + let res = { + let mut rng = self.rng.borrow_mut(); + + core::iter::repeat_with(|| { + let id = rng.gen_id(); + let rng = rng.gen_id(); + + let fut = World::get_by_id(&self.db, id); + async move { + let mut world = fut.await?; + world.randomnumber = rng; + HandleResult::Ok(world) + } + }) + .take(num as _) + .collect::>() + }; + + let mut worlds = Vec::with_capacity(num as _); + + for fut in res { + let mut world = fut.await?; + let rng = world.randomnumber; + world.update().randomnumber(rng).exec(&self.db).await?; + worlds.push(world); + } + + Ok(worlds) + } + + pub async fn tell_fortune(&self) -> HandleResult { + let mut fortunes = Fortune::all().all(&self.db).await?.collect::>().await?; + Ok(Fortunes::new(fortunes)) + } +} diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs old mode 100644 new mode 100755 index cacd6367656..7528d79c719 --- a/frameworks/Rust/xitca-web/src/db_unrealistic.rs +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -13,14 +13,14 @@ use super::{ util::{DB_URL, HandleResult}, }; -use db_util::{FORTUNE_STMT, Shared, WORLD_STMT, not_found, sort_update_params, update_query_from_num}; +use db_util::{FORTUNE_STMT, Shared, UPDATE_STMT, WORLD_STMT, not_found}; pub struct Client { cli: xitca_postgres::Client, shared: RefCell, fortune: Statement, world: Statement, - updates: Box<[Statement]>, + update: Statement, } pub async fn create() -> HandleResult { @@ -33,20 +33,14 @@ pub async fn create() -> HandleResult { let world = WORLD_STMT.execute(&cli).await?.leak(); let fortune = FORTUNE_STMT.execute(&cli).await?.leak(); - - let mut updates = vec![Statement::default()]; - - for update in (1..=500).map(update_query_from_num) { - let stmt = Statement::named(&update, &[]).execute(&cli).await?.leak(); - updates.push(stmt); - } + let update = UPDATE_STMT.execute(&cli).await?.leak(); Ok(Client { cli, shared: Default::default(), world, fortune, - updates: updates.into_boxed_slice(), + update, }) } @@ -63,8 +57,7 @@ impl Client { let mut res = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - // unrealistic as all queries are sent with only one sync point. - let mut pipe = Pipeline::unsync_with_capacity_from_buf(len, buf); + let mut pipe = Pipeline::with_capacity_from_buf(len, buf); (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query(&mut pipe))?; pipe.query(&self.cli)? }; @@ -83,30 +76,32 @@ impl Client { pub async fn update(&self, num: u16) -> HandleResult> { let len = num as usize; - let mut params = Vec::with_capacity(len); - - let mut res = { + let (mut res, worlds) = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); // unrealistic as all queries are sent with only one sync point. let mut pipe = Pipeline::unsync_with_capacity_from_buf(len + 1, buf); - (0..num).try_for_each(|_| { - let w_id = rng.gen_id(); - let r_id = rng.gen_id(); - params.push([w_id, r_id]); - self.world.bind([w_id]).query(&mut pipe) - })?; - self.updates[len].bind(sort_update_params(¶ms)).query(&mut pipe)?; - pipe.query(&self.cli)? - }; - let mut worlds = Vec::with_capacity(len); + let (mut params, worlds) = core::iter::repeat_with(|| { + let id = rng.gen_id(); + let rand = rng.gen_id(); + self.world.bind([id]).query(&mut pipe)?; + HandleResult::Ok(((id, rand), World::new(id, rand))) + }) + .take(len) + .collect::, Vec<_>), _>>()?; + + params.sort(); - let mut r_ids = params.into_iter(); + params + .into_iter() + .try_for_each(|(id, rng)| self.update.bind([rng, id]).query(&mut pipe))?; + + (pipe.query(&self.cli)?, worlds) + }; while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { - let r_id = r_ids.next().unwrap()[1]; - worlds.push(World::new(row.get(0), r_id)) + let _rand = row.get::(1); } } @@ -114,8 +109,7 @@ impl Client { } pub async fn tell_fortune(&self) -> HandleResult { - let mut items = Vec::with_capacity(32); - items.push(Fortune::new(0, "Additional fortune added at request time.")); + let mut items = Vec::with_capacity(16); let mut res = self.fortune.query(&self.cli).await?; @@ -123,8 +117,6 @@ impl Client { items.push(Fortune::new(row.get(0), row.get::(1))); } - items.sort_by(|it, next| it.message.cmp(&next.message)); - Ok(Fortunes::new(items)) } } diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs old mode 100644 new mode 100755 index 74936ab14e4..aa2cb04a6db --- a/frameworks/Rust/xitca-web/src/db_util.rs +++ b/frameworks/Rust/xitca-web/src/db_util.rs @@ -1,24 +1,18 @@ -use crate::util::Error; - -#[cfg(any(feature = "pg-orm", feature = "pg-orm-async"))] +#[cfg(feature = "diesel")] // diesel does not support high level bulk update api. use raw sql to bypass the limitation. // relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 -pub fn update_query_from_ids(ids: &[(i32, i32)]) -> String { - update_query(|query| { - use core::fmt::Write; - ids.iter().for_each(|(w_id, num)| { - write!(query, "({}::int,{}::int),", w_id, num).unwrap(); - }); - }) -} +pub fn update_query_from_ids(mut rngs: Vec<(i32, i32)>) -> String { + rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); -fn update_query(func: impl FnOnce(&mut String)) -> String { - const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; - const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; + const PREFIX: &str = "UPDATE world SET randomNumber=w.r FROM (VALUES "; + const SUFFIX: &str = ") AS w (i,r) WHERE world.id=w.i"; let mut query = String::from(PREFIX); - func(&mut query); + use core::fmt::Write; + rngs.iter().for_each(|(w_id, num)| { + write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + }); if query.ends_with(',') { query.pop(); @@ -29,69 +23,38 @@ fn update_query(func: impl FnOnce(&mut String)) -> String { query } -#[cold] -#[inline(never)] -pub fn not_found() -> Error { - "request World does not exist".into() -} - #[cfg(feature = "pg")] pub use pg::*; #[cfg(feature = "pg")] pub mod pg { + #![allow(dead_code)] + use xitca_io::bytes::BytesMut; use xitca_postgres::{ statement::{Statement, StatementNamed}, types::Type, }; - use crate::util::Rand; + use crate::util::{Error, Rand}; pub type Shared = (Rand, BytesMut); - pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT * FROM fortune", &[]); - pub const WORLD_STMT: StatementNamed = Statement::named("SELECT * FROM world WHERE id=$1", &[Type::INT4]); - - pub fn update_query_from_num(num: usize) -> Box { - super::update_query(|query| { - use core::fmt::Write; - (1..=num).fold(1, |idx, _| { - write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); - idx + 2 - }); - }) - .into_boxed_str() - } - - pub fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator + Clone { - let mut params = params.to_owned(); - params.sort_by(|a, b| a[0].cmp(&b[0])); - - #[derive(Clone)] - struct ParamIter(I); - - impl Iterator for ParamIter - where - I: Iterator, - { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - - // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring - // it's size hint. possible to cause runtime panic. - impl ExactSizeIterator for ParamIter where I: Iterator {} - - ParamIter(params.into_iter().flatten()) + pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT id,message FROM fortune", &[]); + pub const WORLD_STMT: StatementNamed = + Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]); + pub const UPDATE_STMT: StatementNamed = Statement::named( + "UPDATE world SET randomnumber=$1 WHERE id=$2", + &[Type::INT4, Type::INT4], + ); + pub const UPDATE_BATCH_STMT: StatementNamed = Statement::named( + "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i", + &[Type::INT4_ARRAY, Type::INT4_ARRAY], + ); + + #[cold] + #[inline(never)] + pub fn not_found() -> Error { + "request World does not exist".into() } } diff --git a/frameworks/Rust/xitca-web/src/main_orm.rs b/frameworks/Rust/xitca-web/src/main_orm.rs old mode 100644 new mode 100755 index ed5a51069a7..9b07c19a307 --- a/frameworks/Rust/xitca-web/src/main_orm.rs +++ b/frameworks/Rust/xitca-web/src/main_orm.rs @@ -1,25 +1,31 @@ -mod db_diesel_async; -mod schema; mod ser; mod util; +#[cfg(feature = "diesel")] +mod db_diesel; +#[cfg(feature = "diesel")] +mod schema; + +#[cfg(feature = "toasty")] +mod db_toasty; + +use ser::{Num, World}; +use util::{HandleResult, SERVER_HEADER_VALUE}; use xitca_web::{ App, codegen::route, - handler::{html::Html, json::Json, query::Query, state::StateRef, text::Text}, + handler::{html::Html, json::Json, query::Query, state::StateRef}, http::{WebResponse, header::SERVER}, - route::get, }; -use db_diesel_async::Pool; -use ser::{Num, World}; -use util::{HandleResult, SERVER_HEADER_VALUE}; +#[cfg(feature = "diesel")] +use db_diesel::{Pool, create}; +#[cfg(feature = "toasty")] +use db_toasty::{Pool, create}; fn main() -> std::io::Result<()> { App::new() - .with_async_state(db_diesel_async::create) - .at("/plaintext", get(Text("Hello, World!"))) - .at("/json", get(Json(ser::Message::new()))) + .with_async_state(create) .at_typed(db) .at_typed(fortunes) .at_typed(queries) diff --git a/frameworks/Rust/xitca-web/src/main_sync.rs b/frameworks/Rust/xitca-web/src/main_sync.rs deleted file mode 100644 index 48ac2520bd1..00000000000 --- a/frameworks/Rust/xitca-web/src/main_sync.rs +++ /dev/null @@ -1,61 +0,0 @@ -mod db_diesel; -mod schema; -mod ser; -mod util; - -use serde::Serialize; -use xitca_web::{ - App, - codegen::route, - handler::{html::Html, json::Json, query::Query, state::StateOwn, text::Text}, - http::{WebResponse, header::SERVER}, - route::get, -}; - -use db_diesel::Pool; -use ser::Num; -use util::{HandleResult, SERVER_HEADER_VALUE}; - -fn main() -> std::io::Result<()> { - App::new() - .with_state(db_diesel::create()?) - .at("/plaintext", get(Text("Hello, World!"))) - .at("/json", get(Json(ser::Message::new()))) - .at_typed(db) - .at_typed(fortunes) - .at_typed(queries) - .at_typed(updates) - .map(header) - .serve() - .disable_vectored_write() - .bind("0.0.0.0:8080")? - .run() - .wait() -} - -fn header(mut res: WebResponse) -> WebResponse { - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - res -} - -#[route("/db", method = get)] -fn db(StateOwn(pool): StateOwn) -> HandleResult> { - pool.get_world().map(Json) -} - -#[route("/fortunes", method = get)] -fn fortunes(StateOwn(pool): StateOwn) -> HandleResult> { - use sailfish::TemplateOnce; - let html = pool.tell_fortune()?.render_once()?; - Ok(Html(html)) -} - -#[route("/queries", method = get)] -fn queries(Query(Num(num)): Query, StateOwn(pool): StateOwn) -> HandleResult> { - pool.get_worlds(num).map(Json) -} - -#[route("/updates", method = get)] -fn updates(Query(Num(num)): Query, StateOwn(pool): StateOwn) -> HandleResult> { - pool.update(num).map(Json) -} diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs old mode 100644 new mode 100755 index 8eadc873e2c..88ae65f5e7d --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -1,7 +1,5 @@ #![allow(dead_code)] -use std::borrow::Cow; - use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct}; use xitca_http::{ body::Once, @@ -33,9 +31,12 @@ impl Message { pub struct Num(pub u16); -#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))] +#[cfg_attr(feature = "diesel", derive(diesel::Queryable))] +#[cfg_attr(feature = "toasty", derive(toasty::Model))] +#[cfg_attr(feature = "toasty", table = "world")] #[cfg_attr(feature = "perf", derive(simd_json_derive::Serialize))] pub struct World { + #[cfg_attr(feature = "toasty", key)] pub id: i32, pub randomnumber: i32, } @@ -47,15 +48,33 @@ impl World { } } -#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))] +#[cfg_attr(feature = "diesel", derive(diesel::Queryable))] +#[cfg_attr(feature = "toasty", derive(toasty::Model))] +#[cfg_attr(feature = "toasty", table = "fortune")] pub struct Fortune { + #[cfg_attr(feature = "toasty", key)] pub id: i32, - pub message: Cow<'static, str>, + #[cfg(not(feature = "toasty"))] + pub message: std::borrow::Cow<'static, str>, + #[cfg(feature = "toasty")] + pub message: String, +} + +#[cfg(not(feature = "toasty"))] +impl Fortune { + #[inline] + pub fn new(id: i32, message: impl Into>) -> Self { + Self { + id, + message: message.into(), + } + } } +#[cfg(feature = "toasty")] impl Fortune { #[inline] - pub fn new(id: i32, message: impl Into>) -> Self { + pub fn new(id: i32, message: impl Into) -> Self { Self { id, message: message.into(), @@ -100,7 +119,9 @@ impl sailfish::TemplateOnce for Fortunes { impl Fortunes { #[inline] - pub const fn new(items: Vec) -> Self { + pub fn new(mut items: Vec) -> Self { + items.push(Fortune::new(0, "Additional fortune added at request time.")); + items.sort_by(|a, b| a.message.cmp(&b.message)); Self { items } } } diff --git a/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile b/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile new file mode 100755 index 00000000000..ceaacc0f659 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.91.1 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-diesel --features diesel,template,web-codegen + +EXPOSE 8080 + +CMD ./target/release/xitca-web-diesel diff --git a/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile deleted file mode 100644 index 19a4adad80f..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:1.90 - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-orm --features pg-orm-async,template,web-codegen - -EXPOSE 8080 - -CMD ./target/release/xitca-web-orm diff --git a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile deleted file mode 100644 index b2f2b128395..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:1.90 - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-sync --features pg-orm,template,web-codegen - -EXPOSE 8080 - -CMD ./target/release/xitca-web-sync diff --git a/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile b/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile new file mode 100755 index 00000000000..4de7ed3c9a6 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.91.1 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-toasty --features toasty,template,web-codegen + +EXPOSE 8080 + +CMD ./target/release/xitca-web-toasty diff --git a/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile index 6e6ed7828b6..299ee0fbfc1 100644 --- a/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.90 +FROM rust:1.91.1 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web.dockerfile b/frameworks/Rust/xitca-web/xitca-web.dockerfile index 7558d46f428..ed10a355996 100644 --- a/frameworks/Rust/xitca-web/xitca-web.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.90 +FROM rust:1.91.1 ADD ./ /xitca-web WORKDIR /xitca-web From 6dc88370ab49be1dc555744701cfc37ed2b892c5 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 25 Nov 2025 18:10:19 +0100 Subject: [PATCH 068/130] [ruby/sinatra] Update ActiveRecord to 8.1 (#10284) --- frameworks/Ruby/sinatra/Gemfile | 2 +- frameworks/Ruby/sinatra/Gemfile.lock | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/frameworks/Ruby/sinatra/Gemfile b/frameworks/Ruby/sinatra/Gemfile index 6b0a0c45fd8..c02e8ff075b 100644 --- a/frameworks/Ruby/sinatra/Gemfile +++ b/frameworks/Ruby/sinatra/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'activerecord', '~> 8.0', require: 'active_record' +gem 'activerecord', '~> 8.1.0', require: 'active_record' gem 'json', '~> 2.8' gem 'sinatra', '~> 4.2', require: 'sinatra/base' diff --git a/frameworks/Ruby/sinatra/Gemfile.lock b/frameworks/Ruby/sinatra/Gemfile.lock index a9909fd6604..f2d053eab26 100644 --- a/frameworks/Ruby/sinatra/Gemfile.lock +++ b/frameworks/Ruby/sinatra/Gemfile.lock @@ -1,27 +1,26 @@ GEM remote: https://rubygems.org/ specs: - activemodel (8.0.2.1) - activesupport (= 8.0.2.1) - activerecord (8.0.2.1) - activemodel (= 8.0.2.1) - activesupport (= 8.0.2.1) + activemodel (8.1.1) + activesupport (= 8.1.1) + activerecord (8.1.1) + activemodel (= 8.1.1) + activesupport (= 8.1.1) timeout (>= 0.4.0) - activesupport (8.0.2.1) + activesupport (8.1.1) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) base64 (0.3.0) - benchmark (0.4.1) bigdecimal (3.2.2) concurrent-ruby (1.3.5) connection_pool (2.5.3) @@ -70,7 +69,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - activerecord (~> 8.0) + activerecord (~> 8.1.0) iodine (~> 0.7) json (~> 2.8) pg (~> 1.5) From 5f0c9452152e3dad9bcce2d328766f02e7347235 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 25 Nov 2025 18:10:49 +0100 Subject: [PATCH 069/130] [ruby/rack] Update Falcon to 0.52.4 (#10285) --- frameworks/Ruby/rack/Gemfile | 2 +- frameworks/Ruby/rack/Gemfile.lock | 80 +++++++++++++++++++------------ 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/frameworks/Ruby/rack/Gemfile b/frameworks/Ruby/rack/Gemfile index 0512085a64f..47ec614226a 100644 --- a/frameworks/Ruby/rack/Gemfile +++ b/frameworks/Ruby/rack/Gemfile @@ -15,7 +15,7 @@ gem 'sequel_pg', platforms: %i[ruby windows] gem 'tzinfo-data', '1.2023.3' group :falcon, optional: true do - gem 'falcon', '~> 0.47', platforms: %i[ruby windows] + gem 'falcon', '~> 0.52', platforms: %i[ruby windows] end group :iodine, optional: true do diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index 4030d1e1ecb..7028b8ed05d 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -2,47 +2,53 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - async (2.23.0) + async (2.34.0) console (~> 1.29) fiber-annotation - io-event (~> 1.9) + io-event (~> 1.11) metrics (~> 0.12) - traces (~> 0.15) - async-container (0.24.0) + traces (~> 0.18) + async-container (0.27.7) async (~> 2.22) - async-container-supervisor (0.5.1) - async-container (~> 0.22) + async-container-supervisor (0.9.1) async-service io-endpoint + memory (~> 0.7) memory-leak (~> 0.5) - async-http (0.87.0) + process-metrics + async-http (0.92.1) async (>= 2.10.2) - async-pool (~> 0.9) + async-pool (~> 0.11) io-endpoint (~> 0.14) io-stream (~> 0.6) metrics (~> 0.12) protocol-http (~> 0.49) protocol-http1 (~> 0.30) protocol-http2 (~> 0.22) + protocol-url (~> 0.2) traces (~> 0.10) - async-http-cache (0.4.5) + async-http-cache (0.4.6) async-http (~> 0.56) - async-pool (0.10.3) - async (>= 1.25) - async-service (0.13.0) + async-pool (0.11.0) + async (>= 2.0) + async-service (0.14.4) async async-container (~> 0.16) + string-format (~> 0.2) + bake (0.24.1) + bigdecimal + samovar (~> 2.1) bigdecimal (3.1.9) concurrent-ruby (1.3.5) connection_pool (2.5.0) - console (1.30.0) + console (1.34.2) fiber-annotation fiber-local (~> 1.1) json - falcon (0.51.1) + falcon (0.52.4) async async-container (~> 0.20) - async-container-supervisor (~> 0.5.0) + async-container-supervisor (~> 0.6) async-http (~> 0.75) async-http-cache (~> 0.4) async-service (~> 0.10) @@ -55,10 +61,10 @@ GEM fiber-annotation (0.2.0) fiber-local (1.1.0) fiber-storage - fiber-storage (1.0.0) + fiber-storage (1.0.1) io-endpoint (0.15.2) - io-event (1.9.0) - io-stream (0.6.1) + io-event (1.14.2) + io-stream (0.11.0) iodine (0.7.58) itsi (0.2.18) itsi-scheduler (~> 0.2.18) @@ -70,16 +76,21 @@ GEM prism (~> 1.4) rack (>= 1.6) rb_sys (~> 0.9.91) - json (2.13.2) + json (2.16.0) language_server-protocol (3.17.0.4) lint_roller (1.1.0) - localhost (1.3.1) + localhost (1.6.0) logger (1.6.6) - mapping (1.1.1) - memory-leak (0.5.2) - metrics (0.12.2) + mapping (1.1.3) + memory (0.12.0) + bake (~> 0.15) + console + msgpack + memory-leak (0.7.0) + metrics (0.15.0) + msgpack (1.8.0) nio4r (2.7.4) - openssl (3.3.0) + openssl (3.3.2) parallel (1.26.3) parser (3.3.7.1) ast (~> 2.4.1) @@ -95,20 +106,26 @@ GEM logger rack (>= 2.0) prism (1.4.0) + process-metrics (0.7.0) + console (~> 1.8) + json (~> 2) + samovar (~> 2.1) protocol-hpack (1.5.1) - protocol-http (0.54.0) + protocol-http (0.55.0) protocol-http1 (0.35.2) protocol-http (~> 0.22) - protocol-http2 (0.22.1) + protocol-http2 (0.23.0) protocol-hpack (~> 1.4) protocol-http (~> 0.47) - protocol-rack (0.11.2) + protocol-rack (0.16.0) + io-stream (>= 0.10) protocol-http (~> 0.43) rack (>= 1.0) + protocol-url (0.4.0) puma (7.1.0) nio4r (~> 2.0) racc (1.8.1) - rack (3.2.2) + rack (3.2.4) rack-test (2.2.0) rack (>= 1.3) rackup (2.2.1) @@ -133,7 +150,7 @@ GEM rubocop-ast (1.38.1) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) - samovar (2.3.0) + samovar (2.4.1) console (~> 1.0) mapping (~> 1.0) sequel (5.90.0) @@ -141,7 +158,8 @@ GEM sequel_pg (1.17.1) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) - traces (0.15.2) + string-format (0.2.0) + traces (0.18.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) tzinfo-data (1.2023.3) @@ -157,7 +175,7 @@ PLATFORMS DEPENDENCIES connection_pool (~> 2.4) - falcon (~> 0.47) + falcon (~> 0.52) iodine (~> 0.7) itsi jdbc-postgres (~> 42.2) From ce91d99a967e00145b3b51b8aee17dd781f3b667 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Tue, 25 Nov 2025 18:11:06 +0100 Subject: [PATCH 070/130] [ruby/padrino] Update ActiveRecord to 8.1 (#10283) --- frameworks/Ruby/padrino/Gemfile | 2 +- frameworks/Ruby/padrino/Gemfile.lock | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/frameworks/Ruby/padrino/Gemfile b/frameworks/Ruby/padrino/Gemfile index 8ccd7f58765..1fb06aaf3f9 100644 --- a/frameworks/Ruby/padrino/Gemfile +++ b/frameworks/Ruby/padrino/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' gem 'mysql2', '> 0.5' gem 'json' -gem 'activerecord', '>= 7.1', :require => 'active_record' +gem 'activerecord', '~> 8.1.0', :require => 'active_record' gem 'slim', '2.0.3' gem 'padrino', git: 'https://github.com/padrino/padrino-framework.git' diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock index 3636648c76e..8257907ad28 100644 --- a/frameworks/Ruby/padrino/Gemfile.lock +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -38,27 +38,26 @@ GIT GEM remote: https://rubygems.org/ specs: - activemodel (8.0.2) - activesupport (= 8.0.2) - activerecord (8.0.2) - activemodel (= 8.0.2) - activesupport (= 8.0.2) + activemodel (8.1.1) + activesupport (= 8.1.1) + activerecord (8.1.1) + activemodel (= 8.1.1) + activesupport (= 8.1.1) timeout (>= 0.4.0) - activesupport (8.0.2) + activesupport (8.1.1) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) base64 (0.2.0) - benchmark (0.4.0) bigdecimal (3.1.9) concurrent-ruby (1.3.5) connection_pool (2.5.0) @@ -129,7 +128,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - activerecord (>= 7.1) + activerecord (~> 8.1.0) iodine (~> 0.7) json mysql2 (> 0.5) From 5e14b916458115c17f9a00d692baef64636e1523 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Tue, 25 Nov 2025 17:15:02 +0000 Subject: [PATCH 071/130] toolset: Fix the --force-rm option (#10286) * toolset: Fix the --force-rm option Also, clean up the wrk Dockerfile. Signed-off-by: Anton Kirilov * Address code review comments --------- Signed-off-by: Anton Kirilov --- .github/workflows/build.yml | 2 +- toolset/run-tests.py | 2 +- toolset/wrk/wrk.dockerfile | 14 ++------------ 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 46e7a2410e9..309873abc8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -155,7 +155,7 @@ jobs: # run-ci.py runs the diffing to see if github actions needs to test this framework. Ideally/eventually, # we'd like to try and do the diffing before github_actions_clean & setup. # This will run the tests exactly as you would in your own vm: - docker network create tfb > /dev/null 2>&1 && docker run --network=tfb -e USER_ID=$(id -u) -e CI=true -v /var/run/docker.sock:/var/run/docker.sock --mount type=bind,source=`pwd`,target=/FrameworkBenchmarks techempower/tfb --mode verify --test-dir $RUN_TESTS --results-environment Github-Actions; + docker network create tfb > /dev/null 2>&1 && docker run --network=tfb -e USER_ID=$(id -u) -e CI=true -v /var/run/docker.sock:/var/run/docker.sock --mount type=bind,source=`pwd`,target=/FrameworkBenchmarks techempower/tfb --mode verify --force-rm --test-dir $RUN_TESTS --results-environment Github-Actions; dependabot: needs: verify runs-on: ubuntu-latest diff --git a/toolset/run-tests.py b/toolset/run-tests.py index ac24969c4e4..9e65cec801d 100644 --- a/toolset/run-tests.py +++ b/toolset/run-tests.py @@ -210,7 +210,7 @@ def main(argv=None): help='Extra docker arguments to be passed to the test container') parser.add_argument( '--force-rm', - default=False, + action='store_true', help='Remove intermediate docker containers after running.') # Network options diff --git a/toolset/wrk/wrk.dockerfile b/toolset/wrk/wrk.dockerfile index 772fe3268fa..9d65d1108b8 100644 --- a/toolset/wrk/wrk.dockerfile +++ b/toolset/wrk/wrk.dockerfile @@ -1,17 +1,7 @@ FROM ubuntu:24.04 -# Required scripts for benchmarking -COPY concurrency.sh pipeline.lua pipeline.sh query.sh ./ - ARG DEBIAN_FRONTEND=noninteractive RUN apt-get install --no-install-recommends -qqUy curl wrk > /dev/null -# Environment vars required by the wrk scripts with nonsense defaults -ENV accept=accept \ - duration=duration \ - levels=levels \ - max_concurrency=max_concurrency \ - max_threads=max_threads \ - name=name \ - pipeline=pipeline \ - server_host=server_host +# Required scripts for benchmarking +COPY concurrency.sh pipeline.lua pipeline.sh query.sh ./ From e605445baa1922dbde35c0c9a0835da60d89d061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Mon, 1 Dec 2025 10:17:44 -0800 Subject: [PATCH 072/130] Update .NET version to 10.0 for CSharp/aspnetcore (#10241) * Update .NET version to 10.0 for CSharp/aspnetcore * Update database drivers versions * Fix updates * Try older npgsql * Only run "updates" and "queries" * Ensure there are no updated ids duplicated * Prevent collisions * Update connection string * Sync code --- .../aspnetcore/appsettings.postgresql.json | 2 +- .../aspnetcore/aspnetcore-aot.dockerfile | 4 +- .../aspnetcore/aspnetcore-minimal.dockerfile | 4 +- .../aspnetcore/aspnetcore-mvc.dockerfile | 4 +- .../aspnetcore/aspnetcore-mysql.dockerfile | 4 +- .../CSharp/aspnetcore/aspnetcore.dockerfile | 4 +- .../aspnetcore/src/Minimal/Database/Db.cs | 24 ++++- .../aspnetcore/src/Minimal/Minimal.csproj | 8 +- .../CSharp/aspnetcore/src/Mvc/Mvc.csproj | 6 +- .../aspnetcore/src/Platform/Data/Random.cs | 31 ------- .../src/Platform/Data/RawDbMySqlConnector.cs | 53 ++++++----- .../src/Platform/Data/RawDbNpgsql.cs | 92 ++++++++++--------- .../aspnetcore/src/Platform/Platform.csproj | 10 +- .../CSharp/aspnetcore/src/Platform/Program.cs | 47 +++++----- 14 files changed, 148 insertions(+), 145 deletions(-) delete mode 100644 frameworks/CSharp/aspnetcore/src/Platform/Data/Random.cs diff --git a/frameworks/CSharp/aspnetcore/appsettings.postgresql.json b/frameworks/CSharp/aspnetcore/appsettings.postgresql.json index 423af4d19b0..897abdcd96f 100644 --- a/frameworks/CSharp/aspnetcore/appsettings.postgresql.json +++ b/frameworks/CSharp/aspnetcore/appsettings.postgresql.json @@ -1,4 +1,4 @@ { - "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=512;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4", + "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000;", "Database": "postgresql" } diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile index a7396e3b919..3859225dd2a 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile @@ -1,11 +1,11 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build RUN apt-get update RUN apt-get -yqq install clang zlib1g-dev WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql /p:PublishAot=true /p:OptimizationPreference=Speed /p:GarbageCollectionAdaptationMode=0 -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime ENV URLS=http://+:8080 WORKDIR /app diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile index 24893c9717a..96bfb5e1ab4 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/Minimal . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime ENV URLS http://+:8080 ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun=0 diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile index 6922a53bf2a..4382f7b4b3b 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/Mvc . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime ENV URLS http://+:8080 ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun=0 diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile index ecc0a8331c3..19ff86e3dc9 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=MySqlConnector -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime ENV URLS http://+:8080 ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun=0 diff --git a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile index 64510ffe786..4aa5b466752 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime ENV URLS=http://+:8080 ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun=0 diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Database/Db.cs b/frameworks/CSharp/aspnetcore/src/Minimal/Database/Db.cs index ce23c943abe..09ea9e26ce6 100644 --- a/frameworks/CSharp/aspnetcore/src/Minimal/Database/Db.cs +++ b/frameworks/CSharp/aspnetcore/src/Minimal/Database/Db.cs @@ -63,6 +63,9 @@ public async Task LoadMultipleUpdatesRows(string? parameter) var parameters = new Dictionary(); + var ids = new int[count]; + var numbers = new int[count]; + await using var db = _dbProviderFactory.CreateConnection(); db!.ConnectionString = _connectionString; @@ -72,18 +75,33 @@ public async Task LoadMultipleUpdatesRows(string? parameter) for (var i = 0; i < count; i++) { results[i] = await ReadSingleRow(db); + ids[i] = results[i].Id; } + Array.Sort(ids); + + // Ensure unique ids by incrementing duplicates + for (var i = 1; i < count; i++) + if (ids[i] == ids[i - 1]) + ids[i] = (ids[i] % 10000) + 1; for (var i = 0; i < count; i++) { var randomNumber = Random.Shared.Next(1, 10001); - parameters[$"@Rn_{i}"] = randomNumber; - parameters[$"@Id_{i}"] = results[i].Id; + if (results[i].RandomNumber == randomNumber) + { + randomNumber = (randomNumber % 10000) + 1; + } results[i].RandomNumber = randomNumber; + numbers[i] = randomNumber; } - await db.ExecuteAsync(BatchUpdateString.Query(count), parameters); + var update = "UPDATE world w SET randomnumber = u.new_val FROM (SELECT unnest(@ids) as id, unnest(@newValues) as new_val) u WHERE w.id = u.id"; + + parameters["ids"] = ids; + parameters["newValues"] = numbers; + + await db.ExecuteAsync(update, parameters); return results; } diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj b/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj index 12f3446d8b7..256a58e1de0 100644 --- a/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj +++ b/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable enable latest @@ -9,9 +9,9 @@ - - - + + + diff --git a/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj b/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj index 68c70002683..4cdddc7c2d6 100644 --- a/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj +++ b/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable enable latest @@ -9,8 +9,8 @@ - - + + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Data/Random.cs b/frameworks/CSharp/aspnetcore/src/Platform/Data/Random.cs deleted file mode 100644 index a989eb9de2a..00000000000 --- a/frameworks/CSharp/aspnetcore/src/Platform/Data/Random.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Runtime.CompilerServices; -using System.Threading; - -namespace PlatformBenchmarks; - -public sealed class ConcurrentRandom -{ - private static int nextSeed = 0; - - // Random isn't thread safe - [ThreadStatic] - private static Random _random; - - private static Random Random => _random ?? CreateRandom(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private static Random CreateRandom() - { - _random = new Random(Interlocked.Increment(ref nextSeed)); - return _random; - } - - public int Next(int minValue, int maxValue) - { - return Random.Next(minValue, maxValue); - } -} diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbMySqlConnector.cs b/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbMySqlConnector.cs index 340fa1236b2..5c7779b70f0 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbMySqlConnector.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbMySqlConnector.cs @@ -17,16 +17,14 @@ namespace PlatformBenchmarks; // If you are changing RawDbMySqlConnector.cs, also consider changing RawDbNpgsql.cs. public sealed class RawDb { - private readonly ConcurrentRandom _random; private readonly string _connectionString; private readonly MemoryCache _cache = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromMinutes(60) }); private readonly MySqlDataSource _dataSource; - public RawDb(ConcurrentRandom random, AppSettings appSettings) + public RawDb(AppSettings appSettings) { - _random = random; _connectionString = appSettings.ConnectionString; _dataSource = new MySqlDataSource(appSettings.ConnectionString); } @@ -46,10 +44,10 @@ public Task LoadCachedQueries(int count) var result = new CachedWorld[count]; var cacheKeys = _cacheKeys; var cache = _cache; - var random = _random; + for (var i = 0; i < result.Length; i++) { - var id = random.Next(1, 10001); + var id = Random.Shared.Next(1, 10001); var key = cacheKeys[id]; if (cache.TryGetValue(key, out var cached)) { @@ -80,7 +78,7 @@ static async Task LoadUncachedQueries(int id, int i, int count, R { result[i] = await rawdb._cache.GetOrCreateAsync(key, create); - id = rawdb._random.Next(1, 10001); + id = Random.Shared.Next(1, 10001); idParameter.Value = id; key = cacheKeys[id]; } @@ -117,24 +115,18 @@ public async Task LoadMultipleQueriesRows(int count) using var connection = await _dataSource.OpenConnectionAsync(); - using var batch = new MySqlBatch(connection); - - for (var i = 0; i < count; i++) + // It is not acceptable to execute multiple SELECTs within a single complex query. + // It is not acceptable to retrieve all required rows using a SELECT ... WHERE id IN (...) clause. + // Pipelining of network traffic between the application and database is permitted. + + var (queryCmd, queryParameter) = await CreateReadCommandAsync(connection); + using (queryCmd) { - batch.BatchCommands.Add(new MySqlBatchCommand() + for (var i = 0; i < results.Length; i++) { - CommandText = "SELECT id, randomnumber FROM world WHERE id = @id", - Parameters = { new MySqlParameter("@id", _random.Next(1, 10001)) } - }); - } - - using var reader = await batch.ExecuteReaderAsync(); - - for (var i = 0; i < count; i++) - { - await reader.ReadAsync(); - results[i] = new World { Id = reader.GetInt32(0), RandomNumber = reader.GetInt32(1) }; - await reader.NextResultAsync(); + queryParameter.Value = Random.Shared.Next(1, 10001); + results[i] = await ReadSingleRow(queryCmd); + } } return results; @@ -144,23 +136,34 @@ public async Task LoadMultipleUpdatesRows(int count) { var results = new World[count]; + var ids = new int[count]; + for (var i = 0; i < count; i++) + { + ids[i] = Random.Shared.Next(1, 10001); + } + Array.Sort(ids); + using var connection = await _dataSource.OpenConnectionAsync(); + // Each row must be selected randomly using one query in the same fashion as the single database query test + // Use of IN clauses or similar means to consolidate multiple queries into one operation is not permitted. + // Similarly, use of a batch or multiple SELECTs within a single statement are not permitted var (queryCmd, queryParameter) = await CreateReadCommandAsync(connection); using (queryCmd) { for (var i = 0; i < results.Length; i++) { + queryParameter.Value = ids[i]; results[i] = await ReadSingleRow(queryCmd); - queryParameter.Value = _random.Next(1, 10001); } } + // MySql doesn't have the unnest function like PostgreSQL, so we have to do a batch update instead using (var updateCmd = new MySqlCommand(BatchUpdateString.Query(count), connection)) { for (var i = 0; i < results.Length; i++) { - var randomNumber = _random.Next(1, 10001); + var randomNumber = Random.Shared.Next(1, 10001); updateCmd.Parameters.AddWithValue($"@Id_{i}", results[i].Id); updateCmd.Parameters.AddWithValue($"@Random_{i}", randomNumber); @@ -204,7 +207,7 @@ public async Task> LoadFortunesRows() private async Task<(MySqlCommand readCmd, MySqlParameter idParameter)> CreateReadCommandAsync(MySqlConnection connection) { var cmd = new MySqlCommand("SELECT id, randomnumber FROM world WHERE id = @Id", connection); - var parameter = new MySqlParameter("@Id", _random.Next(1, 10001)); + var parameter = new MySqlParameter("@Id", Random.Shared.Next(1, 10001)); cmd.Parameters.Add(parameter); diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbNpgsql.cs b/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbNpgsql.cs index 60aeb9bd9a2..e8e05ab34e9 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbNpgsql.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/Data/RawDbNpgsql.cs @@ -10,21 +10,20 @@ using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; using Npgsql; +using NpgsqlTypes; namespace PlatformBenchmarks; public sealed class RawDb { - private readonly ConcurrentRandom _random; private readonly MemoryCache _cache = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromMinutes(60) }); private readonly NpgsqlDataSource _dataSource; - public RawDb(ConcurrentRandom random, AppSettings appSettings) + public RawDb(AppSettings appSettings) { - _random = random; - _dataSource = NpgsqlDataSource.Create(appSettings.ConnectionString); + _dataSource = new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).EnableArrays().Build(); } public async Task LoadSingleQueryRow() @@ -42,10 +41,10 @@ public Task LoadCachedQueries(int count) var result = new CachedWorld[count]; var cacheKeys = _cacheKeys; var cache = _cache; - var random = _random; + for (var i = 0; i < result.Length; i++) { - var id = random.Next(1, 10001); + var id = Random.Shared.Next(1, 10001); var key = cacheKeys[id]; if (cache.TryGetValue(key, out var cached)) { @@ -76,7 +75,7 @@ static async Task LoadUncachedQueries(int id, int i, int count, R { result[i] = await rawdb._cache.GetOrCreateAsync(key, create); - id = rawdb._random.Next(1, 10001); + id = Random.Shared.Next(1, 10001); idParameter.TypedValue = id; key = cacheKeys[id]; } @@ -109,30 +108,18 @@ public async Task LoadMultipleQueriesRows(int count) using var connection = await _dataSource.OpenConnectionAsync(); - using var batch = new NpgsqlBatch(connection) - { - // Inserts a PG Sync message between each statement in the batch, required for compliance with - // TechEmpower general test requirement 7 - // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview - EnableErrorBarriers = true - }; - - for (var i = 0; i < count; i++) + // It is not acceptable to execute multiple SELECTs within a single complex query. + // It is not acceptable to retrieve all required rows using a SELECT ... WHERE id IN (...) clause. + // Pipelining of network traffic between the application and database is permitted. + + var (queryCmd, queryParameter) = CreateReadCommand(connection); + using (queryCmd) { - batch.BatchCommands.Add(new() + for (var i = 0; i < results.Length; i++) { - CommandText = "SELECT id, randomnumber FROM world WHERE id = $1", - Parameters = { new NpgsqlParameter { TypedValue = _random.Next(1, 10001) } } - }); - } - - using var reader = await batch.ExecuteReaderAsync(); - - for (var i = 0; i < count; i++) - { - await reader.ReadAsync(); - results[i] = new World { Id = reader.GetInt32(0), RandomNumber = reader.GetInt32(1) }; - await reader.NextResultAsync(); + queryParameter.TypedValue = Random.Shared.Next(1, 10001); + results[i] = await ReadSingleRow(queryCmd); + } } return results; @@ -142,34 +129,55 @@ public async Task LoadMultipleUpdatesRows(int count) { var results = new World[count]; - using var connection = CreateConnection(); - await connection.OpenAsync(); + var ids = new int[count]; + var numbers = new int[count]; + + for (var i = 0; i < count; i++) + { + ids[i] = Random.Shared.Next(1, 10001); + } + Array.Sort(ids); + + // Ensure unique ids by incrementing duplicates + for (var i = 1; i < count; i++) + if (ids[i] == ids[i - 1]) + ids[i] = (ids[i] % 10000) + 1; + + using var connection = await _dataSource.OpenConnectionAsync(); + // Each row must be selected randomly using one query in the same fashion as the single database query test + // Use of IN clauses or similar means to consolidate multiple queries into one operation is not permitted. + // Similarly, use of a batch or multiple SELECTs within a single statement are not permitted var (queryCmd, queryParameter) = CreateReadCommand(connection); using (queryCmd) { for (var i = 0; i < results.Length; i++) { + queryParameter.TypedValue = ids[i]; results[i] = await ReadSingleRow(queryCmd); - queryParameter.TypedValue = _random.Next(1, 10001); } } - using (var updateCmd = new NpgsqlCommand(BatchUpdateString.Query(count), connection)) + for (var i = 0; i < count; i++) { - for (var i = 0; i < results.Length; i++) + var randomNumber = Random.Shared.Next(1, 10001); + if (results[i].RandomNumber == randomNumber) { - var randomNumber = _random.Next(1, 10001); - - updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = results[i].Id }); - updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = randomNumber }); - - results[i].RandomNumber = randomNumber; + randomNumber = (randomNumber % 10000) + 1; } - await updateCmd.ExecuteNonQueryAsync(); + results[i].RandomNumber = randomNumber; + numbers[i] = randomNumber; } + var update = "UPDATE world w SET randomnumber = u.new_val FROM (SELECT unnest($1) as id, unnest($2) as new_val) u WHERE w.id = u.id"; + + using var updateCmd = new NpgsqlCommand(update, connection); + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = ids, NpgsqlDbType = NpgsqlDbType.Array | NpgsqlDbType.Integer }); + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = numbers, NpgsqlDbType = NpgsqlDbType.Array | NpgsqlDbType.Integer }); + + await updateCmd.ExecuteNonQueryAsync(); + return results; } @@ -203,7 +211,7 @@ public async Task> LoadFortunesRows() private (NpgsqlCommand readCmd, NpgsqlParameter idParameter) CreateReadCommand(NpgsqlConnection connection) { var cmd = new NpgsqlCommand("SELECT id, randomnumber FROM world WHERE id = $1", connection); - var parameter = new NpgsqlParameter { TypedValue = _random.Next(1, 10001) }; + var parameter = new NpgsqlParameter { TypedValue = Random.Shared.Next(1, 10001) }; cmd.Parameters.Add(parameter); diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj b/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj index 7db51dc3ec7..46911b46548 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj +++ b/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 true true preview @@ -18,10 +18,10 @@ - - - - + + + + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Program.cs b/frameworks/CSharp/aspnetcore/src/Platform/Program.cs index 28fc5d757dd..7877351f2da 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Program.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/Program.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; namespace PlatformBenchmarks; @@ -42,7 +43,7 @@ public static async Task Main(string[] args) await host.RunAsync(); } - public static IWebHost BuildWebHost(string[] args) + public static IHost BuildWebHost(string[] args) { Console.WriteLine($"BuildWebHost()"); Console.WriteLine($"Args: {string.Join(' ', args)}"); @@ -59,30 +60,34 @@ public static IWebHost BuildWebHost(string[] args) var appSettings = config.Get(); Console.WriteLine($"ConnectionString: {appSettings.ConnectionString}"); - BenchmarkApplication.RawDb = new RawDb(new ConcurrentRandom(), appSettings); + BenchmarkApplication.RawDb = new RawDb(appSettings); - var hostBuilder = new WebHostBuilder() - .UseBenchmarksConfiguration(config) - .UseKestrel((context, options) => + var hostBuilder = Host.CreateDefaultBuilder(args) + .ConfigureWebHost(webHostBuilder => { - var endPoint = context.Configuration.CreateIPEndPoint(); - - options.Listen(endPoint, builder => + webHostBuilder + .UseBenchmarksConfiguration(config) + .UseKestrel((context, options) => + { + var endPoint = context.Configuration.CreateIPEndPoint(); + + options.Listen(endPoint, builder => + { + builder.UseHttpApplication(); + }); + }) + .UseStartup(); + + webHostBuilder.UseSockets(options => { - builder.UseHttpApplication(); - }); - }) - .UseStartup(); - - hostBuilder.UseSockets(options => - { - options.WaitForDataBeforeAllocatingBuffer = false; + options.WaitForDataBeforeAllocatingBuffer = false; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - options.UnsafePreferInlineScheduling = true; - } - }); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + options.UnsafePreferInlineScheduling = true; + } + }); + }); var host = hostBuilder.Build(); From c017c6531bc5dbd50ab590ec7aaf369b7d79086e Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:33:27 +0100 Subject: [PATCH 073/130] [ruby/rack] Revert jruby change to MRI (#10353) JRuby should not run with MRI. --- frameworks/Ruby/rack/rack-jruby.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/rack/rack-jruby.dockerfile b/frameworks/Ruby/rack/rack-jruby.dockerfile index 16d2781a114..062547508ca 100644 --- a/frameworks/Ruby/rack/rack-jruby.dockerfile +++ b/frameworks/Ruby/rack/rack-jruby.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM jruby:10.0 RUN apt-get update -y && apt-get install netbase -y From 578ba1353a6e73418d3b54dd18c5081f614dd7b6 Mon Sep 17 00:00:00 2001 From: Diogo Martins <165835485+MDA2AV@users.noreply.github.com> Date: Mon, 1 Dec 2025 19:33:50 +0000 Subject: [PATCH 074/130] Adjust worker threads (#10352) * Adjust worker threads * Bump unhinged to 9.0.7 --- frameworks/CSharp/wiredio/UnhGHttp/Program.cs | 2 +- frameworks/CSharp/wiredio/src/Platform/Platform.csproj | 2 +- frameworks/CSharp/wiredio/src/Platform/Program.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/CSharp/wiredio/UnhGHttp/Program.cs b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs index 82acdd926d6..03d8a523ff3 100644 --- a/frameworks/CSharp/wiredio/UnhGHttp/Program.cs +++ b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs @@ -12,7 +12,7 @@ public static void Main(string[] args) { var builder = UnhingedEngine .CreateBuilder() - .SetNWorkersSolver(() => Environment.ProcessorCount / 2) + .SetNWorkersSolver(() => Environment.ProcessorCount) .SetBacklog(16384) .SetMaxEventsPerWake(512) .SetMaxNumberConnectionsPerWorker(512) diff --git a/frameworks/CSharp/wiredio/src/Platform/Platform.csproj b/frameworks/CSharp/wiredio/src/Platform/Platform.csproj index 16ae7e90e4c..ea26e67a376 100644 --- a/frameworks/CSharp/wiredio/src/Platform/Platform.csproj +++ b/frameworks/CSharp/wiredio/src/Platform/Platform.csproj @@ -20,6 +20,6 @@ - + diff --git a/frameworks/CSharp/wiredio/src/Platform/Program.cs b/frameworks/CSharp/wiredio/src/Platform/Program.cs index 24a76794d6e..cd8793de431 100644 --- a/frameworks/CSharp/wiredio/src/Platform/Program.cs +++ b/frameworks/CSharp/wiredio/src/Platform/Program.cs @@ -39,7 +39,7 @@ public static void Main(string[] args) // It's the number of real cpu cores not cpu threads // This can improve the cache hits on L1/L2 since only one thread // is running per cpu core. - .SetNWorkersSolver(() => Environment.ProcessorCount / 2) + .SetNWorkersSolver(() => Environment.ProcessorCount - 2) // Accept up to 16384 connections .SetBacklog(16384) From 1a50dcff85b86364da6ae653747496439cac1c56 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:34:36 +0100 Subject: [PATCH 075/130] [ruby/agoo] Upgrade OJ gem (#10354) --- frameworks/Ruby/agoo/Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/Ruby/agoo/Gemfile.lock b/frameworks/Ruby/agoo/Gemfile.lock index 7f05c4040ea..8fced2a2ec4 100644 --- a/frameworks/Ruby/agoo/Gemfile.lock +++ b/frameworks/Ruby/agoo/Gemfile.lock @@ -2,12 +2,12 @@ GEM remote: https://rubygems.org/ specs: agoo (2.15.13) - bigdecimal (3.1.9) + bigdecimal (3.3.1) connection_pool (2.5.0) - oj (3.16.10) + oj (3.16.12) bigdecimal (>= 3.0) ostruct (>= 0.2) - ostruct (0.6.1) + ostruct (0.6.3) pg (1.6.2) pg (1.6.2-x86_64-linux) rack (3.2.0) From ecebbf6d83b1b6e41cd18d2d5cc652989b544eac Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Mon, 1 Dec 2025 20:35:03 +0100 Subject: [PATCH 076/130] Revert "H2O: Track connection load across the worker threads (#9520)" (#10355) This reverts commit 05166707892801160d9141dad4b77f6da0c9f9f7. --- frameworks/C/h2o/src/event_loop.c | 29 ----------------------------- frameworks/C/h2o/src/event_loop.h | 5 ----- 2 files changed, 34 deletions(-) diff --git a/frameworks/C/h2o/src/event_loop.c b/frameworks/C/h2o/src/event_loop.c index 6e95bea496e..df4d37de8de 100644 --- a/frameworks/C/h2o/src/event_loop.c +++ b/frameworks/C/h2o/src/event_loop.c @@ -32,16 +32,13 @@ #include #include #include -#include #include #include "error.h" #include "event_loop.h" #include "global_data.h" #include "thread.h" -#include "utility.h" -#define CONN_NUM_SAMPLE_PERIOD 2500 #define DEFAULT_TCP_FASTOPEN_QUEUE_LEN 4096 static void accept_connection(h2o_socket_t *listener, const char *err); @@ -80,7 +77,6 @@ static void accept_connection(h2o_socket_t *listener, const char *err) if (!sock) break; - ctx->event_loop.accepted_conn_num++; ctx->event_loop.conn_num++; sock->on_close.cb = on_close_connection; sock->on_close.data = &ctx->event_loop.conn_num; @@ -299,36 +295,11 @@ static void start_accept_polling(bool is_main_thread, void event_loop(struct thread_context_t *ctx) { - uint64_t last_sample = 0; - while (!ctx->shutdown || ctx->event_loop.conn_num) { h2o_evloop_run(ctx->event_loop.h2o_ctx.loop, INT32_MAX); process_messages(&ctx->global_thread_data->h2o_receiver, &ctx->event_loop.local_messages); - - const uint64_t now = h2o_now(ctx->event_loop.h2o_ctx.loop); - - if (now - last_sample > CONN_NUM_SAMPLE_PERIOD || last_sample > now) { - const size_t i = ctx->event_loop.conn_num_sample_idx; - - ctx->event_loop.conn_num_sample[i] = ctx->event_loop.conn_num; - ctx->event_loop.conn_num_sample_idx = - (i + 1) % ARRAY_SIZE(ctx->event_loop.conn_num_sample); - last_sample = now; - } } - - flockfile(stdout); - printf("Thread %ld statistics:\nAccepted connections: %zu\nConnection number samples: %zu", - syscall(SYS_gettid), - ctx->event_loop.accepted_conn_num, - *ctx->event_loop.conn_num_sample); - - for (size_t i = 1; i < ARRAY_SIZE(ctx->event_loop.conn_num_sample); i++) - printf(",%zu", ctx->event_loop.conn_num_sample[i]); - - putc_unlocked('\n', stdout); - funlockfile(stdout); } void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver) diff --git a/frameworks/C/h2o/src/event_loop.h b/frameworks/C/h2o/src/event_loop.h index 41a1f3b920f..cff091154c7 100644 --- a/frameworks/C/h2o/src/event_loop.h +++ b/frameworks/C/h2o/src/event_loop.h @@ -27,8 +27,6 @@ #include "global_data.h" -#define CONN_NUM_SAMPLES 512 - typedef enum { SHUTDOWN, TASK @@ -43,9 +41,6 @@ typedef struct { h2o_accept_ctx_t h2o_accept_ctx; h2o_context_t h2o_ctx; h2o_linklist_t local_messages; - size_t accepted_conn_num; - size_t conn_num_sample[CONN_NUM_SAMPLES]; - size_t conn_num_sample_idx; } event_loop_t; typedef struct { From 28d378ebc659b793c5042d1c2e41854688f2b2ce Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:35:51 +0100 Subject: [PATCH 077/130] [ruby/sinatra] Use auto-configured workers (#10351) If WEB_CONCURRENCY=auto we don't need to set the workers in the puma.rb --- frameworks/Ruby/sinatra/config/{mri_puma.rb => puma.rb} | 3 +-- frameworks/Ruby/sinatra/sinatra-postgres.dockerfile | 2 +- frameworks/Ruby/sinatra/sinatra.dockerfile | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) rename frameworks/Ruby/sinatra/config/{mri_puma.rb => puma.rb} (67%) diff --git a/frameworks/Ruby/sinatra/config/mri_puma.rb b/frameworks/Ruby/sinatra/config/puma.rb similarity index 67% rename from frameworks/Ruby/sinatra/config/mri_puma.rb rename to frameworks/Ruby/sinatra/config/puma.rb index 95b855bafd3..94b2fefab95 100644 --- a/frameworks/Ruby/sinatra/config/mri_puma.rb +++ b/frameworks/Ruby/sinatra/config/puma.rb @@ -1,7 +1,6 @@ require_relative 'auto_tune' # FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune +_, num_threads = auto_tune -workers num_workers threads num_threads, num_threads diff --git a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile index 5d16f620330..7c4e265bbda 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile @@ -19,4 +19,4 @@ ENV DBTYPE=postgresql EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/sinatra.dockerfile b/frameworks/Ruby/sinatra/sinatra.dockerfile index 252f6743a01..186f4273bc6 100644 --- a/frameworks/Ruby/sinatra/sinatra.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra.dockerfile @@ -19,4 +19,4 @@ ENV DBTYPE=mysql ENV WEB_CONCURRENCY=auto EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 From 97f760a4b5a9c1a1327b81ba0567f12cea0e4441 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:36:09 +0100 Subject: [PATCH 078/130] [ruby] Update json to 2.16.0 (#10350) --- frameworks/Ruby/grape/Gemfile.lock | 2 +- frameworks/Ruby/hanami/Gemfile.lock | 2 +- frameworks/Ruby/padrino/Gemfile.lock | 2 +- frameworks/Ruby/rack-app/Gemfile.lock | 26 +++++++++++++++------ frameworks/Ruby/rack-sequel/Gemfile.lock | 2 +- frameworks/Ruby/rails/Gemfile.lock | 2 +- frameworks/Ruby/roda-sequel/Gemfile.lock | 2 +- frameworks/Ruby/sinatra-sequel/Gemfile.lock | 2 +- frameworks/Ruby/sinatra/Gemfile.lock | 2 +- 9 files changed, 27 insertions(+), 15 deletions(-) diff --git a/frameworks/Ruby/grape/Gemfile.lock b/frameworks/Ruby/grape/Gemfile.lock index a1053906658..c913c77bea0 100644 --- a/frameworks/Ruby/grape/Gemfile.lock +++ b/frameworks/Ruby/grape/Gemfile.lock @@ -51,7 +51,7 @@ GEM zeitwerk i18n (1.14.7) concurrent-ruby (~> 1.0) - json (2.11.3) + json (2.16.0) kgio (2.11.4) logger (1.6.6) minitest (5.25.4) diff --git a/frameworks/Ruby/hanami/Gemfile.lock b/frameworks/Ruby/hanami/Gemfile.lock index 853de823128..d11d1d75794 100644 --- a/frameworks/Ruby/hanami/Gemfile.lock +++ b/frameworks/Ruby/hanami/Gemfile.lock @@ -111,7 +111,7 @@ GEM zeitwerk (~> 2.6) hansi (0.2.1) ice_nine (0.11.2) - json (2.11.3) + json (2.16.0) logger (1.6.6) mustermann (3.0.3) ruby2_keywords (~> 0.0.1) diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock index 8257907ad28..38f3315b358 100644 --- a/frameworks/Ruby/padrino/Gemfile.lock +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -66,7 +66,7 @@ GEM i18n (1.14.7) concurrent-ruby (~> 1.0) iodine (0.7.58) - json (2.11.3) + json (2.16.0) logger (1.6.6) mail (2.8.1) mini_mime (>= 0.1.1) diff --git a/frameworks/Ruby/rack-app/Gemfile.lock b/frameworks/Ruby/rack-app/Gemfile.lock index 7da89e051ce..2620ee87445 100644 --- a/frameworks/Ruby/rack-app/Gemfile.lock +++ b/frameworks/Ruby/rack-app/Gemfile.lock @@ -1,29 +1,32 @@ GEM remote: https://rubygems.org/ specs: - concurrent-ruby (1.3.5) + bigdecimal (3.3.1) date (3.5.0) erb (5.1.3) io-console (0.8.1) + iodine (0.7.58) irb (1.15.3) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.15.2) + json (2.16.0) logger (1.7.0) - nio4r (2.7.5) + pg (1.6.2) + pg (1.6.2-arm64-darwin) pp (0.6.3) prettyprint prettyprint (0.2.0) psych (5.2.6) date stringio - puma (7.1.0) - nio4r (~> 2.0) rack (3.2.4) rack-app (11.0.2) rack (>= 3.0.0) rackup + rack-app-front_end (0.22.2) + rack-app (>= 6.3.1) + tilt rackup (2.2.1) rack (>= 3) rdoc (6.15.1) @@ -32,7 +35,13 @@ GEM tsort reline (0.6.2) io-console (~> 0.5) + sequel (5.98.0) + bigdecimal + sequel_pg (1.17.2) + pg (>= 0.18.0, != 1.2.0) + sequel (>= 4.38.0) stringio (3.1.7) + tilt (2.6.1) tsort (0.2.0) PLATFORMS @@ -40,12 +49,15 @@ PLATFORMS ruby DEPENDENCIES - concurrent-ruby + iodine (~> 0.7) irb json (~> 2.10) logger - puma (~> 7.1) + pg (~> 1.5) rack-app + rack-app-front_end + sequel (~> 5.0) + sequel_pg (~> 1.6) BUNDLED WITH 2.7.2 diff --git a/frameworks/Ruby/rack-sequel/Gemfile.lock b/frameworks/Ruby/rack-sequel/Gemfile.lock index 25aedc6282a..7f052698932 100644 --- a/frameworks/Ruby/rack-sequel/Gemfile.lock +++ b/frameworks/Ruby/rack-sequel/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: bigdecimal (3.3.1) concurrent-ruby (1.3.5) - json (2.13.2) + json (2.16.0) nio4r (2.7.4) pg (1.6.2) pg (1.6.2-x86_64-darwin) diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index 5b86a8d2e48..c14a68a3c0e 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -155,7 +155,7 @@ GEM pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.15.2) + json (2.16.0) localhost (1.6.0) logger (1.7.0) loofah (2.24.1) diff --git a/frameworks/Ruby/roda-sequel/Gemfile.lock b/frameworks/Ruby/roda-sequel/Gemfile.lock index cb7fb373054..37c5ce6a06e 100644 --- a/frameworks/Ruby/roda-sequel/Gemfile.lock +++ b/frameworks/Ruby/roda-sequel/Gemfile.lock @@ -6,7 +6,7 @@ GEM concurrent-ruby (1.3.5) erubi (1.13.1) iodine (0.7.58) - json (2.13.2) + json (2.16.0) nio4r (2.7.4) pg (1.6.2) pg (1.6.2-x86_64-darwin) diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile.lock b/frameworks/Ruby/sinatra-sequel/Gemfile.lock index e9d49e6d9b1..6560b48de8d 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile.lock +++ b/frameworks/Ruby/sinatra-sequel/Gemfile.lock @@ -5,7 +5,7 @@ GEM bigdecimal (3.3.1) concurrent-ruby (1.3.5) iodine (0.7.58) - json (2.13.2) + json (2.16.0) logger (1.6.6) mustermann (3.0.3) ruby2_keywords (~> 0.0.1) diff --git a/frameworks/Ruby/sinatra/Gemfile.lock b/frameworks/Ruby/sinatra/Gemfile.lock index f2d053eab26..c4b7de85016 100644 --- a/frameworks/Ruby/sinatra/Gemfile.lock +++ b/frameworks/Ruby/sinatra/Gemfile.lock @@ -28,7 +28,7 @@ GEM i18n (1.14.7) concurrent-ruby (~> 1.0) iodine (0.7.58) - json (2.13.2) + json (2.16.0) logger (1.7.0) minitest (5.25.5) mustermann (3.0.4) From 8012df6f6ce55c1d2353cdab625065b324d90fba Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:36:24 +0100 Subject: [PATCH 079/130] [ruby/rack-app] Update Gemfile.lock (#10348) From 8abe032aae991fb9c971f22a95b26c45cb2efe4b Mon Sep 17 00:00:00 2001 From: Vladimir Shchur Date: Mon, 1 Dec 2025 11:36:45 -0800 Subject: [PATCH 080/130] [F#/Oxpecker] Upgraded packages to the latest versions (#10347) * [F#/Oxpecker] Upgraded packages to the latest versions * [F#/Oxpecker] Added maintainers field * [F#/Oxpecker] Inlined readSingleRow directly in calling functions --- frameworks/FSharp/oxpecker/benchmark_config.json | 1 + frameworks/FSharp/oxpecker/src/App/App.fsproj | 6 +++--- frameworks/FSharp/oxpecker/src/App/Db.fs | 16 ++++++---------- .../FSharp/oxpecker/src/App/RenderHelpers.fs | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/frameworks/FSharp/oxpecker/benchmark_config.json b/frameworks/FSharp/oxpecker/benchmark_config.json index 562c9514420..4c8cd1bb59e 100644 --- a/frameworks/FSharp/oxpecker/benchmark_config.json +++ b/frameworks/FSharp/oxpecker/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "oxpecker", + "maintainers": ["Lanayx"], "tests": [ { "default": { diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj index c19d5d614ac..a3e2378df54 100644 --- a/frameworks/FSharp/oxpecker/src/App/App.fsproj +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -14,9 +14,9 @@ - - - + + + \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/Db.fs b/frameworks/FSharp/oxpecker/src/App/Db.fs index e4466dc08c8..7c0a4635fa0 100644 --- a/frameworks/FSharp/oxpecker/src/App/Db.fs +++ b/frameworks/FSharp/oxpecker/src/App/Db.fs @@ -32,20 +32,15 @@ module Db = cmd.Parameters.Add(id) |> ignore struct(cmd, id) - let private readSingleRow (cmd: NpgsqlCommand) = - task { - use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.SingleRow) - let! _ = rdr.ReadAsync() - return { id = rdr.GetInt32(0); randomnumber = rdr.GetInt32(1) } - } - let loadSingleRow () = task { use db = new NpgsqlConnection(ConnectionString) let struct(cmd', _) = createReadCommand db use cmd = cmd' do! db.OpenAsync() - return! readSingleRow cmd + use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.SingleRow) + let! _ = rdr.ReadAsync() + return { id = rdr.GetInt32(0); randomnumber = rdr.GetInt32(1) } } let private readMultipleRows (count: int) (conn: NpgsqlConnection) = @@ -54,8 +49,9 @@ module Db = let struct(cmd', idParam) = createReadCommand conn use cmd = cmd' for i in 0..result.Length-1 do - let! row = readSingleRow cmd - result[i] <- row + use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.SingleRow) + let! _ = rdr.ReadAsync() + result[i] <- { id = rdr.GetInt32(0); randomnumber = rdr.GetInt32(1) } idParam.TypedValue <- Random.Shared.Next(1, 10001) return result } diff --git a/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs b/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs index 7a94b2552ba..c26eb0ed93b 100644 --- a/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs +++ b/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs @@ -17,7 +17,7 @@ sb.Append(ht.Head) |> ignore for fortune in fortunesData do (tr() { - td() { raw <| string fortune.id } + td() { fortune.id } td() { fortune.message } }).Render(sb) sb.Append(ht.Tail) |> ignore From 90025728d33759eadea382101110ef85f3a1be15 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Tue, 2 Dec 2025 03:37:45 +0800 Subject: [PATCH 081/130] [xitca-web] reduce memory allocation (#10343) * [xitca-web] reduce memory allocation * generate rng with iterator * clean up module layout --- frameworks/Rust/xitca-web/Cargo.lock | 78 ++++----- frameworks/Rust/xitca-web/Cargo.toml | 27 ++-- frameworks/Rust/xitca-web/src/db.rs | 44 +++-- frameworks/Rust/xitca-web/src/db_diesel.rs | 152 +++++++++++------- frameworks/Rust/xitca-web/src/db_toasty.rs | 93 ++++------- .../Rust/xitca-web/src/db_unrealistic.rs | 46 +++--- frameworks/Rust/xitca-web/src/db_util.rs | 29 ---- frameworks/Rust/xitca-web/src/main_orm.rs | 19 +-- frameworks/Rust/xitca-web/src/schema.rs | 13 -- frameworks/Rust/xitca-web/src/util.rs | 19 ++- 10 files changed, 237 insertions(+), 283 deletions(-) delete mode 100644 frameworks/Rust/xitca-web/src/schema.rs diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index dddca17e554..8d9787826ad 100755 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -151,9 +151,9 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.47" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ "find-msvc-tools", "shlex", @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "diesel" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e7624a3bb9fffd82fff016be9a7f163d20e5a89eb8d28f9daaa6b30fff37500" +checksum = "0c415189028b232660655e4893e8bc25ca7aee8e96888db66d9edb400535456a" dependencies = [ "bitflags 2.10.0", "byteorder", @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.3.4" +version = "2.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9daac6489a36e42570da165a10c424f3edcefdff70c5fd55e1847c23f3dd7562" +checksum = "8587cbca3c929fb198e7950d761d31ca72b80aa6e07c1b7bec5879d187720436" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -664,9 +664,9 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1281,7 +1281,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "std-util" version = "0.1.0" -source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" dependencies = [ "heck", "pluralizer", @@ -1381,7 +1381,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toasty" version = "0.1.0" -source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" dependencies = [ "anyhow", "async-stream", @@ -1399,7 +1399,7 @@ dependencies = [ [[package]] name = "toasty-codegen" version = "0.1.0" -source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" dependencies = [ "proc-macro2", "quote", @@ -1410,7 +1410,7 @@ dependencies = [ [[package]] name = "toasty-core" version = "0.1.0" -source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" dependencies = [ "anyhow", "async-trait", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "toasty-macros" version = "0.1.0" -source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" dependencies = [ "proc-macro2", "quote", @@ -1436,7 +1436,7 @@ dependencies = [ [[package]] name = "toasty-sql" version = "0.1.0" -source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" dependencies = [ "anyhow", "toasty-core", @@ -1537,9 +1537,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "pin-project-lite", "tracing-core", @@ -1547,9 +1547,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" [[package]] name = "typenum" @@ -1661,9 +1661,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -1674,9 +1674,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1684,9 +1684,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ "bumpalo", "proc-macro2", @@ -1697,18 +1697,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.82" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -1851,7 +1851,7 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xitca-codegen" version = "0.4.0" -source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" +source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" dependencies = [ "quote", "syn", @@ -1860,7 +1860,7 @@ dependencies = [ [[package]] name = "xitca-http" version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" +source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" dependencies = [ "futures-core", "http", @@ -1893,7 +1893,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" +source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" dependencies = [ "fallible-iterator", "futures-core", @@ -1909,7 +1909,7 @@ dependencies = [ [[package]] name = "xitca-postgres-diesel" version = "0.2.0" -source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=8ce4e5b#8ce4e5bb138765bc1780642adfefc4d3b8427bb7" +source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=7671975#7671975951fdd71bfaedaa1686aa7c69e4af6caf" dependencies = [ "diesel", "diesel-async", @@ -1946,7 +1946,7 @@ dependencies = [ [[package]] name = "xitca-server" version = "0.5.0" -source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" +source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" dependencies = [ "socket2 0.6.1", "tokio", @@ -1960,7 +1960,7 @@ dependencies = [ [[package]] name = "xitca-service" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" +source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" [[package]] name = "xitca-unsafe-collection" @@ -2006,7 +2006,7 @@ dependencies = [ [[package]] name = "xitca-web" version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4" +source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" dependencies = [ "futures-core", "pin-project-lite", @@ -2046,18 +2046,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 87158075f2e..5b116760b18 100755 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -29,7 +29,7 @@ pg = ["dep:xitca-postgres"] # diesel orm optional diesel = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"] # toasty orm optional -toasty = ["dep:toasty", "dep:xitca-postgres-toasty"] +toasty = ["dep:toasty", "dep:xitca-postgres-toasty", "futures-util/alloc"] # http router optional router = ["xitca-http/router"] # web optional @@ -64,7 +64,7 @@ xitca-postgres = { version = "0.3", optional = true } # diesel orm optional diesel = { version = "2", features = ["postgres"], optional = true } diesel-async = { version = "0.7", features = ["bb8", "postgres"], optional = true } -xitca-postgres-diesel = { version = "0.2", optional = true } +xitca-postgres-diesel = { version = "0.2", default-features = false, optional = true } futures-util = { version = "0.3", default-features = false, optional = true } # toasty orm optional @@ -94,16 +94,17 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "8ce4e5b" } +xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "7671975" } xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "04bedb8" } -toasty = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" } -toasty-core = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" } -toasty-sql = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" } - -xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } -xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } -xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } -xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } -xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } -xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" } +# personal fork for efficient toasty engine fine tuned with pipelined xitca-postgres client +toasty = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } +toasty-core = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } +toasty-sql = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } + +xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } +xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } +xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } +xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } +xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 4a9761e7bb1..697023b33de 100755 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -10,7 +10,7 @@ use super::{ util::{DB_URL, HandleResult}, }; -use db_util::{FORTUNE_STMT, Shared, UPDATE_BATCH_STMT, WORLD_STMT, not_found}; +use db_util::{FORTUNE_STMT, Shared, UPDATE_STMT, WORLD_STMT, not_found}; pub struct Client { pool: Pool, @@ -35,19 +35,19 @@ impl Client { } pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let len = num as usize; - let mut conn = self.pool.get().await?; let stmt = WORLD_STMT.execute(&mut conn).await?; let mut res = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(len, buf); - (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query(&mut pipe))?; + let mut pipe = Pipeline::with_capacity_from_buf(num as _, buf); + rng.gen_multi() + .take(num as _) + .try_for_each(|id| stmt.bind([id]).query(&mut pipe))?; pipe.query(&conn.consume())? }; - let mut worlds = Vec::with_capacity(len); + let mut worlds = Vec::with_capacity(num as _); while let Some(mut item) = res.try_next().await? { let row = item.try_next().await?.ok_or_else(not_found)?; @@ -58,28 +58,26 @@ impl Client { } pub async fn update(&self, num: u16) -> HandleResult> { - let len = num as usize; - let mut conn = self.pool.get().await?; let world_stmt = WORLD_STMT.execute(&mut conn).await?; - let update_stmt = UPDATE_BATCH_STMT.execute(&mut conn).await?; + let update_stmt = UPDATE_STMT.execute(&mut conn).await?; let (mut res, worlds) = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); - - let (mut params, worlds) = core::iter::repeat_with(|| { - let id = rng.gen_id(); - let rand = rng.gen_id(); - world_stmt.bind([id]).query(&mut pipe)?; - HandleResult::Ok(((id, rand), World::new(id, rand))) - }) - .take(len) - .collect::, Vec<_>), _>>()?; - - params.sort(); - let (ids, rngs) = params.into_iter().collect::<(Vec<_>, Vec<_>)>(); - + let mut pipe = Pipeline::with_capacity_from_buf((num + 1) as _, buf); + + let mut ids = rng.gen_multi().take(num as _).collect::>(); + ids.sort(); + + let (rngs, worlds) = ids + .iter() + .cloned() + .zip(rng.gen_multi()) + .map(|(id, rand)| { + world_stmt.bind([id]).query(&mut pipe)?; + HandleResult::Ok((rand, World::new(id, rand))) + }) + .collect::, Vec<_>)>>()?; update_stmt.bind([&ids, &rngs]).query(&mut pipe)?; (pipe.query(&conn.consume())?, worlds) }; diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index 454a3779eab..d6bae3d2d8f 100755 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -1,48 +1,39 @@ -#[path = "./db_util.rs"] -mod db_util; - -use core::cell::RefCell; - -use std::io; - use diesel::prelude::*; use diesel_async::{ RunQueryDsl, pooled_connection::{AsyncDieselConnectionManager, bb8}, }; -use futures_util::future::{TryFutureExt, try_join, try_join_all}; +use futures_util::future::{TryFutureExt, TryJoinAll, try_join}; use xitca_postgres_diesel::AsyncPgConnection; use crate::{ - ser::{Fortune, Fortunes, World}, + ser::{Fortunes, World}, util::{DB_URL, HandleResult, Rand}, }; -use db_util::update_query_from_ids; - pub struct Pool { pool: bb8::Pool, - rng: RefCell, + rng: core::cell::RefCell, } -pub async fn create() -> io::Result { - bb8::Pool::builder() - .max_size(1) - .min_idle(Some(1)) - .test_on_check_out(false) - .build(AsyncDieselConnectionManager::new(DB_URL)) - .await - .map_err(io::Error::other) - .map(|pool| Pool { +impl Pool { + pub async fn create() -> HandleResult { + let pool = bb8::Pool::builder() + .max_size(1) + .min_idle(Some(1)) + .test_on_check_out(false) + .build(AsyncDieselConnectionManager::new(DB_URL)) + .await?; + + Ok(Self { pool, - rng: RefCell::new(Rand::default()), + rng: Default::default(), }) -} + } -impl Pool { pub async fn get_world(&self) -> HandleResult { { - use crate::schema::world::dsl::*; + use schema::world::dsl::*; let w_id = self.rng.borrow_mut().gen_id(); let mut conn = self.pool.get().await?; @@ -52,57 +43,58 @@ impl Pool { } pub async fn get_worlds(&self, num: u16) -> HandleResult> { - try_join_all({ - use crate::schema::world::dsl::*; + { + use schema::world::dsl::*; let mut conn = self.pool.get().await?; - let mut rng = self.rng.borrow_mut(); - - core::iter::repeat_with(|| { - let w_id = rng.gen_id(); - world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into) - }) - .take(num as _) - .collect::>() - }) + self.rng + .borrow_mut() + .gen_multi() + .take(num as _) + .map(|w_id| world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into)) + .collect::>() + } .await } pub async fn update(&self, num: u16) -> HandleResult> { - let (get, update) = { - use crate::schema::world::dsl::*; + { + use schema::world::dsl::*; let mut conn = self.pool.get().await?; let mut rng = self.rng.borrow_mut(); - - let (rngs, get) = core::iter::repeat_with(|| { - let w_id = rng.gen_id(); - let rng = rng.gen_id(); - - let get = world.filter(id.eq(w_id)).first::(&mut conn); - - ((w_id, rng), async move { - let mut w = get.await?; - w.randomnumber = rng; - HandleResult::Ok(w) + let mut params = Vec::with_capacity(num as _); + + let get = rng + .clone() + .gen_multi() + .take(num as _) + .zip(rng.gen_multi()) + .map(|(w_id, rng)| { + let get = world.filter(id.eq(w_id)).first::(&mut conn); + + params.push((w_id, rng)); + + async move { + let mut w = get.await?; + w.randomnumber = rng; + HandleResult::Ok(w) + } }) - }) - .take(num as _) - .collect::<(Vec<_>, Vec<_>)>(); - - let update = diesel::sql_query(update_query_from_ids(rngs)) - .execute(&mut conn) - .map_err(Into::into); + .collect::>(); - (try_join_all(get), update) - }; + let sql = update_query_from_ids(params); + let update = diesel::sql_query(sql).execute(&mut conn).map_err(Into::into); - try_join(get, update).await.map(|(worlds, _)| worlds) + try_join(get, update) + } + .await + .map(|(worlds, _)| worlds) } pub async fn tell_fortune(&self) -> HandleResult { { - use crate::schema::fortune::dsl::*; + use schema::fortune::dsl::*; let mut conn = self.pool.get().await?; fortune.load(&mut conn).map_err(Into::into) @@ -111,3 +103,43 @@ impl Pool { .map(Fortunes::new) } } + +mod schema { + diesel::table! { + world (id) { + id -> Integer, + randomnumber -> Integer, + } + } + + diesel::table! { + fortune (id) { + id -> Integer, + message -> Text, + } + } +} + +// diesel does not support high level bulk update api. use raw sql to bypass the limitation. +// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 +fn update_query_from_ids(mut rngs: Vec<(i32, i32)>) -> String { + rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); + + const PREFIX: &str = "UPDATE world SET randomNumber=w.r FROM (VALUES "; + const SUFFIX: &str = ") AS w (i,r) WHERE world.id=w.i"; + + let mut query = String::from(PREFIX); + + use core::fmt::Write; + rngs.iter().for_each(|(w_id, num)| { + write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + }); + + if query.ends_with(',') { + query.pop(); + } + + query.push_str(SUFFIX); + + query +} diff --git a/frameworks/Rust/xitca-web/src/db_toasty.rs b/frameworks/Rust/xitca-web/src/db_toasty.rs index e74f115f459..f0681ba00e6 100755 --- a/frameworks/Rust/xitca-web/src/db_toasty.rs +++ b/frameworks/Rust/xitca-web/src/db_toasty.rs @@ -1,9 +1,5 @@ -use core::cell::RefCell; - -use std::io; - +use futures_util::future::try_join_all; use toasty::Db; -use xitca_postgres_toasty::PostgreSQL; use crate::{ ser::{Fortune, Fortunes, World}, @@ -13,85 +9,50 @@ use crate::{ // this is not a realistic connection pool. pub struct Pool { db: Db, - rng: RefCell, -} - -pub async fn create() -> io::Result { - let conn = PostgreSQL::connect(DB_URL).await.unwrap(); - - let db = Db::builder() - .register::() - .register::() - .build(conn) - .await - .unwrap(); - - Ok(Pool { - db, - rng: Default::default(), - }) + rng: core::cell::RefCell, } impl Pool { + pub async fn create() -> HandleResult { + let conn = xitca_postgres_toasty::PostgreSQL::connect(DB_URL).await?; + + let db = Db::builder() + .register::() + .register::() + .build(conn) + .await?; + + Ok(Self { + db, + rng: Default::default(), + }) + } + pub async fn get_world(&self) -> HandleResult { let id = self.rng.borrow_mut().gen_id(); World::get_by_id(&self.db, id).await.map_err(Into::into) } pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let res = { - let mut rng = self.rng.borrow_mut(); - core::iter::repeat_with(|| { - let id = rng.gen_id(); - World::get_by_id(&self.db, id) - }) - .take(num as _) - .collect::>() - }; - - let mut worlds = Vec::with_capacity(num as _); - - for fut in res { - let world = fut.await?; - worlds.push(world); - } - - Ok(worlds) + try_join_all(core::iter::repeat_with(|| self.get_world()).take(num as _)).await } pub async fn update(&self, num: u16) -> HandleResult> { - let res = { - let mut rng = self.rng.borrow_mut(); + let mut worlds = self.get_worlds(num).await?; - core::iter::repeat_with(|| { - let id = rng.gen_id(); - let rng = rng.gen_id(); - - let fut = World::get_by_id(&self.db, id); - async move { - let mut world = fut.await?; - world.randomnumber = rng; - HandleResult::Ok(world) - } - }) - .take(num as _) - .collect::>() - }; - - let mut worlds = Vec::with_capacity(num as _); - - for fut in res { - let mut world = fut.await?; - let rng = world.randomnumber; - world.update().randomnumber(rng).exec(&self.db).await?; - worlds.push(world); - } + try_join_all({ + let mut rng = self.rng.borrow_mut(); + worlds + .iter_mut() + .map(move |world| world.update().randomnumber(rng.gen_id()).exec(&self.db)) + }) + .await?; Ok(worlds) } pub async fn tell_fortune(&self) -> HandleResult { - let mut fortunes = Fortune::all().all(&self.db).await?.collect::>().await?; + let fortunes = Fortune::all().all(&self.db).await?.collect().await?; Ok(Fortunes::new(fortunes)) } } diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs index 7528d79c719..6a266483fc7 100755 --- a/frameworks/Rust/xitca-web/src/db_unrealistic.rs +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -26,10 +26,10 @@ pub struct Client { pub async fn create() -> HandleResult { let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?; - tokio::task::spawn(tokio::task::unconstrained(async move { + tokio::task::spawn(async move { while drv.try_next().await?.is_some() {} HandleResult::Ok(()) - })); + }); let world = WORLD_STMT.execute(&cli).await?.leak(); let fortune = FORTUNE_STMT.execute(&cli).await?.leak(); @@ -53,16 +53,16 @@ impl Client { } pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let len = num as usize; - let mut res = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(len, buf); - (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query(&mut pipe))?; + let mut pipe = Pipeline::with_capacity_from_buf(num as _, buf); + rng.gen_multi() + .take(num as _) + .try_for_each(|id| self.world.bind([id]).query(&mut pipe))?; pipe.query(&self.cli)? }; - let mut worlds = Vec::with_capacity(len); + let mut worlds = Vec::with_capacity(num as _); while let Some(mut item) = res.try_next().await? { while let Some(row) = item.try_next().await? { @@ -78,23 +78,21 @@ impl Client { let (mut res, worlds) = { let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - // unrealistic as all queries are sent with only one sync point. - let mut pipe = Pipeline::unsync_with_capacity_from_buf(len + 1, buf); - - let (mut params, worlds) = core::iter::repeat_with(|| { - let id = rng.gen_id(); - let rand = rng.gen_id(); - self.world.bind([id]).query(&mut pipe)?; - HandleResult::Ok(((id, rand), World::new(id, rand))) - }) - .take(len) - .collect::, Vec<_>), _>>()?; - - params.sort(); - - params - .into_iter() - .try_for_each(|(id, rng)| self.update.bind([rng, id]).query(&mut pipe))?; + let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); + + let mut ids = rng.gen_multi().take(num as _).collect::>(); + ids.sort(); + + let (rngs, worlds) = ids + .iter() + .cloned() + .zip(rng.gen_multi()) + .map(|(id, rand)| { + self.world.bind([id]).query(&mut pipe)?; + HandleResult::Ok((rand, World::new(id, rand))) + }) + .collect::, Vec<_>)>>()?; + self.update.bind([&ids, &rngs]).query(&mut pipe)?; (pipe.query(&self.cli)?, worlds) }; diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs index aa2cb04a6db..83d03575709 100755 --- a/frameworks/Rust/xitca-web/src/db_util.rs +++ b/frameworks/Rust/xitca-web/src/db_util.rs @@ -1,28 +1,3 @@ -#[cfg(feature = "diesel")] -// diesel does not support high level bulk update api. use raw sql to bypass the limitation. -// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 -pub fn update_query_from_ids(mut rngs: Vec<(i32, i32)>) -> String { - rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); - - const PREFIX: &str = "UPDATE world SET randomNumber=w.r FROM (VALUES "; - const SUFFIX: &str = ") AS w (i,r) WHERE world.id=w.i"; - - let mut query = String::from(PREFIX); - - use core::fmt::Write; - rngs.iter().for_each(|(w_id, num)| { - write!(query, "({}::int,{}::int),", w_id, num).unwrap(); - }); - - if query.ends_with(',') { - query.pop(); - } - - query.push_str(SUFFIX); - - query -} - #[cfg(feature = "pg")] pub use pg::*; @@ -44,10 +19,6 @@ pub mod pg { pub const WORLD_STMT: StatementNamed = Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]); pub const UPDATE_STMT: StatementNamed = Statement::named( - "UPDATE world SET randomnumber=$1 WHERE id=$2", - &[Type::INT4, Type::INT4], - ); - pub const UPDATE_BATCH_STMT: StatementNamed = Statement::named( "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i", &[Type::INT4_ARRAY, Type::INT4_ARRAY], ); diff --git a/frameworks/Rust/xitca-web/src/main_orm.rs b/frameworks/Rust/xitca-web/src/main_orm.rs index 9b07c19a307..37311cd4f73 100755 --- a/frameworks/Rust/xitca-web/src/main_orm.rs +++ b/frameworks/Rust/xitca-web/src/main_orm.rs @@ -1,13 +1,13 @@ mod ser; mod util; -#[cfg(feature = "diesel")] -mod db_diesel; -#[cfg(feature = "diesel")] -mod schema; +#[cfg(all(feature = "diesel", not(feature = "toasty")))] +#[path = "./db_diesel.rs"] +mod orm; -#[cfg(feature = "toasty")] -mod db_toasty; +#[cfg(all(feature = "toasty", not(feature = "diesel")))] +#[path = "./db_toasty.rs"] +mod orm; use ser::{Num, World}; use util::{HandleResult, SERVER_HEADER_VALUE}; @@ -18,14 +18,11 @@ use xitca_web::{ http::{WebResponse, header::SERVER}, }; -#[cfg(feature = "diesel")] -use db_diesel::{Pool, create}; -#[cfg(feature = "toasty")] -use db_toasty::{Pool, create}; +use orm::Pool; fn main() -> std::io::Result<()> { App::new() - .with_async_state(create) + .with_async_state(Pool::create) .at_typed(db) .at_typed(fortunes) .at_typed(queries) diff --git a/frameworks/Rust/xitca-web/src/schema.rs b/frameworks/Rust/xitca-web/src/schema.rs deleted file mode 100644 index 758acfe9927..00000000000 --- a/frameworks/Rust/xitca-web/src/schema.rs +++ /dev/null @@ -1,13 +0,0 @@ -diesel::table! { - world (id) { - id -> Integer, - randomnumber -> Integer, - } -} - -diesel::table! { - fortune (id) { - id -> Integer, - message -> Text, - } -} diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index 48e2c24cc68..bccb7549ac6 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] -use core::cell::RefCell; - +use rand::{Rng, SeedableRng, distr::Uniform, rngs::SmallRng}; use xitca_http::{bytes::BytesMut, http::header::HeaderValue}; pub trait QueryParse { @@ -33,7 +32,7 @@ pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-databas pub struct State { pub client: DB, - pub write_buf: RefCell, + pub write_buf: core::cell::RefCell, } impl State { @@ -45,8 +44,6 @@ impl State { } } -use rand::{Rng, SeedableRng, rngs::SmallRng}; - pub struct Rand(SmallRng); impl Default for Rand { @@ -55,9 +52,21 @@ impl Default for Rand { } } +impl Clone for Rand { + #[inline] + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + impl Rand { #[inline] pub fn gen_id(&mut self) -> i32 { self.0.random_range(1..=10000) } + + #[inline] + pub fn gen_multi(&mut self) -> impl Iterator { + (&mut self.0).sample_iter(Uniform::new(1, 10001).unwrap()) + } } From 0446810b68ab1d72da640b2116076b2be11bf2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Mon, 1 Dec 2025 20:38:53 +0100 Subject: [PATCH 082/130] [genhttp] Improve database performance (#10340) * Switch to context pooling and compiled models * Fix tracking settings --- .../genhttp/Benchmarks/Benchmarks.csproj | 6 ++ .../DatabaseContextAssemblyAttributes.cs | 9 +++ .../CompiledModel/DatabaseContextModel.cs | 48 +++++++++++++ .../DatabaseContextModelBuilder.cs | 32 +++++++++ .../Model/CompiledModel/FortuneEntityType.cs | 68 +++++++++++++++++++ .../Model/CompiledModel/WorldEntityType.cs | 67 ++++++++++++++++++ .../genhttp/Benchmarks/Model/Database.cs | 15 ++++ .../Benchmarks/Model/DatabaseContext.cs | 41 ++++++----- .../Model/DatabaseContextFactory.cs | 18 +++++ .../Benchmarks/Model/DatabaseContextPool.cs | 46 +++++++++++++ .../genhttp/Benchmarks/Tests/CacheResource.cs | 35 ++++++---- .../genhttp/Benchmarks/Tests/DbResource.cs | 11 ++- .../Benchmarks/Tests/FortuneHandler.cs | 49 +++++++------ .../genhttp/Benchmarks/Tests/QueryResource.cs | 17 +++-- .../Benchmarks/Tests/UpdateResource.cs | 10 ++- 15 files changed, 410 insertions(+), 62 deletions(-) create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs create mode 100644 frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs diff --git a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj index 66a7a9301d9..3a3b23ee153 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj @@ -35,6 +35,12 @@ + + + + + + diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs new file mode 100644 index 00000000000..37f08394aae --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs @@ -0,0 +1,9 @@ +// +using Benchmarks; +using Benchmarks.Model; +using Microsoft.EntityFrameworkCore.Infrastructure; + +#pragma warning disable 219, 612, 618 +#nullable disable + +[assembly: DbContextModel(typeof(DatabaseContext), typeof(DatabaseContextModel))] diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs new file mode 100644 index 00000000000..1f4a1357bcc --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs @@ -0,0 +1,48 @@ +// +using Benchmarks.Model; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace Benchmarks +{ + [DbContext(typeof(DatabaseContext))] + public partial class DatabaseContextModel : RuntimeModel + { + private static readonly bool _useOldBehavior31751 = + System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751; + + static DatabaseContextModel() + { + var model = new DatabaseContextModel(); + + if (_useOldBehavior31751) + { + model.Initialize(); + } + else + { + var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024); + thread.Start(); + thread.Join(); + + void RunInitialization() + { + model.Initialize(); + } + } + + model.Customize(); + _instance = (DatabaseContextModel)model.FinalizeModel(); + } + + private static DatabaseContextModel _instance; + public static IModel Instance => _instance; + + partial void Initialize(); + + partial void Customize(); + } +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs new file mode 100644 index 00000000000..763158097cb --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs @@ -0,0 +1,32 @@ +// +using System; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace Benchmarks +{ + public partial class DatabaseContextModel + { + private DatabaseContextModel() + : base(skipDetectChanges: false, modelId: new Guid("e6a922c5-5e25-4191-8617-6c6410b754cc"), entityTypeCount: 2) + { + } + + partial void Initialize() + { + var fortune = FortuneEntityType.Create(this); + var world = WorldEntityType.Create(this); + + FortuneEntityType.CreateAnnotations(fortune); + WorldEntityType.CreateAnnotations(world); + + AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + AddAnnotation("ProductVersion", "10.0.0"); + AddAnnotation("Relational:MaxIdentifierLength", 63); + } + } +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs new file mode 100644 index 00000000000..e89e9901b1a --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs @@ -0,0 +1,68 @@ +// +using System; +using System.Reflection; +using Benchmarks.Model; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace Benchmarks +{ + [EntityFrameworkInternal] + public partial class FortuneEntityType + { + public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) + { + var runtimeEntityType = model.AddEntityType( + "Benchmarks.Model.Fortune", + typeof(Fortune), + baseEntityType, + propertyCount: 2, + keyCount: 1); + + var id = runtimeEntityType.AddProperty( + "Id", + typeof(int), + propertyInfo: typeof(Fortune).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(Fortune).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + valueGenerated: ValueGenerated.OnAdd, + afterSaveBehavior: PropertySaveBehavior.Throw, + sentinel: 0); + id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + id.AddAnnotation("Relational:ColumnName", "id"); + + var message = runtimeEntityType.AddProperty( + "Message", + typeof(string), + propertyInfo: typeof(Fortune).GetProperty("Message", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(Fortune).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + nullable: true, + maxLength: 2048); + message.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None); + message.AddAnnotation("Relational:ColumnName", "message"); + + var key = runtimeEntityType.AddKey( + new[] { id }); + runtimeEntityType.SetPrimaryKey(key); + + return runtimeEntityType; + } + + public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) + { + runtimeEntityType.AddAnnotation("Relational:FunctionName", null); + runtimeEntityType.AddAnnotation("Relational:Schema", null); + runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); + runtimeEntityType.AddAnnotation("Relational:TableName", "fortune"); + runtimeEntityType.AddAnnotation("Relational:ViewName", null); + runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); + + Customize(runtimeEntityType); + } + + static partial void Customize(RuntimeEntityType runtimeEntityType); + } +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs new file mode 100644 index 00000000000..470b07a82b8 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs @@ -0,0 +1,67 @@ +// +using System; +using System.Reflection; +using Benchmarks.Model; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace Benchmarks +{ + [EntityFrameworkInternal] + public partial class WorldEntityType + { + public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) + { + var runtimeEntityType = model.AddEntityType( + "Benchmarks.Model.World", + typeof(World), + baseEntityType, + propertyCount: 2, + keyCount: 1); + + var id = runtimeEntityType.AddProperty( + "Id", + typeof(int), + propertyInfo: typeof(World).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(World).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + valueGenerated: ValueGenerated.OnAdd, + afterSaveBehavior: PropertySaveBehavior.Throw, + sentinel: 0); + id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + id.AddAnnotation("Relational:ColumnName", "id"); + + var randomNumber = runtimeEntityType.AddProperty( + "RandomNumber", + typeof(int), + propertyInfo: typeof(World).GetProperty("RandomNumber", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(World).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + sentinel: 0); + randomNumber.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None); + randomNumber.AddAnnotation("Relational:ColumnName", "randomnumber"); + + var key = runtimeEntityType.AddKey( + new[] { id }); + runtimeEntityType.SetPrimaryKey(key); + + return runtimeEntityType; + } + + public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) + { + runtimeEntityType.AddAnnotation("Relational:FunctionName", null); + runtimeEntityType.AddAnnotation("Relational:Schema", null); + runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); + runtimeEntityType.AddAnnotation("Relational:TableName", "world"); + runtimeEntityType.AddAnnotation("Relational:ViewName", null); + runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); + + Customize(runtimeEntityType); + } + + static partial void Customize(RuntimeEntityType runtimeEntityType); + } +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs new file mode 100644 index 00000000000..c49a8e9d1a4 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs @@ -0,0 +1,15 @@ +namespace Benchmarks.Model; + +public static class Database +{ + public static readonly DatabaseContextPool NoTrackingPool; + + public static readonly DatabaseContextPool TrackingPool; + + static Database() + { + NoTrackingPool = new DatabaseContextPool(factory: DatabaseContext.CreateNoTracking, maxSize: 512); + TrackingPool = new DatabaseContextPool(factory: DatabaseContext.CreateTracking, maxSize: 512); + } + +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs index f27f1d8e245..bedd6a38454 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs @@ -1,43 +1,48 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; namespace Benchmarks.Model; public sealed class DatabaseContext : DbContext { - private static DbContextOptions _options; + private static readonly Lazy> TrackingOptions = new(() => CreateOptions(true), LazyThreadSafetyMode.ExecutionAndPublication); - private static DbContextOptions _noTrackingOptions; + private static readonly Lazy> NoTrackingOptions = new(() => CreateOptions(false), LazyThreadSafetyMode.ExecutionAndPublication); - #region Factory + public static DatabaseContext CreateTracking() => new(TrackingOptions.Value, true); - public static DatabaseContext Create() => new(_options ??= GetOptions(true)); + public static DatabaseContext CreateNoTracking() => new(NoTrackingOptions.Value, false); - public static DatabaseContext CreateNoTracking() => new(_noTrackingOptions ??= GetOptions(false)); - - private static DbContextOptions GetOptions(bool tracking) + private static DbContextOptions CreateOptions(bool tracking) { - var optionsBuilder = new DbContextOptionsBuilder(); + var services = new ServiceCollection(); + + services.AddEntityFrameworkNpgsql(); + + var provider = services.BuildServiceProvider(); - optionsBuilder.UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=512;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4"); + var builder = new DbContextOptionsBuilder(); + + builder.UseInternalServiceProvider(provider) + .UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=512;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true") + .EnableThreadSafetyChecks(false) + .UseModel(DatabaseContextModel.Instance); if (!tracking) { - optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); + builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } - return optionsBuilder.Options; + return builder.Options; } - private DatabaseContext(DbContextOptions options) : base(options) { } - - #endregion - - #region Entities + internal DatabaseContext(DbContextOptions options, bool tracking = false) : base(options) + { + ChangeTracker.AutoDetectChangesEnabled = tracking; + } public DbSet World { get; set; } public DbSet Fortune { get; set; } - #endregion - } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs new file mode 100644 index 00000000000..8c6c62c83ac --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs @@ -0,0 +1,18 @@ +namespace Benchmarks.Model; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; + +public class DatabaseContextFactory : IDesignTimeDbContextFactory +{ + + public DatabaseContext CreateDbContext(string[] args) + { + var options = new DbContextOptionsBuilder() + .UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable") + .Options; + + return new DatabaseContext(options); + } + +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs new file mode 100644 index 00000000000..aaec09ccf53 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs @@ -0,0 +1,46 @@ +namespace Benchmarks.Model; + +using System.Collections.Concurrent; + +using Microsoft.EntityFrameworkCore; + +public sealed class DatabaseContextPool where TContext : DbContext +{ + private readonly ConcurrentBag _pool = new(); + + private readonly Func _factory; + + private readonly int _maxSize; + + public DatabaseContextPool(Func factory, int maxSize) + { + _factory = factory; + _maxSize = maxSize; + } + + public TContext Rent() + { + if (_pool.TryTake(out var ctx)) + { + ctx.ChangeTracker.Clear(); + return ctx; + } + + return _factory(); + } + + public void Return(TContext context) + { + if (_pool.Count >= _maxSize) + { + context.Dispose(); + return; + } + + + context.ChangeTracker.Clear(); + + _pool.Add(context); + } + +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs index e0e4bc50d91..5a899bcadfd 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs @@ -37,29 +37,36 @@ public async ValueTask> GetWorlds(string queries) var result = new List(count); - await using var context = DatabaseContext.CreateNoTracking(); + var context = Database.NoTrackingPool.Rent(); - for (var i = 0; i < count; i++) + try { - var id = Random.Next(1, 10001); + for (var i = 0; i < count; i++) + { + var id = Random.Next(1, 10001); - var key = CacheKeys[id]; + var key = CacheKeys[id]; - var data = Cache.Get(key); + var data = Cache.Get(key); - if (data != null) - { - result.Add(data); - } - else - { - var resolved = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); + if (data != null) + { + result.Add(data); + } + else + { + var resolved = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - Cache.Set(key, resolved); + Cache.Set(key, resolved); - result.Add(resolved); + result.Add(resolved); + } } } + finally + { + Database.NoTrackingPool.Return(context); + } return result; } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs index ac33808fdfd..3363db1180d 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs @@ -13,9 +13,16 @@ public async ValueTask GetRandomWorld() { var id = Random.Next(1, 10001); - await using var context = DatabaseContext.CreateNoTracking(); + var context = Database.NoTrackingPool.Rent(); - return await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); + try + { + return await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); + } + finally + { + Database.NoTrackingPool.Return(context); + } } } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs index c7a488f5e78..5f4f6d8860c 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs @@ -48,36 +48,43 @@ public async ValueTask HandleAsync(IRequest request) private static async ValueTask> GetFortunes() { - await using var context = DatabaseContext.CreateNoTracking(); + var context = Database.NoTrackingPool.Rent(); - var fortunes = await context.Fortune.ToListAsync().ConfigureAwait(false); + try + { + var fortunes = await context.Fortune.ToListAsync().ConfigureAwait(false); - var result = new List(fortunes.Count + 1); + var result = new List(fortunes.Count + 1); + + foreach (var fortune in fortunes) + { + result.Add(Value.FromDictionary(new Dictionary() + { + ["id"] = fortune.Id, + ["message"] = HttpUtility.HtmlEncode(fortune.Message) + })); + } - foreach (var fortune in fortunes) - { result.Add(Value.FromDictionary(new Dictionary() { - ["id"] = fortune.Id, - ["message"] = HttpUtility.HtmlEncode(fortune.Message) + ["id"] = 0, + ["message"] = "Additional fortune added at request time." })); - } - - result.Add(Value.FromDictionary(new Dictionary() - { - ["id"] = 0, - ["message"] = "Additional fortune added at request time." - })); - result.Sort((one, two) => - { - var firstMessage = one.Fields["message"].AsString; - var secondMessage = two.Fields["message"].AsString; + result.Sort((one, two) => + { + var firstMessage = one.Fields["message"].AsString; + var secondMessage = two.Fields["message"].AsString; - return string.Compare(firstMessage, secondMessage, StringComparison.Ordinal); - }); + return string.Compare(firstMessage, secondMessage, StringComparison.Ordinal); + }); - return result; + return result; + } + finally + { + Database.NoTrackingPool.Return(context); + } } #endregion diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs index 592d9083242..e9a0877f542 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs @@ -29,16 +29,23 @@ public async ValueTask> GetWorlds(string queries) var result = new List(count); - using var context = DatabaseContext.CreateNoTracking(); + var context = Database.NoTrackingPool.Rent(); - for (var _ = 0; _ < count; _++) + try { - var id = Random.Next(1, 10001); + for (var _ = 0; _ < count; _++) + { + var id = Random.Next(1, 10001); - result.Add(await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false)); + result.Add(await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false)); + } + } + finally + { + Database.NoTrackingPool.Return(context); } return result; } -} \ No newline at end of file +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs index 9b2ce8e270c..826c30a7bd3 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs @@ -31,7 +31,9 @@ public async ValueTask> UpdateWorlds(string queries) var ids = Enumerable.Range(1, 10000).Select(x => Random.Next(1, 10001)).Distinct().Take(count).ToArray(); - using (var context = DatabaseContext.Create()) + var context = Database.TrackingPool.Rent(); + + try { foreach (var id in ids) { @@ -58,7 +60,11 @@ public async ValueTask> UpdateWorlds(string queries) await context.SaveChangesAsync(); } } + finally + { + Database.TrackingPool.Return(context); + } return result; } -} \ No newline at end of file +} From 7e0be4b02e790ceca34daa88f499b11475e08175 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 1 Dec 2025 20:39:16 +0100 Subject: [PATCH 083/130] [php] Fat free update to PHP 8.5 (#10339) * [php[ Fat-free update to PHP 8.5 * Hide deprecated warnings --- frameworks/PHP/fat-free/fat-free-raw.dockerfile | 8 ++++---- frameworks/PHP/fat-free/fat-free.dockerfile | 8 ++++---- frameworks/PHP/fat-free/index.php | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frameworks/PHP/fat-free/fat-free-raw.dockerfile b/frameworks/PHP/fat-free/fat-free-raw.dockerfile index 9038161bb87..c6d2550de7b 100644 --- a/frameworks/PHP/fat-free/fat-free-raw.dockerfile +++ b/frameworks/PHP/fat-free/fat-free-raw.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /fat-free COPY --link . . @@ -18,11 +18,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /fat-free EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /fat-free/deploy/nginx.conf diff --git a/frameworks/PHP/fat-free/fat-free.dockerfile b/frameworks/PHP/fat-free/fat-free.dockerfile index 3a91f8cc194..522e778a998 100644 --- a/frameworks/PHP/fat-free/fat-free.dockerfile +++ b/frameworks/PHP/fat-free/fat-free.dockerfile @@ -5,9 +5,9 @@ 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 RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.5 php8.5-common php8.5-cli php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /fat-free COPY --link . . @@ -19,11 +19,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /fat-free EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /fat-free/deploy/nginx.conf diff --git a/frameworks/PHP/fat-free/index.php b/frameworks/PHP/fat-free/index.php index 761ca19ebbb..d25faf51e31 100644 --- a/frameworks/PHP/fat-free/index.php +++ b/frameworks/PHP/fat-free/index.php @@ -9,7 +9,7 @@ /** @var Base $f3 */ $f3 = \Base::instance(); -error_reporting(-1); +error_reporting(E_ALL ^ E_DEPRECATED); $f3->set('DEBUG', 0); $f3->set('HIGHLIGHT', false); From ec593b68557f50733e282b428477c66f1be51d9b Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 1 Dec 2025 20:41:51 +0100 Subject: [PATCH 084/130] [php] DuckPHP update to PHP 8.5 (#10338) --- frameworks/PHP/duckphp/duckphp.dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/PHP/duckphp/duckphp.dockerfile b/frameworks/PHP/duckphp/duckphp.dockerfile index ae97dfc8cf6..b2de21fa9dc 100644 --- a/frameworks/PHP/duckphp/duckphp.dockerfile +++ b/frameworks/PHP/duckphp/duckphp.dockerfile @@ -6,18 +6,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq nginx git unzip \ - php8.4-cli php8.4-fpm php8.4-mysql php8.4-dev > /dev/null + php8.5-cli php8.5-fpm php8.5-mysql php8.5-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /duckphp COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /duckphp/deploy/nginx.conf From 543688a7d0de24b19ac0cb59de8682b7e5241e2d Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:43:09 +0100 Subject: [PATCH 085/130] [ruby/agoo] Change agoo display name to "agoo" (#10334) "rack [agoo]" implies that it's similar to the other "rack [puma]" or "rack [iodine]" where as agoo has a different implementation. --- frameworks/Ruby/agoo/benchmark_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Ruby/agoo/benchmark_config.json b/frameworks/Ruby/agoo/benchmark_config.json index 29c8106d1e2..d1d0d2f42b5 100644 --- a/frameworks/Ruby/agoo/benchmark_config.json +++ b/frameworks/Ruby/agoo/benchmark_config.json @@ -19,7 +19,7 @@ "webserver": "Agoo", "os": "Linux", "database_os": "Linux", - "display_name": "rack [agoo]", + "display_name": "agoo", "notes": "" } }] From abecec03cb78d3850a86ffca3ff6c6fe7c03358b Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 20:43:34 +0100 Subject: [PATCH 086/130] [ruby/grape] Update ActiveRecord to 8.1 (#10333) --- frameworks/Ruby/grape/Gemfile | 2 +- frameworks/Ruby/grape/Gemfile.lock | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/frameworks/Ruby/grape/Gemfile b/frameworks/Ruby/grape/Gemfile index 89f6c86a84e..a4432e800c1 100644 --- a/frameworks/Ruby/grape/Gemfile +++ b/frameworks/Ruby/grape/Gemfile @@ -3,6 +3,6 @@ source 'https://rubygems.org' gem 'mysql2', '0.5.6' gem 'unicorn', '6.1.0' gem 'puma', '~> 7.1' -gem 'activerecord', '~> 8.0.0', :require => 'active_record' +gem 'activerecord', '~> 8.1.0', :require => 'active_record' gem 'grape', '2.1.1' gem 'json', '~> 2.9' diff --git a/frameworks/Ruby/grape/Gemfile.lock b/frameworks/Ruby/grape/Gemfile.lock index c913c77bea0..ea2f567c78f 100644 --- a/frameworks/Ruby/grape/Gemfile.lock +++ b/frameworks/Ruby/grape/Gemfile.lock @@ -1,27 +1,26 @@ GEM remote: https://rubygems.org/ specs: - activemodel (8.0.1) - activesupport (= 8.0.1) - activerecord (8.0.1) - activemodel (= 8.0.1) - activesupport (= 8.0.1) + activemodel (8.1.1) + activesupport (= 8.1.1) + activerecord (8.1.1) + activemodel (= 8.1.1) + activesupport (= 8.1.1) timeout (>= 0.4.0) - activesupport (8.0.1) + activesupport (8.1.1) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) base64 (0.2.0) - benchmark (0.4.0) bigdecimal (3.1.9) concurrent-ruby (1.3.5) connection_pool (2.5.0) @@ -82,7 +81,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - activerecord (~> 8.0.0) + activerecord (~> 8.1.0) grape (= 2.1.1) json (~> 2.9) mysql2 (= 0.5.6) From 3a870b332fc67eeffc5bf792381dbb41299b57d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=A4=E9=9B=A8=E4=B8=9C?= Date: Tue, 2 Dec 2025 03:43:53 +0800 Subject: [PATCH 087/130] Update hyperlane (#10332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: v4.41.0 * feat: v4.42.0 * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * feat: inline * feat: dockerfile * feat: v4.52.1 * feat: remove key * remove: log * remove: log * feat: async * remove: empty loop * feat: utf8 * change: pool_size * remove: utf8 * feat: log * feat: log * feat: v3.14.1 * feat: 4.56.3 * feat: 4.56.4 * feat: 4.56.5 * feat: rename * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: speed * feat: speed * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * feat: runtime * feat: runtime * feat: runtime * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: hyperlane * feat: update * docs: readme * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: lock * feat: use super * feat: update lock * feat: update * feat: update lock * feat: update lock * feat: update lock * feat: lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * Merge remote-tracking branch 'upstream/master' * feat: update * feat: utf8 * feat: utf8 * feat: lock * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * update: code * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update version * feat: update version * update: code * Merge remote-tracking branch 'upstream/master' * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: error handle * feat: dep * feat: get_thread_count * update: code * feat: lock * feat: speed * feat: speed * update: code * feat: speed * update: code * feat: lock * fix: Framework hyperlane does not define a default test in benchmark_config.json * feat: hyperlane http version * feat: hyperlane http version * feat: toml * feat: toml * feat: toml * feat: toml * feat: v0.1.0 * feat: toml * feat: v6 * feat: v6 * feat: v6 * feat: v6 * feat: v6 * debug: test cache * debug: test cache * feat: v6 * feat: send unwrap * feat: v6 * feat: v6 * feat: v0.1.0 * feat: toml * feat: toml * feat: db * feat: toml * feat: toml * feat: toml * feat: toml * feat: dir update * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: 2025-10-24 12:22:32 * feat: v0.1.0 * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: v0.1.0 * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: 2025-11-09 18:38:22 * feat: toml * feat: toml * feat: buffer * feat: toml * feat: toml --------- Co-authored-by: 尤雨东 <83822098+ltpp-universe@users.noreply.github.com> --- frameworks/Rust/hyperlane/Cargo.lock | 64 ++++++++++------------------ frameworks/Rust/hyperlane/Cargo.toml | 2 +- 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/frameworks/Rust/hyperlane/Cargo.lock b/frameworks/Rust/hyperlane/Cargo.lock index 2f8ba49c1ee..2f2555e7d0e 100644 --- a/frameworks/Rust/hyperlane/Cargo.lock +++ b/frameworks/Rust/hyperlane/Cargo.lock @@ -274,9 +274,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -514,9 +514,9 @@ dependencies = [ [[package]] name = "http-compress" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1b2aca6817a5a211bd1aeafd3f3f5c9d222f3b1cac5416f667fd04d5ac655d" +checksum = "5a7b163ab0da395ee1f950d547b44ac3b73ed1a351d53454d6ae811e9daa288e" dependencies = [ "brotli", "flate2", @@ -525,15 +525,15 @@ dependencies = [ [[package]] name = "http-constant" -version = "1.70.0" +version = "1.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dd700ca01982ad65f60942687599f3ac04cf1010673b80af480f1f1f15592a" +checksum = "353963e842122ef31dd4a109444c59b28077852ca41717ebe643e4b70b116838" [[package]] name = "http-type" -version = "5.9.0" +version = "5.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e700017e6818aca191fd8a2f8ba8f524954375b9525f3dd9aabc83c4f999ec" +checksum = "3c268b9b4b2784ef04e3725a037c187d2ae16ef65d745f03324142b39d2a83c4" dependencies = [ "hex", "http-compress", @@ -549,9 +549,9 @@ dependencies = [ [[package]] name = "hyperlane" -version = "10.12.0" +version = "10.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8285c986ed79e5932f112dafb32ee32caf77b561bb782ac4b3b1af49cc27ff09" +checksum = "5d1e64ffb83f03e3c760d206f2ac3fd4a8d799da970db25b76c10813db26f25e" dependencies = [ "aho-corasick", "http-type", @@ -1161,14 +1161,14 @@ dependencies = [ [[package]] name = "serde-xml-rs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53630160a98edebde0123eb4dfd0fce6adff091b2305db3154a9e920206eb510" +checksum = "cc2215ce3e6a77550b80a1c37251b7d294febaf42e36e21b7b411e0bf54d540d" dependencies = [ "log", "serde", - "thiserror 1.0.69", - "xml-rs", + "thiserror", + "xml", ] [[package]] @@ -1347,7 +1347,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror 2.0.17", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -1429,7 +1429,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror", "tracing", "whoami", ] @@ -1466,7 +1466,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror", "tracing", "whoami", ] @@ -1490,7 +1490,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.17", + "thiserror", "tracing", "url", ] @@ -1540,33 +1540,13 @@ dependencies = [ "syn", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.17", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "thiserror-impl", ] [[package]] @@ -1947,10 +1927,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] -name = "xml-rs" -version = "0.8.27" +name = "xml" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" +checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" [[package]] name = "yoke" diff --git a/frameworks/Rust/hyperlane/Cargo.toml b/frameworks/Rust/hyperlane/Cargo.toml index 88209c8ce36..5faf8434fa4 100644 --- a/frameworks/Rust/hyperlane/Cargo.toml +++ b/frameworks/Rust/hyperlane/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ [dependencies] futures = "0.3.31" -hyperlane = "10.12.0" +hyperlane = "10.13.1" hyperlane-time = "0.7.12" num_cpus = "1.17.0" once_cell = "1.21.3" From 732b6bf7d37380a362239cb56748d63d73a705ab Mon Sep 17 00:00:00 2001 From: Gabriel Scatolin <17441745+CypherPotato@users.noreply.github.com> Date: Mon, 1 Dec 2025 16:44:23 -0300 Subject: [PATCH 088/130] update versions (#10331) --- frameworks/CSharp/sisk/.dockerignore | 2 ++ frameworks/CSharp/sisk/sisk-cadente.dockerfile | 11 ++++++----- frameworks/CSharp/sisk/sisk-cadente/sisk.csproj | 2 +- frameworks/CSharp/sisk/sisk.dockerfile | 11 ++++++----- frameworks/CSharp/sisk/sisk/sisk.csproj | 2 +- 5 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 frameworks/CSharp/sisk/.dockerignore diff --git a/frameworks/CSharp/sisk/.dockerignore b/frameworks/CSharp/sisk/.dockerignore new file mode 100644 index 00000000000..36094dc1468 --- /dev/null +++ b/frameworks/CSharp/sisk/.dockerignore @@ -0,0 +1,2 @@ +**/[b|B]in/ +**/[O|o]bj/ \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk-cadente.dockerfile b/frameworks/CSharp/sisk/sisk-cadente.dockerfile index 34092a0e15c..1db042daef7 100644 --- a/frameworks/CSharp/sisk/sisk-cadente.dockerfile +++ b/frameworks/CSharp/sisk/sisk-cadente.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,17 +7,18 @@ RUN dotnet restore -r linux-musl-x64 # copy and publish app and libraries COPY sisk-cadente/ . -RUN dotnet publish -c release -o /app +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun=0 ENV DOTNET_HillClimbing_Disable=1 -# final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime WORKDIR /app COPY --from=build /app . -ENTRYPOINT ["dotnet", "./sisk.dll"] +ENTRYPOINT ["./sisk"] EXPOSE 8080 \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj b/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj index 12f1a5d7c2c..01c1524d5b6 100644 --- a/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj +++ b/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj @@ -9,7 +9,7 @@ - + \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk.dockerfile b/frameworks/CSharp/sisk/sisk.dockerfile index 6509bffbd8a..1c6d9d3f3e2 100644 --- a/frameworks/CSharp/sisk/sisk.dockerfile +++ b/frameworks/CSharp/sisk/sisk.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,17 +7,18 @@ RUN dotnet restore -r linux-musl-x64 # copy and publish app and libraries COPY sisk/ . -RUN dotnet publish -c release -o /app -r linux-musl-x64 +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ENV DOTNET_GCDynamicAdaptationMode=0 ENV DOTNET_ReadyToRun=0 ENV DOTNET_HillClimbing_Disable=1 -# final stage/image -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime WORKDIR /app COPY --from=build /app . -ENTRYPOINT ["dotnet", "./sisk.dll"] +ENTRYPOINT ["./sisk"] EXPOSE 8080 \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk/sisk.csproj b/frameworks/CSharp/sisk/sisk/sisk.csproj index e767d50ede0..17f488a6242 100644 --- a/frameworks/CSharp/sisk/sisk/sisk.csproj +++ b/frameworks/CSharp/sisk/sisk/sisk.csproj @@ -9,7 +9,7 @@ - + From ba8bfe90bbf7d537776f596fb9a372f58207a151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <76547834+RRQM@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:45:11 +0800 Subject: [PATCH 089/130] =?UTF-8?q?Optimization=20(TouchSocket):=20Upgrade?= =?UTF-8?q?=20the=20target=20framework=20and=20dependen=E2=80=A6=20(#10330?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Optimization (TouchSocket): Upgrade the target framework and dependency versions. Upgrade all projects to .NET 10.0 and update the dependency packages to the latest versions. * 新增(Program): 增加管道配置及优化内存管理 新增对 System.Buffers 和 System.IO.Pipelines 的引用,优化内存分配和数据流处理。在 TouchSocketConfig 中新增 ReceivePipeOptions 和 SendPipeOptions 配置,支持自定义管道选项。将部分变量声明改为显式类型以提升代码可读性。新增对 System.Text.Json.Serialization 和 TouchSocket.Rpc 的引用,为后续功能扩展做准备。容器配置中新增 AddRpcStore 调用,支持 RPC 功能。 * 新增(Program.cs): 配置管道选项优化服务器性能 引入 `System.Buffers` 和 `System.IO.Pipelines` 命名空间以支持内存池和管道功能。将 `server` 变量的声明从 `var` 改为显式类型 `MyServer`。在 `SetupAsync` 方法中,添加 `TransportOption` 配置,设置 `BufferOnDemand` 为 `false`,并配置 `ReceivePipeOptions` 和 `SendPipeOptions`,以优化服务器性能。删除多余空行。 --- .../src/TouchSocketHttp/Program.cs | 26 +++++++++++++++-- .../TouchSocketHttp/TouchSocketHttp.csproj | 4 +-- .../TouchSocketHttp31.csproj | 2 +- .../src/TouchSocketHttpPlatform/Program.cs | 28 +++++++++++++++++-- .../TouchSocketHttpPlatform.csproj | 4 +-- .../src/TouchSocketWebApi/Program.cs | 20 +++++++++++++ .../TouchSocketWebApi.csproj | 8 +++--- .../TouchSocketWebApi31.csproj | 4 +-- .../touchsocket/touchsocket-http.dockerfile | 4 +-- .../touchsocket/touchsocket-http31.dockerfile | 4 +-- .../touchsocket-httpplatform.dockerfile | 4 +-- .../touchsocket-webapi31.dockerfile | 4 +-- .../CSharp/touchsocket/touchsocket.dockerfile | 4 +-- 13 files changed, 90 insertions(+), 26 deletions(-) diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs index baa00f9da87..de84e8b6028 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs @@ -1,3 +1,5 @@ +using System.Buffers; +using System.IO.Pipelines; using System.Text; using TouchSocket.Core; using TouchSocket.Http; @@ -10,7 +12,7 @@ public class Program private static async Task Main(string[] args) { int port = 8080; - var service = new MyHttpService(); + MyHttpService service = new MyHttpService(); await service.SetupAsync(new TouchSocketConfig() .SetListenIPHosts(port) @@ -18,6 +20,24 @@ await service.SetupAsync(new TouchSocketConfig() .SetTransportOption(options => { options.BufferOnDemand = false; + + options.ReceivePipeOptions = new PipeOptions( + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 1024 * 1024, + resumeWriterThreshold: 1024 * 512, + minimumSegmentSize: -1, + useSynchronizationContext: false); + + options.SendPipeOptions = new PipeOptions( + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 64 * 1024, + resumeWriterThreshold: 32 * 1024, + minimumSegmentSize: -1, + useSynchronizationContext: false); }) .ConfigureContainer(a => { @@ -48,8 +68,8 @@ internal sealed class MyHttpSessionClient : HttpSessionClient protected override async Task OnReceivedHttpRequest(HttpContext httpContext) { - var request = httpContext.Request; - var response = httpContext.Response; + HttpRequest request = httpContext.Request; + HttpResponse response = httpContext.Response; switch (request.RelativeURL) { diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj index 073c2d99413..c8e3323ca64 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj @@ -1,14 +1,14 @@  - net9.0 + net10.0 enable Exe enable - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj index 8f8a2d69035..9b0d67f1fad 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable Exe enable diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs index 95576ee70b5..7957bcd8c22 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs @@ -10,6 +10,8 @@ // 感谢您的下载和使用 // ------------------------------------------------------------------------------ +using System.Buffers; +using System.IO.Pipelines; using TouchSocket.Core; using TouchSocket.Sockets; @@ -19,10 +21,32 @@ internal class Program { private static async Task Main(string[] args) { - var server = new MyServer(); + MyServer server = new MyServer(); await server.SetupAsync(new TouchSocketConfig() .SetListenIPHosts(8080) .SetMaxCount(1000000) + .SetTransportOption(options => + { + options.BufferOnDemand = false; + + options.ReceivePipeOptions = new PipeOptions( + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 1024 * 1024, + resumeWriterThreshold: 1024 * 512, + minimumSegmentSize: -1, + useSynchronizationContext: false); + + options.SendPipeOptions = new PipeOptions( + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 64 * 1024, + resumeWriterThreshold: 32 * 1024, + minimumSegmentSize: -1, + useSynchronizationContext: false); + }) .ConfigureContainer(a => { a.AddConsoleLogger(); @@ -30,7 +54,7 @@ await server.SetupAsync(new TouchSocketConfig() await server.StartAsync(); Console.WriteLine("HTTP服务器已启动,端口: 8080"); - + while (true) { Console.ReadLine(); diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj index 8e9841293fc..f79663a0b2b 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj @@ -2,12 +2,12 @@ Exe - net9.0 + net10.0 enable enable - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs index 4033ac03745..1dc198dc165 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs @@ -1,3 +1,5 @@ +using System.Buffers; +using System.IO.Pipelines; using System.Text; using System.Text.Json.Serialization; using TouchSocket.Core; @@ -21,6 +23,24 @@ public static void Main(string[] args) .SetTransportOption(options => { options.BufferOnDemand = false; + + options.ReceivePipeOptions = new PipeOptions( + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 1024 * 1024, + resumeWriterThreshold: 1024 * 512, + minimumSegmentSize: -1, + useSynchronizationContext: false); + + options.SendPipeOptions = new PipeOptions( + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 64 * 1024, + resumeWriterThreshold: 32 * 1024, + minimumSegmentSize: -1, + useSynchronizationContext: false); }) .ConfigureContainer(a => { diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj index 909c2f984ee..c2b0eb4e17a 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj @@ -1,15 +1,15 @@ - net9.0 + net10.0 enable enable dotnet-WorkerService1-19b37b17-6043-4334-ad9a-9e0e3c670da3 - - - + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj index d385bc8caed..3dafc4791f5 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable true @@ -11,7 +11,7 @@ - + diff --git a/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile index 28def83f5e4..037e5d84bec 100644 --- a/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile +++ b/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/TouchSocketHttp . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile index b7437e1068b..1b84cee0dab 100644 --- a/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile +++ b/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/TouchSocketHttp31 . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile index c20b0434e76..0f30ba9b1b6 100644 --- a/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile +++ b/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/TouchSocketHttpPlatform . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile index 0d528dbfb91..9c6ec904cca 100644 --- a/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile +++ b/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/TouchSocketWebApi31 . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/touchsocket/touchsocket.dockerfile b/frameworks/CSharp/touchsocket/touchsocket.dockerfile index 96f1a166854..aacbf99557c 100644 --- a/frameworks/CSharp/touchsocket/touchsocket.dockerfile +++ b/frameworks/CSharp/touchsocket/touchsocket.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY src/TouchSocketWebApi . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ From d690f9e3ce2d1c93de504bed4aa63c7be307787f Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 1 Dec 2025 20:45:34 +0100 Subject: [PATCH 090/130] [php] Mako update to PHP 8.5 (#10329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [php] Mako update to PHP 8.5 * Update directory structure and fix deprecations * Delete frameworks/PHP/mako/composer.lock --------- Co-authored-by: Frederic G. Østby --- .../PHP/mako/app/{ => http}/controllers/Index.php | 2 +- .../PHP/mako/app/{ => http}/routing/constraints.php | 0 .../PHP/mako/app/{ => http}/routing/middleware.php | 0 frameworks/PHP/mako/app/{ => http}/routing/routes.php | 2 +- frameworks/PHP/mako/app/init.php | 2 +- frameworks/PHP/mako/app/models/Fortune.php | 2 +- frameworks/PHP/mako/app/models/World.php | 2 +- frameworks/PHP/mako/composer.json | 2 +- frameworks/PHP/mako/mako.dockerfile | 10 +++++----- frameworks/PHP/mako/public/index.php | 3 ++- 10 files changed, 13 insertions(+), 12 deletions(-) rename frameworks/PHP/mako/app/{ => http}/controllers/Index.php (98%) rename frameworks/PHP/mako/app/{ => http}/routing/constraints.php (100%) rename frameworks/PHP/mako/app/{ => http}/routing/middleware.php (100%) rename frameworks/PHP/mako/app/{ => http}/routing/routes.php (91%) diff --git a/frameworks/PHP/mako/app/controllers/Index.php b/frameworks/PHP/mako/app/http/controllers/Index.php similarity index 98% rename from frameworks/PHP/mako/app/controllers/Index.php rename to frameworks/PHP/mako/app/http/controllers/Index.php index 701da352c36..d5ec3eecebc 100644 --- a/frameworks/PHP/mako/app/controllers/Index.php +++ b/frameworks/PHP/mako/app/http/controllers/Index.php @@ -1,6 +1,6 @@ =7.4.0", - "mako/framework": "^9.0" + "mako/framework": "^11.0" }, "autoload": { "psr-4": { diff --git a/frameworks/PHP/mako/mako.dockerfile b/frameworks/PHP/mako/mako.dockerfile index 07010604204..837761967b1 100644 --- a/frameworks/PHP/mako/mako.dockerfile +++ b/frameworks/PHP/mako/mako.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,16 +7,16 @@ 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 nginx git unzip \ - php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null + php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-xml php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ ADD ./ /mako WORKDIR /mako -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --ignore-platform-reqs --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 app EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /mako/deploy/nginx.conf diff --git a/frameworks/PHP/mako/public/index.php b/frameworks/PHP/mako/public/index.php index 8f0116fb5dc..b7e7748bb18 100644 --- a/frameworks/PHP/mako/public/index.php +++ b/frameworks/PHP/mako/public/index.php @@ -1,5 +1,6 @@ run(); +CurrentApplication::set(new Application(MAKO_APPLICATION_PATH))->run(); From fb3e557c5209b995f9f601e7ec049aabb1f1bac3 Mon Sep 17 00:00:00 2001 From: AkazawaYun <62974697+AkazawaYun@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:45:59 +0800 Subject: [PATCH 091/130] akazawayun.pro updates version. (#10327) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add new test : CSharp/akazawayun.pro * modify config and code * add content-type * update url * update package version * add 3 new tests: db、queries、updates 1. add 3 new tests: db、queries、updates; 2. split code to multi files; * - * use generated sql instead const string. * update version * fix bug of db query * set port to 8080 * 升级 akazawayun.pro 框架版本到 14 * i forget to update the port change... * test self whether work fine.. * update nuget version * why pr failed... * 不小心多提交了别人的框架...改回 * akazawayun fix bug * remove db test there is some error in mysql * confirmed there is bug in mysql.data 9.5.0 还是用8080端口吧- -b, 都用8080, 改其他的对比测时不方便 * downgrade mysql.data back to 9.4.0 * fix bug of akazawayun.pro * update version of akazawayun.pro * update version * add platform test * update nupkg version * update version * update version. * fix debug * update version. * update version. --- .../AkazawaYun.Benchmark.Platform.csproj | 2 +- .../AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs | 4 ++-- .../src/AkazawaYun.Benchmark.Platform/Program.cs | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj index cdf987fdeb8..b2312be1bbb 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj @@ -15,7 +15,7 @@ - + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs index e79ab493524..ca9bb7c1362 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs @@ -2,7 +2,7 @@ namespace AkazawaYun.Benchmark.Platform; -class MyBenchmarkReceptor : akzWebReceptorBenchmark +class MyBenchmarkReceptor : akaWebReceptorBenchmark { readonly JsonModel JsonModel; @@ -23,7 +23,7 @@ public override ValueTask SendPlaintext(IHttpContext http) public override async ValueTask SendJson(IHttpContext http) { await http.Slient.Send(DataJson_OnlyHeader); - akzJson.Text2Json(JsonModel, out ReadOnlyMemory json); + akaJson.Text2Json(JsonModel, out ReadOnlyMemory json); await http.Slient.Send(json); } public override ValueTask SendDb(IHttpContext http) diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs index e2acab53351..9be953769c4 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs @@ -4,13 +4,13 @@ namespace AkazawaYun.Benchmark.Platform; class Program { - static readonly akzWebBuilder builder; + static readonly akaWebBuilder builder; static Program() { - akzLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); - akzJson.Config(AotJsonContext.Default); - builder = akzWebBuilder.Shared.Build(new MyBenchmarkReceptor()); + akaLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); + akaJson.Config(AotJsonContext.Default); + builder = akaWebBuilder.Shared.Build(new MyBenchmarkReceptor()); } static async Task Main() { From 94ef1d2fc6623e0b1ad11f679cff7fbdde2840a7 Mon Sep 17 00:00:00 2001 From: Shyam Date: Tue, 2 Dec 2025 01:17:06 +0530 Subject: [PATCH 092/130] updated brahma-firelight with Rust_Native Router (#10300) * brahma-firelight added * cluster mode enabled * updated with native call-mode --- .../TypeScript/brahma-firelight/bun.lock | 4 +- .../TypeScript/brahma-firelight/package.json | 2 +- .../TypeScript/brahma-firelight/src/main.ts | 43 +++++++++++++------ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/frameworks/TypeScript/brahma-firelight/bun.lock b/frameworks/TypeScript/brahma-firelight/bun.lock index 067ff9b71e3..cca959f6240 100644 --- a/frameworks/TypeScript/brahma-firelight/bun.lock +++ b/frameworks/TypeScript/brahma-firelight/bun.lock @@ -4,7 +4,7 @@ "": { "name": "brahma-firelight", "dependencies": { - "brahma-firelight": "^1.5.18", + "brahma-firelight": "^1.5.20", }, "devDependencies": { "@types/bun": "latest", @@ -21,7 +21,7 @@ "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], - "brahma-firelight": ["brahma-firelight@1.5.18", "", {}, "sha512-/raDDeb6/AAHYPfvTi4vWA79BjsHwh5Eg63GWJPwWzyip3mvY0tIsNeMqHit4XBdyJZ9t0UgtsvNaHGx3zqFGw=="], + "brahma-firelight": ["brahma-firelight@1.5.20", "", {}, "sha512-ACx1E77gepT1WvHskT3AP4fGoxcp2i0Wt7/0DdornEZr5R+emrA1M8YfuA9JGfpVe0bH5L1E6lZxkpldcd3YHQ=="], "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], diff --git a/frameworks/TypeScript/brahma-firelight/package.json b/frameworks/TypeScript/brahma-firelight/package.json index c7b49a791fd..80835f2981c 100644 --- a/frameworks/TypeScript/brahma-firelight/package.json +++ b/frameworks/TypeScript/brahma-firelight/package.json @@ -14,6 +14,6 @@ "typescript": "^5" }, "dependencies": { - "brahma-firelight": "^1.5.18" + "brahma-firelight": "^1.5.20" } } \ No newline at end of file diff --git a/frameworks/TypeScript/brahma-firelight/src/main.ts b/frameworks/TypeScript/brahma-firelight/src/main.ts index 3583f916605..e7af361746b 100644 --- a/frameworks/TypeScript/brahma-firelight/src/main.ts +++ b/frameworks/TypeScript/brahma-firelight/src/main.ts @@ -1,25 +1,44 @@ -import { createApp, type Response, type Request, type App, type NextFunction, type Handler } from "brahma-firelight"; +import { createApp, type Response, type Request, type App, type NextFunction, type Handler, registerRustHotpath } from "brahma-firelight"; import cluster from "node:cluster"; import os from "node:os"; const app: App = createApp(); // Server Config Middleware -const serverInfo: Handler = (_req: Request, res: Response, next?: NextFunction) => { - res.setHeader("Server", "brahma-firelight"); - res.setHeader("Connection", "keep-alive") - next?.(); -}; +// const serverInfo: Handler = (_req: Request, res: Response, next?: NextFunction) => { +// res.setHeader("Server", "brahma-firelight"); +// res.setHeader("Connection", "keep-alive") +// next?.(); +// }; // JSON compute -app.get("/json", serverInfo, (_req: Request, res: Response) => { - res.json({ message: "Hello, World!" }); -}); +// app.get("/json", serverInfo, (_req: Request, res: Response) => { +// res.json({ message: "Hello, World!" }); +// }); + +// PLAIN-TEXT +// app.get("/plaintext", serverInfo, (_req: Request, res: Response) => { +// res.text("Hello, World!"); +// }); + + +// JSON compute +registerRustHotpath( + "GET", + "/json", + 200, + '{"Content-Type": "application/json", "Server": "brahma-firelight"}', + Buffer.from(JSON.stringify({ message: "Hello, World!" })) +); // PLAIN-TEXT -app.get("/plaintext", serverInfo, (_req: Request, res: Response) => { - res.text("Hello, World!"); -}); +registerRustHotpath( + "GET", + "/plaintext", + 200, + '{"Content-Type": "text/plain", "Server": "brahma-firelight"}', + Buffer.from("Hello, World!") +); // Port & Host const PORT = process.env.PORT || 8080; From 6e33f8e5667e75efe6ddb83e7fa4c10656a89676 Mon Sep 17 00:00:00 2001 From: ruroru <111705692+ruroru@users.noreply.github.com> Date: Mon, 1 Dec 2025 23:07:28 +0200 Subject: [PATCH 093/130] Add MaxRAMPercentage and clojure.compiler.direct-linking flags to clojure runs (#10349) Co-authored-by: jj --- frameworks/Clojure/aleph/aleph.dockerfile | 2 +- .../Clojure/aleph/src/hello/handler.clj | 12 ++++- .../compojure/compojure-raw.dockerfile | 2 +- .../Clojure/compojure/compojure.dockerfile | 2 +- .../Clojure/http-kit/http-kit-raw.dockerfile | 2 +- .../Clojure/http-kit/http-kit.dockerfile | 2 +- frameworks/Clojure/kit/deps.edn | 2 +- frameworks/Clojure/kit/kit-hiccup.dockerfile | 2 +- frameworks/Clojure/kit/kit-majavat.dockerfile | 2 +- frameworks/Clojure/kit/kit.dockerfile | 2 +- frameworks/Clojure/luminus/luminus.dockerfile | 2 +- .../Clojure/pedestal/pedestal.dockerfile | 2 +- .../Clojure/reitit/benchmark_config.json | 2 + .../Clojure/reitit/reitit-jdbc.dockerfile | 2 +- frameworks/Clojure/reitit/reitit.dockerfile | 2 +- .../Clojure/ring-http-exchange/project.clj | 4 +- .../ring-http-exchange-graalvm.dockerfile | 2 +- ...ng-http-exchange-robaho-graalvm.dockerfile | 2 +- ...ing-http-exchange-robaho-semeru.dockerfile | 2 +- .../ring-http-exchange-robaho.dockerfile | 2 +- .../ring-http-exchange.dockerfile | 2 +- .../src/ring_http_exchange/benchmark.clj | 49 ++++++++----------- .../httpserver/httpserver-graalvm.dockerfile | 2 +- .../httpserver/httpserver-postgres.dockerfile | 2 +- .../httpserver-robaho-graalvm.dockerfile | 2 +- .../httpserver-robaho-postgres.dockerfile | 2 +- .../httpserver/httpserver-robaho.dockerfile | 2 +- .../Java/httpserver/httpserver.dockerfile | 2 +- frameworks/Java/httpserver/pom.xml | 2 +- .../src/main/java/benchmarks/Server.java | 10 ++-- 30 files changed, 65 insertions(+), 62 deletions(-) diff --git a/frameworks/Clojure/aleph/aleph.dockerfile b/frameworks/Clojure/aleph/aleph.dockerfile index 7f5e9642a2c..25f19f6bf0d 100644 --- a/frameworks/Clojure/aleph/aleph.dockerfile +++ b/frameworks/Clojure/aleph/aleph.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /aleph/target/hello-aleph-standalone.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "--enable-native-access=ALL-UNNAMED", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "--enable-native-access=ALL-UNNAMED", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true","-jar", "app.jar"] diff --git a/frameworks/Clojure/aleph/src/hello/handler.clj b/frameworks/Clojure/aleph/src/hello/handler.clj index 758f5e8c98d..d7de60ebe49 100644 --- a/frameworks/Clojure/aleph/src/hello/handler.clj +++ b/frameworks/Clojure/aleph/src/hello/handler.clj @@ -19,7 +19,15 @@ (def jdbc-opts {:builder-fn rs/as-unqualified-maps}) (def db-spec - {:jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass"}) + {:auto-commit false + :connection-timeout 1000 + :validation-timeout 1000 + :idle-timeout 15000 + :max-lifetime 60000 + :minimum-idle 0 + :maximum-pool-size 128 + :register-mbeans false + :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass"}) (def datasource (connection/->pool HikariDataSource db-spec)) @@ -62,7 +70,7 @@ jdbc-opts)) (defn- update-world - [{:keys [randomnumber id]}] + [{:keys [randomnumber id]}] (jdbc/execute-one! datasource ["update \"World\" set randomNumber = ? where id = ? returning *;" randomnumber id] jdbc-opts)) diff --git a/frameworks/Clojure/compojure/compojure-raw.dockerfile b/frameworks/Clojure/compojure/compojure-raw.dockerfile index 08aa20a839b..2a3a4758188 100644 --- a/frameworks/Clojure/compojure/compojure-raw.dockerfile +++ b/frameworks/Clojure/compojure/compojure-raw.dockerfile @@ -13,4 +13,4 @@ COPY resin.xml conf/resin.xml EXPOSE 8080 -CMD ["java", "-jar", "lib/resin.jar", "console"] +CMD ["java", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "lib/resin.jar", "console"] diff --git a/frameworks/Clojure/compojure/compojure.dockerfile b/frameworks/Clojure/compojure/compojure.dockerfile index 08aa20a839b..5205fcb18e6 100644 --- a/frameworks/Clojure/compojure/compojure.dockerfile +++ b/frameworks/Clojure/compojure/compojure.dockerfile @@ -13,4 +13,4 @@ COPY resin.xml conf/resin.xml EXPOSE 8080 -CMD ["java", "-jar", "lib/resin.jar", "console"] +CMD ["java", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true","-jar", "lib/resin.jar", "console"] diff --git a/frameworks/Clojure/http-kit/http-kit-raw.dockerfile b/frameworks/Clojure/http-kit/http-kit-raw.dockerfile index d7e2dcbc93d..f0f00881f3f 100644 --- a/frameworks/Clojure/http-kit/http-kit-raw.dockerfile +++ b/frameworks/Clojure/http-kit/http-kit-raw.dockerfile @@ -7,4 +7,4 @@ RUN lein uberjar EXPOSE 8080 -CMD ["java", "-server", "-jar", "target/http-kit-standalone.jar"] +CMD ["java", "-server", "-Dclojure.compiler.direct-linking=true", "-jar", "target/http-kit-standalone.jar"] diff --git a/frameworks/Clojure/http-kit/http-kit.dockerfile b/frameworks/Clojure/http-kit/http-kit.dockerfile index d7e2dcbc93d..f0f00881f3f 100644 --- a/frameworks/Clojure/http-kit/http-kit.dockerfile +++ b/frameworks/Clojure/http-kit/http-kit.dockerfile @@ -7,4 +7,4 @@ RUN lein uberjar EXPOSE 8080 -CMD ["java", "-server", "-jar", "target/http-kit-standalone.jar"] +CMD ["java", "-server", "-Dclojure.compiler.direct-linking=true", "-jar", "target/http-kit-standalone.jar"] diff --git a/frameworks/Clojure/kit/deps.edn b/frameworks/Clojure/kit/deps.edn index 972f7bb3d3f..9fc78535261 100644 --- a/frameworks/Clojure/kit/deps.edn +++ b/frameworks/Clojure/kit/deps.edn @@ -15,7 +15,7 @@ ;; HTML templating selmer/selmer {:mvn/version "1.12.62"} - org.clojars.jj/majavat {:mvn/version "1.12.3"} + org.clojars.jj/majavat {:mvn/version "1.13.0"} hiccup/hiccup {:mvn/version "2.0.0"} ;; Database diff --git a/frameworks/Clojure/kit/kit-hiccup.dockerfile b/frameworks/Clojure/kit/kit-hiccup.dockerfile index c4b1990a3f8..01449abe9b0 100644 --- a/frameworks/Clojure/kit/kit-hiccup.dockerfile +++ b/frameworks/Clojure/kit/kit-hiccup.dockerfile @@ -13,7 +13,7 @@ COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone. EXPOSE 8080 ENV PORT=8080 -ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" +ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8 -XX:MaxRAMPercentage=70 -Dclojure.compiler.direct-linking=true" ENV JDBC_URL="jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass" ENTRYPOINT exec java $JAVA_OPTS -jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/kit-majavat.dockerfile b/frameworks/Clojure/kit/kit-majavat.dockerfile index c4b1990a3f8..ab578f90cf7 100644 --- a/frameworks/Clojure/kit/kit-majavat.dockerfile +++ b/frameworks/Clojure/kit/kit-majavat.dockerfile @@ -13,7 +13,7 @@ COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone. EXPOSE 8080 ENV PORT=8080 -ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" +ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8 -XX:MaxRAMPercentage=70 -Dclojure.compiler.direct-linking=true" ENV JDBC_URL="jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass" ENTRYPOINT exec java $JAVA_OPTS -jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/kit.dockerfile b/frameworks/Clojure/kit/kit.dockerfile index c4b1990a3f8..ab578f90cf7 100644 --- a/frameworks/Clojure/kit/kit.dockerfile +++ b/frameworks/Clojure/kit/kit.dockerfile @@ -13,7 +13,7 @@ COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone. EXPOSE 8080 ENV PORT=8080 -ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" +ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8 -XX:MaxRAMPercentage=70 -Dclojure.compiler.direct-linking=true" ENV JDBC_URL="jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass" ENTRYPOINT exec java $JAVA_OPTS -jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/luminus/luminus.dockerfile b/frameworks/Clojure/luminus/luminus.dockerfile index 9ea8a1607ac..d57102d5b41 100644 --- a/frameworks/Clojure/luminus/luminus.dockerfile +++ b/frameworks/Clojure/luminus/luminus.dockerfile @@ -12,4 +12,4 @@ COPY --from=lein /luminus/target/hello.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/pedestal/pedestal.dockerfile b/frameworks/Clojure/pedestal/pedestal.dockerfile index d0407c3c50c..fb3e7e23d34 100644 --- a/frameworks/Clojure/pedestal/pedestal.dockerfile +++ b/frameworks/Clojure/pedestal/pedestal.dockerfile @@ -8,4 +8,4 @@ RUN lein uberjar EXPOSE 8080 -CMD ["java", "-jar", "-Dio.pedestal.log.defaultMetricsRecorder=nil", "-Dio.pedestal.log.overrideLogger=nil", "target/pedestal-standalone.jar"] +CMD ["java", "-Dclojure.compiler.direct-linking=true", "-jar", "-Dio.pedestal.log.defaultMetricsRecorder=nil", "-Dio.pedestal.log.overrideLogger=nil", "target/pedestal-standalone.jar"] diff --git a/frameworks/Clojure/reitit/benchmark_config.json b/frameworks/Clojure/reitit/benchmark_config.json index e3793e46827..6f755e49966 100755 --- a/frameworks/Clojure/reitit/benchmark_config.json +++ b/frameworks/Clojure/reitit/benchmark_config.json @@ -39,6 +39,8 @@ "versus": "" }, "async": { + "json_url": "/json", + "plaintext_url": "/plaintext", "db_url": "/db", "port": 8080, "approach": "Realistic", diff --git a/frameworks/Clojure/reitit/reitit-jdbc.dockerfile b/frameworks/Clojure/reitit/reitit-jdbc.dockerfile index e202481097a..f58599d0ccb 100644 --- a/frameworks/Clojure/reitit/reitit-jdbc.dockerfile +++ b/frameworks/Clojure/reitit/reitit-jdbc.dockerfile @@ -10,4 +10,4 @@ COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar", "sync"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar", "sync"] diff --git a/frameworks/Clojure/reitit/reitit.dockerfile b/frameworks/Clojure/reitit/reitit.dockerfile index 2915a6efd2c..da4069ba341 100644 --- a/frameworks/Clojure/reitit/reitit.dockerfile +++ b/frameworks/Clojure/reitit/reitit.dockerfile @@ -10,4 +10,4 @@ COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/project.clj b/frameworks/Clojure/ring-http-exchange/project.clj index 448d887f73e..e0734cff1a5 100644 --- a/frameworks/Clojure/ring-http-exchange/project.clj +++ b/frameworks/Clojure/ring-http-exchange/project.clj @@ -6,9 +6,9 @@ :dependencies [[org.clojure/clojure "1.12.3"] [org.clojure/tools.logging "1.3.0"] - [org.clojars.jj/ring-http-exchange "1.2.4"] + [org.clojars.jj/ring-http-exchange "1.2.9"] [seancorfield/next.jdbc "1.2.659"] - [org.clojars.jj/majavat "1.12.3"] + [org.clojars.jj/majavat "1.13.0"] [hikari-cp "3.3.0"] [org.clojars.jj/boa-sql "1.0.0"] [org.postgresql/postgresql "42.7.8"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile index 53a3998cd03..ad82982bcd9 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile index 8af31aebae0..151a6746e12 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile index 64f06a3418a..bffbb459912 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-Xtune:throughput", "-Xgcpolicy:optthruput", "-XX:MaxRAMPercentage=70", "-XX:+UseContainerSupport", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile index b53eb194c09..095040b74d0 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile index 0910a6d9850..f7b8946ab06 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj index 24063d085e6..6629b7c6a39 100644 --- a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj @@ -12,36 +12,35 @@ (com.zaxxer.hikari HikariDataSource) (java.util.concurrent Executors))) +(defrecord Response [body status headers]) + (def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "fortune.sql")) (def db-spec {:auto-commit false - :connection-timeout 3000 + :connection-timeout 1000 :validation-timeout 1000 - :idle-timeout 300000 - :max-lifetime 1800000 - :minimum-idle 128 - :maximum-pool-size 1024 + :idle-timeout 15000 + :max-lifetime 60000 + :minimum-idle 0 + :maximum-pool-size 128 :register-mbeans false - :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass&prepareThreshold=1"}) + :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass&prepareThreshold=1"} + ) +(def ^:private ^:const hello-world "Hello, World!") (def ^:private ^:const additional-message {:id 0 :message "Additional fortune added at request time."}) (def ^:private ^:const fortune-headers {"Server" "ring-http-exchange" "Content-Type" "text/html; charset=UTF-8"}) (def ^:private ^:const json-headers {"Server" "ring-http-exchange" "Content-Type" "application/json"}) +(def ^:private ^:const plain-text-headers {"Server" "ring-http-exchange" + "Content-Type" "text/plain"}) (def ^:private render-fortune (majavat/build-renderer "fortune.html" {:renderer (->StringRenderer {:sanitizer (->Html)})})) - -(defn- plaintext-response [] - {:status 200 - :headers {"Server" "ring-http-exchange" - "Content-Type" "text/plain"} - :body "Hello, World!"}) - (defn- get-body [datasource] (let [context (as-> (query-fortunes datasource) fortunes (conj fortunes additional-message) @@ -50,23 +49,17 @@ (defn -main [& _] - (System/setProperty "jdk.virtualThreadScheduler.parallelism" - (str (* 4 (.availableProcessors (Runtime/getRuntime))))) - (println "Starting server on port 8080") (let [datasource (connection/->pool HikariDataSource db-spec)] (server/run-http-server (fn [req] (case (req :uri) - "/plaintext" (plaintext-response) - "/json" {:status 200 - :headers json-headers - :body (json/write-value-as-bytes {:message "Hello, World!"})} - "/fortunes" (let [body (get-body datasource)] - {:status 200 - :headers fortune-headers - :body body}) - (plaintext-response))) - {:port 8080 - :host "0.0.0.0" - :executor (Executors/newVirtualThreadPerTaskExecutor)}))) \ No newline at end of file + "/plaintext" (Response. hello-world 200 plain-text-headers) + "/json" (Response. (json/write-value-as-string {:message hello-world}) 200 json-headers) + "/fortunes" (let [body (get-body datasource)] (Response. body 200 fortune-headers)) + (Response. hello-world 200 {"Server" "ring-http-exchange" + "Content-Type" "text/plain"}))) + {:port 8080 + :host "0.0.0.0" + :record-support? true + :executor (Executors/newVirtualThreadPerTaskExecutor)}))) \ No newline at end of file diff --git a/frameworks/Java/httpserver/httpserver-graalvm.dockerfile b/frameworks/Java/httpserver/httpserver-graalvm.dockerfile index f9cd7e29cfb..9af2d5f4026 100644 --- a/frameworks/Java/httpserver/httpserver-graalvm.dockerfile +++ b/frameworks/Java/httpserver/httpserver-graalvm.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar ap EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-postgres.dockerfile index 5991ae20026..6856f3431fa 100644 --- a/frameworks/Java/httpserver/httpserver-postgres.dockerfile +++ b/frameworks/Java/httpserver/httpserver-postgres.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar ap EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar", "postgres"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar", "postgres"] diff --git a/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile index 44b6b0975f0..f6646e3095e 100644 --- a/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies EXPOSE 8080 -CMD ["java", "-server", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile index e7bdfb11102..0b99cb7fe41 100644 --- a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies EXPOSE 8080 -CMD ["java", "-server", "-jar", "app.jar", "postgres"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-jar", "app.jar", "postgres"] diff --git a/frameworks/Java/httpserver/httpserver-robaho.dockerfile b/frameworks/Java/httpserver/httpserver-robaho.dockerfile index 77f57658d2a..0943f9f7ef2 100644 --- a/frameworks/Java/httpserver/httpserver-robaho.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies EXPOSE 8080 -CMD ["java", "-server", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver.dockerfile b/frameworks/Java/httpserver/httpserver.dockerfile index b50fbadc157..2de799e386d 100644 --- a/frameworks/Java/httpserver/httpserver.dockerfile +++ b/frameworks/Java/httpserver/httpserver.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar ap EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/pom.xml b/frameworks/Java/httpserver/pom.xml index 5b983699fe6..58cf78deeda 100644 --- a/frameworks/Java/httpserver/pom.xml +++ b/frameworks/Java/httpserver/pom.xml @@ -68,7 +68,7 @@ true org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.14.1 false 21 diff --git a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java index 80566641a9f..799f183f46b 100755 --- a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java +++ b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java @@ -51,7 +51,7 @@ private static List queryFortunes(DataSource ds) throws SQLException { return fortunes; } - private static DataSource createPostgresDataSource() throws ClassNotFoundException { + private static DataSource createPostgresDataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); @@ -59,11 +59,11 @@ private static DataSource createPostgresDataSource() throws ClassNotFoundExcepti config.setPassword("benchmarkdbpass"); config.setMaximumPoolSize(64); - config.setMinimumIdle(16); + config.setMinimumIdle(0); - config.setConnectionTimeout(10000); - config.setIdleTimeout(600000); - config.setMaxLifetime(1800000); + config.setConnectionTimeout(1000); + config.setIdleTimeout(15000); + config.setMaxLifetime(60000); config.setAutoCommit(true); From e6785e8477a9626f75e09d24513c9424d7288842 Mon Sep 17 00:00:00 2001 From: Qi Yu <2170848+iyuq@users.noreply.github.com> Date: Tue, 2 Dec 2025 05:07:51 +0800 Subject: [PATCH 094/130] [rust/axum] Update axum to 0.8.7, tokio to 1.48.0, and fix compilation errors (#10346) Co-authored-by: Qi Yu --- frameworks/Rust/axum/Cargo.lock | 1340 ++++++++++++-------------- frameworks/Rust/axum/Cargo.toml | 12 +- frameworks/Rust/axum/axum.dockerfile | 2 +- frameworks/Rust/axum/src/server.rs | 2 +- 4 files changed, 624 insertions(+), 732 deletions(-) diff --git a/frameworks/Rust/axum/Cargo.lock b/frameworks/Rust/axum/Cargo.lock index d19c9254f3f..ae79df4e8d4 100644 --- a/frameworks/Rust/axum/Cargo.lock +++ b/frameworks/Rust/axum/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -24,7 +15,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -32,9 +23,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -45,21 +36,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "annotate-snippets" version = "0.9.2" @@ -72,13 +48,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -104,9 +80,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" dependencies = [ "axum-core", "bytes", @@ -123,8 +99,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -137,9 +112,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -148,7 +123,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -178,7 +152,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "simd-json", - "socket2", + "socket2 0.6.1", "sqlx", "tokio", "tokio-pg-mapper", @@ -189,33 +163,6 @@ dependencies = [ "yarte", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -230,17 +177,11 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -271,12 +212,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969a9ba84b0ff843813e7249eed1678d9b6607ce5a3b8f0a47af3fcf7978e6e" dependencies = [ "ahash", - "base64 0.22.1", + "base64", "bitvec", "getrandom 0.2.16", - "getrandom 0.3.3", + "getrandom 0.3.4", "hex", - "indexmap 2.10.0", + "indexmap", "js-sys", "once_cell", "rand 0.9.2", @@ -301,16 +242,17 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.30" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -318,22 +260,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "chrono" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-link", -] +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "concurrent-queue" @@ -376,12 +305,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "cpufeatures" version = "0.2.17" @@ -393,9 +316,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -415,6 +338,30 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -438,9 +385,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -448,9 +395,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ "darling_core", "darling_macro", @@ -458,27 +405,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "darling_macro" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -489,11 +436,12 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "deadpool" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" dependencies = [ "deadpool-runtime", + "lazy_static", "num_cpus", "serde", "tokio", @@ -536,12 +484,11 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde", ] [[package]] @@ -552,18 +499,18 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "derive-where" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -576,7 +523,28 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.104", + "syn 2.0.111", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", + "unicode-xid", ] [[package]] @@ -599,7 +567,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -620,12 +588,6 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" -[[package]] -name = "dyn-clone" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" - [[package]] name = "either" version = "1.15.0" @@ -644,7 +606,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -666,9 +628,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -681,11 +643,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -723,11 +691,17 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -805,7 +779,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -857,35 +831,29 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "h2" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -893,7 +861,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.10.0", + "indexmap", "slab", "tokio", "tokio-util", @@ -902,29 +870,34 @@ dependencies = [ [[package]] name = "halfbrown" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2c385c6df70fd180bbb673d93039dbd2cd34e41d782600bdf6e1ca7bce39aa" +checksum = "0c7ed2f2edad8a14c8186b847909a41fbb9c3eafa44f88bd891114ed5019da09" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.16.1", "serde", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", ] [[package]] @@ -933,7 +906,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -956,9 +929,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hickory-proto" -version = "0.24.4" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" +checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" dependencies = [ "async-trait", "cfg-if", @@ -970,8 +943,9 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.8.5", - "thiserror 1.0.69", + "rand 0.9.2", + "ring", + "thiserror", "tinyvec", "tokio", "tracing", @@ -980,21 +954,21 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.4" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" dependencies = [ "cfg-if", "futures-util", "hickory-proto", "ipconfig", - "lru-cache", + "moka", "once_cell", "parking_lot", - "rand 0.8.5", + "rand 0.9.2", "resolv-conf", "smallvec", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", ] @@ -1019,21 +993,20 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1074,13 +1047,14 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", @@ -1088,15 +1062,16 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", ] [[package]] name = "hyper-util" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df" +checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" dependencies = [ "bytes", "futures-core", @@ -1108,35 +1083,11 @@ dependencies = [ "tower-service", ] -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1147,9 +1098,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1160,11 +1111,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1175,42 +1125,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1226,9 +1172,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1247,35 +1193,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.15.4", - "serde", -] - -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", + "hashbrown 0.16.1", ] [[package]] @@ -1284,7 +1207,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2", + "socket2 0.5.10", "widestring", "windows-sys 0.48.0", "winreg", @@ -1304,19 +1227,19 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1333,9 +1256,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libm" @@ -1345,14 +1268,25 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" dependencies = [ "cc", "libc", ] +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -1363,42 +1297,26 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "macro_magic" @@ -1409,7 +1327,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -1423,7 +1341,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -1434,7 +1352,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -1445,7 +1363,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -1466,15 +1384,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mimalloc" -version = "0.1.47" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" dependencies = [ "libmimalloc-sys", ] @@ -1492,35 +1410,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moka" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "parking_lot", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "mongocrypt" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da0cd419a51a5fb44819e290fbdb0665a54f21dead8923446a799c7f4d26ad9" +dependencies = [ + "bson", + "mongocrypt-sys", + "once_cell", + "serde", ] +[[package]] +name = "mongocrypt-sys" +version = "0.1.5+1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224484c5d09285a7b8cb0a0c117e847ebd14cb6e4470ecf68cdb89c503b0edb9" + [[package]] name = "mongodb" -version = "3.2.4" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f8c69f13acf07eae386a2974f48ffd9187ea2aba8defbea9aa34e7e272c5f3" +checksum = "12f5c20217413bed97c613714e6d6dfe39ef59dd79a68999f1043b0566192975" dependencies = [ - "async-trait", - "base64 0.13.1", - "bitflags 1.3.2", + "base64", + "bitflags", "bson", - "chrono", "derive-where", - "derive_more", + "derive_more 2.0.1", "flate2", "futures-core", - "futures-executor", "futures-io", "futures-util", "hex", @@ -1529,53 +1481,52 @@ dependencies = [ "hmac", "macro_magic", "md-5", + "mongocrypt", "mongodb-internal-macros", - "once_cell", "pbkdf2", "percent-encoding", - "rand 0.8.5", + "rand 0.9.2", "rustc_version_runtime", - "rustls 0.21.12", - "rustls-pemfile", + "rustls", + "rustversion", "serde", "serde_bytes", "serde_with", "sha1", "sha2", "snap", - "socket2", + "socket2 0.6.1", "stringprep", "strsim", "take_mut", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-rustls", "tokio-util", "typed-builder", "uuid", - "webpki-roots 0.25.4", + "webpki-roots 1.0.4", "zstd", ] [[package]] name = "mongodb-internal-macros" -version = "3.2.4" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9202de265a3a8bbb43f9fe56db27c93137d4f9fb04c093f47e9c7de0c61ac7d" +checksum = "20033442aa13664e70bc9f8be1bacabebf6a31b6d4bb5608ceb99c4ec96e9951" dependencies = [ "macro_magic", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -1632,20 +1583,15 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "parking" @@ -1655,9 +1601,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1665,22 +1611,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", ] @@ -1696,24 +1642,25 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_shared", + "serde", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -1757,13 +1704,19 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + [[package]] name = "postgres-protocol" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" dependencies = [ - "base64 0.22.1", + "base64", "byteorder", "bytes", "fallible-iterator", @@ -1777,9 +1730,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" dependencies = [ "bytes", "fallible-iterator", @@ -1788,9 +1741,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1822,30 +1775,30 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quick_cache" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b450dad8382b1b95061d5ca1eb792081fb082adf48c678791fe917509596d5f" +checksum = "7ada44a88ef953a3294f6eb55d2007ba44646015e18613d2f213016379203ef3" dependencies = [ "ahash", "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.1", "parking_lot", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -1918,43 +1871,43 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.14" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3a5d9f0aba1dbcec1cc47f0ff94a4b778fe55bca98a6dfa92e4e094e57b1c4" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.1", + "bitflags", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -1964,9 +1917,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -1975,15 +1928,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "resolv-conf" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3" +checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "ring" @@ -2001,9 +1954,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" dependencies = [ "const-oid", "digest", @@ -2019,12 +1972,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - [[package]] name = "rustc_version" version = "0.4.1" @@ -2046,63 +1993,33 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" -dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.4" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -2111,9 +2028,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2121,102 +2038,81 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.17" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.10.0", + "indexmap", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -2233,34 +2129,24 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.10.0", - "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", - "serde_json", + "serde_core", "serde_with_macros", - "time", ] [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -2293,9 +2179,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -2310,13 +2196,18 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simd-json" -version = "0.15.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c962f626b54771990066e5435ec8331d1462576cd2d1e62f24076ae014f92112" +checksum = "4255126f310d2ba20048db6321c81ab376f6a6735608bf11f0785c41f01f64e3" dependencies = [ - "getrandom 0.3.3", "halfbrown", "ref-cast", "serde", @@ -2339,9 +2230,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -2368,6 +2259,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "spin" version = "0.9.8" @@ -2406,7 +2307,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "crc", "crossbeam-queue", @@ -2416,19 +2317,19 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "hashlink", - "indexmap 2.10.0", + "indexmap", "log", "memchr", "once_cell", "percent-encoding", - "rustls 0.23.29", + "rustls", "serde", "serde_json", "sha2", "smallvec", - "thiserror 2.0.12", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -2446,7 +2347,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -2469,7 +2370,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.104", + "syn 2.0.111", "tokio", "url", ] @@ -2481,8 +2382,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64 0.22.1", - "bitflags 2.9.1", + "base64", + "bitflags", "byteorder", "bytes", "crc", @@ -2511,7 +2412,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.12", + "thiserror", "tracing", "whoami", ] @@ -2523,8 +2424,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64 0.22.1", - "bitflags 2.9.1", + "base64", + "bitflags", "byteorder", "crc", "dotenvy", @@ -2548,7 +2449,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.12", + "thiserror", "tracing", "whoami", ] @@ -2572,16 +2473,16 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.12", + "thiserror", "tracing", "url", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stringprep" @@ -2619,9 +2520,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -2642,9 +2543,15 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "take_mut" version = "0.2.2" @@ -2659,49 +2566,29 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2714,15 +2601,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2739,9 +2626,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -2749,9 +2636,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -2764,33 +2651,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.46.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -2815,9 +2699,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" +checksum = "2b40d66d9b2cfe04b628173409368e58247e8eddbbd3b0e6c6ba1d09f20f6c9e" dependencies = [ "async-trait", "byteorder", @@ -2833,7 +2717,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand 0.9.2", - "socket2", + "socket2 0.6.1", "tokio", "tokio-util", "whoami", @@ -2841,11 +2725,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.21.12", + "rustls", "tokio", ] @@ -2862,9 +2746,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -2900,11 +2784,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ - "bitflags 2.9.1", + "bitflags", "bytes", "http", "pin-project-lite", @@ -2926,9 +2810,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "log", "pin-project-lite", @@ -2938,40 +2822,49 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", ] [[package]] name = "typed-builder" -version = "0.10.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +checksum = "398a3a3c918c96de527dc11e6e846cd549d4508030b8a33e1da12789c856b81a" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e48cea23f68d1f78eb7bc092881b6bb88d3d6b5b7e6234f6f9c911da1ffb221" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-bidi" @@ -2981,24 +2874,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-width" @@ -3020,13 +2913,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -3037,11 +2931,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "serde", "wasm-bindgen", @@ -3065,9 +2959,9 @@ checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" [[package]] name = "value-trait" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0508fce11ad19e0aab49ce20b6bec7f8f82902ded31df1c9fc61b90f0eb396b8" +checksum = "8e80f0c733af0720a501b3905d22e2f97662d8eacfe082a75ed7ffb5ab08cb59" dependencies = [ "float-cmp", "halfbrown", @@ -3094,12 +2988,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -3110,35 +3004,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3146,76 +3027,70 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.104", - "wasm-bindgen-backend", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", "web-sys", ] [[package]] name = "widestring" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "winapi" @@ -3239,64 +3114,11 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -3318,11 +3140,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -3349,13 +3180,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3368,6 +3216,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3380,6 +3234,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3392,12 +3252,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3410,6 +3282,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3422,6 +3300,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3434,6 +3318,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3446,6 +3336,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winreg" version = "0.50.0" @@ -3457,19 +3353,16 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -3548,7 +3441,7 @@ version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee42d2f704a3b1d8bc111d47a705d1302a0943d85e4c230f4e8300ee0dde4a6" dependencies = [ - "derive_more", + "derive_more 0.99.20", "proc-macro2", "quote", "syn 1.0.109", @@ -3565,7 +3458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "538f72049cf7104e12d5c444048d112cb8fc788a31308afd912442a381ba860c" dependencies = [ "annotate-snippets", - "derive_more", + "derive_more 0.99.20", "proc-macro2", "quote", "serde", @@ -3576,11 +3469,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3588,34 +3480,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -3635,21 +3527,21 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -3658,9 +3550,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -3669,13 +3561,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.111", ] [[package]] @@ -3699,9 +3591,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", diff --git a/frameworks/Rust/axum/Cargo.toml b/frameworks/Rust/axum/Cargo.toml index be0bf32250a..b17c3ea4209 100644 --- a/frameworks/Rust/axum/Cargo.toml +++ b/frameworks/Rust/axum/Cargo.toml @@ -39,7 +39,7 @@ simd-json = [ ] [dependencies] -axum = { version = "0.8.4", default-features = false, features = [ +axum = { version = "0.8.7", default-features = false, features = [ "json", "query", "http1", @@ -66,20 +66,20 @@ sqlx = { version = "0.8.6", features = [ "runtime-tokio", "tls-rustls", ] } -tokio = { version = "1.46.1", features = ["full"] } +tokio = { version = "1.48.0", features = ["full"] } tokio-pg-mapper = { version = "0.2.0" } tokio-pg-mapper-derive = { version = "0.2.0" } tokio-postgres = { version = "0.7.13" } tower = { version = "0.5.2", features = ["util"] } -tower-http = { version = "0.6.6", features = ["set-header"] } +tower-http = { version = "0.6.7", features = ["set-header"] } yarte = "0.15.7" -simd-json = { version = "0.15.1", optional = true } +simd-json = { version = "0.17.0", optional = true } axum-core = { version = "0.5.2", optional = true } mime = { version = "0.3.17", optional = true } bytes = { version = "1.10.1", optional = true } serde_path_to_error = { version = "0.1.17", optional = true } -socket2 = "0.5.10" -hyper = { version = "1.6", features = ["server", "http1"] } +socket2 = "0.6.1" +hyper = { version = "1.8.1", features = ["server", "http1"] } hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] } quick_cache = "0.6.14" mimalloc = "0.1.47" diff --git a/frameworks/Rust/axum/axum.dockerfile b/frameworks/Rust/axum/axum.dockerfile index 35167203a19..8ac2f9d687c 100644 --- a/frameworks/Rust/axum/axum.dockerfile +++ b/frameworks/Rust/axum/axum.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/rust:1.88-slim-bookworm AS builder +FROM docker.io/rust:1.91-slim-bookworm AS builder RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config libssl-dev \ diff --git a/frameworks/Rust/axum/src/server.rs b/frameworks/Rust/axum/src/server.rs index 52705143dba..b1a782cf182 100644 --- a/frameworks/Rust/axum/src/server.rs +++ b/frameworks/Rust/axum/src/server.rs @@ -28,7 +28,7 @@ fn set_socket_options(addr: SocketAddr) -> io::Result { socket.set_reuse_port(true)?; socket.set_reuse_address(true)?; socket.set_nonblocking(true)?; - socket.set_nodelay(true)?; + socket.set_tcp_nodelay(true)?; socket.bind(&addr.into())?; socket.listen(4096)?; From 768dccb579405d3ffbcbc05cda199f1ef10ad1b9 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 22:08:12 +0100 Subject: [PATCH 095/130] [ruby/hanami] Update Hanami to 2.3 (#10336) --- frameworks/Ruby/hanami/Gemfile | 12 ++--- frameworks/Ruby/hanami/Gemfile.lock | 77 ++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/frameworks/Ruby/hanami/Gemfile b/frameworks/Ruby/hanami/Gemfile index 956ff09ad32..4220b7be74f 100644 --- a/frameworks/Ruby/hanami/Gemfile +++ b/frameworks/Ruby/hanami/Gemfile @@ -2,12 +2,12 @@ source "https://rubygems.org" -gem "hanami", "~> 2.2" -gem "hanami-router", "~> 2.2" -gem "hanami-controller", "~> 2.2" -gem "hanami-db", "~> 2.2" -gem "hanami-validations", "~> 2.2" -gem "hanami-view", "~> 2.2" +gem "hanami", "~> 2.3" +gem "hanami-router", "~> 2.3" +gem "hanami-controller", "~> 2.3" +gem "hanami-db", "~> 2.3" +gem "hanami-validations", "~> 2.3" +gem "hanami-view", "~> 2.3" gem "dry-types", "~> 1.0", ">= 1.6.1" gem "puma" diff --git a/frameworks/Ruby/hanami/Gemfile.lock b/frameworks/Ruby/hanami/Gemfile.lock index d11d1d75794..953659b0535 100644 --- a/frameworks/Ruby/hanami/Gemfile.lock +++ b/frameworks/Ruby/hanami/Gemfile.lock @@ -1,8 +1,11 @@ GEM remote: https://rubygems.org/ specs: + base64 (0.3.0) bigdecimal (3.1.9) concurrent-ruby (1.3.5) + csv (3.3.5) + date (3.5.0) dry-auto_inject (1.1.0) dry-core (~> 1.1) zeitwerk (~> 2.6) @@ -20,7 +23,7 @@ GEM dry-files (1.1.0) dry-inflector (1.2.0) dry-initializer (3.2.0) - dry-logger (1.0.4) + dry-logger (1.2.0) dry-logic (1.6.0) bigdecimal concurrent-ruby (~> 1.0) @@ -63,46 +66,52 @@ GEM dry-initializer (~> 3.2) dry-schema (~> 1.14) zeitwerk (~> 2.6) - hanami (2.2.1) + erb (6.0.0) + hanami (2.3.0) bundler (>= 1.16, < 3) dry-configurable (~> 1.0, >= 1.2.0, < 2) dry-core (~> 1.0, < 2) dry-inflector (~> 1.0, >= 1.1.0, < 2) - dry-logger (~> 1.0, < 2) + dry-logger (~> 1.2, < 2) dry-monitor (~> 1.0, >= 1.0.1, < 2) dry-system (~> 1.1) - hanami-cli (~> 2.2.1) - hanami-utils (~> 2.2) + hanami-cli (>= 2.3.0) + hanami-utils (>= 2.3.0) json (>= 2.7.2) + rack-session zeitwerk (~> 2.6) - hanami-cli (2.2.1) + hanami-cli (2.3.0) bundler (~> 2.1) dry-cli (~> 1.0, >= 1.1.0) dry-files (~> 1.0, >= 1.0.2, < 2) dry-inflector (~> 1.0, < 2) + irb + rackup rake (~> 13.0) zeitwerk (~> 2.6) - hanami-controller (2.2.0) + hanami-controller (2.3.0) dry-configurable (~> 1.0, < 2) dry-core (~> 1.0) - hanami-utils (~> 2.2) - rack (~> 2.0) + hanami-utils (~> 2.3.0) + rack (>= 2.1) zeitwerk (~> 2.6) - hanami-db (2.2.1) + hanami-db (2.3.0) rom (~> 5.4, >= 5.4.1) rom-sql (~> 3.7) zeitwerk (~> 2.6) - hanami-router (2.2.0) + hanami-router (2.3.0) + csv (~> 3.3) mustermann (~> 3.0) mustermann-contrib (~> 3.0) - rack (~> 2.0) - hanami-utils (2.2.0) + rack (>= 2.0) + hanami-utils (2.3.0) + bigdecimal (~> 3.1) concurrent-ruby (~> 1.0) dry-core (~> 1.0, < 2) dry-transformer (~> 1.0, < 2) - hanami-validations (2.2.0) + hanami-validations (2.3.0) dry-validation (>= 1.10, < 2) - hanami-view (2.2.1) + hanami-view (2.3.0) dry-configurable (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0, < 2) @@ -111,6 +120,11 @@ GEM zeitwerk (~> 2.6) hansi (0.2.1) ice_nine (0.11.2) + io-console (0.8.1) + irb (1.15.3) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) json (2.16.0) logger (1.6.6) mustermann (3.0.3) @@ -121,10 +135,27 @@ GEM nio4r (2.7.4) ostruct (0.6.3) pg (1.5.9) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + psych (5.2.6) + date + stringio puma (6.6.0) nio4r (~> 2.0) - rack (2.2.19) + rack (3.2.4) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rackup (2.2.1) + rack (>= 3) rake (13.2.1) + rdoc (6.15.1) + erb + psych (>= 4.0.0) + tsort + reline (0.6.3) + io-console (~> 0.5) rom (5.4.2) rom-changeset (~> 5.4) rom-core (~> 5.4) @@ -154,9 +185,11 @@ GEM ruby2_keywords (0.0.5) sequel (5.90.0) bigdecimal + stringio (3.1.8) temple (0.10.3) tilt (2.6.0) transproc (1.1.1) + tsort (0.2.0) zeitwerk (2.7.2) PLATFORMS @@ -166,12 +199,12 @@ PLATFORMS DEPENDENCIES dry-types (~> 1.0, >= 1.6.1) - hanami (~> 2.2) - hanami-controller (~> 2.2) - hanami-db (~> 2.2) - hanami-router (~> 2.2) - hanami-validations (~> 2.2) - hanami-view (~> 2.2) + hanami (~> 2.3) + hanami-controller (~> 2.3) + hanami-db (~> 2.3) + hanami-router (~> 2.3) + hanami-validations (~> 2.3) + hanami-view (~> 2.3) ostruct pg puma From c9cfe77ef636f1c10473995d885ff4de3d98c4b5 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 1 Dec 2025 22:08:51 +0100 Subject: [PATCH 096/130] [ruby/grape] Use Iodine instead of Unicorn (#10335) Unicorn is no longer maintained. Replace with Iodine, as it performs better in these benchmarks. --- frameworks/Ruby/grape/Gemfile | 10 +- frameworks/Ruby/grape/Gemfile.lock | 8 +- frameworks/Ruby/grape/README.md | 6 +- frameworks/Ruby/grape/benchmark_config.json | 8 +- frameworks/Ruby/grape/config.ru | 2 +- frameworks/Ruby/grape/config.toml | 6 +- frameworks/Ruby/grape/config/nginx.conf | 158 ------------------ frameworks/Ruby/grape/config/unicorn.rb | 15 -- ...orn.dockerfile => grape-iodine.dockerfile} | 5 +- frameworks/Ruby/grape/grape.dockerfile | 1 + 10 files changed, 26 insertions(+), 193 deletions(-) delete mode 100644 frameworks/Ruby/grape/config/nginx.conf delete mode 100644 frameworks/Ruby/grape/config/unicorn.rb rename frameworks/Ruby/grape/{grape-unicorn.dockerfile => grape-iodine.dockerfile} (67%) diff --git a/frameworks/Ruby/grape/Gemfile b/frameworks/Ruby/grape/Gemfile index a4432e800c1..7a551b00b76 100644 --- a/frameworks/Ruby/grape/Gemfile +++ b/frameworks/Ruby/grape/Gemfile @@ -1,8 +1,14 @@ source 'https://rubygems.org' gem 'mysql2', '0.5.6' -gem 'unicorn', '6.1.0' -gem 'puma', '~> 7.1' gem 'activerecord', '~> 8.1.0', :require => 'active_record' gem 'grape', '2.1.1' gem 'json', '~> 2.9' + +group :iodine, optional: true do + gem "iodine", "~> 0.7", require: false +end + +group :puma, optional: true do + gem "puma", "~> 7.1", require: false +end diff --git a/frameworks/Ruby/grape/Gemfile.lock b/frameworks/Ruby/grape/Gemfile.lock index ea2f567c78f..d79d4469104 100644 --- a/frameworks/Ruby/grape/Gemfile.lock +++ b/frameworks/Ruby/grape/Gemfile.lock @@ -50,8 +50,8 @@ GEM zeitwerk i18n (1.14.7) concurrent-ruby (~> 1.0) + iodine (0.7.58) json (2.16.0) - kgio (2.11.4) logger (1.6.6) minitest (5.25.4) mustermann (3.0.3) @@ -63,15 +63,11 @@ GEM puma (7.1.0) nio4r (~> 2.0) rack (3.2.3) - raindrops (0.20.1) ruby2_keywords (0.0.5) securerandom (0.4.1) timeout (0.4.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicorn (6.1.0) - kgio (~> 2.6) - raindrops (~> 0.7) uri (1.0.3) zeitwerk (2.7.2) @@ -83,10 +79,10 @@ PLATFORMS DEPENDENCIES activerecord (~> 8.1.0) grape (= 2.1.1) + iodine (~> 0.7) json (~> 2.9) mysql2 (= 0.5.6) puma (~> 7.1) - unicorn (= 6.1.0) BUNDLED WITH 2.7.0 diff --git a/frameworks/Ruby/grape/README.md b/frameworks/Ruby/grape/README.md index 87f4e3f1c2a..1e5f2e908af 100644 --- a/frameworks/Ruby/grape/README.md +++ b/frameworks/Ruby/grape/README.md @@ -12,9 +12,9 @@ comparing a variety of web servers. The tests were run with: * [Ruby 3.4](http://www.ruby-lang.org/) -* [Grape 2.0.0](http://www.ruby-grape.org/) -* [Unicorn 6.1.0](https://yhbt.net/unicorn/) -* [Puma 6.4](https://puma.io/) +* [Grape 2.1](http://www.ruby-grape.org/) +* [Iodine](https://github.com/boazsegev/iodine) +* [Puma 7](https://puma.io/) ## Paths & Source for Tests diff --git a/frameworks/Ruby/grape/benchmark_config.json b/frameworks/Ruby/grape/benchmark_config.json index 70e233c3cf6..dd8892f5ea9 100644 --- a/frameworks/Ruby/grape/benchmark_config.json +++ b/frameworks/Ruby/grape/benchmark_config.json @@ -22,7 +22,7 @@ "notes": "", "versus": "rack-puma-mri" }, - "unicorn": { + "iodine": { "json_url": "/json", "db_url": "/db", "query_url": "/query?queries=", @@ -36,12 +36,12 @@ "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Unicorn", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "grape [unicorn]", + "display_name": "grape [iodine]", "notes": "", - "versus": "rack-unicorn-mri" + "versus": "rack-iodine-mri" } }] } diff --git a/frameworks/Ruby/grape/config.ru b/frameworks/Ruby/grape/config.ru index 65396539b64..c06dc281e5d 100644 --- a/frameworks/Ruby/grape/config.ru +++ b/frameworks/Ruby/grape/config.ru @@ -79,7 +79,7 @@ module Acme class API < Grape::API before do header 'Date', Time.now.httpdate if defined?(Puma) - header 'Server', 'WebServer' + header 'Server', 'grape' end logger nil content_type :json, 'application/json' diff --git a/frameworks/Ruby/grape/config.toml b/frameworks/Ruby/grape/config.toml index 3802b46b42b..cc3542e065a 100644 --- a/frameworks/Ruby/grape/config.toml +++ b/frameworks/Ruby/grape/config.toml @@ -17,7 +17,7 @@ platform = "Rack" webserver = "Puma" versus = "rack-puma-mri" -[unicorn] +[iodine] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -30,5 +30,5 @@ database_os = "Linux" os = "Linux" orm = "Full" platform = "Rack" -webserver = "Unicorn" -versus = "rack-unicorn-mri" +webserver = "Iodine" +versus = "rack-iodine-mri" diff --git a/frameworks/Ruby/grape/config/nginx.conf b/frameworks/Ruby/grape/config/nginx.conf deleted file mode 100644 index 19534510faf..00000000000 --- a/frameworks/Ruby/grape/config/nginx.conf +++ /dev/null @@ -1,158 +0,0 @@ -# This is example contains the bare mininum to get nginx going with -# Unicorn or Rainbows! servers. Generally these configuration settings -# are applicable to other HTTP application servers (and not just Ruby -# ones), so if you have one working well for proxying another app -# server, feel free to continue using it. -# -# The only setting we feel strongly about is the fail_timeout=0 -# directive in the "upstream" block. max_fails=0 also has the same -# effect as fail_timeout=0 for current versions of nginx and may be -# used in its place. -# -# Users are strongly encouraged to refer to nginx documentation for more -# details and search for other example configs. - -# you generally only need one nginx worker unless you're serving -# large amounts of static files which require blocking disk reads -worker_processes 8; - -# # drop privileges, root is needed on most systems for binding to port 80 -# # (or anything < 1024). Capability-based security may be available for -# # your system and worth checking out so you won't need to be root to -# # start nginx to bind on 80 -# user nobody nogroup; # for systems with a "nogroup" -#user nobody nobody; # for systems with "nobody" as a group instead - -# Feel free to change all paths to suite your needs here, of course -pid /tmp/nginx.pid; -#error_log /tmp/nginx.error.log; -error_log stderr error; - -events { - worker_connections 4096; # increase if you have lots of clients - accept_mutex off; # "on" if nginx worker_processes > 1 - use epoll; # enable for Linux 2.6+ - # use kqueue; # enable for FreeBSD, OSX -} - -http { - # nginx will find this file in the config directory set at nginx build time - include /etc/nginx/mime.types; - - # fallback in case we can't determine a type - default_type application/octet-stream; - - # click tracking! - #access_log /tmp/nginx.access.log combined; - access_log off; - - # you generally want to serve static files with nginx since neither - # Unicorn nor Rainbows! is optimized for it at the moment - sendfile on; - - tcp_nopush on; # off may be better for *some* Comet/long-poll stuff - tcp_nodelay off; # on may be better for some Comet/long-poll stuff - - # we haven't checked to see if Rack::Deflate on the app server is - # faster or not than doing compression via nginx. It's easier - # to configure it all in one place here for static files and also - # to disable gzip for clients who don't get gzip/deflate right. - # There are other gzip settings that may be needed used to deal with - # bad clients out there, see http://wiki.nginx.org/NginxHttpGzipModule - #gzip on; - #gzip_http_version 1.0; - #gzip_proxied any; - #gzip_min_length 500; - #gzip_disable "MSIE [1-6]\."; - #gzip_types text/plain text/html text/xml text/css - # text/comma-separated-values - # text/javascript application/x-javascript - # application/atom+xml; - - # this can be any application server, not just Unicorn/Rainbows! - upstream app_server { - # fail_timeout=0 means we always retry an upstream even if it failed - # to return a good HTTP response (in case the Unicorn master nukes a - # single worker for timing out). - - # for UNIX domain socket setups: - server unix:/tmp/unicorn.sock fail_timeout=0; - - # for TCP setups, point these to your backend servers - # server 192.168.0.7:8080 fail_timeout=0; - # server 192.168.0.8:8080 fail_timeout=0; - # server 192.168.0.9:8080 fail_timeout=0; - } - - server { - # enable one of the following if you're on Linux or FreeBSD - listen 8080 default deferred; # for Linux - # listen 80 default accept_filter=httpready; # for FreeBSD - - # If you have IPv6, you'll likely want to have two separate listeners. - # One on IPv4 only (the default), and another on IPv6 only instead - # of a single dual-stack listener. A dual-stack listener will make - # for ugly IPv4 addresses in $remote_addr (e.g ":ffff:10.0.0.1" - # instead of just "10.0.0.1") and potentially trigger bugs in - # some software. - # listen [::]:80 ipv6only=on; # deferred or accept_filter recommended - - client_max_body_size 4G; - server_name _; - - # ~2 seconds is often enough for most folks to parse HTML/CSS and - # retrieve needed images/icons/frames, connections are cheap in - # nginx so increasing this is generally safe... - keepalive_timeout 10; - - # path for static files - root /path/to/app/current/public; - - # Prefer to serve static files directly from nginx to avoid unnecessary - # data copies from the application server. - # - # try_files directive appeared in in nginx 0.7.27 and has stabilized - # over time. Older versions of nginx (e.g. 0.6.x) requires - # "if (!-f $request_filename)" which was less efficient: - # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127 - try_files $uri/index.html $uri.html $uri @app; - - location @app { - # an HTTP header important enough to have its own Wikipedia entry: - # http://en.wikipedia.org/wiki/X-Forwarded-For - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # enable this if you forward HTTPS traffic to unicorn, - # this helps Rack set the proper URL scheme for doing redirects: - # proxy_set_header X-Forwarded-Proto $scheme; - - # pass the Host: header from the client right along so redirects - # can be set properly within the Rack application - proxy_set_header Host $http_host; - - # we don't want nginx trying to do something clever with - # redirects, we set the Host: header above already. - proxy_redirect off; - - # set "proxy_buffering off" *only* for Rainbows! when doing - # Comet/long-poll/streaming. It's also safe to set if you're using - # only serving fast clients with Unicorn + nginx, but not slow - # clients. You normally want nginx to buffer responses to slow - # clients, even with Rails 3.1 streaming because otherwise a slow - # client can become a bottleneck of Unicorn. - # - # The Rack application may also set "X-Accel-Buffering (yes|no)" - # in the response headers do disable/enable buffering on a - # per-response basis. - # proxy_buffering off; - - proxy_pass http://app_server; - } - - # Rails error pages - error_page 500 502 503 504 /500.html; - location = /500.html { - root /path/to/app/current/public; - } - } -} diff --git a/frameworks/Ruby/grape/config/unicorn.rb b/frameworks/Ruby/grape/config/unicorn.rb deleted file mode 100644 index 697d61d8016..00000000000 --- a/frameworks/Ruby/grape/config/unicorn.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative 'auto_tune' - -num_workers, = auto_tune -worker_processes num_workers - -listen "/tmp/unicorn.sock", :backlog => 4096 - -preload_app true -GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true - -before_fork do |server, worker| -end - -after_fork do |server, worker| -end diff --git a/frameworks/Ruby/grape/grape-unicorn.dockerfile b/frameworks/Ruby/grape/grape-iodine.dockerfile similarity index 67% rename from frameworks/Ruby/grape/grape-unicorn.dockerfile rename to frameworks/Ruby/grape/grape-iodine.dockerfile index a20de1c8e3f..e103f724274 100644 --- a/frameworks/Ruby/grape/grape-unicorn.dockerfile +++ b/frameworks/Ruby/grape/grape-iodine.dockerfile @@ -13,8 +13,11 @@ ADD ./ /grape WORKDIR /grape +RUN bundle config set with 'iodine' RUN bundle install --jobs=4 --gemfile=/grape/Gemfile +ENV RACK_ENV=production + EXPOSE 8080 -CMD nginx -c /grape/config/nginx.conf && bundle exec unicorn -E production -c config/unicorn.rb +CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) diff --git a/frameworks/Ruby/grape/grape.dockerfile b/frameworks/Ruby/grape/grape.dockerfile index 3108a40dc55..cbaa7fc385e 100644 --- a/frameworks/Ruby/grape/grape.dockerfile +++ b/frameworks/Ruby/grape/grape.dockerfile @@ -11,6 +11,7 @@ ADD ./ /grape WORKDIR /grape +RUN bundle config set with 'puma' RUN bundle install --jobs=4 --gemfile=/grape/Gemfile ENV WEB_CONCURRENCY=auto From 80c46e9540e7f9182a6b8443f757baebed67340c Mon Sep 17 00:00:00 2001 From: caption <101684156+chncaption@users.noreply.github.com> Date: Tue, 2 Dec 2025 05:09:10 +0800 Subject: [PATCH 097/130] update com.fasterxml.jackson.core:jackson-databind 2.12.6.1 to 2.16.0 (#10295) --- frameworks/Java/restexpress/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/restexpress/pom.xml b/frameworks/Java/restexpress/pom.xml index 743f4cf5168..5940ab63e7e 100644 --- a/frameworks/Java/restexpress/pom.xml +++ b/frameworks/Java/restexpress/pom.xml @@ -37,7 +37,7 @@ com.fasterxml.jackson.core jackson-databind - 2.12.6.1 + 2.16.0 com.fasterxml.jackson.core From e54375606bc11e4fca896b096a9b8a19794011b4 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 8 Dec 2025 18:40:20 +0100 Subject: [PATCH 098/130] [rust/ntex] update to ntex-3.0 (#10357) * ntex: update to ntex-3.0 * wip * wip * wip --- frameworks/Rust/ntex/Cargo.toml | 16 +++++++------ frameworks/Rust/ntex/src/db.rs | 2 +- frameworks/Rust/ntex/src/main.rs | 16 ++++--------- frameworks/Rust/ntex/src/main_db.rs | 25 ++++++-------------- frameworks/Rust/ntex/src/main_plt.rs | 9 +++----- frameworks/Rust/ntex/src/utils.rs | 34 +++++++++++++++++++++++++++- 6 files changed, 57 insertions(+), 45 deletions(-) diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index a4baf02318f..ae3e4cc977b 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ntex-bench" -version = "2.1.0" +version = "3.0.0" edition = "2018" [[bin]] @@ -67,11 +67,10 @@ neon = ["ntex/neon"] neon-uring = ["ntex/neon-uring"] [dependencies] -ntex = "2.13" -ntex-compio = "0.3" -ntex-neon = "0.1.31" -ntex-net = "2.5.27" -ntex-bytes = { version = "0.1.21", features=["simd"] } +ntex = "3.0.0-pre.5" +ntex-neon = "0.1.35" +ntex-net = "3.0.0" +ntex-bytes = { version = "1", features=["simd"] } mimalloc = { version = "0.1.25", default-features = false } snmalloc-rs = { version = "0.3.3", features = ["native-cpu"] } yarte = { version = "0.15", features = ["bytes-buf", "json"] } @@ -86,11 +85,14 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" log = { version = "0.4", features = ["release_max_level_off"] } tok_io = {version = "1", package = "tokio" } -tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-2" } +tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-3" } [target.'cfg(target_os = "linux")'.dependencies] compio-driver = { version = "*", features = ["io-uring"]} +[patch.crates-io] +buf-min = { git = "https://github.com/fafhrd91/buf-min.git" } + [profile.release] opt-level = 3 codegen-units = 1 diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index a85b137139c..dc2eb93ffe3 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -39,7 +39,7 @@ pub struct PgConnection { impl PgConnection { pub async fn connect(db_url: &str) -> PgConnection { - let (cl, conn) = connect(db_url) + let (cl, conn) = connect(db_url, utils::db_config()) .await .expect("can not connect to postgresql"); ntex::rt::spawn(async move { diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index b0e53b3f05c..23494837277 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/frameworks/Rust/ntex/src/main.rs @@ -2,7 +2,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; -use ntex::{http, time::Seconds, util::BytesMut, util::PoolId, web}; +use ntex::{http, util::BytesMut, web}; use sonic_rs::Serialize; mod utils; @@ -52,18 +52,10 @@ async fn main() -> std::io::Result<()> { ntex::server::build() .backlog(1024) .enable_affinity() - .bind("techempower", "0.0.0.0:8080", |cfg| { - cfg.memory_pool(PoolId::P1); - PoolId::P1.set_read_params(65535, 2048); - PoolId::P1.set_write_params(65535, 2048); - - http::HttpService::build() - .keep_alive(http::KeepAlive::Os) - .client_timeout(Seconds::ZERO) - .headers_read_rate(Seconds::ZERO, Seconds::ZERO, 0) - .payload_read_rate(Seconds::ZERO, Seconds::ZERO, 0) - .h1(web::App::new().service(json).service(plaintext).finish()) + .bind("tfb", "0.0.0.0:8080", async |_| { + http::HttpService::h1(web::App::new().service(json).service(plaintext).finish()) })? + .config("tfb", utils::config()) .run() .await } diff --git a/frameworks/Rust/ntex/src/main_db.rs b/frameworks/Rust/ntex/src/main_db.rs index 544921fb594..8536a0978bb 100644 --- a/frameworks/Rust/ntex/src/main_db.rs +++ b/frameworks/Rust/ntex/src/main_db.rs @@ -3,10 +3,9 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; -use ntex::http::{HttpService, KeepAlive, Request, Response, StatusCode}; -use ntex::service::{Service, ServiceCtx, ServiceFactory}; -use ntex::web::{Error, HttpResponse}; -use ntex::{time::Seconds, util::PoolId}; +use ntex::http::{HttpService, Request, Response, StatusCode}; +use ntex::service::{cfg::SharedCfg, Service, ServiceCtx, ServiceFactory}; +use ntex::{web::Error, web::HttpResponse}; mod db; mod utils; @@ -64,13 +63,13 @@ impl Service for App { struct AppFactory; -impl ServiceFactory for AppFactory { +impl ServiceFactory for AppFactory { type Response = Response; type Error = Error; type Service = App; type InitError = (); - async fn create(&self, _: ()) -> Result { + async fn create(&self, _: SharedCfg) -> Result { const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; @@ -85,18 +84,8 @@ async fn main() -> std::io::Result<()> { ntex::server::build() .backlog(1024) .enable_affinity() - .bind("techempower", "0.0.0.0:8080", |cfg| { - cfg.memory_pool(PoolId::P1); - PoolId::P1.set_read_params(65535, 2048); - PoolId::P1.set_write_params(65535, 2048); - - HttpService::build() - .keep_alive(KeepAlive::Os) - .client_timeout(Seconds(0)) - .headers_read_rate(Seconds::ZERO, Seconds::ZERO, 0) - .payload_read_rate(Seconds::ZERO, Seconds::ZERO, 0) - .h1(AppFactory) - })? + .bind("tfb", "0.0.0.0:8080", async |_| HttpService::h1(AppFactory))? + .config("tfb", utils::config()) .run() .await } diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index e16070f0b63..83619c5053c 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/frameworks/Rust/ntex/src/main_plt.rs @@ -3,7 +3,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use std::{future::Future, io, pin::Pin, task::ready, task::Context, task::Poll}; -use ntex::{fn_service, http::h1, io::Io, io::RecvError, util::PoolId}; +use ntex::{fn_service, http::h1, io::Io, io::RecvError}; use sonic_rs::Serialize; mod utils; @@ -82,16 +82,13 @@ async fn main() -> io::Result<()> { ntex::server::build() .backlog(1024) .enable_affinity() - .bind("techempower", "0.0.0.0:8080", |cfg| { - cfg.memory_pool(PoolId::P1); - PoolId::P1.set_read_params(65535, 2048); - PoolId::P1.set_write_params(65535, 2048); - + .bind("tfb", "0.0.0.0:8080", async |_| { fn_service(|io| App { io, codec: h1::Codec::default(), }) })? + .config("tfb", utils::config()) .run() .await } diff --git a/frameworks/Rust/ntex/src/utils.rs b/frameworks/Rust/ntex/src/utils.rs index 6fd48e6e265..b3399bd8497 100644 --- a/frameworks/Rust/ntex/src/utils.rs +++ b/frameworks/Rust/ntex/src/utils.rs @@ -2,7 +2,8 @@ use std::{cmp, io, io::Write, mem::MaybeUninit, slice::from_raw_parts_mut}; use atoi::FromRadix10; -use ntex::{http::header::HeaderValue, util::BufMut, util::Bytes, util::BytesMut}; +use ntex::http::{header::HeaderValue, HttpServiceConfig, KeepAlive}; +use ntex::{io::IoConfig, time::Seconds, util::BufMut, util::Bytes, util::BytesMut, SharedCfg}; use sonic_rs::writer::WriteExt; pub const HDR_SERVER: HeaderValue = HeaderValue::from_static("N"); @@ -15,6 +16,37 @@ pub const BODY_PLAIN_TEXT: Bytes = Bytes::from_static(b"Hello, World!"); const HW: usize = 128 * 1024; pub const SIZE: usize = 27; +pub fn config() -> SharedCfg { + thread_local! { + static CFG: SharedCfg = SharedCfg::new("tfb") + .add( + IoConfig::new() + .set_read_buf(65535, 2048, 128) + .set_write_buf(65535, 2048, 128), + ) + .add( + HttpServiceConfig::new() + .set_keepalive(KeepAlive::Os) + .set_client_timeout(Seconds::ZERO) + .set_headers_read_rate(Seconds::ZERO, Seconds::ZERO, 0) + .set_payload_read_rate(Seconds::ZERO, Seconds::ZERO, 0), + ).into(); + } + CFG.with(|cfg| *cfg) +} + +pub fn db_config() -> SharedCfg { + thread_local! { + static CFG: SharedCfg = SharedCfg::new("tfb-db") + .add( + IoConfig::new() + .set_read_buf(65535, 2048, 128) + .set_write_buf(65535, 2048, 128), + ).into() + } + CFG.with(|cfg| *cfg) +} + pub fn get_query_param(query: Option<&str>) -> usize { let query = query.unwrap_or(""); let q = if let Some(pos) = query.find('q') { From 78377a871d30b5981bf81ac0b9753116f66d6749 Mon Sep 17 00:00:00 2001 From: Giovanni Barillari Date: Mon, 8 Dec 2025 18:40:58 +0100 Subject: [PATCH 099/130] [Python] Bump Granian to 2.6, update Emmett55 implementation (#10358) * [Python] Update Granian to 2.6 * [Python] Review `emmett55` implementation --- frameworks/Python/emmett55/app.py | 85 ++++++++++--------- .../Python/emmett55/emmett55.dockerfile | 2 +- frameworks/Python/emmett55/requirements.txt | 2 +- frameworks/Python/granian/app_asgi.py | 1 - .../Python/granian/granian-nogil.dockerfile | 2 +- .../Python/granian/granian-rsgi.dockerfile | 2 +- .../Python/granian/requirements-nogil.txt | 2 +- frameworks/Python/granian/requirements.txt | 2 +- 8 files changed, 53 insertions(+), 45 deletions(-) diff --git a/frameworks/Python/emmett55/app.py b/frameworks/Python/emmett55/app.py index e417e8f75fa..d24f7e98d62 100644 --- a/frameworks/Python/emmett55/app.py +++ b/frameworks/Python/emmett55/app.py @@ -3,12 +3,19 @@ from random import randint, sample import asyncpg -from emmett55 import App, Pipe, current, request, response +from emmett55 import App, Pipe, request, response from emmett55.extensions import Extension, Signals, listen_signal -from emmett55.tools import service +from emmett55.tools import ServicePipe from renoir import Renoir +class NoResetConnection(asyncpg.Connection): + __slots__ = () + + def get_reset_query(self): + return "" + + class AsyncPG(Extension): __slots__ = ["pool"] @@ -23,10 +30,9 @@ async def build_pool(self): database='hello_world', host='tfb-database', port=5432, - min_size=16, - max_size=16, - max_queries=64_000_000_000, - max_inactive_connection_lifetime=0 + min_size=4, + max_size=4, + connection_class=NoResetConnection, ) @listen_signal(Signals.after_loop) @@ -40,18 +46,32 @@ class AsyncPGPipe(Pipe): def __init__(self, ext): self.ext = ext - async def open(self): - conn = current._db_conn = self.ext.pool.acquire() - current.db = await conn.__aenter__() + async def pipe(self, next_pipe, **kwargs): + async with self.ext.pool.acquire() as conn: + kwargs['db'] = conn + return await next_pipe(**kwargs) + - async def close(self): - await current._db_conn.__aexit__() +class TemplatePipe(Pipe): + __slots__ = ["template"] + output = "str" + + def __init__(self, template): + self.template = f"templates/{template}" + + async def pipe(self, next_pipe, **kwargs): + response.content_type = "text/html; charset=utf-8" + ctx = await next_pipe(**kwargs) + return templates.render(self.template, ctx) app = App(__name__) app.config.handle_static = False templates = Renoir() +json_routes = app.module(__name__, 'json') +json_routes.pipeline = [ServicePipe('json')] + db_ext = app.use_extension(AsyncPG) SQL_SELECT = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' @@ -60,17 +80,15 @@ async def close(self): sort_key = itemgetter(1) -@app.route() -@service.json +@json_routes.route() async def json(): return {'message': 'Hello, World!'} -@app.route("/db", pipeline=[db_ext.pipe]) -@service.json -async def get_random_world(): +@json_routes.route("/db", pipeline=[db_ext.pipe]) +async def get_random_world(db): row_id = randint(1, 10000) - number = await current.db.fetchval(SQL_SELECT, row_id) + number = await db.fetchval(SQL_SELECT, row_id) return {'id': row_id, 'randomNumber': number} @@ -86,41 +104,32 @@ def get_qparam(): return rv -@app.route("/queries", pipeline=[db_ext.pipe]) -@service.json -async def get_random_worlds(): +@json_routes.route("/queries", pipeline=[db_ext.pipe]) +async def get_random_worlds(db): num_queries = get_qparam() row_ids = sample(range(1, 10000), num_queries) - worlds = [] - statement = await current.db.prepare(SQL_SELECT) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) - return worlds + rows = await db.fetchmany(SQL_SELECT, [(v,) for v in row_ids]) + return [{'id': row_id, 'randomNumber': number[0]} for row_id, number in zip(row_ids, rows)] -@app.route(pipeline=[db_ext.pipe], output='str') -async def fortunes(): - response.content_type = "text/html; charset=utf-8" - fortunes = await current.db.fetch('SELECT * FROM Fortune') +@app.route(pipeline=[TemplatePipe("fortunes.html"), db_ext.pipe]) +async def fortunes(db): + fortunes = await db.fetch('SELECT * FROM Fortune') fortunes.append(ROW_ADD) fortunes.sort(key=sort_key) - return templates.render("templates/fortunes.html", {"fortunes": fortunes}) + return {"fortunes": fortunes} -@app.route(pipeline=[db_ext.pipe]) -@service.json -async def updates(): +@json_routes.route(pipeline=[db_ext.pipe]) +async def updates(db): num_queries = get_qparam() updates = list(zip( sample(range(1, 10000), num_queries), sorted(sample(range(1, 10000), num_queries)) )) worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] - statement = await current.db.prepare(SQL_SELECT) - for row_id, _ in updates: - await statement.fetchval(row_id) - await current.db.executemany(SQL_UPDATE, updates) + await db.executemany(SQL_SELECT, [(i[0],) for i in updates]) + await db.executemany(SQL_UPDATE, updates) return worlds diff --git a/frameworks/Python/emmett55/emmett55.dockerfile b/frameworks/Python/emmett55/emmett55.dockerfile index 49438fd442d..a3e5039a72f 100644 --- a/frameworks/Python/emmett55/emmett55.dockerfile +++ b/frameworks/Python/emmett55/emmett55.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim +FROM python:3.13-slim ADD ./ /emmett55 diff --git a/frameworks/Python/emmett55/requirements.txt b/frameworks/Python/emmett55/requirements.txt index 341cf834957..8641ee5f52f 100644 --- a/frameworks/Python/emmett55/requirements.txt +++ b/frameworks/Python/emmett55/requirements.txt @@ -1,3 +1,3 @@ -asyncpg==0.29.0 +asyncpg==0.30.0 emmett55[orjson,uvloop]>=1.2.0,<1.3.0 renoir==1.8.0 diff --git a/frameworks/Python/granian/app_asgi.py b/frameworks/Python/granian/app_asgi.py index d7c7b732c27..b6a727e8b0e 100644 --- a/frameworks/Python/granian/app_asgi.py +++ b/frameworks/Python/granian/app_asgi.py @@ -106,7 +106,6 @@ async def route_db(scope, receive, send): async def route_queries(scope, receive, send): num_queries = get_num_queries(scope) row_ids = sample(range(1, 10000), num_queries) - worlds = [] async with pool.acquire() as connection: rows = await connection.fetchmany(SQL_SELECT, [(v,) for v in row_ids]) diff --git a/frameworks/Python/granian/granian-nogil.dockerfile b/frameworks/Python/granian/granian-nogil.dockerfile index 5f0e4045f40..566ac8cca40 100644 --- a/frameworks/Python/granian/granian-nogil.dockerfile +++ b/frameworks/Python/granian/granian-nogil.dockerfile @@ -13,4 +13,4 @@ RUN uv pip install -r requirements-nogil.txt EXPOSE 8080 -CMD uv run python run_nogil.py rsgi st +CMD uv run python run_nogil.py rsgi mt diff --git a/frameworks/Python/granian/granian-rsgi.dockerfile b/frameworks/Python/granian/granian-rsgi.dockerfile index 1eb5066dfeb..a7616266d84 100644 --- a/frameworks/Python/granian/granian-rsgi.dockerfile +++ b/frameworks/Python/granian/granian-rsgi.dockerfile @@ -8,4 +8,4 @@ RUN pip install -r /granian/requirements.txt EXPOSE 8080 -CMD python run.py rsgi st +CMD python run.py rsgi mt diff --git a/frameworks/Python/granian/requirements-nogil.txt b/frameworks/Python/granian/requirements-nogil.txt index c49d8ced726..828e24cd711 100644 --- a/frameworks/Python/granian/requirements-nogil.txt +++ b/frameworks/Python/granian/requirements-nogil.txt @@ -1 +1 @@ -granian[rloop]>=2.5.0,<2.6.0 +granian[rloop]>=2.6.0,<2.7.0 diff --git a/frameworks/Python/granian/requirements.txt b/frameworks/Python/granian/requirements.txt index 8fc318454b4..d3895189e0d 100644 --- a/frameworks/Python/granian/requirements.txt +++ b/frameworks/Python/granian/requirements.txt @@ -1,4 +1,4 @@ asyncpg==0.30.0 -granian[uvloop]>=2.5.0,<2.6.0 +granian[uvloop]>=2.6.0,<2.7.0 jinja2==3.1.6 orjson==3.11.3 From 6fc55b0aefe628c6af8d5cbe9b009f7d90e9547d Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:41:24 +0100 Subject: [PATCH 100/130] [python/tornado] Remove python 2 tests (#10359) Python 2 is end-of-life. No need to test it. --- .../Python/tornado/benchmark_config.json | 70 +---------- ...s_py3_mongo.txt => requirements_mongo.txt} | 0 .../Python/tornado/requirements_py2_mongo.txt | 3 - .../Python/tornado/requirements_py2_pg.txt | 3 - ...py3_uvloop.txt => requirements_uvloop.txt} | 0 .../tornado/{server_py3.py => server.py} | 0 frameworks/Python/tornado/server_pg.py | 77 ------------ frameworks/Python/tornado/server_py2.py | 115 ------------------ ...{server_py3_uvloop.py => server_uvloop.py} | 0 .../tornado/tornado-postgresql-raw.dockerfile | 11 -- .../tornado/tornado-py3-uvloop.dockerfile | 11 -- .../Python/tornado/tornado-py3.dockerfile | 11 -- .../Python/tornado/tornado-pypy2.dockerfile | 11 -- .../Python/tornado/tornado-uvloop.dockerfile | 11 ++ frameworks/Python/tornado/tornado.dockerfile | 6 +- 15 files changed, 16 insertions(+), 313 deletions(-) rename frameworks/Python/tornado/{requirements_py3_mongo.txt => requirements_mongo.txt} (100%) delete mode 100644 frameworks/Python/tornado/requirements_py2_mongo.txt delete mode 100644 frameworks/Python/tornado/requirements_py2_pg.txt rename frameworks/Python/tornado/{requirements_py3_uvloop.txt => requirements_uvloop.txt} (100%) rename frameworks/Python/tornado/{server_py3.py => server.py} (100%) delete mode 100755 frameworks/Python/tornado/server_pg.py delete mode 100644 frameworks/Python/tornado/server_py2.py rename frameworks/Python/tornado/{server_py3_uvloop.py => server_uvloop.py} (100%) delete mode 100644 frameworks/Python/tornado/tornado-postgresql-raw.dockerfile delete mode 100644 frameworks/Python/tornado/tornado-py3-uvloop.dockerfile delete mode 100644 frameworks/Python/tornado/tornado-py3.dockerfile delete mode 100644 frameworks/Python/tornado/tornado-pypy2.dockerfile create mode 100644 frameworks/Python/tornado/tornado-uvloop.dockerfile diff --git a/frameworks/Python/tornado/benchmark_config.json b/frameworks/Python/tornado/benchmark_config.json index a64c47a7cfe..3966265fb04 100644 --- a/frameworks/Python/tornado/benchmark_config.json +++ b/frameworks/Python/tornado/benchmark_config.json @@ -2,72 +2,6 @@ "framework": "tornado", "tests": [{ "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "plaintext_url": "/plaintext", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MongoDB", - "framework": "None", - "language": "Python", - "flavor": "Python2", - "orm": "Raw", - "platform": "None", - "webserver": "Tornado", - "os": "Linux", - "database_os": "Linux", - "display_name": "Tornado", - "notes": "", - "versus": "tornado" - }, - "pypy2": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "plaintext_url": "/plaintext", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MongoDB", - "framework": "None", - "language": "Python", - "flavor": "PyPy2", - "orm": "Raw", - "platform": "None", - "webserver": "Tornado", - "os": "Linux", - "database_os": "Linux", - "display_name": "Tornado", - "notes": "", - "versus": "tornado" - }, - "postgresql-raw": { - "db_url": "/db", - "query_url": "/queries?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "None", - "language": "Python", - "flavor": "Python2", - "orm": "Raw", - "platform": "None", - "webserver": "Tornado", - "os": "Linux", - "database_os": "Linux", - "display_name": "Tornado", - "notes": "", - "versus": "tornado", - "tags": ["broken"] - }, - "py3": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -90,7 +24,7 @@ "notes": "", "versus": "tornado" }, - "py3-uvloop": { + "uvloop": { "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", @@ -107,7 +41,7 @@ "webserver": "Tornado", "os": "Linux", "database_os": "Linux", - "display_name": "Tornado", + "display_name": "Tornado [uvloop]", "notes": "", "versus": "tornado" } diff --git a/frameworks/Python/tornado/requirements_py3_mongo.txt b/frameworks/Python/tornado/requirements_mongo.txt similarity index 100% rename from frameworks/Python/tornado/requirements_py3_mongo.txt rename to frameworks/Python/tornado/requirements_mongo.txt diff --git a/frameworks/Python/tornado/requirements_py2_mongo.txt b/frameworks/Python/tornado/requirements_py2_mongo.txt deleted file mode 100644 index ef65f2641ce..00000000000 --- a/frameworks/Python/tornado/requirements_py2_mongo.txt +++ /dev/null @@ -1,3 +0,0 @@ -tornado==5.1.1 -motor==2.0.0 -ujson==1.35 diff --git a/frameworks/Python/tornado/requirements_py2_pg.txt b/frameworks/Python/tornado/requirements_py2_pg.txt deleted file mode 100644 index 8f204caeb0a..00000000000 --- a/frameworks/Python/tornado/requirements_py2_pg.txt +++ /dev/null @@ -1,3 +0,0 @@ -tornado==5.1.1 -Momoko==2.2.4 -ujson==1.35 \ No newline at end of file diff --git a/frameworks/Python/tornado/requirements_py3_uvloop.txt b/frameworks/Python/tornado/requirements_uvloop.txt similarity index 100% rename from frameworks/Python/tornado/requirements_py3_uvloop.txt rename to frameworks/Python/tornado/requirements_uvloop.txt diff --git a/frameworks/Python/tornado/server_py3.py b/frameworks/Python/tornado/server.py similarity index 100% rename from frameworks/Python/tornado/server_py3.py rename to frameworks/Python/tornado/server.py diff --git a/frameworks/Python/tornado/server_pg.py b/frameworks/Python/tornado/server_pg.py deleted file mode 100755 index 1a354d80dbc..00000000000 --- a/frameworks/Python/tornado/server_pg.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -import json -from random import randint -import momoko -import tornado.ioloop -import tornado.web -from tornado import gen -import tornado.options -from tornado.options import options -import tornado.httpserver -from commons import JsonHandler, JsonHelloWorldHandler, PlaintextHelloWorldHandler, BaseHandler - - -tornado.options.define('port', default=8888, type=int, help="Server port") -tornado.options.define('postgres', default="localhost", - type=str, help="PostgreSQL host") -tornado.options.define('backlog', default=8192, type=int, - help="Server backlog") - - -class SingleQueryHandler(JsonHandler): - SQL = "SELECT id, randomNumber FROM World WHERE id=%s" - - @gen.coroutine - def get(self): - - random_id = randint(1, 10000) - cursor = yield db.execute(self.SQL, (random_id,)) - row = cursor.fetchone() - response = json.dumps({self.ID: row[0], self.RANDOM_NUMBER: row[1]}) - self.finish(response) - - -class MultipleQueriesHandler(JsonHandler): - SQL = "SELECT id, randomNumber FROM World WHERE id=%s" - - @gen.coroutine - def get(self): - queries = self.get_argument(self.QUERIES, "1") - try: - queries = int(queries.strip()) - except ValueError: - queries = 1 - - queries = min(max(1, queries), 500) - worlds = [] - - cursors = yield [db.execute(self.SQL, (randint(1, 10000),)) for _ in xrange(queries)] - for cursor in cursors: - row = cursor.fetchone() - worlds.append({self.ID: row[0], self.RANDOM_NUMBER: row[1]}) - - response = json.dumps(worlds) - self.finish(response) - - -application = tornado.web.Application([ - (r"/json", JsonHelloWorldHandler), - (r"/plaintext", PlaintextHelloWorldHandler), - (r"/db", SingleQueryHandler), - (r"/queries", MultipleQueriesHandler) -], - template_path="templates" -) -application.ui_modules = {} - -if __name__ == "__main__": - tornado.options.parse_command_line() - server = tornado.httpserver.HTTPServer(application) - server.bind(options.port, backlog=options.backlog) - server.start(0) - - ioloop = tornado.ioloop.IOLoop.instance() - dsn = "user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world host=%s" % options.postgres - db = momoko.Pool(dsn, size=100, max_size=200) - ioloop.run_sync(db.connect) - ioloop.start() diff --git a/frameworks/Python/tornado/server_py2.py b/frameworks/Python/tornado/server_py2.py deleted file mode 100644 index 86d7177bccf..00000000000 --- a/frameworks/Python/tornado/server_py2.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python - -import json -import motor -from pymongo.operations import UpdateOne -import tornado.ioloop -import tornado.web -import tornado.httpserver - -from random import randint -from tornado import gen -from tornado.options import options -from commons import JsonHandler, JsonHelloWorldHandler, PlaintextHelloWorldHandler, HtmlHandler - - -options.define('port', default=8888, type=int, help="Server port") -options.define('mongo', default='localhost', type=str, help="MongoDB host") -options.define('backlog', default=8192, type=int, help="Server backlog") - - -class SingleQueryHandler(JsonHandler): - - @gen.coroutine - def get(self): - world = yield db.world.find_one(randint(1, 10000)) - world = {self.ID: int(world['_id']), - self.RANDOM_NUMBER: int(world[self.RANDOM_NUMBER]) - } - - response = json.dumps(world) - self.finish(response) - - -class MultipleQueriesHandler(JsonHandler): - @gen.coroutine - def get(self): - try: - queries = int(self.get_argument(self.QUERIES)) - except Exception: - queries = 1 - else: - if queries < 1: - queries = 1 - elif queries > 500: - queries = 500 - - worlds = yield [db.world.find_one(randint(1, 10000)) for _ in xrange(queries)] - - worlds = [{self.ID: int(world['_id']), - self.RANDOM_NUMBER: int(world[self.RANDOM_NUMBER])} - for world in worlds] - - self.finish(json.dumps(worlds)) - - -class UpdateHandler(JsonHandler): - @gen.coroutine - def get(self): - try: - queries = int(self.get_argument(self.QUERIES)) - except Exception: - queries = 1 - else: - if queries < 1: - queries = 1 - elif queries > 500: - queries = 500 - - worlds = yield [db.world.find_one(randint(1, 10000)) for _ in xrange(queries)] - updates = [] - out = [] - - for world in worlds: - new_value = randint(1, 10000) - updates.append(UpdateOne({'_id': world['_id']}, {"$set": {self.RANDOM_NUMBER: new_value}})) - out.append({self.ID: world["_id"], self.RANDOM_NUMBER: new_value}) - - yield db.world.bulk_write(updates, ordered=False) - self.finish(json.dumps(out)) - - -class FortuneHandler(HtmlHandler): - @gen.coroutine - def get(self): - fortunes = [] - cursor = db.fortune.find() - - while (yield cursor.fetch_next): - fortunes.append(cursor.next_object()) - fortunes.append({self.ID: 0, 'message': 'Additional fortune added at request time.'}) - fortunes.sort(key=lambda f: f['message']) - self.render('fortunes.html', fortunes=fortunes) - - -application = tornado.web.Application([ - (r"/json", JsonHelloWorldHandler), - (r"/plaintext", PlaintextHelloWorldHandler), - (r"/db", SingleQueryHandler), - (r"/queries", MultipleQueriesHandler), - (r"/updates", UpdateHandler), - (r"/fortunes", FortuneHandler), -], - template_path="templates" -) -application.ui_modules = {} - -if __name__ == "__main__": - tornado.options.parse_command_line() - server = tornado.httpserver.HTTPServer(application) - server.bind(options.port, backlog=options.backlog) - server.start(0) - - ioloop = tornado.ioloop.IOLoop.instance() - db = motor.MotorClient(options.mongo, maxPoolSize=500).hello_world - ioloop.start() diff --git a/frameworks/Python/tornado/server_py3_uvloop.py b/frameworks/Python/tornado/server_uvloop.py similarity index 100% rename from frameworks/Python/tornado/server_py3_uvloop.py rename to frameworks/Python/tornado/server_uvloop.py diff --git a/frameworks/Python/tornado/tornado-postgresql-raw.dockerfile b/frameworks/Python/tornado/tornado-postgresql-raw.dockerfile deleted file mode 100644 index 6a6119bda5d..00000000000 --- a/frameworks/Python/tornado/tornado-postgresql-raw.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:2.7.15-stretch - -ADD ./ /tornado - -WORKDIR /tornado - -RUN pip install -r /tornado/requirements_py2_pg.txt - -EXPOSE 8080 - -CMD python server_pg.py --port=8080 --postgres=tfb-database --logging=error diff --git a/frameworks/Python/tornado/tornado-py3-uvloop.dockerfile b/frameworks/Python/tornado/tornado-py3-uvloop.dockerfile deleted file mode 100644 index 2bc64e882a1..00000000000 --- a/frameworks/Python/tornado/tornado-py3-uvloop.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./ /tornado - -WORKDIR /tornado - -RUN pip3 install -r /tornado/requirements_py3_uvloop.txt - -EXPOSE 8080 - -CMD python3 server_py3_uvloop.py --logging=error diff --git a/frameworks/Python/tornado/tornado-py3.dockerfile b/frameworks/Python/tornado/tornado-py3.dockerfile deleted file mode 100644 index 667a7a330ef..00000000000 --- a/frameworks/Python/tornado/tornado-py3.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./ /pyramid - -WORKDIR /pyramid - -RUN pip3 install -r /pyramid/requirements_py3_mongo.txt - -EXPOSE 8080 - -CMD python3 server_py3.py --port=8080 --mongo=tfb-database --logging=error diff --git a/frameworks/Python/tornado/tornado-pypy2.dockerfile b/frameworks/Python/tornado/tornado-pypy2.dockerfile deleted file mode 100644 index 1b9d73f3032..00000000000 --- a/frameworks/Python/tornado/tornado-pypy2.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM pypy:2-5.10 - -ADD ./ /tornado - -WORKDIR /tornado - -RUN pip install -r /tornado/requirements_py2_mongo.txt - -EXPOSE 8080 - -CMD pypy server_py2.py --port=8080 --mongo=tfb-database --logging=error diff --git a/frameworks/Python/tornado/tornado-uvloop.dockerfile b/frameworks/Python/tornado/tornado-uvloop.dockerfile new file mode 100644 index 00000000000..4fe319a75c2 --- /dev/null +++ b/frameworks/Python/tornado/tornado-uvloop.dockerfile @@ -0,0 +1,11 @@ +FROM python:3.6.6-stretch + +ADD ./ /tornado + +WORKDIR /tornado + +RUN pip3 install -r /tornado/requirements_uvloop.txt + +EXPOSE 8080 + +CMD python3 server_uvloop.py --logging=error diff --git a/frameworks/Python/tornado/tornado.dockerfile b/frameworks/Python/tornado/tornado.dockerfile index 1a1f8cdf410..aa9a33f4cdf 100644 --- a/frameworks/Python/tornado/tornado.dockerfile +++ b/frameworks/Python/tornado/tornado.dockerfile @@ -1,11 +1,11 @@ -FROM python:2.7.15-stretch +FROM python:3.6.6-stretch ADD ./ /tornado WORKDIR /tornado -RUN pip install -r /tornado/requirements_py2_mongo.txt +RUN pip3 install -r /tornado/requirements_mongo.txt EXPOSE 8080 -CMD python server_py2.py --port=8080 --mongo=tfb-database --logging=error +CMD python3 server.py --port=8080 --mongo=tfb-database --logging=error From 7f6b28acc0f5b6f31b3fc285bf1cacb8cb3c483d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 17:42:24 +0000 Subject: [PATCH 101/130] Build(deps): bump werkzeug in /frameworks/Python/eve Bumps [werkzeug](https://github.com/pallets/werkzeug) from 0.15.5 to 3.1.4. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/0.15.5...3.1.4) --- updated-dependencies: - dependency-name: werkzeug dependency-version: 3.1.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frameworks/Python/eve/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Python/eve/requirements.txt b/frameworks/Python/eve/requirements.txt index f054d6baf97..089a0d0836c 100644 --- a/frameworks/Python/eve/requirements.txt +++ b/frameworks/Python/eve/requirements.txt @@ -5,4 +5,4 @@ gunicorn==19.9.0 itsdangerous==0.24 meinheld==1.0.2 uWSGI==2.0.22 -Werkzeug==0.15.5 +Werkzeug==3.1.4 From 996962fab4bad188dbac0ef109e5e9ef1296beb2 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Tue, 9 Dec 2025 01:42:52 +0800 Subject: [PATCH 102/130] [xitca-web] enable more optimization (#10360) * [xitca-web] enable more optimization * remove all usage of explict pipeline * dep update * update toasty to support cow * dep dedup * dep update * improve compile time * improve compile time --- frameworks/Rust/xitca-web/Cargo.lock | 467 +++++++----------- frameworks/Rust/xitca-web/Cargo.toml | 48 +- .../Rust/xitca-web/benchmark_config.json | 6 +- frameworks/Rust/xitca-web/src/db.rs | 64 +-- frameworks/Rust/xitca-web/src/db_diesel.rs | 28 +- frameworks/Rust/xitca-web/src/db_toasty.rs | 1 - .../Rust/xitca-web/src/db_unrealistic.rs | 66 ++- frameworks/Rust/xitca-web/src/db_util.rs | 40 +- frameworks/Rust/xitca-web/src/main.rs | 1 - .../{main_unrealistic.rs => main_barebone.rs} | 14 +- frameworks/Rust/xitca-web/src/main_orm.rs | 4 +- frameworks/Rust/xitca-web/src/ser.rs | 57 +-- .../Rust/xitca-web/templates/fortune.stpl | 10 - .../xitca-web/xitca-web-barebone.dockerfile | 10 + .../xitca-web/xitca-web-diesel.dockerfile | 2 +- .../xitca-web/xitca-web-toasty.dockerfile | 2 +- .../xitca-web-unrealistic.dockerfile | 10 - .../Rust/xitca-web/xitca-web.dockerfile | 2 +- 18 files changed, 347 insertions(+), 485 deletions(-) rename frameworks/Rust/xitca-web/src/{main_unrealistic.rs => main_barebone.rs} (92%) delete mode 100644 frameworks/Rust/xitca-web/templates/fortune.stpl create mode 100644 frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile delete mode 100644 frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 8d9787826ad..395d9b82907 100755 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -2,6 +2,19 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -11,12 +24,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "anyhow" version = "1.0.100" @@ -77,18 +84,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bb8" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457d7ed3f888dfd2c7af56d4975cade43c622f74bdcddfed6d4352f57acc6310" -dependencies = [ - "futures-util", - "parking_lot", - "portable-atomic", - "tokio", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -104,12 +99,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.10.0" @@ -151,9 +140,9 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.48" +version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "shlex", @@ -236,7 +225,7 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c415189028b232660655e4893e8bc25ca7aee8e96888db66d9edb400535456a" dependencies = [ - "bitflags 2.10.0", + "bitflags", "byteorder", "diesel_derives", "downcast-rs", @@ -250,13 +239,10 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13096fb8dae53f2d411c4b523bec85f45552ed3044a2ab4d85fb2092d9cb4f34" dependencies = [ - "bb8", "diesel", "futures-core", "futures-util", "scoped-futures", - "tokio", - "tokio-postgres", ] [[package]] @@ -342,19 +328,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] -name = "find-msvc-tools" -version = "0.1.5" +name = "faststr" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "baec6a0289d7f1fe5665586ef7340af82e3037207bef60f5785e57569776f0c8" +dependencies = [ + "bytes", + "rkyv", + "serde", + "simdutf8", +] [[package]] -name = "float-cmp" -version = "0.10.0" +name = "find-msvc-tools" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" -dependencies = [ - "num-traits", -] +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "fnv" @@ -362,12 +351,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -377,16 +360,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - [[package]] name = "futures-core" version = "0.3.31" @@ -416,7 +389,6 @@ dependencies = [ "futures-task", "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -453,25 +425,16 @@ dependencies = [ ] [[package]] -name = "halfbrown" -version = "0.4.0" +name = "hashbrown" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ed2f2edad8a14c8186b847909a41fbb9c3eafa44f88bd891114ed5019da09" -dependencies = [ - "hashbrown", - "serde", -] +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] [[package]] name = "heck" @@ -637,16 +600,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] name = "io-uring" -version = "0.6.4" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" dependencies = [ - "bitflags 1.3.2", + "bitflags", + "cfg-if", "libc", ] @@ -680,9 +644,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libmimalloc-sys" @@ -694,17 +658,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libredox" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags 2.10.0", - "libc", - "redox_syscall", -] - [[package]] name = "litemap" version = "0.8.1" @@ -720,12 +673,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - [[package]] name = "md-5" version = "0.10.6" @@ -753,15 +700,35 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", "windows-sys 0.61.2", ] +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -816,25 +783,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "phf" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" -dependencies = [ - "phf_shared", - "serde", -] - -[[package]] -name = "phf_shared" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -863,12 +811,6 @@ dependencies = [ "regex", ] -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - [[package]] name = "postgres-protocol" version = "0.6.9" @@ -936,6 +878,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.42" @@ -951,6 +913,15 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rancor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +dependencies = [ + "ptr_meta", +] + [[package]] name = "rand" version = "0.8.5" @@ -1016,7 +987,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -1068,6 +1039,41 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "rend" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" + +[[package]] +name = "rkyv" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4" +dependencies = [ + "bytes", + "hashbrown 0.15.5", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1082,9 +1088,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "sailfish" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40efbac4e16ca6b1a5706348ada4d8b67d7b417ac2001aa6c4ae092511bb1763" +checksum = "51bd7299cb39e7e0d9350a2f4ec0c0f2a98de9608ada54983c3c30f4d55051b8" dependencies = [ "itoap", "ryu", @@ -1187,59 +1193,12 @@ dependencies = [ "libc", ] -[[package]] -name = "simd-json" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4255126f310d2ba20048db6321c81ab376f6a6735608bf11f0785c41f01f64e3" -dependencies = [ - "halfbrown", - "ref-cast", - "serde", - "serde_json", - "simdutf8", - "value-trait", -] - -[[package]] -name = "simd-json-derive" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8582b571efbbb6d89a2d3807c283a42de7e2a5d92fa09c6498ac17abb3f58220" -dependencies = [ - "itoa", - "ryu", - "simd-json", - "simd-json-derive-int", - "thiserror", - "value-trait", -] - -[[package]] -name = "simd-json-derive-int" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e60b40db276e0d588874b1317a1603e0795ef38889e09111d841a9845623efd0" -dependencies = [ - "proc-macro2", - "quote", - "simd-json", - "syn", - "thiserror", -] - [[package]] name = "simdutf8" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - [[package]] name = "slab" version = "0.4.11" @@ -1254,22 +1213,51 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.4.10" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "winapi", + "windows-sys 0.60.2", ] [[package]] -name = "socket2" -version = "0.6.1" +name = "sonic-number" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "a8a74044c092f4f43ca7a6cfd62854cf9fb5ac8502b131347c990bf22bef1dfe" dependencies = [ - "libc", - "windows-sys 0.60.2", + "cfg-if", +] + +[[package]] +name = "sonic-rs" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4425ea8d66ec950e0a8f2ef52c766cc3d68d661d9a0845c353c40833179fd866" +dependencies = [ + "ahash", + "bumpalo", + "bytes", + "cfg-if", + "faststr", + "itoa", + "ref-cast", + "ryu", + "serde", + "simdutf8", + "sonic-number", + "sonic-simd", + "thiserror", +] + +[[package]] +name = "sonic-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5707edbfb34a40c9f2a55fa09a49101d9fec4e0cc171ce386086bd9616f34257" +dependencies = [ + "cfg-if", ] [[package]] @@ -1281,7 +1269,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "std-util" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" dependencies = [ "heck", "pluralizer", @@ -1381,7 +1369,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toasty" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" dependencies = [ "anyhow", "async-stream", @@ -1399,7 +1387,7 @@ dependencies = [ [[package]] name = "toasty-codegen" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" dependencies = [ "proc-macro2", "quote", @@ -1410,7 +1398,7 @@ dependencies = [ [[package]] name = "toasty-core" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" dependencies = [ "anyhow", "async-trait", @@ -1424,7 +1412,7 @@ dependencies = [ [[package]] name = "toasty-macros" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" dependencies = [ "proc-macro2", "quote", @@ -1436,7 +1424,7 @@ dependencies = [ [[package]] name = "toasty-sql" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf" +source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" dependencies = [ "anyhow", "toasty-core", @@ -1454,7 +1442,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -1470,32 +1458,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-postgres" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b40d66d9b2cfe04b628173409368e58247e8eddbbd3b0e6c6ba1d09f20f6c9e" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "rand 0.9.2", - "socket2 0.6.1", - "tokio", - "tokio-util", - "whoami", -] - [[package]] name = "tokio-stream" version = "0.1.17" @@ -1509,29 +1471,14 @@ dependencies = [ [[package]] name = "tokio-uring" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748482e3e13584a34664a710168ad5068e8cb1d968aa4ffa887e83ca6dd27967" +version = "0.5.1" +source = "git+http://github.com/fakeshadow/tokio-uring?rev=97d9a98#97d9a988704b5466809633b3ca6ba07acba3f38b" dependencies = [ "bytes", - "futures-util", "io-uring", "libc", "slab", - "socket2 0.4.10", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", + "socket2", "tokio", ] @@ -1604,9 +1551,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom 0.3.4", "js-sys", @@ -1614,18 +1561,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "value-trait" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e80f0c733af0720a501b3905d22e2f97662d8eacfe082a75ed7ffb5ab08cb59" -dependencies = [ - "float-cmp", - "halfbrown", - "itoa", - "ryu", -] - [[package]] name = "vcpkg" version = "0.2.15" @@ -1653,12 +1588,6 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.106" @@ -1704,27 +1633,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "web-sys" -version = "0.3.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "whoami" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", - "web-sys", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1851,7 +1759,7 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xitca-codegen" version = "0.4.0" -source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" +source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" dependencies = [ "quote", "syn", @@ -1860,7 +1768,7 @@ dependencies = [ [[package]] name = "xitca-http" version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" +source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" dependencies = [ "futures-core", "http", @@ -1868,7 +1776,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.6.1", + "socket2", "tokio", "tokio-uring", "tracing", @@ -1893,7 +1801,7 @@ dependencies = [ [[package]] name = "xitca-postgres" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" +source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" dependencies = [ "fallible-iterator", "futures-core", @@ -1909,7 +1817,7 @@ dependencies = [ [[package]] name = "xitca-postgres-diesel" version = "0.2.0" -source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=7671975#7671975951fdd71bfaedaa1686aa7c69e4af6caf" +source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=fb5dcba#fb5dcba5a89164a880a3e82d62dcb3ae5e99ae6e" dependencies = [ "diesel", "diesel-async", @@ -1946,9 +1854,9 @@ dependencies = [ [[package]] name = "xitca-server" version = "0.5.0" -source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" +source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" dependencies = [ - "socket2 0.6.1", + "socket2", "tokio", "tokio-uring", "tracing", @@ -1960,7 +1868,7 @@ dependencies = [ [[package]] name = "xitca-service" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" +source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" [[package]] name = "xitca-unsafe-collection" @@ -1985,10 +1893,9 @@ dependencies = [ "mimalloc", "rand 0.9.2", "sailfish", - "serde", + "serde_core", "serde_json", - "simd-json", - "simd-json-derive", + "sonic-rs", "toasty", "tokio", "tokio-uring", @@ -2006,7 +1913,7 @@ dependencies = [ [[package]] name = "xitca-web" version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736" +source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" dependencies = [ "futures-core", "pin-project-lite", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 5b116760b18..153519e5575 100755 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -6,22 +6,22 @@ edition = "2024" [[bin]] name = "xitca-web" path = "./src/main.rs" -required-features = ["io-uring", "pg", "router", "template"] +required-features = ["io-uring", "json", "pg", "router", "template"] [[bin]] -name = "xitca-web-unrealistic" -path = "./src/main_unrealistic.rs" -required-features = ["perf", "pg", "template"] +name = "xitca-web-barebone" +path = "./src/main_barebone.rs" +required-features = ["perf", "perf-json", "pg", "template"] [[bin]] name = "xitca-web-diesel" path = "./src/main_orm.rs" -required-features = ["diesel", "template", "web-codegen"] +required-features = ["diesel", "perf", "template", "web-codegen"] [[bin]] name = "xitca-web-toasty" path = "./src/main_orm.rs" -required-features = ["toasty", "template", "web-codegen"] +required-features = ["perf", "template", "toasty", "web-codegen"] [features] # pg client optional @@ -41,7 +41,11 @@ template = ["dep:sailfish"] # io-uring optional io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"] # unrealistic performance optimization -perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot", "simd-json", "simd-json-derive"] +perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot"] +# regular json serializer +json = ["serde_json"] +# performance optimization json serializer +perf-json = ["sonic-rs"] [dependencies] xitca-http = "0.7" @@ -52,8 +56,7 @@ xitca-unsafe-collection = "0.2" atoi = "2" httparse = "1" -serde = { version = "1" } -serde_json = { version = "1" } +serde_core = { version = "1" } # web optional xitca-web = { version = "0.7", features = ["json"], optional = true } @@ -63,7 +66,7 @@ xitca-postgres = { version = "0.3", optional = true } # diesel orm optional diesel = { version = "2", features = ["postgres"], optional = true } -diesel-async = { version = "0.7", features = ["bb8", "postgres"], optional = true } +diesel-async = { version = "0.7", optional = true } xitca-postgres-diesel = { version = "0.2", default-features = false, optional = true } futures-util = { version = "0.3", default-features = false, optional = true } @@ -80,12 +83,14 @@ tokio-uring = { version = "0.5", optional = true } # perf optional core_affinity = { version = "0.8.1", optional = true } mimalloc = { version = "0.1", default-features = false, optional = true } -simd-json = { version = "0.17", optional = true } -simd-json-derive = { version = "0.18", default-features = false, optional = true } + +# json optioanl +serde_json = { version = "1", optional = true } +sonic-rs = { version = "0.5.6", optional = true } futures-core = { version = "0.3", default-features = false } rand = { version = "0.9", features = ["os_rng", "small_rng"], default-features = false } -tokio = "1.41" +tokio = "1.48" [profile.release] lto = true @@ -94,17 +99,18 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "7671975" } +xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "fb5dcba" } xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "04bedb8" } # personal fork for efficient toasty engine fine tuned with pipelined xitca-postgres client toasty = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } toasty-core = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } toasty-sql = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } - -xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } -xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } -xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } -xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } -xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } -xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" } +tokio-uring = { git = "http://github.com/fakeshadow/tokio-uring", rev = "97d9a98" } + +xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } +xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } +xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } +xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } +xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index 4481eae03b2..b1b96249711 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -24,7 +24,7 @@ "notes": "", "versus": "" }, - "unrealistic": { + "barebone": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", @@ -32,7 +32,7 @@ "query_url": "/queries?q=", "update_url": "/updates?q=", "port": 8080, - "approach": "Stripped", + "approach": "Realistic", "classification": "Platform", "database": "Postgres", "framework": "xitca-web", @@ -42,7 +42,7 @@ "webserver": "xitca-server", "os": "Linux", "database_os": "Linux", - "display_name": "xitca-web [unrealistic]", + "display_name": "xitca-web [barebone]", "notes": "", "versus": "" }, diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 697023b33de..7a380357cd5 100755 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,26 +1,24 @@ #[path = "./db_util.rs"] mod db_util; -use core::cell::RefCell; - -use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool}; +use xitca_postgres::{Execute, iter::AsyncLendingIterator, pool::Pool}; use super::{ ser::{Fortune, Fortunes, World}, - util::{DB_URL, HandleResult}, + util::{DB_URL, HandleResult, Rand}, }; -use db_util::{FORTUNE_STMT, Shared, UPDATE_STMT, WORLD_STMT, not_found}; +use db_util::{FORTUNE_STMT, UPDATE_STMT, WORLD_STMT, not_found}; pub struct Client { pool: Pool, - shared: RefCell, + rng: core::cell::RefCell, } pub async fn create() -> HandleResult { Ok(Client { pool: Pool::builder(DB_URL).capacity(1).build()?, - shared: Default::default(), + rng: Default::default(), }) } @@ -28,7 +26,7 @@ impl Client { pub async fn get_world(&self) -> HandleResult { let mut conn = self.pool.get().await?; let stmt = WORLD_STMT.execute(&mut conn).await?; - let id = self.shared.borrow_mut().0.gen_id(); + let id = self.rng.borrow_mut().gen_id(); let mut res = stmt.bind([id]).query(&conn.consume()).await?; let row = res.try_next().await?.ok_or_else(not_found)?; Ok(World::new(row.get(0), row.get(1))) @@ -38,19 +36,21 @@ impl Client { let mut conn = self.pool.get().await?; let stmt = WORLD_STMT.execute(&mut conn).await?; - let mut res = { - let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(num as _, buf); - rng.gen_multi() - .take(num as _) - .try_for_each(|id| stmt.bind([id]).query(&mut pipe))?; - pipe.query(&conn.consume())? - }; + let get = self + .rng + .borrow_mut() + .gen_multi() + .take(num as _) + .map(|id| stmt.bind([id]).query(&conn)) + .collect::>(); + + drop(conn); let mut worlds = Vec::with_capacity(num as _); - while let Some(mut item) = res.try_next().await? { - let row = item.try_next().await?.ok_or_else(not_found)?; + for get in get { + let mut res = get.await?; + let row = res.try_next().await?.ok_or_else(not_found)?; worlds.push(World::new(row.get(0), row.get(1))); } @@ -62,32 +62,32 @@ impl Client { let world_stmt = WORLD_STMT.execute(&mut conn).await?; let update_stmt = UPDATE_STMT.execute(&mut conn).await?; - let (mut res, worlds) = { - let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf((num + 1) as _, buf); - + let (get, update, worlds) = { + let mut rng = self.rng.borrow_mut(); let mut ids = rng.gen_multi().take(num as _).collect::>(); ids.sort(); - let (rngs, worlds) = ids + let (get, rngs, worlds) = ids .iter() .cloned() .zip(rng.gen_multi()) .map(|(id, rand)| { - world_stmt.bind([id]).query(&mut pipe)?; - HandleResult::Ok((rand, World::new(id, rand))) + let get = world_stmt.bind([id]).query(&conn); + (get, rand, World::new(id, rand)) }) - .collect::, Vec<_>)>>()?; - update_stmt.bind([&ids, &rngs]).query(&mut pipe)?; - (pipe.query(&conn.consume())?, worlds) + .collect::<(Vec<_>, Vec<_>, Vec<_>)>(); + + let update = update_stmt.bind([&ids, &rngs]).query(&conn.consume()); + + (get, update, worlds) }; - while let Some(mut item) = res.try_next().await? { - while let Some(row) = item.try_next().await? { - let _rand = row.get::(1); - } + for fut in get { + let _rand = fut.await?.try_next().await?.ok_or_else(not_found)?.get::(1); } + update.await?; + Ok(worlds) } diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index d6bae3d2d8f..19231abee85 100755 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -1,8 +1,5 @@ use diesel::prelude::*; -use diesel_async::{ - RunQueryDsl, - pooled_connection::{AsyncDieselConnectionManager, bb8}, -}; +use diesel_async::{AsyncConnection, RunQueryDsl}; use futures_util::future::{TryFutureExt, TryJoinAll, try_join}; use xitca_postgres_diesel::AsyncPgConnection; @@ -12,18 +9,13 @@ use crate::{ }; pub struct Pool { - pool: bb8::Pool, + pool: AsyncPgConnection, rng: core::cell::RefCell, } impl Pool { pub async fn create() -> HandleResult { - let pool = bb8::Pool::builder() - .max_size(1) - .min_idle(Some(1)) - .test_on_check_out(false) - .build(AsyncDieselConnectionManager::new(DB_URL)) - .await?; + let pool = AsyncPgConnection::establish(DB_URL).await?; Ok(Self { pool, @@ -36,8 +28,7 @@ impl Pool { use schema::world::dsl::*; let w_id = self.rng.borrow_mut().gen_id(); - let mut conn = self.pool.get().await?; - world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into) + world.filter(id.eq(w_id)).first(&mut &self.pool).map_err(Into::into) } .await } @@ -46,12 +37,11 @@ impl Pool { { use schema::world::dsl::*; - let mut conn = self.pool.get().await?; self.rng .borrow_mut() .gen_multi() .take(num as _) - .map(|w_id| world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into)) + .map(|w_id| world.filter(id.eq(w_id)).first(&mut &self.pool).map_err(Into::into)) .collect::>() } .await @@ -61,7 +51,6 @@ impl Pool { { use schema::world::dsl::*; - let mut conn = self.pool.get().await?; let mut rng = self.rng.borrow_mut(); let mut params = Vec::with_capacity(num as _); @@ -71,7 +60,7 @@ impl Pool { .take(num as _) .zip(rng.gen_multi()) .map(|(w_id, rng)| { - let get = world.filter(id.eq(w_id)).first::(&mut conn); + let get = world.filter(id.eq(w_id)).first::(&mut &self.pool); params.push((w_id, rng)); @@ -84,7 +73,7 @@ impl Pool { .collect::>(); let sql = update_query_from_ids(params); - let update = diesel::sql_query(sql).execute(&mut conn).map_err(Into::into); + let update = diesel::sql_query(sql).execute(&mut &self.pool).map_err(Into::into); try_join(get, update) } @@ -96,8 +85,7 @@ impl Pool { { use schema::fortune::dsl::*; - let mut conn = self.pool.get().await?; - fortune.load(&mut conn).map_err(Into::into) + fortune.load(&mut &self.pool).map_err(Into::into) } .await .map(Fortunes::new) diff --git a/frameworks/Rust/xitca-web/src/db_toasty.rs b/frameworks/Rust/xitca-web/src/db_toasty.rs index f0681ba00e6..092f483a61b 100755 --- a/frameworks/Rust/xitca-web/src/db_toasty.rs +++ b/frameworks/Rust/xitca-web/src/db_toasty.rs @@ -6,7 +6,6 @@ use crate::{ util::{DB_URL, HandleResult, Rand}, }; -// this is not a realistic connection pool. pub struct Pool { db: Db, rng: core::cell::RefCell, diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs index 6a266483fc7..364e020b3b0 100755 --- a/frameworks/Rust/xitca-web/src/db_unrealistic.rs +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -4,20 +4,18 @@ #[path = "./db_util.rs"] mod db_util; -use std::cell::RefCell; - -use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement}; +use xitca_postgres::{Execute, iter::AsyncLendingIterator, statement::Statement}; use super::{ ser::{Fortune, Fortunes, World}, - util::{DB_URL, HandleResult}, + util::{DB_URL, HandleResult, Rand}, }; -use db_util::{FORTUNE_STMT, Shared, UPDATE_STMT, WORLD_STMT, not_found}; +use db_util::{FORTUNE_STMT, UPDATE_STMT, WORLD_STMT, not_found}; pub struct Client { cli: xitca_postgres::Client, - shared: RefCell, + rng: core::cell::RefCell, fortune: Statement, world: Statement, update: Statement, @@ -37,7 +35,7 @@ pub async fn create() -> HandleResult { Ok(Client { cli, - shared: Default::default(), + rng: Default::default(), world, fortune, update, @@ -46,63 +44,59 @@ pub async fn create() -> HandleResult { impl Client { pub async fn get_world(&self) -> HandleResult { - let id = self.shared.borrow_mut().0.gen_id(); + let id = self.rng.borrow_mut().gen_id(); let mut res = self.world.bind([id]).query(&self.cli).await?; let row = res.try_next().await?.ok_or_else(not_found)?; Ok(World::new(row.get(0), row.get(1))) } pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let mut res = { - let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(num as _, buf); - rng.gen_multi() - .take(num as _) - .try_for_each(|id| self.world.bind([id]).query(&mut pipe))?; - pipe.query(&self.cli)? - }; + let get = self + .rng + .borrow_mut() + .gen_multi() + .take(num as _) + .map(|id| self.world.bind([id]).query(&self.cli)) + .collect::>(); let mut worlds = Vec::with_capacity(num as _); - while let Some(mut item) = res.try_next().await? { - while let Some(row) = item.try_next().await? { - worlds.push(World::new(row.get(0), row.get(1))); - } + for query in get { + let mut res = query.await?; + let row = res.try_next().await?.ok_or_else(not_found)?; + worlds.push(World::new(row.get(0), row.get(1))); } Ok(worlds) } pub async fn update(&self, num: u16) -> HandleResult> { - let len = num as usize; - - let (mut res, worlds) = { - let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); - let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); - + let (get, update, worlds) = { + let mut rng = self.rng.borrow_mut(); let mut ids = rng.gen_multi().take(num as _).collect::>(); ids.sort(); - let (rngs, worlds) = ids + let (get, rngs, worlds) = ids .iter() .cloned() .zip(rng.gen_multi()) .map(|(id, rand)| { - self.world.bind([id]).query(&mut pipe)?; - HandleResult::Ok((rand, World::new(id, rand))) + let get = self.world.bind([id]).query(&self.cli); + (get, rand, World::new(id, rand)) }) - .collect::, Vec<_>)>>()?; - self.update.bind([&ids, &rngs]).query(&mut pipe)?; + .collect::<(Vec<_>, Vec<_>, Vec<_>)>(); + + let update = self.update.bind([&ids, &rngs]).query(&self.cli); - (pipe.query(&self.cli)?, worlds) + (get, update, worlds) }; - while let Some(mut item) = res.try_next().await? { - while let Some(row) = item.try_next().await? { - let _rand = row.get::(1); - } + for fut in get { + let _rand = fut.await?.try_next().await?.ok_or_else(not_found)?.get::(1); } + update.await?; + Ok(worlds) } diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs index 83d03575709..afde4496d9e 100755 --- a/frameworks/Rust/xitca-web/src/db_util.rs +++ b/frameworks/Rust/xitca-web/src/db_util.rs @@ -1,31 +1,21 @@ -#[cfg(feature = "pg")] -pub use pg::*; +use xitca_postgres::{ + statement::{Statement, StatementNamed}, + types::Type, +}; -#[cfg(feature = "pg")] -pub mod pg { - #![allow(dead_code)] +use crate::util::Error; - use xitca_io::bytes::BytesMut; - use xitca_postgres::{ - statement::{Statement, StatementNamed}, - types::Type, - }; +pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT id,message FROM fortune", &[]); - use crate::util::{Error, Rand}; +pub const WORLD_STMT: StatementNamed = Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]); - pub type Shared = (Rand, BytesMut); +pub const UPDATE_STMT: StatementNamed = Statement::named( + "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i", + &[Type::INT4_ARRAY, Type::INT4_ARRAY], +); - pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT id,message FROM fortune", &[]); - pub const WORLD_STMT: StatementNamed = - Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]); - pub const UPDATE_STMT: StatementNamed = Statement::named( - "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i", - &[Type::INT4_ARRAY, Type::INT4_ARRAY], - ); - - #[cold] - #[inline(never)] - pub fn not_found() -> Error { - "request World does not exist".into() - } +#[cold] +#[inline(never)] +pub fn not_found() -> Error { + "request World does not exist".into() } diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 449651ed129..30fded2d8d9 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -47,7 +47,6 @@ fn main() -> std::io::Result<()> { "/fortunes", get(fn_service(async |ctx: Ctx| { let (req, state) = ctx.into_parts(); - use sailfish::TemplateOnce; let fortunes = state.client.tell_fortune().await?.render_once()?; req.html_response(fortunes) })), diff --git a/frameworks/Rust/xitca-web/src/main_unrealistic.rs b/frameworks/Rust/xitca-web/src/main_barebone.rs similarity index 92% rename from frameworks/Rust/xitca-web/src/main_unrealistic.rs rename to frameworks/Rust/xitca-web/src/main_barebone.rs index 2b45164fd8d..8e603ad05e1 100644 --- a/frameworks/Rust/xitca-web/src/main_unrealistic.rs +++ b/frameworks/Rust/xitca-web/src/main_barebone.rs @@ -13,14 +13,11 @@ mod util; use std::io; use xitca_http::{ - bytes::BufMutWriter, + bytes::BufMut, h1::dispatcher_unreal::{Dispatcher, Request, Response}, http::StatusCode, }; use xitca_service::Service; -// simd-json crate is realistic approach to json serializer. -// That said xitca-web by default utilize serde-json as serializer making it an unrealistic representation of framework performance -use simd_json_derive::Serialize; use self::{ ser::Message, @@ -109,11 +106,12 @@ async fn handler<'h>(req: Request<'h, State>, res: Response<'h>) -> .header("server", "X") // unrealistic content length header. .header("content-length", "27") - .body_writer(|buf| Message::new().json_write(&mut BufMutWriter(buf)).unwrap()), + // snoic-rs crate is realistic approach to json serializer. + // That said xitca-web by default utilize serde-json as serializer making it an unrealistic representation of framework performance + .body_writer(|buf| sonic_rs::to_writer(buf.writer(), &Message::new()).unwrap()), // all database related categories are unrealistic. please reference db_unrealistic module for detail. "/fortunes" => { - use sailfish::TemplateOnce; let fortunes = req.ctx.client.tell_fortune().await.unwrap().render_once().unwrap(); res.status(StatusCode::OK) .header("content-type", "text/html; charset=utf-8") @@ -142,10 +140,10 @@ async fn handler<'h>(req: Request<'h, State>, res: Response<'h>) -> fn json_response<'r, DB, T>(res: Response<'r>, state: &State, val: &T) -> Response<'r, 3> where - T: Serialize, + T: serde_core::Serialize, { let buf = &mut *state.write_buf.borrow_mut(); - val.json_write(&mut BufMutWriter(buf)).unwrap(); + sonic_rs::to_writer(buf.writer(), val).unwrap(); let res = res .status(StatusCode::OK) .header("content-type", "application/json") diff --git a/frameworks/Rust/xitca-web/src/main_orm.rs b/frameworks/Rust/xitca-web/src/main_orm.rs index 37311cd4f73..6fd0e7a3732 100755 --- a/frameworks/Rust/xitca-web/src/main_orm.rs +++ b/frameworks/Rust/xitca-web/src/main_orm.rs @@ -1,3 +1,6 @@ +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + mod ser; mod util; @@ -47,7 +50,6 @@ async fn db(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { #[route("/fortunes", method = get)] async fn fortunes(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { - use sailfish::TemplateOnce; let html = pool.tell_fortune().await?.render_once()?; Ok(Html(html)) } diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index 88ae65f5e7d..1597e19ab09 100755 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -1,22 +1,23 @@ #![allow(dead_code)] -use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct}; +use std::borrow::Cow; + +use serde_core::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct}; use xitca_http::{ body::Once, - bytes::{BufMutWriter, Bytes}, + bytes::Bytes, http::{ self, IntoResponse as _, RequestExt, StatusCode, - const_header_value::{JSON, TEXT_HTML_UTF8, TEXT_UTF8}, + const_header_value::{TEXT_HTML_UTF8, TEXT_UTF8}, header::CONTENT_TYPE, }, }; -use crate::util::{Error, State}; +use crate::util::Error; const HELLO: &str = "Hello, World!"; const HELLO_BYTES: &[u8] = HELLO.as_bytes(); -#[cfg_attr(feature = "perf", derive(simd_json_derive::Serialize))] #[derive(Clone)] pub struct Message { message: &'static str, @@ -34,7 +35,6 @@ pub struct Num(pub u16); #[cfg_attr(feature = "diesel", derive(diesel::Queryable))] #[cfg_attr(feature = "toasty", derive(toasty::Model))] #[cfg_attr(feature = "toasty", table = "world")] -#[cfg_attr(feature = "perf", derive(simd_json_derive::Serialize))] pub struct World { #[cfg_attr(feature = "toasty", key)] pub id: i32, @@ -54,27 +54,12 @@ impl World { pub struct Fortune { #[cfg_attr(feature = "toasty", key)] pub id: i32, - #[cfg(not(feature = "toasty"))] - pub message: std::borrow::Cow<'static, str>, - #[cfg(feature = "toasty")] - pub message: String, + pub message: Cow<'static, str>, } -#[cfg(not(feature = "toasty"))] impl Fortune { #[inline] - pub fn new(id: i32, message: impl Into>) -> Self { - Self { - id, - message: message.into(), - } - } -} - -#[cfg(feature = "toasty")] -impl Fortune { - #[inline] - pub fn new(id: i32, message: impl Into) -> Self { + pub fn new(id: i32, message: impl Into>) -> Self { Self { id, message: message.into(), @@ -90,8 +75,8 @@ pub struct Fortunes { // using the macro does not have any perf cost and this piece of code is expanded manually to speed up compile time of // bench to reduce resource usage of bench runner #[cfg(feature = "template")] -impl sailfish::TemplateOnce for Fortunes { - fn render_once(self) -> sailfish::RenderResult { +impl Fortunes { + pub fn render_once(self) -> sailfish::RenderResult { use sailfish::runtime::{Buffer, Render}; const PREFIX: &str = "\n\nFortunes\n\n\n\n"; @@ -111,10 +96,6 @@ impl sailfish::TemplateOnce for Fortunes { Ok(buf.into_string()) } - - fn render_once_to(self, _: &mut sailfish::runtime::Buffer) -> Result<(), sailfish::runtime::RenderError> { - unimplemented!("") - } } impl Fortunes { @@ -133,7 +114,7 @@ impl<'de> Deserialize<'de> for Num { { use core::fmt; - use serde::de::{Error, MapAccess, Visitor}; + use serde_core::de::{Error, MapAccess, Visitor}; const FIELDS: &[&str] = &["q"]; @@ -217,7 +198,8 @@ pub type Request = http::Request>; pub type Response = http::Response>; pub trait IntoResponse: Sized { - fn json_response(self, state: &State, val: &impl Serialize) -> Result; + #[cfg(any(feature = "json", feature = "perf-json"))] + fn json_response(self, state: &crate::util::State, val: &impl Serialize) -> Result; fn text_response(self) -> Result; @@ -225,11 +207,18 @@ pub trait IntoResponse: Sized { } impl IntoResponse for Request { - fn json_response(self, state: &State, val: &impl Serialize) -> Result { + #[cfg(any(feature = "json", feature = "perf-json"))] + fn json_response(self, state: &crate::util::State, val: &impl Serialize) -> Result { let buf = &mut *state.write_buf.borrow_mut(); - serde_json::to_writer(BufMutWriter(buf), val)?; + #[cfg(all(feature = "json", not(feature = "perf-json")))] + serde_json::to_writer(xitca_http::bytes::BufMutWriter(buf), val)?; + + #[cfg(all(feature = "perf-json", not(feature = "json")))] + sonic_rs::to_writer(xitca_http::bytes::BufMut::writer(&mut *buf), val)?; + let mut res = self.into_response(buf.split().freeze()); - res.headers_mut().insert(CONTENT_TYPE, JSON); + res.headers_mut() + .insert(CONTENT_TYPE, xitca_http::http::const_header_value::JSON); Ok(res) } diff --git a/frameworks/Rust/xitca-web/templates/fortune.stpl b/frameworks/Rust/xitca-web/templates/fortune.stpl deleted file mode 100644 index 28227945b4c..00000000000 --- a/frameworks/Rust/xitca-web/templates/fortune.stpl +++ /dev/null @@ -1,10 +0,0 @@ - - - Fortunes - -
idmessage
- - <% for item in self.items { %><% } %> -
idmessage
<%= item.id %><%= &*item.message %>
- - \ No newline at end of file diff --git a/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile b/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile new file mode 100644 index 00000000000..4a5bbf9d898 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.91.1 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-barebone --features perf,perf-json,pg,template + +EXPOSE 8080 + +CMD ./target/release/xitca-web-barebone diff --git a/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile b/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile index ceaacc0f659..66ff80b5dfd 100755 --- a/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile @@ -3,7 +3,7 @@ FROM rust:1.91.1 ADD ./ /xitca-web WORKDIR /xitca-web -RUN cargo build --release --bin xitca-web-diesel --features diesel,template,web-codegen +RUN cargo build --release --bin xitca-web-diesel --features diesel,perf,template,web-codegen EXPOSE 8080 diff --git a/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile b/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile index 4de7ed3c9a6..30a2cea648d 100755 --- a/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile @@ -3,7 +3,7 @@ FROM rust:1.91.1 ADD ./ /xitca-web WORKDIR /xitca-web -RUN cargo build --release --bin xitca-web-toasty --features toasty,template,web-codegen +RUN cargo build --release --bin xitca-web-toasty --features perf,template,toasty,web-codegen EXPOSE 8080 diff --git a/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile deleted file mode 100644 index 299ee0fbfc1..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:1.91.1 - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-unrealistic --features perf,pg,template - -EXPOSE 8080 - -CMD ./target/release/xitca-web-unrealistic diff --git a/frameworks/Rust/xitca-web/xitca-web.dockerfile b/frameworks/Rust/xitca-web/xitca-web.dockerfile index ed10a355996..86d7818009e 100644 --- a/frameworks/Rust/xitca-web/xitca-web.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web.dockerfile @@ -3,7 +3,7 @@ FROM rust:1.91.1 ADD ./ /xitca-web WORKDIR /xitca-web -RUN cargo build --release --bin xitca-web --features io-uring,pg,router,template +RUN cargo build --release --bin xitca-web --features io-uring,json,pg,router,template EXPOSE 8080 From 00275371a6be487a208ac1898a33b8cea13981fb Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:43:23 +0100 Subject: [PATCH 103/130] [ruby/padrino] Use latest released Padrino (#10361) --- frameworks/Ruby/padrino/Gemfile | 4 +- frameworks/Ruby/padrino/Gemfile.lock | 116 +++++++++++++-------------- 2 files changed, 58 insertions(+), 62 deletions(-) diff --git a/frameworks/Ruby/padrino/Gemfile b/frameworks/Ruby/padrino/Gemfile index 1fb06aaf3f9..18ff5f9566c 100644 --- a/frameworks/Ruby/padrino/Gemfile +++ b/frameworks/Ruby/padrino/Gemfile @@ -4,8 +4,8 @@ gem 'mysql2', '> 0.5' gem 'json' gem 'activerecord', '~> 8.1.0', :require => 'active_record' -gem 'slim', '2.0.3' -gem 'padrino', git: 'https://github.com/padrino/padrino-framework.git' +gem 'slim' +gem 'padrino', '0.16.0' gem 'rack' group :iodine, optional: true do diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock index 38f3315b358..e0e649da789 100644 --- a/frameworks/Ruby/padrino/Gemfile.lock +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -1,40 +1,3 @@ -GIT - remote: https://github.com/padrino/padrino-framework.git - revision: 9a38042351c9f5768231e94abca87bb1592cdcfa - specs: - padrino (0.16.0.pre3) - padrino-admin (= 0.16.0.pre3) - padrino-cache (= 0.16.0.pre3) - padrino-core (= 0.16.0.pre3) - padrino-gen (= 0.16.0.pre3) - padrino-helpers (= 0.16.0.pre3) - padrino-mailer (= 0.16.0.pre3) - padrino-support (= 0.16.0.pre3) - padrino-admin (0.16.0.pre3) - padrino-core (= 0.16.0.pre3) - padrino-helpers (= 0.16.0.pre3) - padrino-cache (0.16.0.pre3) - moneta (~> 1.6) - padrino-core (= 0.16.0.pre3) - padrino-helpers (= 0.16.0.pre3) - padrino-core (0.16.0.pre3) - padrino-support (= 0.16.0.pre3) - rackup (~> 2.1) - sinatra (~> 4) - thor (~> 1.0) - padrino-gen (0.16.0.pre3) - bundler (>= 1.0, < 3) - padrino-core (= 0.16.0.pre3) - padrino-helpers (0.16.0.pre3) - i18n (>= 0.6.7, < 2) - padrino-support (= 0.16.0.pre3) - tilt (>= 1.4.1, < 3) - padrino-mailer (0.16.0.pre3) - mail (~> 2.5) - mime-types (< 4) - padrino-core (= 0.16.0.pre3) - padrino-support (0.16.0.pre3) - GEM remote: https://rubygems.org/ specs: @@ -57,33 +20,34 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) - base64 (0.2.0) + base64 (0.3.0) bigdecimal (3.1.9) concurrent-ruby (1.3.5) connection_pool (2.5.0) - date (3.4.1) + date (3.5.0) drb (2.2.1) i18n (1.14.7) concurrent-ruby (~> 1.0) iodine (0.7.58) json (2.16.0) - logger (1.6.6) - mail (2.8.1) + logger (1.7.0) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - mime-types (3.6.1) + mime-types (3.7.0) logger - mime-types-data (~> 3.2015) - mime-types-data (3.2025.0318) + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2025.0924) mini_mime (1.1.5) minitest (5.25.5) moneta (1.6.0) - mustermann (3.0.3) + mustermann (3.0.4) ruby2_keywords (~> 0.0.1) mysql2 (0.5.6) - net-imap (0.5.6) + net-imap (0.5.12) date net-protocol net-pop (0.1.2) @@ -92,32 +56,64 @@ GEM timeout net-smtp (0.5.1) net-protocol - rack (3.1.18) - rack-protection (4.1.1) + padrino (0.16.0) + padrino-admin (= 0.16.0) + padrino-cache (= 0.16.0) + padrino-core (= 0.16.0) + padrino-gen (= 0.16.0) + padrino-helpers (= 0.16.0) + padrino-mailer (= 0.16.0) + padrino-support (= 0.16.0) + padrino-admin (0.16.0) + padrino-core (= 0.16.0) + padrino-helpers (= 0.16.0) + padrino-cache (0.16.0) + moneta (~> 1.6) + padrino-core (= 0.16.0) + padrino-helpers (= 0.16.0) + padrino-core (0.16.0) + padrino-support (= 0.16.0) + rackup (~> 2.1) + sinatra (~> 4) + thor (~> 1.0) + padrino-gen (0.16.0) + bundler (>= 1.0, < 3) + padrino-core (= 0.16.0) + padrino-helpers (0.16.0) + i18n (>= 0.6.7, < 2) + padrino-support (= 0.16.0) + tilt (>= 2.1, < 3) + padrino-mailer (0.16.0) + mail (~> 2.5) + mime-types (>= 3.1, < 4) + padrino-core (= 0.16.0) + padrino-support (0.16.0) + rack (3.2.4) + rack-protection (4.2.1) base64 (>= 0.1.0) logger (>= 1.6.0) rack (>= 3.0.0, < 4) - rack-session (2.1.0) + rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) rackup (2.2.1) rack (>= 3) ruby2_keywords (0.0.5) securerandom (0.4.1) - sinatra (4.1.1) + sinatra (4.2.1) logger (>= 1.6.0) mustermann (~> 3.0) rack (>= 3.0.0, < 4) - rack-protection (= 4.1.1) + rack-protection (= 4.2.1) rack-session (>= 2.0.0, < 3) tilt (~> 2.0) - slim (2.0.3) - temple (~> 0.6.6) - tilt (>= 1.3.3, < 2.1) - temple (0.6.10) - thor (1.3.2) - tilt (2.0.11) - timeout (0.4.3) + slim (5.2.1) + temple (~> 0.10.0) + tilt (>= 2.1.0) + temple (0.10.4) + thor (1.4.0) + tilt (2.6.1) + timeout (0.4.4) tzinfo (2.0.6) concurrent-ruby (~> 1.0) uri (1.0.3) @@ -132,9 +128,9 @@ DEPENDENCIES iodine (~> 0.7) json mysql2 (> 0.5) - padrino! + padrino (= 0.16.0) rack - slim (= 2.0.3) + slim BUNDLED WITH 2.7.0 From 065589b794c904065984059cc0de4557526b9b94 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:43:46 +0100 Subject: [PATCH 104/130] [groovy/hot] Remove Hot framework (#10362) The current test are both failing as they use an EOL version of Java. Hot hasn't been updated in 3 years. --- frameworks/Groovy/hot/benchmark_config.json | 83 ------------ frameworks/Groovy/hot/config-mysql.json | 16 --- frameworks/Groovy/hot/config-pgsql.json | 16 --- frameworks/Groovy/hot/config.json | 16 --- frameworks/Groovy/hot/config.toml | 60 --------- frameworks/Groovy/hot/hot-mongodb.dockerfile | 12 -- frameworks/Groovy/hot/hot-mysql.dockerfile | 12 -- frameworks/Groovy/hot/hot-postgres.dockerfile | 12 -- frameworks/Groovy/hot/hot.dockerfile | 12 -- .../Groovy/hot/shows/benchmark.show.groovy | 122 ------------------ 10 files changed, 361 deletions(-) delete mode 100644 frameworks/Groovy/hot/benchmark_config.json delete mode 100644 frameworks/Groovy/hot/config-mysql.json delete mode 100644 frameworks/Groovy/hot/config-pgsql.json delete mode 100644 frameworks/Groovy/hot/config.json delete mode 100644 frameworks/Groovy/hot/config.toml delete mode 100644 frameworks/Groovy/hot/hot-mongodb.dockerfile delete mode 100644 frameworks/Groovy/hot/hot-mysql.dockerfile delete mode 100644 frameworks/Groovy/hot/hot-postgres.dockerfile delete mode 100644 frameworks/Groovy/hot/hot.dockerfile delete mode 100644 frameworks/Groovy/hot/shows/benchmark.show.groovy diff --git a/frameworks/Groovy/hot/benchmark_config.json b/frameworks/Groovy/hot/benchmark_config.json deleted file mode 100644 index 0f309f9fce4..00000000000 --- a/frameworks/Groovy/hot/benchmark_config.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "framework": "hot", - "tests": [{ - "default": { - "json_url": "/rest/json", - "plaintext_url": "/rest/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "Hot", - "language": "Groovy", - "orm": "Raw", - "platform": "Jetty", - "webserver": "Jetty", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hot", - "notes": "", - "versus": "" - }, - "mongodb" : { - "db_url": "/rest/db/mongodb", - "query_url": "/rest/queries/mongodb?queries=", - "fortune_url": "/rest/fortunes/mongodb", - "update_url": "/rest/updates/mongodb?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MongoDB", - "framework": "Hot", - "language": "Groovy", - "orm": "Raw", - "platform": "Jetty", - "webserver": "Jetty", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hot", - "notes": "", - "versus": "", - "tags": ["broken"] - }, "postgres" : { - "db_url": "/rest/db/pgsql", - "query_url": "/rest/queries/pgsql?queries=", - "fortune_url": "/rest/fortunes/pgsql", - "update_url": "/rest/updates/pgsql?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "Hot", - "language": "Groovy", - "orm": "Raw", - "platform": "Jetty", - "webserver": "Jetty", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hot", - "notes": "", - "versus": "", - "tags": ["broken"] - }, "mysql" : { - "db_url": "/rest/db/mysql", - "query_url": "/rest/queries/mysql?queries=", - "fortune_url": "/rest/fortunes/mysql", - "update_url": "/rest/updates/mysql?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "framework": "Hot", - "language": "Groovy", - "orm": "Raw", - "platform": "Jetty", - "webserver": "Jetty", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hot", - "notes": "", - "versus": "" - } - }] -} diff --git a/frameworks/Groovy/hot/config-mysql.json b/frameworks/Groovy/hot/config-mysql.json deleted file mode 100644 index f8c78fe4db1..00000000000 --- a/frameworks/Groovy/hot/config-mysql.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "techempower", - "version": "0.1", - "devMode": false, - "dataSources": [ - { - "name": "mysql", - "engine": "MYSQL", - "hostname": "tfb-database", - "port": 3306, - "database": "hello_world", - "username": "benchmarkdbuser", - "password": "benchmarkdbpass" - } - ] -} \ No newline at end of file diff --git a/frameworks/Groovy/hot/config-pgsql.json b/frameworks/Groovy/hot/config-pgsql.json deleted file mode 100644 index 42bff295fe5..00000000000 --- a/frameworks/Groovy/hot/config-pgsql.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "techempower", - "version": "0.1", - "devMode": false, - "dataSources": [ - { - "name": "pgsql", - "engine": "PGSQL", - "hostname": "tfb-database", - "port": 5432, - "database": "hello_world", - "username": "benchmarkdbuser", - "password": "benchmarkdbpass" - } - ] -} \ No newline at end of file diff --git a/frameworks/Groovy/hot/config.json b/frameworks/Groovy/hot/config.json deleted file mode 100644 index eff1c92811d..00000000000 --- a/frameworks/Groovy/hot/config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "techempower", - "version": "0.1", - "devMode": false, - "dataSources": [ - { - "name": "mongo", - "engine": "MONGODB", - "hostname": "tfb-database", - "port": 27017, - "database": "hello_world", - "username": "", - "password": "" - } - ] -} \ No newline at end of file diff --git a/frameworks/Groovy/hot/config.toml b/frameworks/Groovy/hot/config.toml deleted file mode 100644 index 040ce1c5526..00000000000 --- a/frameworks/Groovy/hot/config.toml +++ /dev/null @@ -1,60 +0,0 @@ -[framework] -name = "hot" - -[main] -urls.plaintext = "/rest/plaintext" -urls.json = "/rest/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Jetty" -webserver = "Jetty" -versus = "" - -[mongodb] -urls.db = "/rest/db/mongodb" -urls.query = "/rest/queries/mongodb?queries=" -urls.update = "/rest/updates/mongodb?queries=" -urls.fortune = "/rest/fortunes/mongodb" -approach = "Realistic" -classification = "Platform" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Jetty" -webserver = "Jetty" -versus = "" - -[postgres] -urls.db = "/rest/db/pgsql" -urls.query = "/rest/queries/pgsql?queries=" -urls.update = "/rest/updates/pgsql?queries=" -urls.fortune = "/rest/fortunes/pgsql" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Jetty" -webserver = "Jetty" -versus = "" - -[mysql] -urls.db = "/rest/db/mysql" -urls.query = "/rest/queries/mysql?queries=" -urls.update = "/rest/updates/mysql?queries=" -urls.fortune = "/rest/fortunes/mysql" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Jetty" -webserver = "Jetty" -versus = "" diff --git a/frameworks/Groovy/hot/hot-mongodb.dockerfile b/frameworks/Groovy/hot/hot-mongodb.dockerfile deleted file mode 100644 index 5dbec3b87b6..00000000000 --- a/frameworks/Groovy/hot/hot-mongodb.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM openjdk:8-jdk -WORKDIR /hot -COPY shows shows -COPY config.json config.json -ENV HOT_VERSION 0.9.15-SNAPSHOT -RUN curl -sL https://github.com/dsolimando/Hot/releases/download/${HOT_VERSION}/hot-${HOT_VERSION}.tar.gz | tar xz -ENV HOT_HOME /hot/hot-${HOT_VERSION} -ENV PATH ${HOT_HOME}:${PATH} - -EXPOSE 8080 - -CMD ["hot", "run"] diff --git a/frameworks/Groovy/hot/hot-mysql.dockerfile b/frameworks/Groovy/hot/hot-mysql.dockerfile deleted file mode 100644 index f4efb402f16..00000000000 --- a/frameworks/Groovy/hot/hot-mysql.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM openjdk:8-jdk -WORKDIR /hot -COPY shows shows -COPY config-mysql.json config.json -ENV HOT_VERSION 0.9.15-SNAPSHOT -RUN curl -sL https://github.com/dsolimando/Hot/releases/download/${HOT_VERSION}/hot-${HOT_VERSION}.tar.gz | tar xz -ENV HOT_HOME /hot/hot-${HOT_VERSION} -ENV PATH ${HOT_HOME}:${PATH} - -EXPOSE 8080 - -CMD ["hot", "run"] diff --git a/frameworks/Groovy/hot/hot-postgres.dockerfile b/frameworks/Groovy/hot/hot-postgres.dockerfile deleted file mode 100644 index 567a7181896..00000000000 --- a/frameworks/Groovy/hot/hot-postgres.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM openjdk:8-jdk -WORKDIR /hot -COPY shows shows -COPY config-pgsql.json config.json -ENV HOT_VERSION 0.9.15-SNAPSHOT -RUN curl -sL https://github.com/dsolimando/Hot/releases/download/${HOT_VERSION}/hot-${HOT_VERSION}.tar.gz | tar xz -ENV HOT_HOME /hot/hot-${HOT_VERSION} -ENV PATH ${HOT_HOME}:${PATH} - -EXPOSE 8080 - -CMD ["hot", "run"] diff --git a/frameworks/Groovy/hot/hot.dockerfile b/frameworks/Groovy/hot/hot.dockerfile deleted file mode 100644 index 5dbec3b87b6..00000000000 --- a/frameworks/Groovy/hot/hot.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM openjdk:8-jdk -WORKDIR /hot -COPY shows shows -COPY config.json config.json -ENV HOT_VERSION 0.9.15-SNAPSHOT -RUN curl -sL https://github.com/dsolimando/Hot/releases/download/${HOT_VERSION}/hot-${HOT_VERSION}.tar.gz | tar xz -ENV HOT_HOME /hot/hot-${HOT_VERSION} -ENV PATH ${HOT_HOME}:${PATH} - -EXPOSE 8080 - -CMD ["hot", "run"] diff --git a/frameworks/Groovy/hot/shows/benchmark.show.groovy b/frameworks/Groovy/hot/shows/benchmark.show.groovy deleted file mode 100644 index 7f00feccb25..00000000000 --- a/frameworks/Groovy/hot/shows/benchmark.show.groovy +++ /dev/null @@ -1,122 +0,0 @@ -import org.apache.commons.lang3.StringEscapeUtils - -show.scale() - -def mongo = show.dbs.mongo -def pgsqldb = show.dbs.pgsql -def mysql = show.dbs.mysql - -def generator = new Random () - -def generate = { - Math.max(generator.nextInt(10000),1) -} - -def validateNumQueries = { - Integer numQueries - - if (!it) numQueries = 1 - - try { - numQueries = it[0] as Integer - } catch (e) { - numQueries = 1 - } - Math.max(1,Math.min(500,numQueries)) -} - -def query = { db, idLabel = '_id' -> - db.world.findOne([(idLabel):generate()]) -} - -rest.get('/db/mongodb').then { query mongo } -rest.get('/db/pgsql').then { query pgsqldb, 'id' } -rest.get('/db/mysql').then { query mysql, 'id' } - -def queries = { req, db, idLabel = '_id' -> - - def numQueries = validateNumQueries(req?.requestParams?.queries) - def deferred = show.Deferred() - def promise = deferred.promise() - def results = [] - - (1..numQueries).each { i -> - promise = promise.then { - db.world.findOne((idLabel):generate()) - }.then { world -> - results << world - results - } - } - deferred.resolve() - promise -} - -rest.get('/queries/mongodb').then { req -> queries req, mongo } -rest.get('/queries/pgsql').then { req -> queries req, pgsqldb, 'id' } -rest.get('/queries/mysql').then { req -> queries req, mysql, 'id' } - -def template = { content -> - """Fortunes -$content -
idmessage
-""" -} - -def fortune = { db, idLabel = '_id', parseId = { it } -> - db.fortune.find().promise().then { fortunes -> - - fortunes << [(idLabel):'0', message:'Additional fortune added at request time.'] - response = template(fortunes - .sort { it.message } - .collect({ - "${parseId(it[idLabel])}${StringEscapeUtils.escapeHtml4(it.message)}" - }).join('') - ) - new hot.Response(200,['Content-Type':'text/html'], response) - } -} - -rest.get('/fortunes/mongodb').then { - fortune mongo, '_id', { Float.parseFloat(it) as Integer } -} -rest.get('/fortunes/pgsql').then { fortune pgsqldb, 'id' } -rest.get('/fortunes/mysql').then { fortune mysql, 'id' } - -def update = { req, db, idLabel = '_id' -> - def numQueries = validateNumQueries(req?.requestParams?.queries) - - def deferred = show.Deferred() - def promise = deferred.promise() - def results = [] - - (1..numQueries).each { i -> - def genId = generate() - - promise = promise.then { - db.world.findOne((idLabel):genId).promise() - }.then { world -> - world.randomNumber = generate() - db.world.update([(idLabel):genId],[$set:[randomNumber:world.randomNumber]]).then { - world - } - }.then { world -> - results << world - results - } - } - deferred.resolve() - promise -} - -rest.get('/updates/mongodb').then { req -> update req, mongo } -rest.get('/updates/pgsql').then { req -> update req, pgsqldb, 'id' } -rest.get('/updates/mysql').then { req -> update req, mysql, 'id' } - -rest.get("/json").then { - [message:'Hello, World!'] -} - -rest.get('/plaintext').then { - new hot.Response(200,['Content-Type':'text/plain'],'Hello, World!') -} \ No newline at end of file From fe28ddbdc6c9f81897296fa85ccf625fb3b33692 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:44:08 +0100 Subject: [PATCH 105/130] [groovy/grails] Mark tests as broken. (#10363) The current test fails as it is using an EOL version of Java. Grails is actively maintained, so mark it as broken instead. --- frameworks/Groovy/grails/benchmark_config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frameworks/Groovy/grails/benchmark_config.json b/frameworks/Groovy/grails/benchmark_config.json index 10e22e0217b..aa247529c33 100644 --- a/frameworks/Groovy/grails/benchmark_config.json +++ b/frameworks/Groovy/grails/benchmark_config.json @@ -22,7 +22,8 @@ "database_os": "Linux", "display_name": "Grails", "notes": "", - "versus": "servlet" + "versus": "servlet", + "tags": ["broken"] } }] } From 932cf08ee4c60e9a4407ad892dfb28306bccc5fa Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:44:22 +0100 Subject: [PATCH 106/130] [ruby/sinatra] Upgrade to Ruby 4.0-rc (#10364) --- frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile | 2 +- frameworks/Ruby/sinatra/sinatra-postgres.dockerfile | 2 +- frameworks/Ruby/sinatra/sinatra.dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile index a6a29633958..7dbd84dfeca 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile index 7c4e265bbda..36ccd2eb6c0 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/sinatra/sinatra.dockerfile b/frameworks/Ruby/sinatra/sinatra.dockerfile index 186f4273bc6..de5ba291d61 100644 --- a/frameworks/Ruby/sinatra/sinatra.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 From c7591cfa3472b0c580e58eb99e40f677b4a7d632 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Tue, 9 Dec 2025 00:45:41 +0700 Subject: [PATCH 107/130] update ktor to user Gradle (#10365) * update ktor to user Gradle * fix r2dbc update * improve updates * use pipelining of r2dbc to improve perf * fixed and optimized pgclient * fixed jettyf --- .../Kotlin/ktor/ktor-asyncdb/build.gradle.kts | 2 +- frameworks/Kotlin/ktor/ktor-cio.dockerfile | 9 +- .../ktor/ktor-exposed/app/build.gradle.kts | 17 +- .../ktor-exposed/app/src/main/kotlin/App.kt | 49 ++-- frameworks/Kotlin/ktor/ktor-jetty.dockerfile | 9 +- .../ktor/ktor-pgclient/build.gradle.kts | 23 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../ktor-pgclient/src/main/kotlin/main.kt | 67 ++++-- frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile | 9 +- frameworks/Kotlin/ktor/ktor-r2dbc/README.md | 12 +- .../Kotlin/ktor/ktor-r2dbc/build.gradle.kts | 99 ++++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 56172 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + frameworks/Kotlin/ktor/ktor-r2dbc/gradlew | 172 ++++++++++++++ frameworks/Kotlin/ktor/ktor-r2dbc/gradlew.bat | 84 +++++++ frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml | 179 --------------- .../ktor/ktor-r2dbc/settings.gradle.kts | 2 + .../org/jetbrains/ktor/benchmarks/Hello.kt | 155 +++++++------ frameworks/Kotlin/ktor/ktor.dockerfile | 9 +- frameworks/Kotlin/ktor/ktor/README.md | 12 +- frameworks/Kotlin/ktor/ktor/build.gradle.kts | 108 +++++++++ .../ktor/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 56172 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + frameworks/Kotlin/ktor/ktor/gradlew | 172 ++++++++++++++ frameworks/Kotlin/ktor/ktor/gradlew.bat | 84 +++++++ frameworks/Kotlin/ktor/ktor/pom.xml | 213 ------------------ .../Kotlin/ktor/ktor/settings.gradle.kts | 2 + .../org/jetbrains/ktor/benchmarks/main.kt | 80 ++++--- 28 files changed, 990 insertions(+), 590 deletions(-) create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/build.gradle.kts create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.jar create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.properties create mode 100755 frameworks/Kotlin/ktor/ktor-r2dbc/gradlew create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/gradlew.bat delete mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/settings.gradle.kts create mode 100644 frameworks/Kotlin/ktor/ktor/build.gradle.kts create mode 100644 frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.jar create mode 100644 frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.properties create mode 100755 frameworks/Kotlin/ktor/ktor/gradlew create mode 100644 frameworks/Kotlin/ktor/ktor/gradlew.bat delete mode 100644 frameworks/Kotlin/ktor/ktor/pom.xml create mode 100644 frameworks/Kotlin/ktor/ktor/settings.gradle.kts diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts index 0622963101a..382ad0c83f9 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts @@ -2,7 +2,7 @@ plugins { application kotlin("jvm") version "2.0.21" kotlin("plugin.serialization") version "2.0.0" - id("com.github.johnrengelman.shadow") version "8.1.0" + id("com.gradleup.shadow") version "8.3.9" } group = "org.jetbrains.ktor" diff --git a/frameworks/Kotlin/ktor/ktor-cio.dockerfile b/frameworks/Kotlin/ktor/ktor-cio.dockerfile index 7443aed952f..aaa05c4659b 100644 --- a/frameworks/Kotlin/ktor/ktor-cio.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-cio.dockerfile @@ -1,12 +1,11 @@ -FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven +FROM gradle:8.13-jdk21 AS build WORKDIR /ktor -COPY ktor/pom.xml pom.xml -COPY ktor/src src -RUN mvn clean package -q +COPY ktor/ ./ +RUN chmod +x gradlew && ./gradlew --no-daemon clean cioBundle FROM amazoncorretto:21-al2023-headless WORKDIR /ktor -COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar +COPY --from=build /ktor/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar EXPOSE 9090 diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts index 1ce1ba7f1fb..5f29b997834 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts @@ -1,15 +1,18 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { application kotlin("jvm") version "2.1.21" kotlin("plugin.serialization") version "2.1.21" - id("com.github.johnrengelman.shadow") version "8.1.0" + id("com.gradleup.shadow") version "8.3.9" } repositories { mavenCentral() } -val ktorVersion = "3.1.3" +val ktorVersion = "3.3.3" val kotlinxSerializationVersion = "1.8.1" val exposedVersion = "0.61.0" @@ -31,3 +34,13 @@ dependencies { } application.mainClass.set("AppKt") + +kotlin { + jvmToolchain(21) +} + +tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } +} diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt index 50ffd37975d..4b4bf93741d 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt @@ -10,7 +10,6 @@ import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.response.* import io.ktor.server.routing.* import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import kotlinx.html.* import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json @@ -22,8 +21,9 @@ import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.sql.statements.BatchUpdateStatement +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.sql.transactions.TransactionManager import java.util.concurrent.ThreadLocalRandom @Serializable @@ -73,12 +73,12 @@ fun main(args: Array) { } fun Application.module(exposedMode: ExposedMode) { - val dbRows = 10000 - val poolSize = 48 + val poolSize = Runtime.getRuntime().availableProcessors() * 2 val pool = HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) - Database.connect(pool) - suspend fun withDatabaseContextAndTransaction(statement: Transaction.() -> T) = - withContext(Dispatchers.IO) { transaction(statement = statement) } + val database = Database.connect(pool) + val databaseDispatcher = Dispatchers.IO.limitedParallelism(poolSize) + suspend fun withDatabaseTransaction(statement: suspend Transaction.() -> T) = + newSuspendedTransaction(context = databaseDispatcher, db = database, statement = statement) install(DefaultHeaders) @@ -93,7 +93,7 @@ fun Application.module(exposedMode: ExposedMode) { Fortune(this[FortuneTable.id].value, this[FortuneTable.message]) fun ThreadLocalRandom.nextIntWithinRows() = - nextInt(dbRows) + 1 + nextInt(DB_ROWS) + 1 fun selectSingleWorld(random: ThreadLocalRandom): World = selectWorldsWithIdQuery(random.nextIntWithinRows()).single().toWorld() @@ -103,7 +103,7 @@ fun Application.module(exposedMode: ExposedMode) { get("/db") { val random = ThreadLocalRandom.current() - val result = withDatabaseContextAndTransaction { + val result = withDatabaseTransaction { when (exposedMode) { Dsl -> selectSingleWorld(random) Dao -> WorldDao[random.nextIntWithinRows()].toWorld() @@ -117,7 +117,7 @@ fun Application.module(exposedMode: ExposedMode) { val queries = call.queries() val random = ThreadLocalRandom.current() - val result = withDatabaseContextAndTransaction { + val result = withDatabaseTransaction { when (exposedMode) { Dsl -> selectWorlds(queries, random) Dao -> //List(queries) { WorldDao[random.nextIntWithinRows()].toWorld() } @@ -129,7 +129,7 @@ fun Application.module(exposedMode: ExposedMode) { } get("/fortunes") { - val result = withDatabaseContextAndTransaction { + val result = withDatabaseTransaction { when (exposedMode) { Dsl -> FortuneTable.select(FortuneTable.id, FortuneTable.message) .asSequence().map { it.toFortune() } @@ -164,23 +164,17 @@ fun Application.module(exposedMode: ExposedMode) { val random = ThreadLocalRandom.current() lateinit var result: List - withDatabaseContextAndTransaction { + withDatabaseTransaction { when (exposedMode) { Dsl -> { result = selectWorlds(queries, random) - result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 } - result - // sort the data to avoid data race because all updates are in one transaction - .sortedBy { it.id } - .forEach { world -> - WorldTable.update({ WorldTable.id eq world.id }) { - it[randomNumber] = world.randomNumber - } - /* - // An alternative approach: commit every change to avoid data race - commit() - */ - } + result.forEach { it.randomNumber = random.nextIntWithinRows() } + val batch = BatchUpdateStatement(WorldTable) + result.sortedBy { it.id }.forEach { world -> + batch.addBatch(EntityID(world.id, WorldTable)) + batch[WorldTable.randomNumber] = world.randomNumber + } + batch.execute(TransactionManager.current()) } Dao -> /*{ @@ -202,6 +196,8 @@ fun Application.module(exposedMode: ExposedMode) { } } +private const val DB_ROWS = 10_000 + fun HikariConfig.configurePostgres(poolSize: Int) { jdbcUrl = "jdbc:postgresql://tfb-database/hello_world?useSSL=false" driverClassName = org.postgresql.Driver::class.java.name @@ -224,3 +220,4 @@ fun HikariConfig.configureCommon(poolSize: Int) { fun ApplicationCall.queries() = request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 + diff --git a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile index 52855ab4a55..c8fd555f50f 100644 --- a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile @@ -1,12 +1,11 @@ -FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven +FROM gradle:8.13-jdk21 AS build WORKDIR /ktor -COPY ktor/pom.xml pom.xml -COPY ktor/src src -RUN mvn clean package -q +COPY ktor/ ./ +RUN chmod +x gradlew && ./gradlew --no-daemon clean jettyBundle FROM amazoncorretto:21-al2023-headless WORKDIR /ktor -COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar +COPY --from=build /ktor/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar EXPOSE 9090 diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts index c98ef463979..baf22d05337 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts @@ -1,8 +1,11 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { application - kotlin("jvm") version "2.0.21" - kotlin("plugin.serialization") version "2.0.0" - id("com.github.johnrengelman.shadow") version "8.1.0" + kotlin("jvm") version "2.1.21" + kotlin("plugin.serialization") version "2.1.21" + id("com.gradleup.shadow") version "8.3.9" } group = "org.jetbrains.ktor" @@ -16,8 +19,8 @@ application { mainClass = "io.ktor.server.netty.EngineMain" } -val ktor_version = "3.1.2" -val vertx_version = "4.5.11" +val ktor_version = "3.3.3" +val vertx_version = "5.0.5" dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") @@ -36,6 +39,16 @@ java { } } +kotlin { + jvmToolchain(21) +} + +tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } +} + tasks.shadowJar { archiveBaseName.set("ktor-pgclient") archiveClassifier.set("") diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties index 81aa1c0448a..2733ed5dc3c 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt index 1afafc28fcd..261e9749611 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt @@ -1,3 +1,5 @@ +import io.ktor.http.ContentType +import io.ktor.http.content.TextContent import io.ktor.server.application.* import io.ktor.server.html.* import io.ktor.server.plugins.defaultheaders.* @@ -8,14 +10,23 @@ import io.vertx.pgclient.PgBuilder import io.vertx.pgclient.PgConnectOptions import io.vertx.sqlclient.PoolOptions import io.vertx.sqlclient.Tuple +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope import kotlinx.html.* import java.util.concurrent.ThreadLocalRandom val rand: ThreadLocalRandom get() = ThreadLocalRandom.current() +private const val HELLO_WORLD = "Hello, World!" +private const val WORLD_ROWS = 10_000 + +private fun nextWorldId(): Int = rand.nextInt(1, WORLD_ROWS + 1) + interface Repository { suspend fun getWorld(): World + suspend fun getWorlds(count: Int): List suspend fun getFortunes(): List suspend fun updateWorlds(worlds: List) } @@ -23,8 +34,8 @@ interface Repository { class PgclientRepository : Repository { companion object { private const val FORTUNES_QUERY = "select id, message from FORTUNE" - private const val SELECT_WORLD_QUERY = "SELECT id, randomnumber from WORLD where id=$1" - private const val UPDATE_WORLD_QUERY = "UPDATE WORLD SET randomnumber=$1 WHERE id=$2" + private const val SELECT_WORLD_QUERY = "SELECT id, randomnumber from WORLD where id=\$1" + private const val UPDATE_WORLD_QUERY = "UPDATE WORLD SET randomnumber=\$1 WHERE id=\$2" } private val connectOptions = @@ -38,35 +49,43 @@ class PgclientRepository : Repository { pipeliningLimit = 100000 } + private val poolSize = Runtime.getRuntime().availableProcessors() * 2 private val poolOptions = PoolOptions() + .setMaxSize(poolSize) + .setMaxWaitQueueSize(poolSize * 2) private val client = PgBuilder.client() .with(poolOptions) .connectingTo(connectOptions) .build() + private val selectWorldStatement = client.preparedQuery(SELECT_WORLD_QUERY) + private val updateWorldStatement = client.preparedQuery(UPDATE_WORLD_QUERY) + private val fortunesStatement = client.preparedQuery(FORTUNES_QUERY) + override suspend fun getFortunes(): List { - val results = client.preparedQuery(FORTUNES_QUERY).execute().coAwait() + val results = fortunesStatement.execute().coAwait() return results.map { Fortune(it.getInteger(0), it.getString(1)) } } - override suspend fun getWorld(): World { - val worldId = rand.nextInt(1, 10001) - val result = - client - .preparedQuery(SELECT_WORLD_QUERY) - .execute(Tuple.of(worldId)) - .coAwait() + override suspend fun getWorld(): World = + getWorlds(1).first() + + override suspend fun getWorlds(count: Int): List = coroutineScope { + List(count) { + async { fetchWorld(nextWorldId()) } + }.awaitAll() + } + + private suspend fun fetchWorld(id: Int): World { + val result = selectWorldStatement.execute(Tuple.of(id)).coAwait() val row = result.first() return World(row.getInteger(0), row.getInteger(1)!!) } override suspend fun updateWorlds(worlds: List) { - // Worlds should be sorted before being batch-updated with to avoid data race and deadlocks. + if (worlds.isEmpty()) return val batch = worlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) } - client - .preparedQuery(UPDATE_WORLD_QUERY) - .executeBatch(batch) - .coAwait() + updateWorldStatement.executeBatch(batch).coAwait() } } @@ -115,11 +134,11 @@ fun Application.main() { install(DefaultHeaders) routing { get("/plaintext") { - call.respondText("Hello, World!") + call.respond(TextContent(HELLO_WORLD, ContentType.Text.Plain)) } get("/json") { - call.respondJson(Message("Hello, World!")) + call.respondJson(Message(HELLO_WORLD)) } get("/db") { @@ -128,7 +147,7 @@ fun Application.main() { get("/query") { val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 - val worlds = List(queries) { db.getWorld() } + val worlds = db.getWorlds(queries) call.respondJson(worlds) } @@ -142,12 +161,12 @@ fun Application.main() { get("/updates") { val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 - val worlds = List(queries) { db.getWorld() } - val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1, 10001)) } - - db.updateWorlds(newWorlds) - - call.respondJson(newWorlds) + val worlds = db.getWorlds(queries).map { world -> + world.randomNumber = nextWorldId() + world + } + db.updateWorlds(worlds) + call.respondJson(worlds) } } } diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile index 0c7fc7c2e15..9aa09916483 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile @@ -1,12 +1,11 @@ -FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven +FROM gradle:8.13-jdk21 AS build WORKDIR /ktor-r2dbc -COPY ktor-r2dbc/pom.xml pom.xml -COPY ktor-r2dbc/src src -RUN mvn clean package -q +COPY ktor-r2dbc/ ./ +RUN chmod +x gradlew && ./gradlew --no-daemon clean nettyBundle FROM amazoncorretto:21-al2023-headless WORKDIR /ktor-r2dbc -COPY --from=maven /ktor-r2dbc/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar +COPY --from=build /ktor-r2dbc/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar EXPOSE 9090 diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/README.md b/frameworks/Kotlin/ktor/ktor-r2dbc/README.md index 5b758d68dbd..0cf954902e5 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/README.md +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/README.md @@ -10,27 +10,25 @@ More information is available at [ktor.io](http://ktor.io). # Requirements -* Maven 3 * JDK 21 +* Gradle (wrapper provided) * Kotlin * ktor * netty * R2DBC -Maven is downloaded automatically via Maven Wrapper script (`mvnw`), add dependencies are specified in `pom.xml` so will be downloaded automatically from maven central and jcenter repositories. - # Deployment -Run maven to build a bundle +Use the Gradle wrapper to build the executable bundle: ```bash -./mvnw package +./gradlew nettyBundle ``` -Once bundle build complete and mysql server is running you can launch the application +Once the bundle build completes and Postgres is running you can launch the application ```bash -java -jar target/tech-empower-framework-benchmark-1.0-SNAPSHOT.jar +java -jar build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar ``` Please note that the server holds tty so you may need nohup. See `setup.sh` for details. diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-r2dbc/build.gradle.kts new file mode 100644 index 00000000000..1a9fe97655b --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/build.gradle.kts @@ -0,0 +1,99 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "2.1.21" + kotlin("plugin.serialization") version "2.1.21" + id("com.gradleup.shadow") version "8.3.9" +} + +group = "org.jetbrains.ktor" +version = "1.0-SNAPSHOT" + +val ktorVersion = "3.3.3" +val serializationVersion = "1.8.1" +val kotlinxHtmlVersion = "0.12.0" +val coroutinesVersion = "1.10.1" +val logbackVersion = "1.5.13" +val reactorVersion = "3.8.0" +val r2dbcPstgrsVersion = "1.1.1.RELEASE" +val r2dbcPoolVersion = "1.0.2.RELEASE" +val postgresqlVersion = "42.7.5" + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("reflect")) + + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-io:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:$kotlinxHtmlVersion") + + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$coroutinesVersion") + + implementation("io.ktor:ktor-server-default-headers-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-html-builder-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-netty-jvm:$ktorVersion") + + implementation("org.postgresql:r2dbc-postgresql:$r2dbcPstgrsVersion") + implementation("io.r2dbc:r2dbc-pool:$r2dbcPoolVersion") + implementation("io.projectreactor:reactor-core:$reactorVersion") + + implementation("ch.qos.logback:logback-classic:$logbackVersion") +} + +sourceSets { + main { + java.srcDirs("src/main/kotlin") + } +} + +kotlin { + jvmToolchain(21) +} + +tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } +} + +tasks.named("shadowJar") { + enabled = false +} + +fun registerBundle( + name: String, + classifier: String, + mainClass: String +) = tasks.register(name, ShadowJar::class) { + archiveBaseName.set("tech-empower-framework-benchmark") + archiveVersion.set(project.version.toString()) + archiveClassifier.set(classifier) + manifest { + attributes["Main-Class"] = mainClass + } + from(sourceSets.main.get().output) + configurations = listOf(project.configurations.runtimeClasspath.get()) +} + +val nettyBundle by registerBundle( + name = "nettyBundle", + classifier = "netty-bundle", + mainClass = "io.ktor.server.netty.EngineMain" +) + +tasks.register("bundleAll") { + description = "Builds the runnable Netty uber-jar." + dependsOn(nettyBundle) +} + +tasks.named("build") { + dependsOn(nettyBundle) +} + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..28861d273a5d270fd8f65dd74570c17c9c507736 GIT binary patch literal 56172 zcmagFV{~WVwk?_pE4FRhwr$(CRk3Z`c2coz+fFL^#m=jD_df5v|GoR1_hGCxKaAPt z?5)i;2YO!$(jcHHKtMl#0s#RD{xu*V;Q#dm0)qVemK9YIq?MEtqXz*}_=lrH_H#1- zUkBB{_ILXK>nJNICn+YXtU@O%b}u_MDI-lwHxDaKOEoh!+oZ&>#JqQWH$^)pIW0R) zElKkO>LS!6^{7~jvK^hY^r+ZqY@j9c3={bA&gsYhw&342{-2$J{vF#png1V~`v3Ys z|J%ph$+Elc9rysnh>4g@{9znhgvHh#m?Ei1t5E5wf>;ad!DTU)Ipl zPT9rK$;H%(&e+D#**Qi{+kH_C;R|h2%}C_u2qcGqkpzJo9a~9qYH;ZOJi2lcQ=i<|gKQUuNz* zeRzLwpgkbJpG3jTf>&Z%BiYff1YVA8;m#hM;b101PJBP{=|CI8ql`RDKr{(EmI6pI z(@dkm8Zhf7+L4B=+o^=N!x>UdkGSH||FmmB8Bw|!kp6^SHPN~GMb}zF;MN~+$OIZ| z5o#vS_+kVQ1*bGU;T$|^HoJY5vdqvvT{g`jDQM16eiU6^81j~-Sf|#?Ak1Z}F>17^ z@XR5%*Sff%YD*lIU8LK5U@Ef`8&RXp(oTZ;YFuN28BSeTUBb3fQjalWGS<#i%yuEo z%*bAG;X6Mn(h`lVZ;4?Po`dByPNhhz9T|klseNj;QhefEtbe8DE~z?p+EBUA4n}+q z?!P_?3317h!l6@Ki48ZD*0m8Q5rY22X;Yu#5!TNM7>4GWU6)iBPwkEw+SYpp!^4Z|TuvFg&b|^G}2S>#jW(>8J zCrA^lSf!{Jkgx$m-HLZq?x)>SyA9QN+LOh!r}V(Sq3}SzL1eRP4%S``)&t4mIPQwl zLFtNv|M`moj?nr*y+5pdaPCvX$L$qsInqP*7Ll)1%3G$`rD+Q68;Y+#Kg}tI=r{H6 zR+@!(m45RVoqqI}M4(R37;n!Qaxpq&>eT2u6rULTa(O&)y>g6JwS&uH6OIffYA-&k zbT^f<*apufy?sS=?WKE6USAu+O3Yl2Iz`Op`J@r}P zd&tvT=l5(Y#~?E4tt=Y7V)AUH!;)I`nK}&}(!MMwRB4X8ok3Vb-3p1GscV(2f(3MM zsdl-XrAoeT+*)zxid^c5*k=-(tF|c)!uNGR@n7IdLso+@Q$dsR^~Vfw}lyqR2vwH zLXxT2WM7EC6wo#8XWm*1xs``gBLqnLB#ZOZg+5DF zJs|x1lpE>&e4hWgfg1bbx&3!o0ISHigBA7JdC3x}q#`h{T>bOn7efEeX)!W^CwnZi z0sn7_tN}*s@a+{c8G$#Uo0&fThn9MLX0rZ}R>8@C(5B~p* zIcj)i!$p5D-sQhW{GTsi5qoz#8+$_&62^aByS~w~Py-AIA-fi=TGVdzfzYeq-GTgj zLOLFSYoTjMiHR!S?C5xX!V#1QE1px{Jn64`H>1dXSdbvb;gEp!9UZdgkknwn3Y(aA z0=={&dhqy+$;R72c~Ny8n>hxe*$QQC_E^hN46-UI?)N9H8Yn_y5aWVv^R1qj(8fYL zniycQBw157{VSmO{@2+a_clQ=S^+wf5dRB<4US#8?fD+aKQXR4ne@Q_jlcqbV;sx> z4@Lzidk;@RR~HLYI~Pl1Ll^sh$C?ynU3(-!6kd?zVN**-)%q1FTWj6Q#-%z71~O1% zBO#e2E9Av8N*RM`w=kHXWPOu^q@Fb~WdC3M6CM!dNK#tcVIA&&IG<-aoX!2e-kw1E ze0f?E#QH;n0z*^3xpwV*C3X|SGCV_>&h5yQ+47YA@dkD3Ue9-Kql)wfI~mQ0ix zXqJK`y8hr^K|hAxgrPWIHuewd)&e)-Lm>agb%ESeyK_*uK5q?oncLH%0zXwnfmDU| zY@-fWu9aTC(~e{p-hW2DaS6WDAM-=L-NX6cvoU2uNM%5vDRz&%Jtv# zBWdQ(QfY8V`vFt6lVNVJDs$K{$RxavLlo3a>|IHy2VVL)1*yWMgk!=W&pMMZ%&@!i zTlpeAb=NJV(P35)l5hJ^e~)C9z!X{=PWCx~bH5-&9H!*EQzmo^Usbv9E(4d@BrJk3 zPU~wXziRl0@Wzy=q|wEX!BF+Qd<#^O8YzHF`2IM|0e`7knK6mbq*hi{rBb#CN!Nj1 z3?ctvcy}h|%>t&aQOFk-#7PvfS*b*vS%4d#rk7y)CXdh+G$*5pr7T=5{u^=VTk3>X7M` zL~O(nt?0Jk%faSj!f$Z8B-e52qHyVY#}t~zirs%6uuI4jn-(}Apg3G0Aj1Fofc@(e z%F%>0Kw0(t^0RDV)`|(%aHPf1fLRkN>&LKh#2}#yAPGhj1RZ%Ih$#+PuI1s5iqGL7 zOJ)Z0q&=e7iXY_t@JW{#puq88V;! z=4JQ&=H^r0=eU!;3)CP<2gcxM9r#=fy?W#GW#wz6m7g$cZ-tuwrHiz8i3a zz8kRH_m?1`F9iSM%sQ$}ezoa5PzQ*wrM^`dAKqVFADTddAD%$|0lg}dy9(3#884SW zU*Nkc)4P=?H^496AHqQ2;r>d~mnkNXvt&J}eZ717upe0w{_qC0Uq!$d^0WpA{2(v% zAMU6KyKJcP~wjp z2a>gyDyU&KO~V>dTS(AywkV!f{z!-!mR8fMpP7`gctumD>YKEabe=@~N@hy_Ag0aG%S4xk_CnVKy3!Td`FSuZm}}V-}XEPmwc-$WBtOAQYc#Djg>c zi1=`DB|B!WDCW%Q>(oV-5ohsuHf`g~TNuL{ZNRE7nNLS>>sos2m?udyEw<5PI5UF` z;bAG~F_edkVR8t`&qWV4^;n0!F@d~i;kgd260)qFdAJXA4@a&sLZmwyG|Su^wPmT! z+dIXxZPFJ2Wy*ttR7MkWt;)F`R@JkLjq1woT9cPf2gExRz8O&su_988hI9BNsOQdR zZtat!y2);uh}vXgTbL?^O26(zCXi{ytDHHGW6F52wi`y!HhHegG=+19d6 z1O@ber1z+=Tt~x`hZC1w7dM&S@4V#8g=}6(2WwOe)#5sKO_8;20>qG6F7AN2Rxx7} zw5`oz9#V@UoSVhW&d>%&_7~0DB|G$|w_Vq^tvega3$=6vQsT;S_E&&~dfgbgrJ>y{ z(ytbvUEsfK&}d8o;Y*ELPajTW9IY+$P^@cX&{yNlWAC>jf~7+OMMuxaP-!aZJ%t3O zah(r@p^B@Rf@nnOvNb1WUy;XQ2GqzBLy|hT1;Kp?5+yohiV0pMuCCOlT7D7?KZyVQVMrY?0B1Zkdl$cI?JO(0D4?4E!Q3 zGo4E$MsD-AWHR1q9{`y;50@rz<2&kGelU zx;$OMKa*ps?SqKNJ%zH$1V=d%WpkXi8*j zYBAL|`$*_WCk_NxsCsLUv8^oBI!3HpNlMMkcQgMIPR>i&OqCgXwK+nu(@)z~O!|>s z6cH_>sTNXiJXTB!KS|8u{5|hG4O8DX$sKv-qONJQk%(zU7zeglNW zY4Tjn6m`*y)qH1!DbZ?}Lw|RREGz$Bsx2rL{nFLSw=zUcuZZW0j8eXsK~JAuPO%pK z9Cu@_riF^IQOt5mVRb${;38s{hFhLDIh}%4(TIDZ${v?iQa8%{V8w7$uSk?%|9I~) zI+JCMPCCX7$>J8XWiPbB#&?OdD%;M~8s;jo{P>Y8kWA;!3wS*!Ni;#kSNy#)O|=Y% zr^2Kz)2pVVg)wZeIY zqG*Q8;8mulHrYXx0Xa(=jkeZe&xG>&;mS9^&@l!@-cc@Cr_>cEr@8z-r86GZWX~?v zHAYOHbau(*4W;2|5~+;#g=Hbk3g3B!{%;z}k^-+>wkdpK&!gF{olEYM`;^F@4D?8U zj{Vs69U4?AjmlssO{(gCgx`b?d!tU-{hCk4Kobljj$H=X0t&o1Yw(qAL0?|$^!f-N z;1b*c_cr957vf+(A8KqYQp)!zN1VP>gPHZwwismV`~!Nzp$PV)+z)m4RIJ4Fyu+0; z&nQh!(+Bf3QSQ#7pTG{PgD4YNSak(m1+Q2>u!Os;Dl9CzL3z+4FuSS@Yqg|pt~~a< zRu0%``)b% z>NDlbS|dj;%VmuXv%bLtLD&`81xBJu>)XkX>IxW-vIdkgeKfNW@4$o!iDQll z^|7cosL)mp@6EC*#M*2iRqSdix3q98e`Z)#QF#+k<3b^MO0=e`8_8SxuT*p_+NICo1QQ zi2_MWRpE~V=g$;2dp($7!OF|<%i9rtXAPsW8-P(Qo?q}mhMl%-<_l`Eg_f$rw&HEx zJ3e)p>keJDY+MDO-2~d6^ z`%{Jj^1^ny(O8H1cLI6J!XW0?pVCG zsD%3EfmPce$1(kbmJf;fr>Hm`6E%n}k7w02gn7wC_V?QY-vYPkfpv%U$`VPCtE0V$ zMsHw#%xYHowgNS>;IB-fp46z;#9B{`4MZ{(%rd3WGG$RRq^1q;7D1-PFD!h6$XXR& z^i8LSQ%pL;&JX*TTAa-834Y%+$XlaHt%uH6ltVq)ZBM4QnrJvj-msPvOCnBn*c3YfL{>pa6>K4fUcGs>tM%=$yc2s%ZRAQKffD{L*k@X5%mID8Br-NR|yZ z^sr9O?A3PwX#GH6&}o5u`cNgE6Y1fcly=6nEE?o!Fo0(4NH;RDh9mFEdN)u1=b(Zr z*MV*(v*GX03h^4G=@HP12Az7nRx-l^7a}Cu!)(zSQ_V)SZ$QOQAOFNl=~X<~1r7uh0RsfY{GaiPdKlZdI$OG#idov23K|>#g)D1m zXK4Okh*Q)yow3z1zi~AeHtx9GwuWjlH@PIW$0KT*!IVsp5855$jkzt4(tkrrt}aA$ z1FY1m)f}g46eJ+qfJ;Kyl3V8%_!x35&C3(_0&YQ>c?NIMZ`aWE(gS`xyStH&wgp#+ z^Lfv>_q;#9_iXom+_?J#-TvH>+at`j><{9oN~O2pNE1LgW#!2cz%gIySLr-ALs@Dn zr%<9rUt%gs)r3`JrmMWx0miLIR#9EpV;Ph+s507(bOP27F0-S8d?{x;Ok7~!jh?L0 z=u1O-Vd_cjQwOwQEa|@|4Ayvn>#yFz!p>T~lnRWVMHC#KhB+6B&z{P|!=L7&oZ)m^ z=rJ+3o==(F^_X)qe*)VI*D3>KNAp;&D^V-}HHj`&UmBtUN1$vex|=hcJr8sltwbXb zG^2O$kV8rxI$lZyTt{e>YkXFmPF-4=sXM`(w$i4vwCPX9=b9HfzE0s`t3#zjW+VsY_9GXVq)nGi<}J2AjxSXrh0 zdPd+SN@XrNEch*rSP#?vmWvV^0wS*7tZ?2m9$|PTolDr67xD;nMrk(H@~xyw zG-swsoej0%*6l?36kCeznagzBY(dcpnSSo13LR27%!2b=QGh4ASLqe#J?pxQS>`3K z&WBZTJsI}K>RqAFsf(2za=+B}bz5@-B$gYa78U`#KKi5Zw>*F)bMzCJ4+X@xTVh=P z5oj*I!c=qsu%M&%Xhmhwh8yP%FhuB9r7jE3Dmzpzi?3y}Y>If%8c?QV|04_-{~_=v zlS>y0)>}oa@)-1%JNX!-NS7xr|KMbGN36Po>?o+5^~>K806JhL!XX&r518=q9oFV{ zK5~erCd-NJqz|t?GZ7tP~sDxibBI%`Ns*Sm7t$xClx*mr3 zf!;%G`z-Shp?e}HN)W;Z;N=oYwe()7kMy4Eo6c`RPs?oI!|@CsICGA0Yq}@hZ9C=X2gr*_bGE!Y*+r zn*dL1_}NkqmQhr=yl&Wtturib4kR6GvtAhA&g7;I3uaBhH5Q)QtZZGrD(_}pfj1(q zvg`WHGzyWsx$sl2HW4=RI*0K3!o9XgZ8`*Nf~{oh2WC*@N=f$%6&#(>rHZ}zs_Rx( z45=~eR$2`CAu9>UNJ%g0A-jV=(?|$aX6;sAt9$BKxynN=OLq=iN(7dh%bz2^T`Kmc z-66UF8zRX-M2ced068v?O#vo=UaPBd?uxdiFIbUZ)ay3{AIkNVVdq+PE=6Rx1jMQD zg(RG6-KhpO0#qj?2w3o7^(3d-kjZ@15k-?1>dKX-+NtNtDJjm;+$W2<37UNoes4dJ zRkGF)0WIEe7)Pi-QJB9W==X>tjiHK&gOCM>BzUhyr4Yzk~-s;oPR8WsOSf( zutzq2lQ?B9y)>Ni9R{VR#rLowY~G>$C{k;_s4yKzY_JIIC~LGBYxIxr{scbh!55@X zvCVjR7#AG!3*UPn5ak#E==W=E)$<&2Kkl3l$hLNU=ffYT`yr6Ga{^4SF=cq3f*lXn zS7#rwK)es+4KF*Rx<2mk*dBSO`K#H1|dBkmacZrwxiLvltmeTkAoCxdn)mhKkKn z<&~zt;pzAphM3(kVrX_GBPTo8>zDT+?XVBJ{(zY9d~uQ%{rL+id*gjeNFR zrM;{Ud~%!Wd1Z?@*KK=HE2P>zE$a=Y8zAB5voC*k-VooANQlM?y|%xSmGL4WPlpAj&U?!FAepU9kjPYnQF&KZkX2s z287*zcr?>At$h@sqfi|H#}Zgwb}>M80thg?i{%!9`--x;#=R}vU8=lfYm=+w<2O2^ zarWPIj#%e6Ob_4Xmc?7e`5VLL=hTfh5}Df=?WCe zAj27m$YbO4!ASs8+S2OWe7fo{*eyUIuY#-Je9KvUl1kAdh-Ny-I3@`(Y)B!p8KxL% z>~cI>7fec0L4JY-JGA+gFF%kDo*~wYW0a~BWqt;n@PUa^lXR6WwEUYQyYQXcgb}Ng zO^bgRV6Zj%{lBSS$o5CkUjOP&x-fu%sQz~c%8sqL zFccY2Kz$?^PvL=Lc9MPE__49mYdd=0?LiV%*Gux2zgGVt6<^S7r3Y}HGQiVEa2Opx z3Z}1ii;9|ctBR^WxZ3>^TKrmyzN>U=`}&6K`BKdDQET#0jJ}%`-E%VxkMg0g;gqK1 zcQkx`_i9YpQ)FagJ$TK|yFS}vXxDv%%E z)nuLD&Aqgoajcvpw%%0NX-xpFn+-urM74<&AzEDnO!^2L1e^=!oW5WdM#Nae&gr%m z4u2L_6socSb2%@_i#upN1)zSU$ch=*ehxcVjESqygr5mT6g_RKaf-6`mRD*Q z3&5`KX~7b=YYxh`D-J4djitIaSS{YNf8^v+KhO=1?&5?sb4pH~D4NBF`tRjIeUS zEd%JlqWw`3$sj}7N7Xnx=&@VxDpFJ{nKUf(WI|(oG-QK1Jt_`GKViXO z6Wc_FG>(qIO7p1Hp#r_oiLWy{l-Af9dtn&0H4Y)8%JA$s7j(v*NIl=7TvwwsY9%`f z@5sDmEG*2djKJC&(Q}3!#MP%%NRTEviFi${P31KuLk}QAvlyU9qcTb$LyIDf)ToRw zCCU#!&eR~JD_EpcXn%Ni>A8{}sUAyD;7zuwHo>$uN?BTU4mPtgYAHuv+b9?{Dn-R$ zJBwu`6C%J_MvidwVsjXZhFG`&_vi+V9hzxbn<8PZXHhuA)O$ zpTM(FLypkoEl3vyRhaO zsZkdJYeYP$s8bs*o4FRfi84=hd1%J9-!(0w)Mo0$fV&mV^~%d6KOQjO?zxb`Ua6^c zGVa@8%&4ZIf1;$Nxyz6g)jcJX<<)Wd;`js2Hv{_+7`KLgy30sKzIjwU(O7Kice<5k zkJAYU5~k#c)s3#{0X|3xRMW0r2PX%t?YF`NW3eXr9#b%NFGg0GLf2L04PLht=HVC&%mEUFNV=>S=>zXzU|Jzq8E`An|M}^As_* z!TWw^BrJTaFV4Yvo^r4)a7DHK=(j`)b%oi8HK;2p2^sJ z`Jpl7`j-5GmVFc59i1(-j>*j(z+JpcBA?sAg8a*b5aittNuUquqCkT7n z)66H1d5^Z-oi}ZPs?_`1(oZ-q&%NiaWWSv9-S04Dk$!hH1YKP*$PB~7(Ugu+9b*1n zTPLLp|B6rWT!IRPGnBAf#)Gmx|cuiDHYAl$H5 z8gY!lA)*EjVMo+pUbYC$f>O!k2M54|T!D)PuxSlmFFBZL@2>LO&n{uop1Uu?IQeV& z0wOS5EFH>zRirL|s3u9yvX&)%D$CP1-WbXktw}P)?aCKap~+GO;bc$BDfxnx*(9(U zz1}uYB)<;LHLV^qq$n-b-VKhBVd1YkN}Bx(ZLSDY$Q4#%3oJlNDxsIYKEKp8AF`j2>PeKg<)Q zF*$LD9ES=N)VReL6g?%TVj-spB=UKLS6J!<8_nn z-CGGde>*o;4Lm`Q9hA~UJ+bK3)Hpy{zgR!DyaZC}a0N_4tv?>sS4}q_ws~i6qv(=9 z?r6reP*zJD`a)qVt+ik3sf3o+Tb5e_XU!^#Rn^gk&^{XkfWFn<@&wihlg4}|wL1aN za;B-3`U0!xw3tp8*wdAz!L5T8Ib4(5#LxX$GQd|h=TADbQoH$~JqYA@dg~6IJE{vC z^z761D?2rx6V{v1KZW94{kE`7p>}Tt$aoswaulH<96(DtK>!PIEuQPB0ywH{Ot^7k z*%|BE!?P+*^}ik9djK{TVG)RL2vt?Orq@>1+2?T(2(Xfb_`}C*|a{T_`0+bX4EIV6S{U=iHO>!Q82p}MKg#R9?owJLf zjm>|FBy-eX-LchCzj9d@DDK)Fx5z|g7qBkK8kMv)GlMyxC9jh+C*-U~86`nnXk?2c zMwyLRCX`YelT%v|S`QlQ3@KS?8xC0JfJ1;w1fWgB^k30AAhhk<8Rg`8v(B_(MjOGz3?9gWt410&f-5kjg8F@#~jH~~lMl#z!{ zJcR0UQchBd-hZin7|$-&(6;?+#Vu;}9YXaT%;C^lCR>RfPxQo*aZb%9B_{D8-UpX(4@R} zX5_l{MAcUSh@$EvS@73t>!v2n*9@BNvn?`#)=J?o#$8e_N{+v}1*nZDu}1CuI)~EH z&FMH18E3}zo@%iQvl*0*iGjJBV;WC&yecxQJ-SGg&*#2w?@*apZc0ty+P?@1{HqxW zYUs^PIX#TA61#sJnbsDQRtClmV3KZgu25uJR9YE1)LS4g-t$aivKePdS9yjy zD)K=I2zVpkRyn8yJqldCR(~j?7WP5AfPt)%cYZs4H=SLz+>}2#MbeJ36SNi*1Jjq9 z^$hc2z;T>ztfh<0*kN}k3A0FHT+2qvog9`OVc85@td(OgyPj5j_HNIxu&f-P6&!26 z$WxBc7KfdND7vS4l~OKAUF(J`mb~7`Peu;4((&AeqtUo0sgt76c4?70N!Y8Of8b3O zV2Y}*2vALhk*#}GQ~|Jh>BA=H)%zlkMn|)ljF)FLxz-&io#%$YxSAn+WF%fz5hc-F&V8>Z{ z;Os6t$R%QSsEv4{Heu22K?XS33%c{dq8~p!-}+kBlx7WZmkg1s@|5gDycC4u?^~ks zuiPT@6z%`53q$h`HO&MD>2Gls^Y_z~X6hIOvtck&_azC3h(Rvf%P9V=dg%QnCH;bS znLM%dhHhB?R*eMy$UI0ApK{|9ZX2u-L^|&h)bDj3%va@ zAZ@HSPBPib!Ey+b<8do#%{|^-&!vAUrQ93(PFPeYbg0poZdSkKiX`Q>8B_oZ;YEAN z)sr|F7i!Mh+T_-lIp#;g@9MOshik%I=}2)u%b?&^9bvw^($DstWkf3;(Kh5hi@Zg? z`y;cT7_~G;)OYNZP4uvzWZEo6ysnD7A5LSAOPygmuh_+}u*n-QZS`xPXafP98;OzdFY+CzchX7HVFyX*@&uQxbO3ViMRTC z#=085j<@IEkv}SYP{1&x)a~*>oEIK zUDW8VjgGaf-V2P6>K|EdYCo}YXgoA5pTMLj$jPQ|(%|c|!b*y|&{SMpEE`H;s>MxP zFb70JS&L`G@S5s~molk=XH^xyv^)K%5)P*hXuce+GMhdK-nV)C1YIn z;gzyCNVI`&so+GMGDQ49T3=d7ftMk=`jYX@qndz2cUa2QB;@;Xda^MgCY{gb2=4wI zf-OQ$$yBcZb)$hUBb;(ReUGw&dzpZyXlNfph*!ITcyNLx#yf`!KT9Oqa5;Lo--J-8 zA05v46|C$dv!-$WEg*}KwHZFmg6J7+F@+T2X#`+NctL3Jh?VdO)$qy1c*U0Q3I5T5 z47#&{5NR>PI0{{&7w#GeyUs^_a31_5V zQ0%(&JLK$x+dYgSnt^mH#COP3V$3{#=t2BAqSKpW!-JNO$OLQRkKS+K ze}?aS(?=V+zkk%3Py+!G{5Ofpzry#w`+J%Y1}ew6-`~!My0H*K1bvM1CMHO1NGPy` z5-gx3Fd(Wvl6r|j*nmH{Bvw@|8r8Zhs`FeI1A?k5NDRO$0oa>XX)RjjHJvTBk)^%g z&wuFBju7JGZ{By%AjJ5v7Q!T_i>4;PjuMff_=PMPa3;ZRoEtvPb-4A99!PxE^2De z>Hd8&zdprl&j`B5creENM?Sv&0d&c0!AMqjbF8|wbAruB!U($chcUgViG8|15riL= z&ezl=|EcuRJrd@p5Q7wlY z1m({w;aad{uNV!?|)Vv6kh#BEj7mKSIcktLK99BSY z7Ws5^yVQk(r9aqS>Mc{MHPj+#JI=MOGGi>6&6kISWr6|+-U6FNW9Ua+RBtRxF~gGY zUiiv>X(CTS1J9!>OIK zX=iZ!+Lf|sR1BDf>L(T3+%z`x<-w}okU|?oGYp3YmNlD7Oo}Od*g}b&aFE^t)>-^% zm_i8duG`h1D8p+#?c<@Xi`{Im0j|szzk$L4dn3H;<0^%sYmE7LiH=P>F@r#lu*uq^ zbf|CT0#V2TOjcbx-aIh?OFeCo-$1LIKS_j$v5~ANbVeP-_ryxG4TP57@E82>N>vjf z0@y6bHL?bLstQ;#L+H~(RBLLn{fqZCZ!LMN=a`uK{tI~4M{rsyd)DKnap7Qwr!OQQ ziLiqKt%)^sBiltyJE96&0&dh$(PL@jyPuhLl%{49D|41CSDPF$7B0NG z)}pq{Og`p_keWf4SR9DHY(Axp2B3Uh9kILr2@yty*h~wxrk-Egq+=;M6u2RMji;-Y zy*VY2HI<2cYSYYwjfOb}oZDxlI#gmyYQ0*hn*j+HGqr?`Bj~65uSKP>xg4_9lKF7Z zgI9pST<8$3OwhYsJZe*zG>zoz`BpMzIdY0&e)Nbo!S@5L9=91yWH3-!@24UjWJojv zj?!p^1j~MCrQTX$WgtQ#?;Xz&Zg>q;aKaLU+tKk~(keltg|NO6dn%u@pFLC1ZLNIx zfNK30h>zz*R=?F!@Ho6)5~EcgB8yktI4XP|?k|=RGnXcp>-MR7R9k6E2}pc#X@o^8 z6VX7N=A=l%17%49>4g(gIjHhqDA0oozf^+{37JvPa3g8VgDBUHVrIm8uA&RLVAN98k^LMo_?!DUJ( ziQ%*~Ym|#KsHU6kRFuI~PfW5zQW$+pt%^zVErHM4i6N5pgh>r$`B|!kL-R?hF@dXI zBn)c)@bM_a<#}O*#j$*twaDF!FiF=>@fx|7amynuT@jzC!L62;+jIZQU1Qg5J%6CN zUOg9nlPKeDRxk5k*yQ4siaUSs{Vh;-f98|3Q6XG5?L&)zuh>r&R=apE^j09ppD&B0 zUw04tVVz@tl*Q7c$!9nJs$=)3yGwq)vj=yc_v~jkx-0M(yNTKh4kDQfJFlnPB%JeX(Mwb;{eN4*C>7(|epF zQ-+@$4*CZ}LFA*rUOZq1{+^giSA6cK=p%jRodDHN4NNm%Z`jzscs?&8R15^lio;9D zL#Q2%Ez?nc%;KIM8(YRd$1?OY711i8_|GmzeI~j5&#E^*tUK-L(2$V_`3a3~`MWj| zVh)RzSHg3)ep78N$AJYh@|FHpeJcZh0`Ps25OIo9!Pu7=3JGZu=CyF4G>$*^(PBb= zgZ83_j0tJF=CWubALpzU_$BHU{z5iF9GGaIN*oi3yg7*;zJ;JPs*%7L{uz~rZ!~8g z?HY&3T>RtmmLJVCv*8DM$Da~A+lEavSgac)ZWkXo-4*vYFV9@xf?~76<`1D7jcs%Y zavu5Vv(OSN5Y&NQ>AH={?#t|9L=-AGP3AL8uW>#}0!J*W)g1nvh8R&bT zH%D&uvKI89Lyt^-@Ne;@{>WIz9nqd@^F|*%5NYcgD_yyw_v>9rcPH4qt)QyQSKzWa zXGjaSCA4d#n066SS_@)@G9L7prX&Y(Fb3n*vAXF&1bz199}wuk!4gKzeAF<*D)1cw>w^1 zHfE;CLenK==$MF~q&#ouc|B5caj0jsdRI#%!qFmB{cO=_H~EdNs->Ww$Je*=kYXct z=gf>q6j#*Hw|-DQCyKwLoavNhPS`r?B`8^#RMp{2+=km$O@{_KLaVG(U~XkA%=_cU zg+R2Vmxcz6bsPPlAG4G&_AjG7(V4Q2r2y4}8cmO?+;luIZllOse)Q})eU2VZE0O9+ z&~NeUPb}wyHFhnJ+Wn!)pA2laaPXE*!#>?xH5mq94De zNV6-~Gk#51O00YwqUsaD%Y-8nxSsd>Lk2dB7KqqCO@mKD;Esh{hA zcF{hDS{LC;K4(XBu_Y6mpCk?hH7gW(8AUCXPdrxcj>=+MPeNrCWW+3POU+e6XAnck zq}z7ZE?JWccpuax6Ivssy+Q1Mt@@SY;Jfx^>R`N>ENg*aQWdI!P1Bc&M8(-oteySH z(z?ip#5o~uBF`n_sO@ni|3W!duY`Fbp{?oIiB^NZdgu_! zdm5;4{b&CcS4`10{&&zbCfYesRjwse3tXi8RKOW*Z@;BvJnk7+=ItyJ&lk4n5@t5g zf{0s_O0-3$Bg$J<5_Xgft(f3)I(C#+y!1EhH#}C6afR!|P(K4BUi>Dk@vh^*7b}o2 zK{8na7QB1Ot%bOH#{)k8Ic-Uya~O}S0-DN3PEdQm*{LwgMgES%F{n7m06hquC@V7g zFMFzJSy8sO)I0~%2q;cdx@v+aVsI$R~$+uy0 zo~?0Qj!0VAhOaK=5cFZ#Z`W#JvUpUurav!4ZVJI?t6ydw<+dc^Kcoii@ibJIDEA9! z^2TKBjR6c6?vxWI_l6*o3VykDD95E`PmFvyRoy){C3$IFQI-32*f|*PFb( zI4dlWZSY+>W1H{$LlkD8s+)swf;c48ksP(;cZ0Y>&u^d-u}kNT%a;j``KF|>0YYpx zJIt2kC(oHEnXV9VC(;Td5@@qIH|`1-?1E;Ot7}DjIGl&I7K*CS1wC`-3f0GhsCCgd z6yrx=SFj-@?+&WK+|pV*UNyajvsN(e7ISVEb54qL!;a7+RPgcyB0pz2h&k68rm$Q_ zYGk4ao~~s909D&6XIK|U#XiPcmrk;Fxz22(?);;y){wM`6yjZ{6YS{hYuwWOP;Y`M zKan3i&OK{uPr9s8yYz)u5DLScA*GkI&9{JuJk#1two-z(juDO$bDF^mr01xwvKoSt z713CtFJ4|7%CcReZSeM+6XKbC?IVOKm6#gZMZtAo{#P1m07le?TuVlAZ((uu$d6)b z1y~#Ftn_pP)f1ZPGQdk_k9OIKK?X4f_iRg&xt-#Vajv32Z~=~}cR?y)MA?r>vaumG zna~c}LYg#R4?v&la$krYcX}qcZ*_Szo%9p7TLTF+lw~Ehg|)43!>=3L)bw^3L7B2T zC6DSL{6B;lV|D*XH*8@I$`qzIgcKLhRxzxzjvl4&jfB{&Nxg6DEi|h9np{(G`4w-l z>vEC5Q*Sv>fw{V!l5bxXqYUyZptmBg$%YECv;^b~FIq7`nzBHgK<|KJ?@F{Z{(gEV z*PSbKAI7YQH1CX(*%`)(+F%p~=N=^Eke#+j(|ccd40@7ucshi_Y`u-$E0Q>WItP4n zmZp?HXv4y)6TiIykBAia=H*-Tpab#2y#kJgZaQmCkb>6Oe3q+ml{aU~Jdg9f=s5SD z5{qj`ZgCLJsbwqD^k?P93XcA?P`oKiO`CRu(tU~=UyaGmozWwGR3R)AR$oq%^ywa|$+u^DRgc z-m>38Y{%I$vcsgk0<5q*g#3deWslIFQQxp}TClu7MEv_#(XDUuS+0Dkn=T4Eshbcb z0=%SucrYBkc#rha4(%L)87Qi3Ja&o}q_KO67x-J=(oBQm1hp^>PapjZ-?zD49>(dY z-UC0yy)`HK$+;uTXC*d)&1-em;cCu{tscS+I8)03u(o8b;H{{vXBG_kV!1s+_q|Y6 zdgP!CDB+3(B4mA;(j8F^F-0V9|B4A)zl$LF9YDE=8I_}7+HT9z8rmQ0Sr8Rp63d{( zq0Q!n6I~yanYa_rjlaUd-3ML=u;!F@3-E+Z^v4O$`5wg&r++Frrq6;1uYr=Zb0~&aPs#m)F1uZ``_}lOmI>OW;IKdlafa&lC8A{8u zG!dpnYh#k!@JtL4l2ba=G8G=Vi>NEy`o#8^c4tT^jEnd+GKBXTS|BIihO|+$N+EDi z2dc?+N}Ed8N8v~0^C~_X>aTjBivLPCT@KLQW??UojUkDE{o3>19xADXbWcK9Kbdac z+i3Uaw8NLPpWfv6n03!62!(0LS%%*o4MHvr3U-bFVn@F~j_kU;psZf?g}k6zeGzK~ zgycSu;su1>ZW2(gS%ysbvLrqvngLsLTF>e4aPo*^_AkK#kP<^QYNB~Dk@)6KL=lGg_ z%;Z)s=ahC$zw0FS^72)Q!5x)8h{0|RwqHs-aAO@TVv)@9 zRGLb3$5vgX@R};XyT!1_Np@|oYWhHYHR>|B*k?rG}bJ|1+)k@O|#ENBSR!w5|4&* z21a2aA}S*b=x?|1u@&$%uoOI*0}Qf?73xxq`1q2TxL8kvpuuCeliv6OCp21!;kp;z z-N`X$7$ZIq{~c?*?Buz3_-u`3`((8u{LfgUoP)*x%!Gs_**MI6LmT`+OjEZviQW=g zq;R3Z)aPuEVrC|jmAXu<{Z{WjIg(V}&{&BUW7w~lCt>!WUet_a`7oH65N&V@dd~J2xOxF;8gKni zI}(pFbebw5hvMlK<8b%0x`GIPQH+%ITWj3`vIG&*2#7@3b8;s_L^M9RZDeO@v`eiF z${9X#g>MVksS}Sih;bnjFx7g=D0_MdCh1ofet0d$LYVjI`OZl)@VdUDq)t{$frzE? zr;vke<9Vw;FoL|6eD=}Y886=T6J-dn9S%H`bTBS8R8j^a(06^teGOUlUqYuS`#MSV z1jWT*!z_ZMl$7%Co}(STXflhF)KSK~mF4zzyV!H4ZeV`E5Hk~tZTu0)F-eZ7lP1<> zjUG!*$itJdh;AIzy1}NH$Io+c>yeU{usTD7yGe#sE-%!0plXs{OisL`c5aGAU<{+H zo~3z>%e)%e+dPgeQQB{zadM|BL{?g(uzxjNOXXbo>Hn9RreG^Uka|!M5Djn;5U&4h zt4c<$mclMBW_HH5X3k`C4kkvnVxMDN&Q`_%S1X5q^uwm8=*r>>qrFdT3?otMyZ4$FJl3GWix9qozEd6jU``%@?GDT0{&m3; z*5Uu?3-t|^aF8i5goKYS|rWw{ywVA5LU0|}lic)pS$(IhWr_(gmHi(GDLU0`LQ{Li?0DoS84TZ$JWGTk_- zVW^JoQ(W){28Y?Z!*F$pnznCi8_DFAhWx5uO$d! zfj}zEPsWEK`^prt!tqC&D)JNVJSFA|Iz*FRln-oz4_3(F0dUDYW{6~&f&8;eimS*; zm9J6rj2;G z*nk4|przj$W1Ls~C~LWncWJ8);&w1WgWm;+jn1`eU(kG>;1|2w`8R5HFIOUXFP_M6 zq5gf(Qpp8EVt%$a7=3csQ2c+`!QZPSDH>LyxC`j~;E599peER-0mLcH^1%?LZn(eL zBXog_GDyv~)NUv&xpi2&(aF<8q32d7g)fN=R?Cg@53ZDUBrSO{oe!J*EvoxpBBwA@% ziBbw!WNY3kx%Yq=;iF2;uL?@z}iTCdSd#GI^a(FNbs9+lQH-zh{+&1 ziLvxCFOra&i$`B;_9n@ExNdyD-UNdVQfIjy-kYQ*O-4exJ0i-(BxzQaHtI&zg*MHc zRh9Mz&gJMw6m0(N!rf0Vni}1fIX(of7G+2~RLF|m!_QEd^PnaEwe=UsZE&UO9cfGVzhFV8)j96MWpoPWBu!1fnYA;WV#?}YJo|vhm1TKew zt<`p<&@eV%7txw4ciX;JEqP=5aSXNV0B_Q6XL!g5rjpKW0%k59S3;F(j<`)`#<0mH zg>y>OSpJLvk8F!rybVVh)%+SI91GF;ggHvXAw)gx1vP6!hvL7K zJQC7vRu-vN*@`*vdudt{5Vh>P(7s4Xvqt+ddl;QQWYxh_HgTm1kinvCiSrs(oao!( zFxI1}wHFeJwC#-j{F(ILYogYP3M$QtIDt8GpF#Yy^20ZUorIDtdRrKQ@Usy?@DJ1X z97_){MQg235S^{qv*SVM&!uX6r4fR*!EF%Tz^J)^%_5E;1&`n$BUW;9sNsk;TIbBA zO@d!g8hWPh1AvjkK>11+fi-@u!C#dUI@$opLYkqS5=C-{6Usc@*w&1~9VI<}r-y8=6Bs3Hi-| zNo94qc4SHwuErL|aNjyZa9<@aYn#`amdm}}_)Cc22XA{nA08o}R>9!c#!jbSr#w3d zHgCE0Q$_w@W_7ut8`FCa6>>U1R2T2IZof~gc1$CSvcjKhd5 z>By?~Xf-lNiD~urwJ=&^SWV2i#Z0HMI6)$jDig;--2e(v%N( zdCTKJfgrpW9x*zvqj&ZRuXu3L;DSO`r>bc!$K;aW0{4a9H1G*d+^60uz}lhvGT;l2 zsH*BpYD|>igD(%DJu8HK{{|`50Qpv3w37{VkS5C`C!=6GT6twmP@DLLIt-gp0d0yR zst#d+(mPBeasbY&l(whd9GQwQmRe!CCsUD2zdVu0+m#ncs_vSJcz#To!!)h4R$YQM00Bphy%Sq;ApP3i?Eok-9_5vsqy;8|!>y*7Z>+pDwHc__Z0 zA5mhja)Q_E42B^nbbyrs6MBstN+iW==aH-up7F}{)J^4#zR4F))VmMcTFxb)`p`!z zc$%;w5Z}crx2m0{+tZ-D!?Ag-q-QlEpC9TS@6^IR%sC|KA9Ap}D|Oq4znVn+?O_aQ z+RM$+nOjJrL;V&2ujY8+W)4-icSvns{!wl7gr@pVuv{@{AHBn+bL0Y*w5GT_+lS#t znEOF|yUijX@v1Rk@%4t!JL4J*L*GHd`c$%Zx86V68G58VGEUW`W#E}dQRWChQBXpQ zY_)?YrgbrGd_;F*!oB~MXs1^dNNjOz*~1DG@& z+;$w_hAh7hs>;z$zjQN7!_(vJY(v}RO}*~^0CF`5^9&))H>_4w8-C0G%e!8}2StKj zd3R>L|6yU3WSn_VrTEppUT!J${V%Td?1g}G^K(kB_LKRS=|8(xRnO0{c)QOb`A>pe zS1U6YDI@z&cHMt++^VW-qP=rSa}nc-3C(G#MQZfW*I`zWOX;FpQ$fg3g?B89a#2Y3 zavu#x2szyQ)hK37EQb9CoXVB3-jjbdD;97o798ej+7O5!hMDI1QTe&qZ5Vi;IaGBd zc7D9=D1s<%>42=ID_uH+Af!WoLs5m@27N4a<^h3Zb-s$s9H)_@N>{zK2BA;CG%<*U zQ^`y+W(Gk&Ab)K#Z;$27xT0W?x=Q6UokpY&ASWx*N)<_)iW-+9uIf^9l+NX^OHarB z*~-Mq%P-2zLBK1yw@ZE&i7{+xPLt?p+bbsysiUB4J~1t4VKBN2_&$K#%a*AOs#xk^ z(B-|XQw#*mFx`3hnMwaTXe^3m$kLXkXRTQZ)k{k@ptReC_(Dm~i!Qyi>?{#ixvaxc zv69f|H8HJeZW{$RIOSr&o@D-$*tO8L|{dX2^yEBU%Yc&VIE&vas1OYdF5W_=*MZ0daZxBe<6)m&<$Lb>tb6+X+;Ef~+;AaEF3 z2gXk^giOkDzUP6p>9Y41E;cIA(C8LF*6rY)(&5qE7&rUk5xjU*65 zI-zTwUUjc61=^6sWY1JFk&`(BAJ&es?6+OHiaw z$<+41#?X1<6u#%%$e@UNW26n{4(G`3S#_W$8!ma(-u5%jw81QXc>x_~WmXgO^?cp% zih_N&dphpctltY;5ki6%6+&; za2@2#W3bN;ImAD!f;=sZ0)j1v+2`%te*vVM@1a{qw|2 zwMlKeM`b{@k>S+flHwsA^t0ZqpAM&ES5OG<1IHKp9#H`=Wb;iUJis7PtO?e5du+Q8 z9)9x6)*xtO;vfeL7MVZ4X;oSd=nTrfM`nZ33<^0j9G3Af_#GPT4v8AUP3hM_i%Z(r z7P5&MT|}M;*qc|X)^OgDCH7O&`moz&kJOL2Y;$-Visl=vs>0Oe9lW@oR ziaYk(hWTL)=XCdk|DK4P%i=;Me1a!WpF|t~m$~A93}cEq*qd8f0Gy5fnT5tA*(st5 zBMpA6SR4!IfPjiuMK*>xszByQdz40&8J7xe<2r{l;8ANjyU+J27DdEFFusELQSF?r zft|I=`>?X|vVJUWOf+?VyuL!_21;7#_4vTTiAwcKZ4o>~t*SM*Opb%wrzUDCY!e5$ zS$hAr;pF+f=7uFqxh;xU}vw5`R`z^CP=I9?@H;c$V#0%_YNmgLhWY80$oS zK5lGe#<|0#C;rtqCp5_e?VcigDfX;}NlbQ6KXlRSCI0wF#+jA_FD1gLuLFlp_u3hF zLz7J_hhUWHm|#7BsB_gBM@+E|0g!H|!6rLfr@9XF`3`t9ZSSU+)PQ7PZ1sfe%Q%@j za=pTuy_!sW_u%*^kd4M?`EaTEogJM|{YL9(!(jfM;d-t+HwJ^O7rYV;o8J0*Il1}tkBe`#`B&%b4P0lYuv|NJZuMK;9> zo&1gTk>Y_1LE=Lqj_l{X+0b(k zJPBtA{mO)OK*_66!au@#J^PHv#7}rcQhs2f-xtJ%+&Ap-{gq|Osc$%zL_#@(MO#jV zEd*x7dW&d8F2SNXuwok}h_9yq?n26!pD-0E5YFjUk1xhXq+MhUdA({9kkBe54YfpK zW&Z_rpqGL9yQI#gM(9a%9!SIp5vxo*NsMNIm{~lF)h#H|Ywu;01GVrr%TPPYE)a)| zA&4%qm<5E4R>(Y=NR(wL5oI?P$5iTzr(6alxR5iLsRm49yl^(Hu#9zlFnqmCMiVHJ zC#Z@>AemWwIf|HO(C54SOgjOH3KEga_x*Fjf46O|sS|O=&nSTBvk{T%KSu)pux)V< zGZVl+nTIu>{Ac&EKWOSmCBs3!f})7nh=7>zLQpAH&m9yK*O`JTTJ8eUJ@dw?@Hm9^6a5K(+FQerbDokqGSxSPrs7wIw}3u zin0JoFZ;Z(l$o(U;k{idebVA&C(;#4u$FF_!;~ziVJB!r<=ML6x0uaKpPiqVo{?Q3 zd$-dn>>OKe<b_iVrsK{d;;e3bWxr4U?mP(G6`SzDF&ts_#Xe~I# zWoy)jp^5HvxD2`RIuDl=hJmM7GPxR!sLc#|rL?=$n8&5gj&*?j(X>3eXhjHvfOf6w zPWqgqnzdfP66(sF8@j6cWt^}7UClFj3$3C(Zy#NBtp=THcpws<%hVDKLy~i`$GLn- zfNg5LoBB|kR3CPQ9o9_1vuD19Xq(owE{_HqPMwgY-j%X~_D3P5tcXtRwT^nRUc(U7 zT8qzgV;szV1<7xUZCG&=5%vz8L@!sBR4B0R=?_XPv3X}`Z5J}H-DjN}(c}H)QFC7_ z{8sx!KbhZ}Mr~-lY6!Hpp#AAYHYdKO@hBMx)VWXQV32h9H{G4WDUanMp!G{%k5x@? zz?^eX;b~F;(|B7j zvTKS1M86gC-y*ZDHa3l<23#H~?yeHY!TU4I z)jWxC>Y5rh*jn}xTh-q{qV~Igcd#K#-g=3DA}a5lF^36vWSiPSht2@CoZ%>DiGvP=ms$t+?vX#;0V2yMe4$L5 zd}W~!NhcxxDn4L%#fj{nc7^z=+Vxw2-+0ewH`rW3BDQSS?GnzDy(-4Wnj(MCN4_8N&C5CK`n?B>4RCEUJbg}y+nJ-6U}`q^fcu?0@ThWvgMIB0 zk{oxo&p{`LTVr|kIIIW2@d%LW#7w)TNlyh-{ocSt4>e|gbJr63NU)v`?`Zz%#+a** z&N1zmW6_y;kDvV}v+VA5|7+T>(_%y9g<;ZFDv5-37^luGtUAZU7)PL$#82i2~P(0nV@qAr_SyK2CDW zr7>3E#zhC2-5t1ftaXgC%T3ol)?>WKQcjNzU;}6F2`|95BhZE!j85*SWt$aqD4|zt z4r72gG^OAO;{h`e>xyDDmZoz;-qLy{Io>H8*UpTfWH7Qi1ykOiVu~{R!_uBvqFtFT zxMsk+a0!^e}I|5XNm^P?^mwY;6(Zup?AX(<&x&Zc;1)d=EKu3>RIu64S zG&qNh-qhZkW|Ku7`>bBz$k;JC`m>TEY%+^YQ$b*o_8q|w6#q*umK-7y-Fj<+m9SxO z_xl0VhDG7dtOKIEt5pfms(kBGQE+CC_y~mRSBi2%g(V$WX?$t;q_HmQ0i`V z_e{BKxVYxLsUbh%CInURu!v9E`yD3yDkpUT3BhMCM{6gzaa*Gyg+cw4CZC)^IO0J# zup;$|mW}gO#Ot?_QPk{F;fMOz_MI9!Y_#1+O53A0cgW@Km}GqKi8d)WrPzd=1}%|5 zY^Ms}(eVYQ^O7;tN_EiU6m}ytr_6Ji!h0BJtuBC2^5JdA9#-w(@S+kO14OAMt=*6} z3-hiF{1#|M63a}`*BMZea$o|ApHwkr_yXzG@m^zjJrkibQ%<4&R5|5{F-`V(8(7SD z+EOd{F|ul+^mJ_iMpGRZ`CYV<%q~U`Se}&W9!U=(>NQJ`-giwEmX6575R zFW0Sk+Cz+&x(NGqc@F19=~6!eBVB#c z$B$P^ZM-!)Sm*Y>XmQzJUla8AfB&K+u_Oe>%j1S1R%;?Oc+=&L?4ga%jqiyM8R{{A zr>AWaZthY7znrj9hpmBIZ9$0WZKvDl(IzWZzNOplJraU@N|{R`*ajYI+>5C&jNCrk zB&)GNKfeM_-Ao?$Y7pn06>vKAFkwe*r);#?Ja*UgkyGP?nr~g9UWWYBJ_b3o*LEj5 z=SC&XTj2;l1fntp`?S#4T(>?EPP8xtF08SVK0ntc@pd`2o1bnd=Ai{^G0@1yplhsq zqXH|^z;)yp{!enx9bOT=3=Vemf+1ZSqy7f&;i5_Nyeod(XkIQYuU1A(sdMDHXcGWS zLm5s~GaLrcZTT!}wB)dw8~3B)8Av$CY_!QC`rLZLqTKg80_CgRYOic)4+2FnF?UUb zkvEL;77ME~U<=+GNLeDE7di#)=Zrrezjk`ZisWO(%+3m5gYnhQK3mMp&Ajw*Vk1;0 zq#!lJk6zS21VRe>jhDom(Owm}J0>>Xnpw-+-rP4GS}aX!+wbK+}|uhAxxZ`t@w7=!4|etrC<^cxj) z=VbkfOJaR$dhz~m%l&Ut{3j~;e>ci1jWtbNb)=6q)1(kHI5HHZJoNav;6gDwS(`kn zqPc-kM0rRnTDJ!69+AbEHeC2;!N+s%-w#c{#jf!9eeVTl3jVbGjHj?Iq#oSe^&88I z+ZbE@@pI$jX^#`+VoMiBw3*ykxrfO9#z?vc--m3AVaDf$*>Ei>zPmmcz4HDWLeA}` zs_BzsCtQy7rBMeQEgEU$m}+$#A;KqKfY?p#@ge+gV%YOYjP{8i1$+!*2fm%LK@@W z*RKD;6KAyc44vk%09qdbV%Ey7Y)?Y!#p4U=lD_@St)fnqZ}uPxBzGTYx^nj0<~S)< z*r_HawO6hR3D`=7im71PAY<2slUSOLDl;o$!xgM68B39q0h3ityl?CU6lwiQr6HGX zu)|bo)@Sp5CKGR!R?k4m=b~_zsN^>Jbu|zbD@?;)KgKvA?HW{tc~I-><5>-?pYSyD zqP{7-)cd16$DinU7yg(y60Ah0u2vPQ+h;Q3slkX9xwHS;rWxxT_HEn3b<2J*KyP?{ zwYr$6!HF?~_`|Sip?Z6NA~=mSwcdP5rHPkkQZK*ZIeWj=v^~}+^gYSTtUZDmdj|_u zSk8fzQY0lIjKU-^$F_jTI4tLo#Let9kIL9E6g0`1p&+=%RBMy-qZl5_?8^{W*8&R- z*KRMTtESFt3i2SDemg6G*7*gUMBeP6ioPb2Vj8kSX?+2{#3>GYz~GN(>D>T@ zujEuok9X;st-ba$c4<#V6ux)>p0#`O*uLfI5T|EdW{7v>Zjbrd$1i6pY^ru7On0b@ zagCQo!2`Ln(cjS8?e)K84nhhcdDu7}Ts`x3TWov6B>{@ax9?|tn2{gRf6ITUp}(IN z3nj%@kj;rvf^1FRK*j243YA$6|k`kT{S0O8=hE1dX3K#5<6wgnh zw;JRr!WIMJn-t6tN!u*u4NAOPfY!eA{A>Qw0q$aELvFvC0ksBE6W4Py89QIk<%aY% zBtHDapOk#t_Z}+ry|4h6fh|;ftR=5wsZ)q)->SdYB_!I(Wk!wU>2tzTEIT{Vt?cV@ zh=QU13Do0M7UnzTzXK}1RTG|)pWQ36pC0u;c+-E`u!Nm00Ct~(PM-w5W{&>^3{w)u zWx$!yLKL4_3z~pBcC^Pm=Z)%6s~WH*usxeSspqp+=@RBB!(*j2d*z!wP?vdqWc2Ed z(B@7_-p&{9ibF4hC%6HuY_e3}MuY7z0hkD22bpl$_t3{-@BF@n24doecdGs3i~Kk! zXbgMl$ZEa}i*^`s={Qr$g((?~;5Z0n+Y~ubA+9~BfvAS%Q*h|`l4Ecr=lUaD#m2To zm^5R?6f+eE0sMt}kqqB)8_4qVir$@trwq2wezK%fJ(=$7_Vx#uM^MbCX&@y(v#5f$ z?GHGdFq)KnI(Fn(81%piK?CvH7xoVZRO+~;Z4~<5JI3@BaAs6jSHPcHPlXGGHdaW_ zx(8aG)XL?#6ke_Ql7UK@6PwiS+-Sf!Q{_k|pul4H?i|QFsJiRdbMHF)I|P4h1cS-_ zD{Bc2M`geKivA14zpqNe#`ZJz=c-tIt_t=4b}aw0Du0P>VwB}&dxemEXa5Y$)s$0C zlCZ%_@NpCoi7P`>k$G$spVX7D4Y{d4ukbyBzbbEYgrLa5>T9{}kNG))a2vTlrP3n~ZYmNwDDX+_7QuuEYtsqi>rrGQ%%k zhu1`CAP6FZWmRUraqqL)v{-1MPj6E7c^53=4&FOq42C z-f@LZPP!MVxDh*`P#Q)_$#x!@3YcIPI^$V)Ys?z%DCw()k}vEe&$@d=p21sq(-L*qIb41^&0aBT!4cvL}RI!SAldyIu8 zi15H8)I>>242WRyFpM^n^g`z~?KV+WR@OQT?~3{uqQkL<2R<4{NGkJH!(5zfJBbc_ z3OP!}yLie@n!%wg4=_|L%$ZKl#Ox-UBgk0(m|@kPr^(0&K1(qSlaUo2H&0YeEwf+^ z>b+G`V^!6gtN(L5&X=X(tq_A{o!3QbQ}GbG-NTys2bNm(*RWLhT#qdD(UO{zK~r-g z(RhO4z!>^XLu(UJUT22k#26WCaRx`D>Bv+PX-mI2`%i+|hUG&1zI|L78&6f)veeX6 zB&?Z+R(3jKoSR_6CN|Y9&c^O_Y?${1Jss2{k})wSCj-`!eokSoG?f_a`MLh(CHUP; zS0AsqpUvY_Uz(gLs2{5!v*tJMU3*fRTs)-@E8!<*cp;AWrgL2?is{$^W_sf*)j%Hm zVGmUi<9?!ip}c5wc?Mc*K;*Tq%#K5zPD^zRU1RF(L z@j*01#p2bG*SJq)(2aXTh8{|;N{KC9+kJe2RD4a!W}k>M(@y!ull~{c0xTqZZ!Cog z!sO)q05U#IG7{HO)F@HauAZ>7BK`45B$`oc7y_yLnr=|B7Gs!8){9kU#IdL74W6fR#i3!xUUzQkFawFrNq{~O>><}$q!`e~2u zoG*8ebW?2?6)cBQL-a57_MkIZV1#7NVoTAce*2)X>ZQO0)#E4mk7bR0XmlK!PqgA< zE6Z)VL9Smu!fx(2sBC4XSVeR)BopPyl#5n4Sc8G|z^o#~J?|7k`<>vx$;+0@H<9kN zN15&glH1f0^zy*R-B&YualeG+Q4`OGZHh)S)`rYnUq6ZxRowTZhLTum=;QP530QuQ zYLy?Y*;DpR<$^YyG+{Mj(yIV;*l(un<3jj#%MBt!zJRcTX|%+$6k0o{dwBYv$SCIa z1t=VS67QqTLO7XN>o5i}vAgg=YQad5xCVGpEjBp7YbZa`k0@v&l19k;Fj~R~UlD`z z)-ZpyK)Z%DAIaeB)eEP0^3ylB^D_~`g|?PwaQVxdHz77l!Em=a9AL=HmLXUPX^1d8%0^ZjrX(X z0T(d%KTYxCyKw=~k5R%hWt~H!yKL| z<=PI&+}FKK+JR9f1D!SP4L1m)ZI=INYjqnU(Xo-gc!)N_RHoQUeEGE{TCDb13#^e2LbZ!Xwe0S0WBI zfD8J_!FBkwRdLnoYn84Z%$=J5GRY6PjtwD{9cAATNxDNFsupL|MveX=?KH^Eg%wD8|l zK*c{Sn{?pZ_FBVjf(-Jgpd$k*!_Sm-XCM-fxAZ(f5Xp<1UAKJp{RPI_|4Y9?0*?e9 z89Be9WhwJlig6Det2`;7u7)kA5MZ0u)GpiOTHs=)S2PO#OH(yC9ch0cHNUZ5iOyL) zBIlq#5=5kZHp8yC(B%|bIt)$bSOt%f{S)+mlax`JJlf**Wqic=w#nKx^|I)&>riSl zeE1h3(0V%G8|BYl=abJe+c0;)37 zy8<F5tRAGDlq ztbPkABj ztDgCCOB+1@m1bz=B$d~+R2qw!)R%+y@)56mBJ?O0tC;z_X;rweZC6u7cALUt9+Xfw zd3oGK`$8bRxGE%{(P904Dm4mD@SQVN%V#zf2q`@dH5*!8`lQ8f(fs>BeQ{Sbsqnya zyZrKS)T&s3TOC=ae2n*KMVE(9s6KH`D;YSZX!K_R9vq8fq6p(y5|87g|DK~SjmeM% zK3n3PIoztM&|(ie1T&#c#v<5aEW%#Tu_uH9v_WCa$e>G=5+mO9uqKTtG@>=OU5Qi8 zPPa-K-FGk|^RsfiT8Eb6q7M!?*wq$?3V}n%S`l5^O%u0TW%j$0DLT7s7AIo3{<8tt z^~q9h5Qe100slDQS>4qbSxZLELWP4CGb;NEN!_aP`v4X&qsf#igy;_AqJb3N`ncVe z30`9&M$KG*0_Vk@RvRpP`j!V}xlIT40B^a@`Ic?D9S%XhQ)1dL%jhywZ;P@l4QlH{ zChLQ(^st1`pOPOreY776=Pcvf&P~id05NO-a8+#X=*~BA{N&~${|G$G?y#sSXmpV- zV+jw>mf%xFN?PK%IeavrrC?Z$FVx0#T*Nm{V=-c&gV5*&zU>1p!|pLQwWtfx^+H(d zCZTYC)NLBr0Ob^Oa@Jk9e}g)Ty@(0CNdM}h*~(3%D~72n!YJF_t0Cv!o|*^lzTF%F z>Kt@oKRqEK9JbkQ*Mm)FPrK;g0kP`jBTK5B1wdXrEr~sJ7 z{)EGRzy%ltS0SRxG~r(Jw`uxB5$|=gnz&I z)uMeb$uxP}Bj&$n5%+tBW`%#tAU?a&|Dv|?pLeDIdQ$%$@w)u|39U-8Q=C=$oUHkU zdvf>%mnwV`E>H+AIWIq)8QBMVSPaz^*&tmH$Wy*nbriWRdD-?Tf|4SJ`d_0p_L`Dw z60ieoNBjq?F8&9Z-jjBJ7wzRsWh+geiyu&9lx~f*LXaM_W@0YMFE!34R&_c7FqD() zYQYzfFI4gkeC3_=Ov^pO)^u@QDz^!zSG6`T`2&kJ&RX3{#9uykc{rYX^ zIr#__P3=z9-BS4B4V)7-nc1krgoHTB1D8pu;DFb_{1L_&-7vxj~! zUX7MX5}2=@4_PJG@Il76ZTYZI_a8vFseV+I->-pBZJWm+WWc;&^(M$B*NFbX zz82f;8sypZ{B82V;|FisA7sMsEU>rza-zVG+*9gAuiPO4QdvT)I4M=jvBOi4NP8b) z;~X`}x7%~cKn(#&#FgLyU_9xH<1D^sCK#BsF*bh*GnxpdWwL?Hwn0c$ zLvs0;ac@zPHOk8B$Sczccnodkr zNsSb5iDv!EwMEf%oSq>9A{!)GR$+y5N$)3e8~Oe(U(arzrUQofnZ~?geLF`=a6F~?~>`I5^qOFoB81N!D^6KUUgHVR6GAVVKH5ecXR>C zkKHFwh*AS!cSF zpSM4Bi)~MXpLJwl)yuhd_h0K}*Ia&eo^{9WW3R|(&D;)+G4H5c`8DqxL$}plRMym1 zZg=T4O6A-PpP>Hs+w5ckzHJNb=bnb#m%U=E<9i)>J2qEm-AhR96P$22oVk1bw)oi= z%uwM`I-c?~Gy?8WGnwXIrro;^J+>pI%Br$g(K~N;ebsU6*2Be6?Qwuk@mrpI9|b(< ze6{m2&-V0^cC}!_E}$I-2jeUJYzM_U9N(OTdS1#76}zWECX+~&-G&NbOPFj11+pxW ze1OqQ74(=tqf0e(2xY@7>!2WZs21Z1)^7fMBRdMB=Dt+eB)lL5WC?TmH;4lhL!BAVy&^} zPr#aMwZQakD$xW`L_*hCdVYxUn3|b~dpbSS2>Pr7sN`2_6AK|P49PR;k+YR}k@^R5 zX-et=h9Hg1|7yHkj4_}+nKn*cR}lKJHe&3mhJTI2zlDGrZ!*HDqhx08q$p8ceik=o zv4>8-`i6h?z=~0Gmf6~>9JXBqk4ee1;`nQCi(7iOib0hf=NajcGX!b}QEt?IK;#Fg zoB!d!h%OcXSxTFxf@lqCUaP`PWrdh55N^U-lC?>*msJ1HwU2+NF!ueE(c=g9JEL>b zU_>Mpe*?)ak4YX9{h=ZVgdnGD&FpjIS~LOb_fXX$q4G!gJbd_$Rq^IN%|eNO&Fl+4 z0B8SJ_IEMI1_%JM30;^IFqlkNB38efLKm<#>D_g|d6M3T*1g|hbqoV-4Ch2fy^l4W z)C1pPGVFY%romE@sm9E@t*FR<57AW~!fafA$uiaj>J& zXXB;AKU&m_ROKCJKY_awpJte^2v)ecN;)!mPx%TXpm}QONHEkYuu^4S8)W~7vbTWB zE6KV*A-Dy1cX#*T?oM!bcMb0D?(Po3-5~^b3l^N<`o8{q=5;sIGp}E*br+Yls9l%3 zr|O=nI%n_I+QFuZCZ$WYd-ygxN+gJZG~Yl9{Dx)~WkpCNi1Uf5E_Y_zj;DvGkQgAg zO9B{V*M`&?Dd@ZFdYk;heq&@6WLD%m%7|~EtMTCD-UhDh z@rDouMK2yq;i)N}@9HtRk$MO3q1}nB-UJ>G2K3$I|4u}5Qh;{kCC-8Ut{qJB;%xRh_Sy@QGeVNQe6^QJzZ

ZM+x{iQDVZRnLYbdXrQjU&=u%hsN4|smH&B~F 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 b+=;!jU|P+J`>$CfFsoU|bwOU-ceCsYH7qU$ literal 0 HcmV?d00001 diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..e6045a98350 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/gradlew b/frameworks/Kotlin/ktor/ktor-r2dbc/gradlew new file mode 100755 index 00000000000..cccdd3d517f --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/gradlew.bat b/frameworks/Kotlin/ktor/ktor-r2dbc/gradlew.bat new file mode 100644 index 00000000000..e95643d6a2c --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml deleted file mode 100644 index 9f0754b9512..00000000000 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml +++ /dev/null @@ -1,179 +0,0 @@ - - - - 4.0.0 - - org.jetbrains.ktor - tech-empower-framework-benchmark - 1.0-SNAPSHOT - jar - - org.jetbrains.ktor tech-empower-framework-benchmark - - - 2.1.21 - 1.10.1 - 3.1.3 - 1.8.1 - 0.12.0 - UTF-8 - 1.5.13 - 3.7.1 - 42.7.5 - 1.0.7.RELEASE - 1.0.2.RELEASE - - - - - - org.jetbrains.kotlin - kotlin-reflect - ${kotlin.version} - - - org.jetbrains.kotlinx - kotlinx-serialization-core - ${serialization.version} - - - org.jetbrains.kotlinx - kotlinx-serialization-json - ${serialization.version} - - - org.jetbrains.kotlinx - kotlinx-serialization-json-io - ${serialization.version} - - - org.jetbrains.kotlinx - kotlinx-html-jvm - ${kotlinx.html.version} - - - org.jetbrains.kotlinx - kotlinx-coroutines-core - ${kotlin.coroutines.version} - - - org.jetbrains.kotlinx - kotlinx-coroutines-reactor - ${kotlin.coroutines.version} - - - io.ktor - ktor-server-default-headers-jvm - ${ktor.version} - - - io.ktor - ktor-server-html-builder-jvm - ${ktor.version} - - - org.postgresql - r2dbc-postgresql - ${r2dbc.version} - - - io.r2dbc - r2dbc-pool - ${r2dbc.pool.version} - - - io.projectreactor - reactor-core - ${reactor.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - io.ktor - ktor-server-netty-jvm - ${ktor.version} - - - - - src/main/kotlin - - - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - - - - kotlinx-serialization - - - - - org.jetbrains.kotlin - kotlin-maven-serialization - ${kotlin.version} - - - - - maven-jar-plugin - - true - - - - default-jar - none - - - - - maven-assembly-plugin - 3.7.1 - - - - netty - - single - - - package - - - - src/main/assembly/netty-bundle.xml - - - - io.ktor.server.netty.EngineMain - - - - - - - - - diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/settings.gradle.kts b/frameworks/Kotlin/ktor/ktor-r2dbc/settings.gradle.kts new file mode 100644 index 00000000000..b031caa3339 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "tech-empower-framework-benchmark" + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index b0a05351157..54a77082a07 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -15,15 +15,15 @@ import io.r2dbc.postgresql.PostgresqlConnectionFactory import io.r2dbc.postgresql.client.SSLMode import io.r2dbc.spi.Connection import io.r2dbc.spi.ConnectionFactory -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow import kotlinx.coroutines.reactive.awaitFirst import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactor.awaitSingle import kotlinx.html.* import reactor.core.publisher.Flux import reactor.core.publisher.Mono import java.time.Duration -import kotlin.random.Random +import java.util.concurrent.ThreadLocalRandom +import kotlin.math.min const val HELLO_WORLD = "Hello, World!" const val WORLD_QUERY = "SELECT id, randomnumber FROM world WHERE id = $1" @@ -36,7 +36,6 @@ fun Application.main() { val dbConnFactory = configurePostgresR2DBC(config) val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain) - val random = Random.Default install(DefaultHeaders) @@ -50,44 +49,18 @@ fun Application.main() { } get("/db") { - val request = getWorld(dbConnFactory, random) - val result = request.awaitFirstOrNull() - - call.respondJson(result) - } - - fun selectWorlds(queries: Int, random: Random): Flow = flow { - repeat(queries) { - emit(getWorld(dbConnFactory, random).awaitFirst()) - } + val world = dbConnFactory.fetchWorld() + call.respondJson(world) } get("/queries") { val queries = call.queries() - - val result = buildList { - selectWorlds(queries, random).collect { - add(it) - } - } - - call.respondJson(result) + val worlds = dbConnFactory.fetchWorlds(queries) + call.respondJson(worlds) } get("/fortunes") { - val result = mutableListOf() - - val request = Flux.usingWhen(dbConnFactory.create(), { connection -> - Flux.from(connection.createStatement(FORTUNES_QUERY).execute()).flatMap { r -> - Flux.from(r.map { row, _ -> - Fortune( - row.get(0, Int::class.java)!!, row.get(1, String::class.java)!! - ) - }) - } - }, { connection -> connection.close() }) - - request.collectList().awaitFirstOrNull()?.let { result.addAll(it) } + val result = dbConnFactory.fetchFortunes().toMutableList() result.add(Fortune(0, "Additional fortune added at request time.")) result.sortBy { it.message } @@ -113,47 +86,85 @@ fun Application.main() { get("/updates") { val queries = call.queries() - val worlds = selectWorlds(queries, random) - - val worldsUpdated = buildList { - worlds.collect { world -> - world.randomNumber = random.nextInt(DB_ROWS) + 1 - add(world) - - Mono.usingWhen(dbConnFactory.create(), { connection -> - Mono.from( - connection.createStatement(UPDATE_QUERY) - .bind(0, world.randomNumber) - .bind(1, world.id) - .execute() - ).flatMap { Mono.from(it.rowsUpdated) } - }, Connection::close).awaitFirstOrNull() - } - } - - call.respondJson(worldsUpdated) + val worlds = dbConnFactory.fetchWorlds(queries) + val updatedWorlds = worlds.map { + it.copy(randomNumber = ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1)) + }.sortedBy { it.id } + + Mono.usingWhen(dbConnFactory.create(), { connection -> + Mono.from(connection.beginTransaction()) + .thenMany( + Flux.fromIterable(updatedWorlds) + .concatMap { world -> + Mono.from( + connection.createStatement(UPDATE_QUERY) + .bind("$1", world.randomNumber) + .bind("$2", world.id) + .execute() + ).flatMap { Mono.from(it.rowsUpdated) } + } + ) + .then(Mono.from(connection.commitTransaction())) + }, + Connection::close, + { connection, _ -> connection.rollbackTransaction() }, + { connection -> connection.rollbackTransaction() } + ).awaitFirstOrNull() + + call.respondJson(updatedWorlds) } } } -private fun getWorld( - dbConnFactory: ConnectionFactory, random: Random -): Mono = Mono.usingWhen(dbConnFactory.create(), { connection -> - Mono.from(connection.createStatement(WORLD_QUERY) - .bind("$1", random.nextInt(DB_ROWS) + 1) - .execute()) - .flatMap { r -> - Mono.from(r.map { row, _ -> - val id = row.get(0, Int::class.java) - val randomNumber = row.get(1, Int::class.java) - if (id != null && randomNumber != null) { - World(id, randomNumber) - } else { - throw IllegalStateException("Database returned null values for required fields") - } - }) - } -}, Connection::close) +private suspend fun ConnectionFactory.fetchWorld(): World = + Mono.usingWhen(create(), { connection -> + selectWorld(connection) + }, Connection::close).awaitSingle() + +private suspend fun ConnectionFactory.fetchWorlds( + count: Int +): List { + if (count <= 0) return emptyList() + val concurrency = min(count, 32) + return Mono.usingWhen(create(), { connection -> + Flux.range(0, count) + .flatMap({ selectWorldPublisher(connection) }, concurrency) + .collectList() + }, Connection::close).awaitSingle() +} + +private fun selectWorld(connection: Connection): Mono = + selectWorldPublisher(connection) + +private fun selectWorldPublisher(connection: Connection): Mono { + val worldId = ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1) + return Mono.from( + connection.createStatement(WORLD_QUERY) + .bind("$1", worldId) + .execute() + ).flatMap { result -> + Mono.from(result.map { row, _ -> + World( + row.get(0, Int::class.java) ?: error("id is null"), + row.get(1, Int::class.java) ?: error("randomNumber is null") + ) + }) + } +} + +private suspend fun ConnectionFactory.fetchFortunes(): List = + Mono.usingWhen(create(), { connection -> + Flux.from(connection.createStatement(FORTUNES_QUERY).execute()) + .flatMap { result -> + Flux.from(result.map { row, _ -> + Fortune( + row.get(0, Int::class.java) ?: error("id is null"), + row.get(1, String::class.java) ?: error("message is null") + ) + }) + } + .collectList() + }, Connection::close).awaitSingle() private fun configurePostgresR2DBC(config: ApplicationConfig): ConnectionFactory { val cfo = PostgresqlConnectionConfiguration.builder() diff --git a/frameworks/Kotlin/ktor/ktor.dockerfile b/frameworks/Kotlin/ktor/ktor.dockerfile index c2624695540..d0d81f0217f 100644 --- a/frameworks/Kotlin/ktor/ktor.dockerfile +++ b/frameworks/Kotlin/ktor/ktor.dockerfile @@ -1,12 +1,11 @@ -FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven +FROM gradle:8.13-jdk21 AS build WORKDIR /ktor -COPY ktor/pom.xml pom.xml -COPY ktor/src src -RUN mvn clean package -q +COPY ktor/ ./ +RUN chmod +x gradlew && ./gradlew --no-daemon clean nettyBundle FROM amazoncorretto:21-al2023-headless WORKDIR /ktor -COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar +COPY --from=build /ktor/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar EXPOSE 9090 diff --git a/frameworks/Kotlin/ktor/ktor/README.md b/frameworks/Kotlin/ktor/ktor/README.md index 02a13760b07..a265333db59 100644 --- a/frameworks/Kotlin/ktor/ktor/README.md +++ b/frameworks/Kotlin/ktor/ktor/README.md @@ -10,27 +10,25 @@ More information is available at [ktor.io](http://ktor.io). # Requirements -* Maven 3 * JDK 21 +* Gradle (wrapper provided) * Kotlin * ktor * netty * hikariCP -Maven is downloaded automatically via Maven Wrapper script (`mvnw`), add dependencies are specified in `pom.xml` so will be downloaded automatically from maven central and jcenter repositories. - # Deployment -Run maven to build a bundle +Use the Gradle wrapper to assemble the desired runnable bundle (Netty shown below). ```bash -./mvnw package +./gradlew nettyBundle ``` -Once bundle build complete and mysql server is running you can launch the application +Once the bundle build completes and Postgres is running you can launch the application ```bash -java -jar target/tech-empower-framework-benchmark-1.0-SNAPSHOT.jar +java -jar build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar ``` Please note that the server holds tty so you may need nohup. See `setup.sh` for details. diff --git a/frameworks/Kotlin/ktor/ktor/build.gradle.kts b/frameworks/Kotlin/ktor/ktor/build.gradle.kts new file mode 100644 index 00000000000..366dc9f1c04 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/build.gradle.kts @@ -0,0 +1,108 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "2.1.21" + kotlin("plugin.serialization") version "2.1.21" + id("com.gradleup.shadow") version "8.3.9" +} + +group = "org.jetbrains.ktor" +version = "1.0-SNAPSHOT" + +val ktorVersion = "3.3.3" +val serializationVersion = "1.8.1" +val kotlinxHtmlVersion = "0.12.0" +val hikariVersion = "5.1.0" +val logbackVersion = "1.5.13" +val mysqlVersion = "8.0.33" +val postgresqlVersion = "42.7.5" + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib")) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:$kotlinxHtmlVersion") + + implementation("io.ktor:ktor-server-default-headers-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-html-builder-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-cio-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-netty-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-jetty-jvm:$ktorVersion") + + implementation("com.zaxxer:HikariCP:$hikariVersion") + implementation("ch.qos.logback:logback-classic:$logbackVersion") + + implementation("org.postgresql:postgresql:$postgresqlVersion") + implementation("mysql:mysql-connector-java:$mysqlVersion") +} + +kotlin { + jvmToolchain(21) +} + +tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } +} + +tasks.named("shadowJar") { + enabled = false +} + +fun registerBundle( + name: String, + classifier: String, + mainClass: String, + exclusions: List +) = tasks.register(name, ShadowJar::class) { + archiveBaseName.set("tech-empower-framework-benchmark") + archiveVersion.set(project.version.toString()) + archiveClassifier.set(classifier) + manifest { + attributes["Main-Class"] = mainClass + } + from(sourceSets.main.get().output) + configurations = listOf(project.configurations.runtimeClasspath.get()) + dependencies { + exclusions.forEach { exclude(dependency(it)) } + } + mergeServiceFiles() +} + +val nettyBundle by registerBundle( + name = "nettyBundle", + classifier = "netty-bundle", + mainClass = "io.ktor.server.netty.EngineMain", + exclusions = listOf("io.ktor:ktor-server-jetty.*", "io.ktor:ktor-server-cio.*") +) + +val jettyBundle by registerBundle( + name = "jettyBundle", + classifier = "jetty-bundle", + mainClass = "io.ktor.server.jetty.EngineMain", + exclusions = listOf("io.ktor:ktor-server-netty.*", "io.ktor:ktor-server-cio.*") +) + +val cioBundle by registerBundle( + name = "cioBundle", + classifier = "cio-bundle", + mainClass = "io.ktor.server.cio.EngineMain", + exclusions = listOf("io.ktor:ktor-server-netty.*", "io.ktor:ktor-server-jetty.*") +) + +tasks.register("bundleAll") { + description = "Builds all runnable uber-jars (CIO, Jetty, Netty)." + dependsOn(nettyBundle, jettyBundle, cioBundle) +} + +tasks.named("build") { + dependsOn("bundleAll") +} + diff --git a/frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..28861d273a5d270fd8f65dd74570c17c9c507736 GIT binary patch literal 56172 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

ZM+x{iQDVZRnLYbdXrQjU&=u%hsN4|smH&B~F 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 b+=;!jU|P+J`>$CfFsoU|bwOU-ceCsYH7qU$ literal 0 HcmV?d00001 diff --git a/frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..e6045a98350 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip diff --git a/frameworks/Kotlin/ktor/ktor/gradlew b/frameworks/Kotlin/ktor/ktor/gradlew new file mode 100755 index 00000000000..cccdd3d517f --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/frameworks/Kotlin/ktor/ktor/gradlew.bat b/frameworks/Kotlin/ktor/ktor/gradlew.bat new file mode 100644 index 00000000000..e95643d6a2c --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frameworks/Kotlin/ktor/ktor/pom.xml b/frameworks/Kotlin/ktor/ktor/pom.xml deleted file mode 100644 index a6adb0a651b..00000000000 --- a/frameworks/Kotlin/ktor/ktor/pom.xml +++ /dev/null @@ -1,213 +0,0 @@ - - - - 4.0.0 - - org.jetbrains.ktor - tech-empower-framework-benchmark - 1.0-SNAPSHOT - jar - - org.jetbrains.ktor tech-empower-framework-benchmark - - - 2.1.21 - 3.1.3 - 1.8.1 - 0.12.0 - UTF-8 - 5.1.0 - 1.5.13 - 8.0.33 - 42.7.5 - - - - - org.jetbrains.kotlin - kotlin-stdlib - ${kotlin.version} - - - - org.jetbrains.kotlinx - kotlinx-serialization-core - ${serialization.version} - - - org.jetbrains.kotlinx - kotlinx-serialization-json - ${serialization.version} - - - org.jetbrains.kotlinx - kotlinx-html-jvm - ${kotlinx.html.version} - - - io.ktor - ktor-server-default-headers-jvm - ${ktor.version} - - - io.ktor - ktor-server-html-builder-jvm - ${ktor.version} - - - com.zaxxer - HikariCP - ${hikaricp.version} - - - - org.postgresql - postgresql - ${postgresql.version} - - - - mysql - mysql-connector-java - ${mysql.version} - - - - ch.qos.logback - logback-classic - ${logback.version} - - - io.ktor - ktor-server-netty-jvm - ${ktor.version} - - - io.ktor - ktor-server-jetty-jvm - ${ktor.version} - - - io.ktor - ktor-server-cio-jvm - ${ktor.version} - - - - - src/main/kotlin - - - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - - - - kotlinx-serialization - - - - - org.jetbrains.kotlin - kotlin-maven-serialization - ${kotlin.version} - - - - - maven-jar-plugin - - true - - - - default-jar - none - - - - - maven-assembly-plugin - 3.7.1 - - - - cio - - single - - - package - - - - src/main/assembly/cio-bundle.xml - - - - io.ktor.server.cio.EngineMain - - - - - - netty - - single - - - package - - - - src/main/assembly/netty-bundle.xml - - - - io.ktor.server.netty.EngineMain - - - - - - jetty - - single - - - package - - - - src/main/assembly/jetty-bundle.xml - - - - io.ktor.server.jetty.EngineMain - - - - - - - - - diff --git a/frameworks/Kotlin/ktor/ktor/settings.gradle.kts b/frameworks/Kotlin/ktor/ktor/settings.gradle.kts new file mode 100644 index 00000000000..b031caa3339 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "tech-empower-framework-benchmark" + diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt index eea3566b953..aaca738fa49 100644 --- a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt +++ b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt @@ -13,9 +13,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.withContext import kotlinx.html.* -import java.sql.Connection import java.util.StringJoiner -import kotlin.random.Random +import java.util.concurrent.ThreadLocalRandom +import kotlinx.coroutines.CoroutineDispatcher const val HELLO_WORLD = "Hello, World!" const val WORLD_QUERY = "SELECT id, randomNumber FROM World WHERE id = ?" @@ -30,7 +30,6 @@ fun Application.main() { // Create a dedicated dispatcher for database operations val databaseDispatcher = Dispatchers.IO.limitedParallelism(poolSize) val helloWorldContent = TextContent(HELLO_WORLD, ContentType.Text.Plain) - val random = Random.Default install(DefaultHeaders) @@ -44,36 +43,13 @@ fun Application.main() { } get("/db") { - val world = withContext(databaseDispatcher) { - pool.connection.use { connection -> - connection.prepareStatement(WORLD_QUERY).use { statement -> - statement.setInt(1, random.nextInt(DB_ROWS) + 1) - statement.executeQuery().use { rs -> - rs.next() - World(rs.getInt(1), rs.getInt(2)) - } - } - } - } + val world = fetchWorld(pool, databaseDispatcher) call.respondJson(world) } - fun Connection.selectWorlds(queries: Int): Array = - prepareStatement(WORLD_QUERY).use { statement -> - Array(queries) { i -> - statement.setInt(1, random.nextInt(DB_ROWS) + 1) - statement.executeQuery().use { rs -> - rs.next() - World(rs.getInt(1), rs.getInt(2)) - } - } - } - get("/queries") { val queries = call.queries() - val result = withContext(databaseDispatcher) { - pool.connection.use { it.selectWorlds(queries) } - } + val result = fetchWorlds(pool, queries, databaseDispatcher) call.respondJson(result) } @@ -113,20 +89,18 @@ fun Application.main() { get("/updates") { val queries = call.queries() - val result: Array + val result = fetchWorlds(pool, queries, databaseDispatcher) withContext(databaseDispatcher) { pool.connection.use { connection -> - result = connection.selectWorlds(queries) - val updateSql = StringJoiner( ", ", "UPDATE World SET randomNumber = temp.randomNumber FROM (VALUES ", " ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = World.id" ) - for (i in result.indices) { - result[i].randomNumber = random.nextInt(DB_ROWS) + 1 + for (world in result) { + world.randomNumber = ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1) updateSql.add("(?, ?)") } @@ -146,6 +120,46 @@ fun Application.main() { } } +suspend fun fetchWorld( + pool: HikariDataSource, + dispatcher: CoroutineDispatcher +): World = withContext(dispatcher) { + pool.connection.use { connection -> + fetchWorld(connection) + } +} + +private fun fetchWorld(connection: java.sql.Connection): World = + connection.prepareStatement(WORLD_QUERY).use { statement -> + statement.setInt(1, ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1)) + statement.executeQuery().use { rs -> + rs.next() + World(rs.getInt(1), rs.getInt(2)) + } + } + +suspend fun fetchWorlds( + pool: HikariDataSource, + queries: Int, + dispatcher: CoroutineDispatcher +): Array = withContext(dispatcher) { + if (queries <= 0) { + emptyArray() + } else { + pool.connection.use { connection -> + connection.prepareStatement(WORLD_QUERY).use { statement -> + Array(queries) { + statement.setInt(1, ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1)) + statement.executeQuery().use { rs -> + rs.next() + World(rs.getInt(1), rs.getInt(2)) + } + } + } + } + } +} + fun ApplicationCall.queries() = request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 From 865587a1f5df88f98331addd96e84546b46be311 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:50:46 +0100 Subject: [PATCH 108/130] [ruby/rage] Update to 1.17.1 (#10368) --- frameworks/Ruby/rage-sequel/Gemfile | 2 +- frameworks/Ruby/rage-sequel/Gemfile.lock | 8 ++++---- frameworks/Ruby/rage/Gemfile | 2 +- frameworks/Ruby/rage/Gemfile.lock | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/Ruby/rage-sequel/Gemfile b/frameworks/Ruby/rage-sequel/Gemfile index c3d6bfb0968..35b2df23c98 100644 --- a/frameworks/Ruby/rage-sequel/Gemfile +++ b/frameworks/Ruby/rage-sequel/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" -gem "rage-rb", "~> 1.10" +gem "rage-rb", "~> 1.17.0" gem "pg", "~> 1.0" gem 'sequel', '~> 5.0' diff --git a/frameworks/Ruby/rage-sequel/Gemfile.lock b/frameworks/Ruby/rage-sequel/Gemfile.lock index 566a7025400..fb432a9f4d3 100644 --- a/frameworks/Ruby/rage-sequel/Gemfile.lock +++ b/frameworks/Ruby/rage-sequel/Gemfile.lock @@ -8,11 +8,11 @@ GEM rack (2.2.20) rack-test (2.2.0) rack (>= 1.3) - rage-iodine (4.0.0) - rage-rb (1.11.0) + rage-iodine (4.4.0) + rage-rb (1.17.1) rack (~> 2.0) rack-test (~> 2.1) - rage-iodine (~> 4.0) + rage-iodine (~> 4.3) rake (>= 12.0) thor (~> 1.0) zeitwerk (~> 2.6) @@ -32,7 +32,7 @@ PLATFORMS DEPENDENCIES logger pg (~> 1.0) - rage-rb (~> 1.10) + rage-rb (~> 1.17.0) sequel (~> 5.0) sequel_pg (~> 1.6) diff --git a/frameworks/Ruby/rage/Gemfile b/frameworks/Ruby/rage/Gemfile index ad9ccba5aa8..f2a24ddb082 100644 --- a/frameworks/Ruby/rage/Gemfile +++ b/frameworks/Ruby/rage/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" -gem "rage-rb", "~> 1.10" +gem "rage-rb", "~> 1.17.0" gem "pg", "~> 1.0" gem "activerecord", "~> 8.0.0", require: "active_record" diff --git a/frameworks/Ruby/rage/Gemfile.lock b/frameworks/Ruby/rage/Gemfile.lock index d5d524b3192..f0bf4cd1dad 100644 --- a/frameworks/Ruby/rage/Gemfile.lock +++ b/frameworks/Ruby/rage/Gemfile.lock @@ -35,11 +35,11 @@ GEM rack (2.2.18) rack-test (2.2.0) rack (>= 1.3) - rage-iodine (4.0.0) - rage-rb (1.11.0) + rage-iodine (4.4.0) + rage-rb (1.17.1) rack (~> 2.0) rack-test (~> 2.1) - rage-iodine (~> 4.0) + rage-iodine (~> 4.3) rake (>= 12.0) thor (~> 1.0) zeitwerk (~> 2.6) @@ -59,7 +59,7 @@ PLATFORMS DEPENDENCIES activerecord (~> 8.0.0) pg (~> 1.0) - rage-rb (~> 1.10) + rage-rb (~> 1.17.0) BUNDLED WITH 2.7.0 From dcc0ceaa92464338482f9c33371a11d4b3bacb49 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Tue, 9 Dec 2025 01:51:30 +0800 Subject: [PATCH 109/130] [rust/vidi] viz has been renamed to vidi (#10369) --- frameworks/Rust/{viz => vidi}/.gitignore | 0 frameworks/Rust/vidi/Cargo.toml | 47 +++++++ frameworks/Rust/{viz => vidi}/README.md | 4 +- frameworks/Rust/vidi/benchmark_config.json | 47 +++++++ frameworks/Rust/vidi/config.toml | 30 ++++ frameworks/Rust/{viz => vidi}/rustfmt.toml | 0 frameworks/Rust/{viz => vidi}/src/db_pg.rs | 10 +- frameworks/Rust/{viz => vidi}/src/main.rs | 14 +- frameworks/Rust/{viz => vidi}/src/main_pg.rs | 28 ++-- frameworks/Rust/{viz => vidi}/src/models.rs | 0 frameworks/Rust/{viz => vidi}/src/server.rs | 13 +- frameworks/Rust/{viz => vidi}/src/utils.rs | 0 .../Rust/{viz => vidi}/templates/fortune.hbs | 0 .../Rust/{viz => vidi}/templates/fortune.html | 0 .../Rust/{viz => vidi}/templates/fortune.stpl | 0 frameworks/Rust/vidi/vidi-pg.dockerfile | 11 ++ .../viz.dockerfile => vidi/vidi.dockerfile} | 10 +- frameworks/Rust/viz/Cargo.toml | 72 ---------- frameworks/Rust/viz/benchmark_config.json | 89 ------------ frameworks/Rust/viz/config.toml | 60 -------- frameworks/Rust/viz/src/db_diesel.rs | 120 ---------------- frameworks/Rust/viz/src/db_sqlx.rs | 119 ---------------- frameworks/Rust/viz/src/main_diesel.rs | 104 -------------- frameworks/Rust/viz/src/main_sqlx.rs | 129 ------------------ frameworks/Rust/viz/src/models_diesel.rs | 28 ---- frameworks/Rust/viz/src/models_sqlx.rs | 14 -- frameworks/Rust/viz/src/schema.rs | 13 -- frameworks/Rust/viz/viz-diesel.dockerfile | 11 -- frameworks/Rust/viz/viz-pg.dockerfile | 11 -- frameworks/Rust/viz/viz-sqlx.dockerfile | 11 -- 30 files changed, 174 insertions(+), 821 deletions(-) rename frameworks/Rust/{viz => vidi}/.gitignore (100%) create mode 100644 frameworks/Rust/vidi/Cargo.toml rename frameworks/Rust/{viz => vidi}/README.md (55%) create mode 100755 frameworks/Rust/vidi/benchmark_config.json create mode 100644 frameworks/Rust/vidi/config.toml rename frameworks/Rust/{viz => vidi}/rustfmt.toml (100%) rename frameworks/Rust/{viz => vidi}/src/db_pg.rs (93%) rename frameworks/Rust/{viz => vidi}/src/main.rs (75%) rename frameworks/Rust/{viz => vidi}/src/main_pg.rs (70%) rename frameworks/Rust/{viz => vidi}/src/models.rs (100%) rename frameworks/Rust/{viz => vidi}/src/server.rs (84%) rename frameworks/Rust/{viz => vidi}/src/utils.rs (100%) rename frameworks/Rust/{viz => vidi}/templates/fortune.hbs (100%) rename frameworks/Rust/{viz => vidi}/templates/fortune.html (100%) rename frameworks/Rust/{viz => vidi}/templates/fortune.stpl (100%) create mode 100644 frameworks/Rust/vidi/vidi-pg.dockerfile rename frameworks/Rust/{viz/viz.dockerfile => vidi/vidi.dockerfile} (56%) delete mode 100644 frameworks/Rust/viz/Cargo.toml delete mode 100755 frameworks/Rust/viz/benchmark_config.json delete mode 100644 frameworks/Rust/viz/config.toml delete mode 100644 frameworks/Rust/viz/src/db_diesel.rs delete mode 100644 frameworks/Rust/viz/src/db_sqlx.rs delete mode 100644 frameworks/Rust/viz/src/main_diesel.rs delete mode 100644 frameworks/Rust/viz/src/main_sqlx.rs delete mode 100644 frameworks/Rust/viz/src/models_diesel.rs delete mode 100644 frameworks/Rust/viz/src/models_sqlx.rs delete mode 100644 frameworks/Rust/viz/src/schema.rs delete mode 100644 frameworks/Rust/viz/viz-diesel.dockerfile delete mode 100644 frameworks/Rust/viz/viz-pg.dockerfile delete mode 100644 frameworks/Rust/viz/viz-sqlx.dockerfile diff --git a/frameworks/Rust/viz/.gitignore b/frameworks/Rust/vidi/.gitignore similarity index 100% rename from frameworks/Rust/viz/.gitignore rename to frameworks/Rust/vidi/.gitignore diff --git a/frameworks/Rust/vidi/Cargo.toml b/frameworks/Rust/vidi/Cargo.toml new file mode 100644 index 00000000000..c3ea4dc571a --- /dev/null +++ b/frameworks/Rust/vidi/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "vidi" +version = "0.1.0" +edition = "2024" +publish = false +authors = ["Fangdun Tsai "] + +[[bin]] +name = "vidi" +path = "src/main.rs" + +[[bin]] +name = "vidi-pg" +path = "src/main_pg.rs" +required-features = ["tokio-postgres", "yarte"] + +[dependencies] +vidi = "0.1" +hyper = "1.0" +hyper-util = "0.1" +http-body-util = "0.1" +atoi = "2.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1" +mime = "0.3" +rand = { version = "0.9", features = ["small_rng"] } +thiserror = "2.0" +futures-util = "0.3" +socket2 = { version = "0.6.0", features = ["all"] } +num_cpus = "1.0" + +[target.'cfg(not(unix))'.dependencies] +nanorand = { version = "0.8" } + +[target.'cfg(unix)'.dependencies] +nanorand = { version = "0.8", features = ["getrandom"] } + +tokio = { version = "1", features = ["full"] } +tokio-postgres = { version = "0.7", optional = true } + +yarte = { version = "0.15", features = ["bytes-buf", "json"], optional = true } + +[profile.release] +lto = true +codegen-units = 1 +strip = true +opt-level = 3 diff --git a/frameworks/Rust/viz/README.md b/frameworks/Rust/vidi/README.md similarity index 55% rename from frameworks/Rust/viz/README.md rename to frameworks/Rust/vidi/README.md index 84c2be44a52..2a5575441eb 100644 --- a/frameworks/Rust/viz/README.md +++ b/frameworks/Rust/vidi/README.md @@ -1,5 +1,7 @@ -# [viz](https://github.com/viz-rs) web framework +# [vidi] web framework ## Description Fast, robust, flexible, lightweight web framework for Rust. + +[vidi]: https://github.com/viz-rs/vidi diff --git a/frameworks/Rust/vidi/benchmark_config.json b/frameworks/Rust/vidi/benchmark_config.json new file mode 100755 index 00000000000..9b5755ae71f --- /dev/null +++ b/frameworks/Rust/vidi/benchmark_config.json @@ -0,0 +1,47 @@ +{ + "framework": "vidi", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "none", + "framework": "Vidi", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "Vidi", + "notes": "", + "versus": "None" + }, + "pg": { + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Vidi", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "Vidi [Postgresql]", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/vidi/config.toml b/frameworks/Rust/vidi/config.toml new file mode 100644 index 00000000000..187fb23966a --- /dev/null +++ b/frameworks/Rust/vidi/config.toml @@ -0,0 +1,30 @@ +[framework] +name = "vidi" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "vidi" +versus = "" + +[pg] +urls.db = "/db" +urls.query = "/queries?q=" +urls.update = "/updates?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "vidi" +versus = "" diff --git a/frameworks/Rust/viz/rustfmt.toml b/frameworks/Rust/vidi/rustfmt.toml similarity index 100% rename from frameworks/Rust/viz/rustfmt.toml rename to frameworks/Rust/vidi/rustfmt.toml diff --git a/frameworks/Rust/viz/src/db_pg.rs b/frameworks/Rust/vidi/src/db_pg.rs similarity index 93% rename from frameworks/Rust/viz/src/db_pg.rs rename to frameworks/Rust/vidi/src/db_pg.rs index da7a5a0be5f..b307df01e81 100644 --- a/frameworks/Rust/viz/src/db_pg.rs +++ b/frameworks/Rust/vidi/src/db_pg.rs @@ -1,10 +1,10 @@ use std::{collections::HashMap, fmt::Write, io, sync::Arc}; -use futures_util::{stream::FuturesUnordered, StreamExt, TryFutureExt, TryStreamExt}; -use rand::{rng, rngs::SmallRng, Rng, SeedableRng}; +use futures_util::{StreamExt, TryFutureExt, TryStreamExt, stream::FuturesUnordered}; +use rand::{Rng, SeedableRng, rng, rngs::SmallRng}; use tokio::pin; -use tokio_postgres::{connect, types::ToSql, Client, NoTls, Statement}; -use viz::{Error, IntoResponse, Response, StatusCode}; +use tokio_postgres::{Client, NoTls, Statement, connect, types::ToSql}; +use vidi::{Error, IntoResponse, Response, StatusCode}; use crate::models::{Fortune, World}; @@ -21,7 +21,7 @@ pub enum PgError { impl From for Error { fn from(e: PgError) -> Self { - Error::Responder(e.into_response()) + Error::Responder(Box::new(e.into_response())) } } diff --git a/frameworks/Rust/viz/src/main.rs b/frameworks/Rust/vidi/src/main.rs similarity index 75% rename from frameworks/Rust/viz/src/main.rs rename to frameworks/Rust/vidi/src/main.rs index 3552b23920c..179badbf0d2 100644 --- a/frameworks/Rust/viz/src/main.rs +++ b/frameworks/Rust/vidi/src/main.rs @@ -1,9 +1,9 @@ #![allow(clippy::unused_async)] use serde::Serialize; -use viz::{ - header::{HeaderValue, CONTENT_TYPE, SERVER}, +use vidi::{ Bytes, Request, Response, ResponseExt, Result, Router, + header::{CONTENT_TYPE, HeaderValue}, }; mod server; @@ -14,12 +14,11 @@ struct Message { message: &'static str, } +const HELLO_WORLD: &str = "Hello, World!"; + #[inline(always)] async fn plaintext(_: Request) -> Result { - let mut res = Response::text("Hello, World!"); - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) + Ok(Response::text(HELLO_WORLD)) } #[inline(always)] @@ -28,7 +27,7 @@ async fn json(_: Request) -> Result { .body( http_body_util::Full::new(Bytes::from( serde_json::to_vec(&Message { - message: "Hello, World!", + message: HELLO_WORLD, }) .unwrap(), )) @@ -36,7 +35,6 @@ async fn json(_: Request) -> Result { ) .unwrap(); let headers = res.headers_mut(); - headers.insert(SERVER, HeaderValue::from_static("Viz")); headers.insert( CONTENT_TYPE, HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), diff --git a/frameworks/Rust/viz/src/main_pg.rs b/frameworks/Rust/vidi/src/main_pg.rs similarity index 70% rename from frameworks/Rust/viz/src/main_pg.rs rename to frameworks/Rust/vidi/src/main_pg.rs index 4898ca8f24a..553d4805a1f 100644 --- a/frameworks/Rust/viz/src/main_pg.rs +++ b/frameworks/Rust/vidi/src/main_pg.rs @@ -1,10 +1,6 @@ use std::sync::Arc; -use viz::{ - header::{HeaderValue, SERVER}, - types::State, - Request, RequestExt, Response, ResponseExt, Result, Router, -}; +use vidi::{Request, RequestExt, Response, ResponseExt, Result, Router, types::State}; use yarte::Template; mod db_pg; @@ -12,7 +8,7 @@ mod models; mod server; mod utils; -use db_pg::{get_conn, PgConnection}; +use db_pg::{PgConnection, get_conn}; #[derive(Template)] #[template(path = "fortune.hbs")] @@ -28,9 +24,8 @@ async fn db(req: Request) -> Result { let world = conn.get_world().await?; - let mut res = Response::json(world)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); + let res = Response::json(world)?; + Ok(res) } @@ -43,10 +38,7 @@ async fn fortunes(req: Request) -> Result { .call() .expect("error rendering template"); - let mut res = Response::html(buf); - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) + Ok(Response::html(buf)) } async fn queries(req: Request) -> Result { @@ -55,9 +47,8 @@ async fn queries(req: Request) -> Result { let worlds = conn.get_worlds(count).await?; - let mut res = Response::json(worlds)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); + let res = Response::json(worlds)?; + Ok(res) } @@ -67,9 +58,8 @@ async fn updates(req: Request) -> Result { let worlds = conn.update(count).await?; - let mut res = Response::json(worlds)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); + let res = Response::json(worlds)?; + Ok(res) } diff --git a/frameworks/Rust/viz/src/models.rs b/frameworks/Rust/vidi/src/models.rs similarity index 100% rename from frameworks/Rust/viz/src/models.rs rename to frameworks/Rust/vidi/src/models.rs diff --git a/frameworks/Rust/viz/src/server.rs b/frameworks/Rust/vidi/src/server.rs similarity index 84% rename from frameworks/Rust/viz/src/server.rs rename to frameworks/Rust/vidi/src/server.rs index 047da0ba88a..69b12b7b595 100644 --- a/frameworks/Rust/viz/src/server.rs +++ b/frameworks/Rust/vidi/src/server.rs @@ -9,19 +9,28 @@ use hyper::server::conn::http1::Builder; use hyper_util::rt::TokioIo; use socket2::{Domain, SockAddr, Socket}; use tokio::{net::TcpListener, runtime}; -use viz::{Responder, Router, Tree}; +use vidi::header::{HeaderValue, SERVER}; +use vidi::{HandlerExt, Responder, Response, Router, Tree}; pub async fn serve(router: Router) -> Result<(), Box> { let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 8080)); let socket = create_socket(addr).expect("couldn't bind to addr"); let listener = TcpListener::from_std(socket.into())?; + let router = router.map_handler(|h| { + h.map(|mut res: Response| { + let headers = res.headers_mut(); + headers.insert(SERVER, HeaderValue::from_static("Vidi")); + res + }) + .boxed() + }); let tree = Arc::::new(router.into()); let mut http = Builder::new(); http.pipeline_flush(true); - println!("Started viz server at 8080"); + println!("Started vidi server at 8080"); loop { let (tcp, _) = listener.accept().await?; diff --git a/frameworks/Rust/viz/src/utils.rs b/frameworks/Rust/vidi/src/utils.rs similarity index 100% rename from frameworks/Rust/viz/src/utils.rs rename to frameworks/Rust/vidi/src/utils.rs diff --git a/frameworks/Rust/viz/templates/fortune.hbs b/frameworks/Rust/vidi/templates/fortune.hbs similarity index 100% rename from frameworks/Rust/viz/templates/fortune.hbs rename to frameworks/Rust/vidi/templates/fortune.hbs diff --git a/frameworks/Rust/viz/templates/fortune.html b/frameworks/Rust/vidi/templates/fortune.html similarity index 100% rename from frameworks/Rust/viz/templates/fortune.html rename to frameworks/Rust/vidi/templates/fortune.html diff --git a/frameworks/Rust/viz/templates/fortune.stpl b/frameworks/Rust/vidi/templates/fortune.stpl similarity index 100% rename from frameworks/Rust/viz/templates/fortune.stpl rename to frameworks/Rust/vidi/templates/fortune.stpl diff --git a/frameworks/Rust/vidi/vidi-pg.dockerfile b/frameworks/Rust/vidi/vidi-pg.dockerfile new file mode 100644 index 00000000000..4b4af96db76 --- /dev/null +++ b/frameworks/Rust/vidi/vidi-pg.dockerfile @@ -0,0 +1,11 @@ +FROM rust:1.91 + +ADD ./ /vidi +WORKDIR /vidi + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin vidi-pg --features="tokio-postgres,yarte" + +EXPOSE 8080 + +CMD ./target/release/vidi-pg diff --git a/frameworks/Rust/viz/viz.dockerfile b/frameworks/Rust/vidi/vidi.dockerfile similarity index 56% rename from frameworks/Rust/viz/viz.dockerfile rename to frameworks/Rust/vidi/vidi.dockerfile index bf5102b2bec..cecc153db93 100644 --- a/frameworks/Rust/viz/viz.dockerfile +++ b/frameworks/Rust/vidi/vidi.dockerfile @@ -1,11 +1,11 @@ -FROM rust:1.89 +FROM rust:1.91 -ADD ./ /viz -WORKDIR /viz +ADD ./ /vidi +WORKDIR /vidi RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin viz +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin vidi EXPOSE 8080 -CMD ./target/release/viz +CMD ./target/release/vidi diff --git a/frameworks/Rust/viz/Cargo.toml b/frameworks/Rust/viz/Cargo.toml deleted file mode 100644 index 7047dbe3666..00000000000 --- a/frameworks/Rust/viz/Cargo.toml +++ /dev/null @@ -1,72 +0,0 @@ -[package] -name = "viz" -version = "0.1.0" -edition = "2021" -authors = ["Fangdun Tsai "] - -[[bin]] -name = "viz" -path = "src/main.rs" - -[[bin]] -name = "viz-pg" -path = "src/main_pg.rs" -required-features = ["tokio-postgres", "yarte"] - -[[bin]] -name = "viz-sqlx" -path = "src/main_sqlx.rs" -required-features = ["sqlx", "markup", "v_htmlescape"] - -[[bin]] -name = "viz-diesel" -path = "src/main_diesel.rs" -required-features = ["diesel", "diesel-async", "sailfish"] - -[dependencies] -viz = "0.10" -hyper = "1.0" -hyper-util = "0.1" -http-body-util = "0.1" -atoi = "2.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1" -mime = "0.3" -rand = { version = "0.9", features = ["small_rng"] } -thiserror = "2.0" -futures-util = "0.3" -socket2 = { version = "0.6.0", features = ["all"] } -num_cpus = "1.16.0" - -[target.'cfg(not(unix))'.dependencies] -nanorand = { version = "0.8" } - -[target.'cfg(unix)'.dependencies] -nanorand = { version = "0.8", features = ["getrandom"] } - -tokio = { version = "1", features = ["full"] } -tokio-postgres = { version = "0.7", optional = true } -sqlx = { version = "0.8", features = [ - "postgres", - "macros", - "runtime-tokio", - "tls-native-tls", -], optional = true } -diesel = { version = "2.2", default-features = false, features = [ - "i-implement-a-third-party-backend-and-opt-into-breaking-changes", -], optional = true } -diesel-async = { version = "0.6", default-features = false, features = [ - "postgres", - "bb8", -], optional = true } - -yarte = { version = "0.15", features = ["bytes-buf", "json"], optional = true } -markup = { version = "0.15", optional = true } -v_htmlescape = { version = "0.15", optional = true } -sailfish = { version = "0.10", optional = true } - -[profile.release] -lto = true -codegen-units = 1 -strip = true -opt-level = 3 diff --git a/frameworks/Rust/viz/benchmark_config.json b/frameworks/Rust/viz/benchmark_config.json deleted file mode 100755 index 94a26df121e..00000000000 --- a/frameworks/Rust/viz/benchmark_config.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "framework": "viz", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "none", - "framework": "Viz", - "language": "Rust", - "flavor": "None", - "orm": "Raw", - "platform": "Rust", - "webserver": "Hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Viz", - "notes": "", - "versus": "None" - }, - "pg": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "Viz", - "language": "Rust", - "flavor": "None", - "orm": "Raw", - "platform": "Rust", - "webserver": "Hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Viz [Postgresql]", - "notes": "", - "versus": "None" - }, - "sqlx": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "Viz", - "language": "Rust", - "flavor": "None", - "orm": "Raw", - "platform": "Rust", - "webserver": "Hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Viz [Postgresql - SQLx]", - "notes": "", - "versus": "None" - }, - "diesel": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "Viz", - "language": "Rust", - "flavor": "None", - "orm": "Full", - "platform": "Rust", - "webserver": "Hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Viz [Postgresql - Diesel]", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Rust/viz/config.toml b/frameworks/Rust/viz/config.toml deleted file mode 100644 index b8b2bfb6bda..00000000000 --- a/frameworks/Rust/viz/config.toml +++ /dev/null @@ -1,60 +0,0 @@ -[framework] -name = "viz" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "viz" -versus = "" - -[pg] -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "viz" -versus = "" - -[sqlx] -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "viz" -versus = "" - -[diesel] -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "None" -webserver = "viz" -versus = "" diff --git a/frameworks/Rust/viz/src/db_diesel.rs b/frameworks/Rust/viz/src/db_diesel.rs deleted file mode 100644 index 624000a7d1d..00000000000 --- a/frameworks/Rust/viz/src/db_diesel.rs +++ /dev/null @@ -1,120 +0,0 @@ -use diesel::prelude::*; -use diesel_async::{ - pooled_connection::bb8::{Pool, RunError}, - AsyncPgConnection, RunQueryDsl, -}; -use nanorand::{Rng, WyRand}; -use sailfish::{RenderError, TemplateOnce}; -use viz::{Error, IntoResponse, Response, StatusCode}; - -use crate::models_diesel::*; -use crate::schema::*; -use crate::RANGE; - -/// Postgres Error -#[derive(Debug, thiserror::Error)] -pub enum PgError { - #[error("missing pool")] - Missing, - #[error(transparent)] - DieselError(#[from] diesel::result::Error), - #[error(transparent)] - PoolError(#[from] RunError), - #[error(transparent)] - RenderError(#[from] RenderError), -} - -impl From for Error { - fn from(e: PgError) -> Self { - Error::Responder(e.into_response()) - } -} - -impl IntoResponse for PgError { - fn into_response(self) -> Response { - (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response() - } -} - -async fn _get_world(conn: &mut AsyncPgConnection, id: i32) -> Result { - let world = world::table.find(id).first(conn).await?; - Ok(world) -} - -pub async fn get_world( - pool: Pool, - id: i32, -) -> Result { - let mut conn = pool.get().await?; - _get_world(&mut conn, id).await -} - -pub async fn get_worlds( - pool: Pool, - mut rng: WyRand, - count: u16, -) -> Result, PgError> { - let mut conn = pool.get().await?; - - let mut worlds = Vec::::with_capacity(count as usize); - - for _ in 0..count { - let id = rng.generate_range(RANGE); - let w = _get_world(&mut conn, id).await?; - worlds.push(w); - } - - Ok(worlds) -} - -pub async fn update_worlds( - pool: Pool, - mut rng: WyRand, - count: u16, -) -> Result, PgError> { - let mut conn = pool.get().await?; - - let mut worlds = Vec::::with_capacity(count as usize); - - for _ in 0..count { - let id = rng.generate_range(RANGE); - let rid = rng.generate_range(RANGE); - let mut w = _get_world(&mut conn, id).await?; - w.randomnumber = rid; - worlds.push(w); - } - - worlds.sort_by_key(|w| w.id); - - conn.build_transaction() - .run(move |conn| { - Box::pin(async move { - for w in &worlds { - diesel::update(world::table) - .filter(world::id.eq(w.id)) - .set(world::randomnumber.eq(w.randomnumber)) - .execute(conn) - .await?; - } - - Ok::<_, PgError>(worlds) - }) - }) - .await -} - -pub async fn tell_fortune(pool: Pool) -> Result { - let mut conn = pool.get().await?; - - let mut items = fortune::table.load::(&mut conn).await?; - - items.push(Fortune { - id: 0, - message: "Additional fortune added at request time.".to_string(), - }); - items.sort_by(|it, next| it.message.cmp(&next.message)); - - let html = Fortunes::new(items).render_once()?; - - Ok(html) -} diff --git a/frameworks/Rust/viz/src/db_sqlx.rs b/frameworks/Rust/viz/src/db_sqlx.rs deleted file mode 100644 index 40c39290265..00000000000 --- a/frameworks/Rust/viz/src/db_sqlx.rs +++ /dev/null @@ -1,119 +0,0 @@ -use nanorand::{Rng, WyRand}; - -pub use sqlx::{ - pool::PoolConnection, - postgres::{PgArguments, PgPoolOptions, PgRow}, - Arguments, PgPool, Postgres, Row, -}; - -use viz::{Error, FromRequest, IntoResponse, Request, RequestExt, Response, StatusCode}; - -use crate::models_sqlx::*; -use crate::utils::get_query_param; -use crate::RANGE; - -pub struct DatabaseConnection(pub PoolConnection); - -impl FromRequest for DatabaseConnection { - type Error = PgError; - - async fn extract(req: &mut Request) -> Result { - req.state::() - .ok_or(PgError(sqlx::Error::Io(std::io::Error::from( - std::io::ErrorKind::NotConnected, - ))))? - .acquire() - .await - .map(Self) - .map_err(PgError) - } -} - -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct PgError(#[from] pub sqlx::Error); - -impl From for Error { - fn from(e: PgError) -> Self { - Error::Responder(e.into_response()) - } -} - -impl IntoResponse for PgError { - fn into_response(self) -> Response { - (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response() - } -} - -pub struct Counter(pub u16); - -impl FromRequest for Counter { - type Error = Error; - - async fn extract(req: &mut Request) -> Result { - Ok(Counter(get_query_param(req.query_string()))) - } -} - -pub async fn get_world( - conn: &mut PoolConnection, - id: i32, -) -> Result { - let mut args = PgArguments::default(); - let _ = args.add(id); - - let world = - sqlx::query_as_with("SELECT id, randomnumber FROM World WHERE id = $1", args) - .fetch_one(&mut **conn) - .await?; - Ok(world) -} - -pub async fn update_worlds( - mut conn: PoolConnection, - mut rng: WyRand, - count: u16, -) -> Result, PgError> { - let mut worlds = Vec::::with_capacity(count as usize); - - for _ in 0..count { - let id = rng.generate_range(RANGE); - let rid = rng.generate_range(RANGE); - let mut w = get_world(&mut conn, id).await?; - w.randomnumber = rid; - worlds.push(w); - } - - for w in &worlds { - let mut args = PgArguments::default(); - let _ = args.add(w.randomnumber); - let _ = args.add(w.id); - - sqlx::query_with("UPDATE World SET randomNumber = $1 WHERE id = $2", args) - .execute(&mut *conn) - .await?; - } - - Ok(worlds) -} - -pub async fn get_fortunes( - mut conn: PoolConnection, -) -> Result, PgError> { - let mut items = sqlx::query("SELECT * FROM Fortune") - .map(|row: PgRow| Fortune { - id: row.get(0), - message: row.get(1), - }) - .fetch_all(&mut *conn) - .await?; - - items.push(Fortune { - id: 0, - message: "Additional fortune added at request time.".to_string(), - }); - - items.sort_by(|it, next| it.message.cmp(&next.message)); - - Ok(items) -} diff --git a/frameworks/Rust/viz/src/main_diesel.rs b/frameworks/Rust/viz/src/main_diesel.rs deleted file mode 100644 index ec3a002c2a7..00000000000 --- a/frameworks/Rust/viz/src/main_diesel.rs +++ /dev/null @@ -1,104 +0,0 @@ -#[macro_use] -extern crate diesel; - -use std::thread::available_parallelism; - -use diesel_async::{ - pooled_connection::{bb8::Pool, AsyncDieselConnectionManager}, - AsyncPgConnection, -}; -use nanorand::{Rng, WyRand}; -use viz::{ - header::{HeaderValue, SERVER}, - types::State, - Request, RequestExt, Response, ResponseExt, Result, Router, -}; - -mod db_diesel; -pub mod models_diesel; -pub mod schema; -mod server; -mod utils; - -use db_diesel::*; -use utils::RANGE; - -const DB_URL: &str = - "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - -async fn db(req: Request) -> Result { - let mut rng = req.state::().unwrap(); - let pool = req.state::>().unwrap(); - - let random_id = rng.generate_range(RANGE); - - let world = get_world(pool, random_id).await?; - - let mut res = Response::json(world)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn fortunes(req: Request) -> Result { - let pool = req.state::>().unwrap(); - - let fortunes = tell_fortune(pool).await?; - - let mut res = Response::html(fortunes); - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn queries(req: Request) -> Result { - let rng = req.state::().unwrap(); - let pool = req.state::>().unwrap(); - let count = utils::get_query_param(req.query_string()); - - let worlds = get_worlds(pool, rng, count).await?; - - let mut res = Response::json(worlds)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn updates(req: Request) -> Result { - let rng = req.state::().unwrap(); - let pool = req.state::>().unwrap(); - let count = utils::get_query_param(req.query_string()); - - let worlds = update_worlds(pool, rng, count).await?; - - let mut res = Response::json(worlds)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn app() { - let max = available_parallelism().map(|n| n.get()).unwrap_or(16) as u32; - - let pool = Pool::::builder() - .max_size(max) - .min_idle(Some(max)) - .idle_timeout(None) - .build_unchecked(AsyncDieselConnectionManager::new(DB_URL)); - - let rng = WyRand::new(); - - let app = Router::new() - .get("/db", db) - .get("/fortunes", fortunes) - .get("/queries", queries) - .get("/updates", updates) - .with(State::new(pool)) - .with(State::new(rng)); - - server::serve(app).await.unwrap() -} - -fn main() { - server::run(app) -} diff --git a/frameworks/Rust/viz/src/main_sqlx.rs b/frameworks/Rust/viz/src/main_sqlx.rs deleted file mode 100644 index e2aff0ff98f..00000000000 --- a/frameworks/Rust/viz/src/main_sqlx.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::thread::available_parallelism; - -use nanorand::{Rng, WyRand}; -use viz::{ - header::{HeaderValue, SERVER}, - types::State, - BytesMut, Error, Request, RequestExt, Response, ResponseExt, Result, Router, -}; - -mod db_sqlx; -mod models_sqlx; -mod server; -mod utils; - -use db_sqlx::*; -use models_sqlx::{Fortune, World}; -use utils::RANGE; - -const DB_URL: &str = - "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - -async fn db(mut req: Request) -> Result { - let (State(mut rng), DatabaseConnection(mut conn)) = - req.extract::<(State, DatabaseConnection)>().await?; - - let random_id = rng.generate_range(RANGE); - - let world = get_world(&mut conn, random_id).await?; - - let mut res = Response::json(world)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn fortunes(mut req: Request) -> Result { - let DatabaseConnection(conn) = req.extract::().await?; - - let items = get_fortunes(conn).await?; - - let mut buf = BytesMut::with_capacity(2048); - buf.extend(FortunesTemplate { items }.to_string().as_bytes()); - - let mut res = Response::html(buf.freeze()); - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn queries(mut req: Request) -> Result { - let (Counter(count), State(mut rng), DatabaseConnection(mut conn)) = req - .extract::<(Counter, State, DatabaseConnection)>() - .await?; - - let mut worlds = Vec::::with_capacity(count as usize); - - for _ in 0..count { - let id = rng.generate_range(RANGE); - let w = get_world(&mut conn, id).await?; - worlds.push(w); - } - - let mut res = Response::json(worlds)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn updates(mut req: Request) -> Result { - let (Counter(count), State(rng), DatabaseConnection(conn)) = req - .extract::<(Counter, State, DatabaseConnection)>() - .await?; - - let worlds = update_worlds(conn, rng, count).await?; - - let mut res = Response::json(worlds)?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); - Ok(res) -} - -async fn app() -> Result<()> { - let max = available_parallelism().map(|n| n.get()).unwrap_or(16) as u32; - - let pool = PgPoolOptions::new() - .max_connections(max) - .min_connections(max) - .connect(DB_URL) - .await - .map_err(PgError)?; - - let rng = WyRand::new(); - - let app = Router::new() - .get("/db", db) - .get("/fortunes", fortunes) - .get("/queries", queries) - .get("/updates", updates) - .with(State::new(pool)) - .with(State::new(rng)); - - server::serve(app).await.map_err(Error::Boxed) -} - -fn main() { - server::run(app) -} - -markup::define! { - FortunesTemplate(items: Vec) { - {markup::doctype()} - html { - head { - title { "Fortunes" } - } - body { - table { - tr { th { "id" } th { "message" } } - @for item in items { - tr { - td { {item.id} } - td { {markup::raw(v_htmlescape::escape(&item.message).to_string())} } - } - } - } - } - } - } -} diff --git a/frameworks/Rust/viz/src/models_diesel.rs b/frameworks/Rust/viz/src/models_diesel.rs deleted file mode 100644 index 63711594223..00000000000 --- a/frameworks/Rust/viz/src/models_diesel.rs +++ /dev/null @@ -1,28 +0,0 @@ -use diesel::Queryable; -use sailfish::TemplateOnce; -use serde::Serialize; - -#[derive(Serialize, Queryable, Debug)] -pub struct World { - pub id: i32, - pub randomnumber: i32, -} - -#[derive(Serialize, Queryable, Debug)] -pub struct Fortune { - pub id: i32, - pub message: String, -} - -#[derive(TemplateOnce)] -#[template(path = "fortune.stpl", rm_whitespace = true)] -pub struct Fortunes { - items: Vec, -} - -impl Fortunes { - #[inline] - pub fn new(items: Vec) -> Self { - Self { items } - } -} diff --git a/frameworks/Rust/viz/src/models_sqlx.rs b/frameworks/Rust/viz/src/models_sqlx.rs deleted file mode 100644 index 2f3657a9936..00000000000 --- a/frameworks/Rust/viz/src/models_sqlx.rs +++ /dev/null @@ -1,14 +0,0 @@ -use serde::{Deserialize, Serialize}; -use sqlx::FromRow; - -#[derive(Debug, PartialEq, Deserialize, Serialize, FromRow)] -pub struct World { - pub id: i32, - pub randomnumber: i32, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize, FromRow)] -pub struct Fortune { - pub id: i32, - pub message: String, -} diff --git a/frameworks/Rust/viz/src/schema.rs b/frameworks/Rust/viz/src/schema.rs deleted file mode 100644 index 30b1bfeb7fc..00000000000 --- a/frameworks/Rust/viz/src/schema.rs +++ /dev/null @@ -1,13 +0,0 @@ -table! { - world (id) { - id -> Integer, - randomnumber -> Integer, - } -} - -table! { - fortune (id) { - id -> Integer, - message -> Text, - } -} diff --git a/frameworks/Rust/viz/viz-diesel.dockerfile b/frameworks/Rust/viz/viz-diesel.dockerfile deleted file mode 100644 index 4d10b67baa1..00000000000 --- a/frameworks/Rust/viz/viz-diesel.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.89 - -ADD ./ /viz -WORKDIR /viz - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin viz-diesel --features="diesel,diesel-async,sailfish" - -EXPOSE 8080 - -CMD ./target/release/viz-diesel diff --git a/frameworks/Rust/viz/viz-pg.dockerfile b/frameworks/Rust/viz/viz-pg.dockerfile deleted file mode 100644 index 23bc34e49c3..00000000000 --- a/frameworks/Rust/viz/viz-pg.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.89 - -ADD ./ /viz -WORKDIR /viz - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin viz-pg --features="tokio-postgres,yarte" - -EXPOSE 8080 - -CMD ./target/release/viz-pg diff --git a/frameworks/Rust/viz/viz-sqlx.dockerfile b/frameworks/Rust/viz/viz-sqlx.dockerfile deleted file mode 100644 index c9a7685855f..00000000000 --- a/frameworks/Rust/viz/viz-sqlx.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.89 - -ADD ./ /viz -WORKDIR /viz - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin viz-sqlx --features="sqlx,markup,v_htmlescape" - -EXPOSE 8080 - -CMD ./target/release/viz-sqlx From bfe549e3354741a420264edab869ba6082e20c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=A4=E9=9B=A8=E4=B8=9C?= Date: Tue, 9 Dec 2025 01:51:58 +0800 Subject: [PATCH 110/130] Update Hyperlane (#10370) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: inline * feat: dockerfile * feat: v4.52.1 * feat: remove key * remove: log * remove: log * feat: async * remove: empty loop * feat: utf8 * change: pool_size * remove: utf8 * feat: log * feat: log * feat: v3.14.1 * feat: 4.56.3 * feat: 4.56.4 * feat: 4.56.5 * feat: rename * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: speed * feat: speed * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * feat: runtime * feat: runtime * feat: runtime * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * lock: toml * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: hyperlane * feat: update * docs: readme * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: lock * feat: use super * feat: update lock * feat: update * feat: update lock * feat: update lock * feat: update lock * feat: lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * feat: update lock * Merge remote-tracking branch 'upstream/master' * feat: update * feat: utf8 * feat: utf8 * feat: lock * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * update: code * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * Merge remote-tracking branch 'upstream/master' * feat: update version * feat: update version * update: code * Merge remote-tracking branch 'upstream/master' * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: lock * feat: error handle * feat: dep * feat: get_thread_count * update: code * feat: lock * feat: speed * feat: speed * update: code * feat: speed * update: code * feat: lock * fix: Framework hyperlane does not define a default test in benchmark_config.json * feat: hyperlane http version * feat: hyperlane http version * feat: toml * feat: toml * feat: toml * feat: toml * feat: v0.1.0 * feat: toml * feat: v6 * feat: v6 * feat: v6 * feat: v6 * feat: v6 * debug: test cache * debug: test cache * feat: v6 * feat: send unwrap * feat: v6 * feat: v6 * feat: v0.1.0 * feat: toml * feat: toml * feat: db * feat: toml * feat: toml * feat: toml * feat: toml * feat: dir update * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: 2025-10-24 12:22:32 * feat: v0.1.0 * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: v0.1.0 * Merge branch 'master' of github.com:TechEmpower/FrameworkBenchmarks * feat: 2025-11-09 18:38:22 * feat: toml * feat: toml * feat: buffer * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml * feat: toml --------- Co-authored-by: 尤雨东 <83822098+ltpp-universe@users.noreply.github.com> --- frameworks/Rust/hyperlane/Cargo.lock | 12 ++++++------ frameworks/Rust/hyperlane/Cargo.toml | 2 +- frameworks/Rust/hyperlane/src/db/fn.rs | 11 +++++++---- frameworks/Rust/hyperlane/src/main.rs | 5 +---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frameworks/Rust/hyperlane/Cargo.lock b/frameworks/Rust/hyperlane/Cargo.lock index 2f2555e7d0e..9b9082f85bb 100644 --- a/frameworks/Rust/hyperlane/Cargo.lock +++ b/frameworks/Rust/hyperlane/Cargo.lock @@ -525,15 +525,15 @@ dependencies = [ [[package]] name = "http-constant" -version = "1.72.1" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353963e842122ef31dd4a109444c59b28077852ca41717ebe643e4b70b116838" +checksum = "7886400d92b0eb2db84097de69ed4649ca9466f4c6b4e8cb342a3b46934a8d43" [[package]] name = "http-type" -version = "5.10.1" +version = "5.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c268b9b4b2784ef04e3725a037c187d2ae16ef65d745f03324142b39d2a83c4" +checksum = "b27d55be58ea8bc2ab73573aeafa68fd50b3098813f83029bcb766f1f1c61b3b" dependencies = [ "hex", "http-compress", @@ -549,9 +549,9 @@ dependencies = [ [[package]] name = "hyperlane" -version = "10.13.1" +version = "10.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1e64ffb83f03e3c760d206f2ac3fd4a8d799da970db25b76c10813db26f25e" +checksum = "6abaa8b50397c4a9d2d0d969ccba9cecdad7bf0fa75c7da0335d6895c3d0ce98" dependencies = [ "aho-corasick", "http-type", diff --git a/frameworks/Rust/hyperlane/Cargo.toml b/frameworks/Rust/hyperlane/Cargo.toml index 5faf8434fa4..40fddf212ec 100644 --- a/frameworks/Rust/hyperlane/Cargo.toml +++ b/frameworks/Rust/hyperlane/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ [dependencies] futures = "0.3.31" -hyperlane = "10.13.1" +hyperlane = "10.14.0" hyperlane-time = "0.7.12" num_cpus = "1.17.0" once_cell = "1.21.3" diff --git a/frameworks/Rust/hyperlane/src/db/fn.rs b/frameworks/Rust/hyperlane/src/db/fn.rs index 8418f711c88..ab7ea1dd86e 100644 --- a/frameworks/Rust/hyperlane/src/db/fn.rs +++ b/frameworks/Rust/hyperlane/src/db/fn.rs @@ -87,13 +87,16 @@ pub(crate) async fn connection_db() -> DbPoolConnection { "{DATABASE_TYPE}://{DATABASE_USER_NAME}:{DATABASE_USER_PASSWORD}@{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_NAME}" ), }; - let pool_size: u32 = (get_thread_count() as u32).min(DB_MAX_CONNECTIONS); + let thread_count: u32 = get_thread_count() as u32; + let max_connections: u32 = (thread_count * 4).min(DB_MAX_CONNECTIONS); + let min_connections: u32 = thread_count.max(1); let pool: DbPoolConnection = PgPoolOptions::new() - .max_connections(DB_MAX_CONNECTIONS) - .min_connections(pool_size) + .max_connections(max_connections) + .min_connections(min_connections) + .acquire_timeout(std::time::Duration::from_secs(2)) + .idle_timeout(None) .max_lifetime(None) .test_before_acquire(false) - .idle_timeout(None) .connect(db_url) .await .unwrap(); diff --git a/frameworks/Rust/hyperlane/src/main.rs b/frameworks/Rust/hyperlane/src/main.rs index ea346052b05..3e16079e292 100644 --- a/frameworks/Rust/hyperlane/src/main.rs +++ b/frameworks/Rust/hyperlane/src/main.rs @@ -34,10 +34,7 @@ async fn main() { init_db().await; let config: ServerConfig = ServerConfig::new().await; - config.host("0.0.0.0").await; config.port(8080).await; - config.buffer(256).await; - config.disable_linger().await; config.disable_nodelay().await; let server: Server = Server::from(config).await; @@ -50,6 +47,6 @@ async fn main() { server.route::("/fortunes").await; server.route::("/upda").await; - let server_hook: ServerControlHook = server.run().await.unwrap_or_default(); + let server_hook: ServerControlHook = server.run().await.unwrap(); server_hook.wait().await; } From b0f2f174b1f98946d0e4eb2c124ba1ffb04cc3a0 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 8 Dec 2025 18:52:21 +0100 Subject: [PATCH 111/130] [php] Leaf update to v4 (#10371) --- frameworks/PHP/leaf/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/PHP/leaf/composer.json b/frameworks/PHP/leaf/composer.json index 25dd1d1aa6e..f391f601d71 100644 --- a/frameworks/PHP/leaf/composer.json +++ b/frameworks/PHP/leaf/composer.json @@ -1,5 +1,5 @@ { "require": { - "leafs/leaf": "^3.11" + "leafs/leaf": "^4" } } From 760710eb7158d4bc5c18d1cdf13e79daa2f49f6f Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Mon, 8 Dec 2025 18:52:42 +0100 Subject: [PATCH 112/130] [ruby] Remove RUBY_THREAD_TIMESLICE variable (#10374) This setting seems to improve performance so I'd like to enable it for a lot more frameworks. By removing it this run and enabling it for all next run, we can have a better comparison. --- frameworks/Ruby/rack/rack.dockerfile | 1 - frameworks/Ruby/roda-sequel/roda-sequel.dockerfile | 1 - 2 files changed, 2 deletions(-) diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index 4efbac15571..b91c8e10c11 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -1,7 +1,6 @@ FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 -ENV RUBY_THREAD_TIMESLICE=10 # Use Jemalloc RUN apt-get update && \ diff --git a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile index ceadc12af5d..03272f96929 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile @@ -4,7 +4,6 @@ ADD ./ /roda-sequel WORKDIR /roda-sequel ENV RUBY_YJIT_ENABLE=1 -ENV RUBY_THREAD_TIMESLICE=10 # Use Jemalloc RUN apt-get update && \ From 4c1958dbd9d8fa1404eb7ad5cde9905ccaa91484 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Mon, 8 Dec 2025 10:08:28 -0800 Subject: [PATCH 113/130] Add operating system info to results.json (#10375) --- toolset/utils/results.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toolset/utils/results.py b/toolset/utils/results.py index 0df26636404..28bfae16ff6 100644 --- a/toolset/utils/results.py +++ b/toolset/utils/results.py @@ -12,6 +12,7 @@ import math import csv import traceback +import platform from datetime import datetime # Cross-platform colored text @@ -52,6 +53,10 @@ def __init__(self, benchmarker): except Exception: #Could not read local git repository, which is fine. self.git = None + # OS information - only set once during initialization + self.operatingSystem = dict() + self.operatingSystem['name'] = platform.system() + self.operatingSystem['version'] = platform.release() self.startTime = int(round(time.time() * 1000)) self.completionTime = None self.concurrencyLevels = self.config.concurrency_levels @@ -320,6 +325,7 @@ def __to_jsonable(self): toRet['name'] = self.name toRet['environmentDescription'] = self.environmentDescription toRet['git'] = self.git + toRet['operatingSystem'] = self.operatingSystem toRet['startTime'] = self.startTime toRet['completionTime'] = self.completionTime toRet['concurrencyLevels'] = self.concurrencyLevels From 4da5558bdbc434c62502f9b81d51e4bf9c016201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <76547834+RRQM@users.noreply.github.com> Date: Tue, 9 Dec 2025 02:09:43 +0800 Subject: [PATCH 114/130] upgrade(touchsocket):nuget version to 4.0.2 (#10367) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 优化(MyTcpSessionClientBase): 优化异步逻辑与代码结构 重构MyTcpSessionClientBase类以提升性能与可读性: - 将Json和Plaintext字段从public改为private - 优化pipeReader.ReadAsync与pipeWriter.FlushAsync的异步调用逻辑 - 为关键方法添加AggressiveOptimization标记以启用编译优化 - 简化TryReadLine方法的行尾标记处理逻辑 - 优化ParseUrlFast方法的URL解析逻辑,减少冗余代码 - 重构WriteResponseSync方法,使用if-else替代switch语句 - 删除冗余注释与代码,提升代码整洁度 * 优化(project): 升级TouchSocket相关包版本 升级TouchSocket相关包版本以使用最新功能和修复 - 在 `TouchSocketHttp.csproj` 中,将 `TouchSocket.WebApi` 替换为 `TouchSocket.Http`,并将版本更新至 `4.0.2` - 在 `TouchSocketHttpPlatform.csproj` 中,将 `TouchSocket` 包版本更新至 `4.0.2` - 在 `TouchSocketWebApi.csproj` 中: - 将 `TouchSocket.Hosting` 包版本更新至 `4.0.2` - 将 `TouchSocket.WebApi` 包版本更新至 `4.0.2` --- .../TouchSocketHttp/TouchSocketHttp.csproj | 2 +- .../MyTcpSessionClientBase.cs | 183 +++++++----------- .../TouchSocketHttpPlatform.csproj | 2 +- .../TouchSocketWebApi.csproj | 4 +- 4 files changed, 79 insertions(+), 112 deletions(-) diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj index c8e3323ca64..c694366fc8d 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj @@ -8,7 +8,7 @@ - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs index 1b95c2ddd72..788205e483c 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs @@ -41,11 +41,10 @@ internal enum RouteType internal sealed class MyTcpSessionClientBase : TcpSessionClient { #region Paths - public static ReadOnlySpan Json => "/json"u8; - public static ReadOnlySpan Plaintext => "/plaintext"u8; + private static ReadOnlySpan Json => "/json"u8; + private static ReadOnlySpan Plaintext => "/plaintext"u8; #endregion - private static ReadOnlySpan PlainTextBody => "Hello, World!"u8; private static ReadOnlySpan JsonBody => "{\"message\":\"Hello, World!\"}"u8; @@ -68,14 +67,30 @@ protected override async Task ReceiveLoopAsync(ITransport transport) while (true) { - var readResult = await pipeReader.ReadAsync(); + ValueTask readTask = pipeReader.ReadAsync(); + ReadResult readResult; + + if (readTask.IsCompleted) + { + readResult = readTask.Result; + } + else + { + readResult = await readTask.ConfigureAwait(false); + } + var bufferSequence = readResult.Buffer; var totalConsumed = ProcessRequests(bufferSequence, pipeWriter, out var responseCount); if (responseCount > 0) { - await pipeWriter.FlushAsync(); + ValueTask flushTask = pipeWriter.FlushAsync(); + + if (!flushTask.IsCompleted) + { + await flushTask.ConfigureAwait(false); + } } if (totalConsumed > 0) @@ -94,7 +109,7 @@ protected override async Task ReceiveLoopAsync(ITransport transport) } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter writer, out int responseCount) { var seqReader = new SequenceReader(buffer); @@ -105,23 +120,20 @@ private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter wr { var startConsumed = seqReader.Consumed; - // 请求行 if (!TryReadLine(ref seqReader, out var requestLineLength)) { - // 请求行不完整,不消费任何数据 break; } var requestLineConsumed = requestLineLength + 2; - // 读取Headers,直到空行;若不完整,回退并等待更多数据 var headersStartConsumed = seqReader.Consumed; bool headersComplete = false; + while (!seqReader.End) { if (!TryReadLine(ref seqReader, out var headerLength)) { - // 回退到读取Headers前的位置,等待更多数据 var rewind = seqReader.Consumed - headersStartConsumed; if (rewind > 0) { @@ -134,24 +146,20 @@ private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter wr if (headerLength == 0) { headersComplete = true; - break; // headers 结束 + break; } } if (!headersComplete) { - // 不完整,等待更多数据 break; } - // 解析URL - 直接在原始位置解析,避免Slice var routeType = ParseUrlFast(buffer.Slice(startConsumed), requestLineConsumed); - // 计算本次消费的字节数 var consumed = seqReader.Consumed - startConsumed; totalConsumed += consumed; - // 写入响应 WriteResponseSync(writer, routeType); responseCount++; } @@ -159,138 +167,97 @@ private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter wr return totalConsumed; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private static void WriteResponseSync(PipeWriter writer, RouteType routeType) { - switch (routeType) + if (routeType == RouteType.Plaintext) { - case RouteType.Plaintext: - writer.Write(PlaintextPreamble); - writer.Write(DateHeader.HeaderBytes); - writer.Write(PlainTextBody); - break; - case RouteType.Json: - writer.Write(JsonPreamble); - writer.Write(DateHeader.HeaderBytes); - writer.Write(JsonBody); - break; + writer.Write(PlaintextPreamble); + writer.Write(DateHeader.HeaderBytes); + writer.Write(PlainTextBody); + } + else if (routeType == RouteType.Json) + { + writer.Write(JsonPreamble); + writer.Write(DateHeader.HeaderBytes); + writer.Write(JsonBody); } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private static bool TryReadLine(ref SequenceReader reader, out long length) { - var start = reader.Consumed; - - while (!reader.End) + if (reader.TryAdvanceTo((byte)'\r', advancePastDelimiter: false)) { - if (reader.TryRead(out var b)) + var start = reader.Consumed; + + if (!reader.TryPeek(1, out var next)) { - if (b == '\r') - { - // 查看是否有'\n',若暂不可用则回退并判定不完整 - if (!reader.TryPeek(out var next)) - { - // 回退已读取的'\r' - reader.Rewind(1); - length = 0; - return false; - } - if (next == '\n') - { - // 消费'\n'并返回本行长度(不含CRLF) - reader.Advance(1); - length = reader.Consumed - start - 2; - return true; - } - } + length = 0; + return false; } + + if (next == '\n') + { + var lineLength = reader.Consumed; + reader.Advance(2); + length = lineLength - start; + return true; + } + + reader.Advance(1); + return TryReadLine(ref reader, out length); } length = 0; return false; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private static RouteType ParseUrlFast(ReadOnlySequence sequence, long requestLineLength) { var reader = new SequenceReader(sequence); - // 跳过方法 - var spaceCount = 0; - var urlStart = 0L; - var urlEnd = 0L; - - while (reader.Consumed < requestLineLength && !reader.End) + if (!reader.TryAdvanceTo((byte)' ', advancePastDelimiter: true)) { - if (reader.TryRead(out var b)) - { - if (b == ' ') - { - spaceCount++; - if (spaceCount == 1) - { - urlStart = reader.Consumed; - } - else if (spaceCount == 2) - { - urlEnd = reader.Consumed - 1; - break; - } - } - } + return RouteType.Unknown; } - if (spaceCount < 2) + var urlStart = reader.Consumed; + + if (!reader.TryAdvanceTo((byte)' ', advancePastDelimiter: false)) { return RouteType.Unknown; } - var urlLength = urlEnd - urlStart; + var urlLength = reader.Consumed - urlStart; - // 截取URL片段 - var startPos = sequence.GetPosition(urlStart); - var urlSlice = sequence.Slice(startPos, urlLength); - - // "/plaintext" if (urlLength == Plaintext.Length) { + var urlSlice = sequence.Slice(urlStart, urlLength); + if (urlSlice.IsSingleSegment) { - if (urlSlice.FirstSpan.SequenceEqual(Plaintext)) - { - return RouteType.Plaintext; - } - } - else - { - Span tmp = stackalloc byte[(int)urlLength]; - urlSlice.CopyTo(tmp); - if (tmp.SequenceEqual(Plaintext)) - { - return RouteType.Plaintext; - } + return urlSlice.FirstSpan.SequenceEqual(Plaintext) ? RouteType.Plaintext : RouteType.Unknown; } + + Span tmp = stackalloc byte[(int)urlLength]; + urlSlice.CopyTo(tmp); + return tmp.SequenceEqual(Plaintext) ? RouteType.Plaintext : RouteType.Unknown; } - // "/json" - else if (urlLength == Json.Length) + + if (urlLength == Json.Length) { + var urlSlice = sequence.Slice(urlStart, urlLength); + if (urlSlice.IsSingleSegment) { - if (urlSlice.FirstSpan.SequenceEqual(Json)) - { - return RouteType.Json; - } - } - else - { - Span tmp = stackalloc byte[(int)urlLength]; - urlSlice.CopyTo(tmp); - if (tmp.SequenceEqual(Json)) - { - return RouteType.Json; - } + return urlSlice.FirstSpan.SequenceEqual(Json) ? RouteType.Json : RouteType.Unknown; } + + Span tmp = stackalloc byte[(int)urlLength]; + urlSlice.CopyTo(tmp); + return tmp.SequenceEqual(Json) ? RouteType.Json : RouteType.Unknown; } return RouteType.Unknown; diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj index f79663a0b2b..25feeea4984 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj @@ -8,6 +8,6 @@ - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj index c2b0eb4e17a..3b3d56852ce 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj @@ -9,7 +9,7 @@ - - + + From a8258631ec60e83be1945cddb6a767ad52712eba Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Mon, 8 Dec 2025 19:32:45 +0000 Subject: [PATCH 115/130] Update the set of broken implementations (#10366) Signed-off-by: Anton Kirilov --- frameworks/Kotlin/http4k/benchmark_config.json | 2 ++ frameworks/PHP/flight/benchmark_config.json | 1 + frameworks/R/plumber/benchmark_config.json | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frameworks/Kotlin/http4k/benchmark_config.json b/frameworks/Kotlin/http4k/benchmark_config.json index 448f868871c..ed160cd0d0d 100755 --- a/frameworks/Kotlin/http4k/benchmark_config.json +++ b/frameworks/Kotlin/http4k/benchmark_config.json @@ -22,6 +22,7 @@ "webserver": "None", "os": "Linux", "notes": "https://http4k.org", + "tags": [ "broken" ], "versus": "servlet" }, "apache4": { @@ -88,6 +89,7 @@ "webserver": "None", "os": "Linux", "notes": "https://http4k.org", + "tags": [ "broken" ], "versus": "helidon-jdbc" }, "jetty": { diff --git a/frameworks/PHP/flight/benchmark_config.json b/frameworks/PHP/flight/benchmark_config.json index 5a2cb9f89fb..64d12cac7b4 100644 --- a/frameworks/PHP/flight/benchmark_config.json +++ b/frameworks/PHP/flight/benchmark_config.json @@ -45,6 +45,7 @@ "database_os": "Linux", "display_name": "flight [workerman]", "notes": "", + "tags": [ "broken" ], "versus": "php" } }] diff --git a/frameworks/R/plumber/benchmark_config.json b/frameworks/R/plumber/benchmark_config.json index ceb6f0c608a..a2ad2107710 100755 --- a/frameworks/R/plumber/benchmark_config.json +++ b/frameworks/R/plumber/benchmark_config.json @@ -4,7 +4,6 @@ { "default": { "json_url": "/json", - "plaintext_url": "/plaintext", "db_url": "/db", "query_url": "/query?queries=", "fortune_url": "/fortunes", From b0ad9a31a62c52d42b81ca3d5f35d8fb79a6236d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <76547834+RRQM@users.noreply.github.com> Date: Wed, 10 Dec 2025 05:06:25 +0800 Subject: [PATCH 116/130] update(touchsocket):display name (#10379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 优化(MyTcpSessionClientBase): 优化异步逻辑与代码结构 重构MyTcpSessionClientBase类以提升性能与可读性: - 将Json和Plaintext字段从public改为private - 优化pipeReader.ReadAsync与pipeWriter.FlushAsync的异步调用逻辑 - 为关键方法添加AggressiveOptimization标记以启用编译优化 - 简化TryReadLine方法的行尾标记处理逻辑 - 优化ParseUrlFast方法的URL解析逻辑,减少冗余代码 - 重构WriteResponseSync方法,使用if-else替代switch语句 - 删除冗余注释与代码,提升代码整洁度 * 优化(project): 升级TouchSocket相关包版本 升级TouchSocket相关包版本以使用最新功能和修复 - 在 `TouchSocketHttp.csproj` 中,将 `TouchSocket.WebApi` 替换为 `TouchSocket.Http`,并将版本更新至 `4.0.2` - 在 `TouchSocketHttpPlatform.csproj` 中,将 `TouchSocket` 包版本更新至 `4.0.2` - 在 `TouchSocketWebApi.csproj` 中: - 将 `TouchSocket.Hosting` 包版本更新至 `4.0.2` - 将 `TouchSocket.WebApi` 包版本更新至 `4.0.2` * 优化(benchmark_config): 更新display_name格式以包含版本信息 --- frameworks/CSharp/touchsocket/benchmark_config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frameworks/CSharp/touchsocket/benchmark_config.json b/frameworks/CSharp/touchsocket/benchmark_config.json index 86036458c9a..2a6d6c27e98 100644 --- a/frameworks/CSharp/touchsocket/benchmark_config.json +++ b/frameworks/CSharp/touchsocket/benchmark_config.json @@ -55,7 +55,7 @@ "webserver": "touchsocket", "os": "Linux", "database_os": "Linux", - "display_name": "touchsocket.http31", + "display_name": "touchsocket.http [v3.1]", "notes": "", "versus": "aspnetcore" }, @@ -74,7 +74,7 @@ "webserver": "touchsocket", "os": "Linux", "database_os": "Linux", - "display_name": "touchsocket.webapi31", + "display_name": "touchsocket.webapi [v3.1]", "notes": "", "versus": "aspnetcore-mvc" }, @@ -93,7 +93,7 @@ "webserver": "touchsocket", "os": "Linux", "database_os": "Linux", - "display_name": "touchsocket.httpplatform", + "display_name": "touchsocket.http [Platform]", "notes": "High-performance custom pipeline-based implementation variant.", "versus": "aspnetcore" } From a775dce2e41701898e487494aedab56f57c2f5d2 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 10 Dec 2025 18:28:10 +0100 Subject: [PATCH 117/130] [ruby] Hardcode Puma to 5 threads (#10381) 5 threads is recommended, this also makes sure results are more predictable when run on different environments. --- frameworks/Ruby/rack-sequel/boot.rb | 4 ++-- frameworks/Ruby/rack-sequel/config/mri_puma.rb | 10 ---------- frameworks/Ruby/rack-sequel/config/puma.rb | 3 +++ .../Ruby/rack-sequel/rack-sequel-postgres.dockerfile | 4 +++- frameworks/Ruby/rack-sequel/rack-sequel.dockerfile | 4 +++- frameworks/Ruby/roda-sequel/boot.rb | 5 ++--- frameworks/Ruby/roda-sequel/config/mri_puma.rb | 10 ---------- frameworks/Ruby/roda-sequel/config/puma.rb | 3 +++ .../Ruby/roda-sequel/roda-sequel-postgres.dockerfile | 4 +++- frameworks/Ruby/roda-sequel/roda-sequel.dockerfile | 4 +++- frameworks/Ruby/sinatra-sequel/boot.rb | 4 ++-- frameworks/Ruby/sinatra-sequel/config/mri_puma.rb | 10 ---------- frameworks/Ruby/sinatra-sequel/config/puma.rb | 3 +++ .../sinatra-sequel/sinatra-sequel-postgres.dockerfile | 6 ++++-- .../Ruby/sinatra-sequel/sinatra-sequel.dockerfile | 6 ++++-- frameworks/Ruby/sinatra/boot.rb | 5 ++--- frameworks/Ruby/sinatra/config/puma.rb | 6 ------ frameworks/Ruby/sinatra/sinatra-postgres.dockerfile | 6 ++++-- frameworks/Ruby/sinatra/sinatra.dockerfile | 4 +++- 19 files changed, 44 insertions(+), 57 deletions(-) delete mode 100644 frameworks/Ruby/rack-sequel/config/mri_puma.rb create mode 100644 frameworks/Ruby/rack-sequel/config/puma.rb delete mode 100644 frameworks/Ruby/roda-sequel/config/mri_puma.rb create mode 100644 frameworks/Ruby/roda-sequel/config/puma.rb delete mode 100644 frameworks/Ruby/sinatra-sequel/config/mri_puma.rb create mode 100644 frameworks/Ruby/sinatra-sequel/config/puma.rb delete mode 100644 frameworks/Ruby/sinatra/config/puma.rb diff --git a/frameworks/Ruby/rack-sequel/boot.rb b/frameworks/Ruby/rack-sequel/boot.rb index 9c06a7f981f..91594951944 100644 --- a/frameworks/Ruby/rack-sequel/boot.rb +++ b/frameworks/Ruby/rack-sequel/boot.rb @@ -20,8 +20,8 @@ def connect(dbtype) end # Determine threading/thread pool size and timeout - if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = threads + if defined?(Puma) + opts[:max_connections] = ENV.fetch('MAX_THREADS') opts[:pool_timeout] = 10 else opts[:max_connections] = 512 diff --git a/frameworks/Ruby/rack-sequel/config/mri_puma.rb b/frameworks/Ruby/rack-sequel/config/mri_puma.rb deleted file mode 100644 index d70db95a94f..00000000000 --- a/frameworks/Ruby/rack-sequel/config/mri_puma.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -_, num_threads = auto_tune - -threads num_threads, num_threads - -before_fork do - Sequel::DATABASES.each(&:disconnect) -end diff --git a/frameworks/Ruby/rack-sequel/config/puma.rb b/frameworks/Ruby/rack-sequel/config/puma.rb new file mode 100644 index 00000000000..907837b4892 --- /dev/null +++ b/frameworks/Ruby/rack-sequel/config/puma.rb @@ -0,0 +1,3 @@ +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile index 2e973cf9ecc..a1cf4826f9c 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile @@ -17,6 +17,8 @@ RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile ENV DBTYPE=postgresql ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile index 748cfc05b9e..bf8a4a28f13 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile @@ -17,6 +17,8 @@ RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile ENV DBTYPE=mysql ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/roda-sequel/boot.rb b/frameworks/Ruby/roda-sequel/boot.rb index 0878b21e9d3..6d2d2e44e9f 100644 --- a/frameworks/Ruby/roda-sequel/boot.rb +++ b/frameworks/Ruby/roda-sequel/boot.rb @@ -34,9 +34,8 @@ def connect(dbtype) end # Determine threading/thread pool size and timeout - if defined?(Puma) && - (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = threads + if defined?(Puma) + opts[:max_connections] = ENV.fetch('MAX_THREADS') opts[:pool_timeout] = 10 else opts[:max_connections] = 512 diff --git a/frameworks/Ruby/roda-sequel/config/mri_puma.rb b/frameworks/Ruby/roda-sequel/config/mri_puma.rb deleted file mode 100644 index 794c18f0c08..00000000000 --- a/frameworks/Ruby/roda-sequel/config/mri_puma.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -_, num_threads = auto_tune - -threads num_threads - -before_fork do - Sequel::DATABASES.each(&:disconnect) -end diff --git a/frameworks/Ruby/roda-sequel/config/puma.rb b/frameworks/Ruby/roda-sequel/config/puma.rb new file mode 100644 index 00000000000..907837b4892 --- /dev/null +++ b/frameworks/Ruby/roda-sequel/config/puma.rb @@ -0,0 +1,3 @@ +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile index 80a1934282c..f64942e8994 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile @@ -17,7 +17,9 @@ RUN bundle install --jobs=8 ENV RACK_ENV=production ENV DBTYPE=postgresql +ENV MAX_THREADS=5 ENV WEB_CONCURRENCY=auto + EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile index 03272f96929..d72f87057db 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile @@ -18,6 +18,8 @@ ENV RACK_ENV=production ENV DBTYPE=mysql ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra-sequel/boot.rb b/frameworks/Ruby/sinatra-sequel/boot.rb index ca44bdc08df..58cdb0c25cb 100644 --- a/frameworks/Ruby/sinatra-sequel/boot.rb +++ b/frameworks/Ruby/sinatra-sequel/boot.rb @@ -27,8 +27,8 @@ def connect(dbtype) end # Determine threading/thread pool size and timeout - if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = threads + if defined?(Puma) + opts[:max_connections] = ENV.fetch('MAX_THREADS') opts[:pool_timeout] = 10 else opts[:max_connections] = 512 diff --git a/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb b/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb deleted file mode 100644 index 794c18f0c08..00000000000 --- a/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -_, num_threads = auto_tune - -threads num_threads - -before_fork do - Sequel::DATABASES.each(&:disconnect) -end diff --git a/frameworks/Ruby/sinatra-sequel/config/puma.rb b/frameworks/Ruby/sinatra-sequel/config/puma.rb new file mode 100644 index 00000000000..907837b4892 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/config/puma.rb @@ -0,0 +1,3 @@ +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile index 058c6f6de73..7cfbf8d9cb6 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile @@ -13,10 +13,12 @@ WORKDIR /sinatra-sequel ENV BUNDLE_WITH=postgresql:puma RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile -ENV WEB_CONCURRENCY=auto ENV APP_ENV=production ENV DBTYPE=postgresql +ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile index 6804394c054..bc8a7a8b871 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile @@ -13,10 +13,12 @@ WORKDIR /sinatra-sequel ENV BUNDLE_WITH=mysql:puma RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile -ENV WEB_CONCURRENCY=auto ENV APP_ENV=production ENV DBTYPE=mysql +ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/boot.rb b/frameworks/Ruby/sinatra/boot.rb index e27fe4e928c..33843258016 100644 --- a/frameworks/Ruby/sinatra/boot.rb +++ b/frameworks/Ruby/sinatra/boot.rb @@ -30,10 +30,9 @@ def connect(dbtype) opts[:adapter] = 'postgresql' end - # Determine threading/thread pool size and timeout - if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:pool] = threads + if defined?(Puma) + opts[:pool] = ENV.fetch('MAX_THREADS') opts[:checkout_timeout] = 10 else opts[:pool] = 512 diff --git a/frameworks/Ruby/sinatra/config/puma.rb b/frameworks/Ruby/sinatra/config/puma.rb deleted file mode 100644 index 94b2fefab95..00000000000 --- a/frameworks/Ruby/sinatra/config/puma.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -_, num_threads = auto_tune - -threads num_threads, num_threads diff --git a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile index 36ccd2eb6c0..61cb25c2551 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile @@ -13,10 +13,12 @@ WORKDIR /sinatra ENV BUNDLE_WITH=postgresql:puma RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile -ENV WEB_CONCURRENCY=auto ENV APP_ENV=production ENV DBTYPE=postgresql +ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/sinatra.dockerfile b/frameworks/Ruby/sinatra/sinatra.dockerfile index de5ba291d61..f6082c07919 100644 --- a/frameworks/Ruby/sinatra/sinatra.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra.dockerfile @@ -17,6 +17,8 @@ ENV APP_ENV=production ENV DBTYPE=mysql ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec puma -b tcp://0.0.0.0:8080 From 761a47ac52b8b260382517c472588c9f5ee391ff Mon Sep 17 00:00:00 2001 From: LLT21 <43903768+LLT21@users.noreply.github.com> Date: Wed, 10 Dec 2025 18:28:32 +0100 Subject: [PATCH 118/130] Upgrade to .NET 10.0.1 (#10382) * Upgrade to .NET 10.0.1 * Avoid extra copy by pinning the internal buffer instead --------- Co-authored-by: LLT21 <> --- .../appmpower/appmpower-odbc-my.dockerfile | 6 ++- .../appmpower/appmpower-odbc-pg.dockerfile | 6 ++- .../CSharp/appmpower/appmpower.dockerfile | 6 ++- .../src/appMpower.Orm/NativeMethods.cs | 53 +++++++++---------- .../src/appMpower.Orm/appMpower.Orm.csproj | 4 +- .../appmpower/src/appMpower/appMpower.csproj | 9 ++-- 6 files changed, 43 insertions(+), 41 deletions(-) diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile index ad6c396e22b..9f3e85a6439 100644 --- a/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build RUN apt-get update RUN apt-get -yqq install clang zlib1g-dev RUN apt-get update @@ -8,7 +8,7 @@ COPY src . RUN dotnet publish -c Release -o out /p:Database=mysql # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0.1 AS runtime RUN apt-get update # The following installs standard versions unixodbc and pgsqlodbc @@ -51,6 +51,8 @@ RUN cp /usr/lib/x86_64-linux-gnu/libodbc* /app #TODOLOCAL #RUN cp /usr/lib/aarch64-linux-gnu/libodbc* /app +#TEST: ./tfb --test appmpower-odbc-my --type db + EXPOSE 8080 ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile index 1cf7855dd7f..56dfaba77bb 100644 --- a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build RUN apt-get update RUN apt-get -yqq install clang zlib1g-dev @@ -7,7 +7,7 @@ COPY src . RUN dotnet publish -c Release -o out /p:Database=postgresql # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0.1 AS runtime RUN apt-get update RUN apt-get install -y unixodbc-dev unixodbc odbc-postgresql @@ -32,6 +32,8 @@ RUN cp /usr/lib/x86_64-linux-gnu/libodbc* /app #TODOLOCAL #RUN cp /usr/lib/aarch64-linux-gnu/libodbc* /app +#TEST: ./tfb --test appmpower-odbc-pg --type db + EXPOSE 8080 ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower.dockerfile b/frameworks/CSharp/appmpower/appmpower.dockerfile index 6621b6b6deb..abdc5cfcb7c 100644 --- a/frameworks/CSharp/appmpower/appmpower.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build RUN apt-get update RUN apt-get -yqq install clang zlib1g-dev @@ -8,7 +8,7 @@ COPY src . RUN dotnet publish -c Release -o out # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0.1 AS runtime # Full PGO ENV DOTNET_TieredPGO 1 ENV DOTNET_TC_QuickJitForLoops 1 @@ -18,6 +18,8 @@ ENV ASPNETCORE_URLS http://+:8080 WORKDIR /app COPY --from=build /app/out ./ +#TEST: ./tfb --test appmpower --type json + EXPOSE 8080 ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs index 6c20aded37a..bdeb98565a5 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs @@ -1,9 +1,9 @@ using System.Runtime.InteropServices; -using System.Text; -using System.Text.Json; -using appMpower.Orm.Data; -using appMpower.Orm.Objects; -using appMpower.Orm.Serializers; +using System.Text; +using System.Text.Json; +using appMpower.Orm.Data; +using appMpower.Orm.Objects; +using appMpower.Orm.Serializers; namespace appMpower.Orm; @@ -11,7 +11,7 @@ public static class NativeMethods { private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions { - Indented = false, + Indented = false, SkipValidation = true }; @@ -24,17 +24,17 @@ public static class NativeMethods [UnmanagedCallersOnly(EntryPoint = "Dbms")] public static void Dbms(int dbms) { - Constants.Dbms = (Dbms)dbms; + Constants.Dbms = (Dbms)dbms; DbProviderFactory.SetConnectionString(); } [UnmanagedCallersOnly(EntryPoint = "DbProvider")] public static void DbProvider(int dbProvider) { - Constants.DbProvider = (DbProvider)dbProvider; + Constants.DbProvider = (DbProvider)dbProvider; DbProviderFactory.SetConnectionString(); } - + [UnmanagedCallersOnly(EntryPoint = "FreeHandlePointer")] public static void FreeHandlePointer(IntPtr handlePointer) { @@ -48,25 +48,22 @@ public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); var memoryStream = new MemoryStream(); - using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + using (var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions)) + { + _worldSerializer.Serialize(utf8JsonWriter, world); + } - _worldSerializer.Serialize(utf8JsonWriter, world); + // Flush everything to the MemoryStream + memoryStream.Flush(); + byte[] buffer = memoryStream.GetBuffer(); + int len = (int)memoryStream.Position; // or (int)memoryStream.Length; - *length = (int)utf8JsonWriter.BytesCommitted; - byte[] byteArray = memoryStream.ToArray(); + *length = len; - GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); - // return the managed and byteArrayPointer pointer - IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); *handlePointer = GCHandle.ToIntPtr(handle); - return byteArrayPointer; - /* - fixed(byte* b = memoryStream.ToArray()) - { - return b; - } - */ + return handle.AddrOfPinnedObject(); } /* @@ -90,7 +87,7 @@ public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) [UnmanagedCallersOnly(EntryPoint = "Fortunes")] public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) { - List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); + List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); int totalSize = 0; @@ -122,7 +119,7 @@ public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) } byte[] byteArray = buffer.ToArray(); - *length = byteArray.Length; + *length = byteArray.Length; /* var memoryStream = new MemoryStream(); @@ -151,7 +148,7 @@ public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointe _worldsSerializer.Serialize(utf8JsonWriter, worlds); - *length = (int)utf8JsonWriter.BytesCommitted; + *length = (int)utf8JsonWriter.BytesCommitted; byte[] byteArray = memoryStream.ToArray(); GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); @@ -171,7 +168,7 @@ public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointe _worldsSerializer.Serialize(utf8JsonWriter, worlds); - *length = (int)utf8JsonWriter.BytesCommitted; + *length = (int)utf8JsonWriter.BytesCommitted; byte[] byteArray = memoryStream.ToArray(); GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); @@ -191,7 +188,7 @@ public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer) _worldSerializer.Serialize(utf8JsonWriter, world); - *length = (int)utf8JsonWriter.BytesCommitted; + *length = (int)utf8JsonWriter.BytesCommitted; byte[] byteArray = memoryStream.ToArray(); GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj index 23a9b6c47cb..19ac29572de 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable true @@ -41,7 +41,7 @@ - + diff --git a/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj index 5db0aac55f8..dbb2d8436c4 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj +++ b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 Exe true @@ -11,13 +11,12 @@ - - From 975a93d576ddda5560112c6aa5025f7eaa771207 Mon Sep 17 00:00:00 2001 From: Yongshun Ye Date: Thu, 11 Dec 2025 01:29:40 +0800 Subject: [PATCH 119/130] Keep the `vertx-web-kotlinx` portion updated (#10383) * Bump all dependencies and toolchains to the latest * Migrate to Vert.x 5 APIs and bump Kotlin to 2.3.0-RC2 to support Java 25 * Update catching the "connection" reset exceptions * Try setting `date` with kotlinx-datetime but it doesn't work as expected Got `java.lang.IllegalStateException: Field offsetHours is not set`. * Remove the kotlinx-datetime dependency and update the comment See commit 9cf28f15b6f1806b3ed75260adee8acd822cac91 for a failed attempt to try using kotlinx-datetime. * Get setting `date` with `kotlinx-datetime` to work ref: https://github.com/huanshankeji/FrameworkBenchmarks/pull/1 * Review and port some of the changes in `FrameworkBenchmarks/frameworks/Java/vertx/` from commit 057c25b234bae395b1228d6afe0a7fd1c225a74d to commit 1838aa5df242f103a335b74c9095bc88f22643b1, and fix some typos Some changes are not ported. There is about 5% performance improvement in the JSON test as tested on my device. * Increase the io_uring completion queue size to resolve warnings and improve the plaintext test performance ``` io.netty.channel.uring.IoUringIoHandler processCompletionsAndHandleOverflow vertx: WARNING: CompletionQueue overflow detected, consider increasing size: 4096 ``` This is still one warning when the value is set to 8192 as tested on my device, instead of many for the default 4096. * Benchmark Approach 1 and Approach 3 in `jsonResponseCoHandler` again and fix capitalization BTW The "Requests/sec" result of Approach 1 is only 40% of Approach 3 as tested on my device. * Remove an outdated comment as found by Gemini Code Assist * Use the "connection reset" error code from Netty instead of hard-coding it and also catch Java NIO `SocketException` for developing on other OSs such as macOS and Windows Tested with the `tfb` command on both macOS and Linux. * Fix some errors and keep things updated in benchmark_config.json and README.md --- frameworks/Kotlin/vertx-web-kotlinx/README.md | 7 +- .../vertx-web-kotlinx/benchmark_config.json | 2 +- .../Kotlin/vertx-web-kotlinx/build.gradle.kts | 22 +++-- .../gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 45633 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- frameworks/Kotlin/vertx-web-kotlinx/gradlew | 12 +-- .../Kotlin/vertx-web-kotlinx/gradlew.bat | 3 +- .../vertx-web-kotlinx/src/main/kotlin/Main.kt | 14 +++- .../src/main/kotlin/MainVerticle.kt | 78 +++++++++++------- .../src/main/kotlin/VertxCoroutine.kt | 2 +- .../vertx-web-kotlinx-postgresql.dockerfile | 16 ++-- .../vertx-web-kotlinx.dockerfile | 16 ++-- 12 files changed, 100 insertions(+), 74 deletions(-) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/README.md b/frameworks/Kotlin/vertx-web-kotlinx/README.md index b9fe8d87eef..f3134cb1b35 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/README.md +++ b/frameworks/Kotlin/vertx-web-kotlinx/README.md @@ -2,7 +2,7 @@ Vert.x-Web in Kotlin with request handling implemented as much with official kotlinx libraries as possible. -Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 21. +Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 25. ## Test Type Implementation Source Code @@ -13,7 +13,6 @@ Code is written from scratch to be as concise as possible with common code extra * [PLAINTEXT](src/main/kotlin/MainVerticle.kt) * [DB](src/main/kotlin/MainVerticle.kt) * [QUERY](src/main/kotlin/MainVerticle.kt) -* [CACHED QUERY](src/main/kotlin/MainVerticle.kt) * [UPDATE](src/main/kotlin/MainVerticle.kt) * [FORTUNES](src/main/kotlin/MainVerticle.kt) @@ -48,10 +47,6 @@ http://localhost:8080/db http://localhost:8080/query?queries= -### CACHED QUERY - -http://localhost:8080/cached_query?queries= - ### UPDATE http://localhost:8080/update?queries= diff --git a/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json index 970a9f80b46..826470e61f9 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json @@ -40,7 +40,7 @@ "database_os": "Linux", "display_name": "vertx-web-kotlinx-postgresql", "notes": "", - "versus": "vertx-web" + "versus": "vertx-web-postgres" } } ] diff --git a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts index 2e0035ab3e7..57ecdf9e59a 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts @@ -3,7 +3,7 @@ tasks.wrapper { } plugins { - val kotlinVersion = "2.0.21" + val kotlinVersion = "2.3.0-RC2" kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion application @@ -13,29 +13,27 @@ repositories { mavenCentral() } -val vertxVersion = "4.5.10" -val kotlinxSerializationVersion = "1.7.3" +val vertxVersion = "5.0.5" +val kotlinxSerializationVersion = "1.9.0" dependencies { implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion")) implementation("io.vertx:vertx-web") implementation("io.vertx:vertx-pg-client") - implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + //implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + implementation("io.netty", "netty-transport-native-io_uring", classifier = "linux-x86_64") implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") - runtimeOnly("io.vertx:vertx-io_uring-incubator") - // This dependency has to be added for io_uring to work. - runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-io:$kotlinxSerializationVersion") - implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.4") + implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.8.2") - implementation("org.jetbrains.kotlinx:kotlinx-html:0.11.0") - //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") // the latest version is 0.6.1 + implementation("org.jetbrains.kotlinx:kotlinx-html:0.12.0") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1") } -kotlin.jvmToolchain(21) +kotlin.jvmToolchain(25) application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..f8e1ee3125fe0768e9a76ee977ac089eb657005e 100644 GIT binary patch delta 37538 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 }= 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 F{{RkpxF!Gq diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties index 79eb9d003fe..4eac4a84cc3 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew b/frameworks/Kotlin/vertx-web-kotlinx/gradlew index f5feea6d6b1..adff685a034 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -206,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat index 9d21a21834d..c4bdd3ab8e3 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt index 987c22162b3..52864f79f16 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt @@ -3,9 +3,11 @@ import io.vertx.core.impl.cpu.CpuCoreSensor import io.vertx.kotlin.core.deploymentOptionsOf import io.vertx.kotlin.core.vertxOptionsOf import io.vertx.kotlin.coroutines.coAwait +import java.util.function.Supplier import java.util.logging.Logger const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark server" +val numProcessors = CpuCoreSensor.availableProcessors() val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark") suspend fun main(args: Array) { @@ -13,12 +15,18 @@ suspend fun main(args: Array) { ?: throw IllegalArgumentException("Specify the first `hasDb` Boolean argument") logger.info("$SERVER_NAME starting...") - val vertx = Vertx.vertx(vertxOptionsOf(preferNativeTransport = true)) + val vertx = Vertx.vertx( + vertxOptionsOf( + eventLoopPoolSize = numProcessors, preferNativeTransport = true, disableTCCL = true + ) + ) vertx.exceptionHandler { logger.info("Vertx exception caught: $it") it.printStackTrace() } - vertx.deployVerticle({ MainVerticle(hasDb) }, deploymentOptionsOf(instances = CpuCoreSensor.availableProcessors())) - .coAwait() + vertx.deployVerticle( + Supplier { MainVerticle(hasDb) }, + deploymentOptionsOf(instances = numProcessors) + ).coAwait() logger.info("$SERVER_NAME started.") } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt index 4dce51388ae..d12330de363 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt @@ -1,4 +1,6 @@ +import io.netty.channel.unix.Errors import io.netty.channel.unix.Errors.NativeIoException +import io.vertx.core.MultiMap import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpHeaders import io.vertx.core.http.HttpServer @@ -18,6 +20,9 @@ import io.vertx.sqlclient.Row import io.vertx.sqlclient.RowSet import io.vertx.sqlclient.Tuple import kotlinx.coroutines.Dispatchers +import kotlinx.datetime.UtcOffset +import kotlinx.datetime.format.DateTimeComponents +import kotlinx.datetime.format.format import kotlinx.html.* import kotlinx.html.stream.appendHTML import kotlinx.io.buffered @@ -26,10 +31,17 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.json.Json import kotlinx.serialization.json.io.encodeToSink -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter +import java.net.SocketException +import kotlin.time.Clock class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSupport { + object HttpHeaderValues { + val vertxWeb = HttpHeaders.createOptimized("Vert.x-Web") + val applicationJson = HttpHeaders.createOptimized("application/json") + val textHtmlCharsetUtf8 = HttpHeaders.createOptimized("text/html; charset=utf-8") + val textPlain = HttpHeaders.createOptimized("text/plain") + } + // `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s. lateinit var pgConnection: PgConnection lateinit var date: String @@ -37,12 +49,13 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup lateinit var selectWorldQuery: PreparedQuery> lateinit var selectFortuneQuery: PreparedQuery> - lateinit var updateWordQuery: PreparedQuery> + lateinit var updateWorldQuery: PreparedQuery> fun setCurrentDate() { - // kotlinx-datetime doesn't support the format yet. - //date = Clock.System.now().toString() - date = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()) + date = DateTimeComponents.Formats.RFC_1123.format { + // We don't need a more complicated system `TimeZone` here (whose offset depends dynamically on the actual time due to DST) since UTC works. + setDateTimeOffset(Clock.System.now(), UtcOffset.ZERO) + } } override suspend fun start() { @@ -56,27 +69,25 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup user = "benchmarkdbuser", password = "benchmarkdbpass", cachePreparedStatements = true, - pipeliningLimit = 100000 + pipeliningLimit = 256 ) ).coAwait() selectWorldQuery = pgConnection.preparedQuery(SELECT_WORLD_SQL) selectFortuneQuery = pgConnection.preparedQuery(SELECT_FORTUNE_SQL) - updateWordQuery = pgConnection.preparedQuery(UPDATE_WORLD_SQL) + updateWorldQuery = pgConnection.preparedQuery(UPDATE_WORLD_SQL) } setCurrentDate() vertx.setPeriodic(1000) { setCurrentDate() } - httpServer = vertx.createHttpServer(httpServerOptionsOf(port = 8080)) + httpServer = vertx.createHttpServer( + httpServerOptionsOf(port = 8080, http2ClearTextEnabled = false, strictThreadMode = true) + ) .requestHandler(Router.router(vertx).apply { routes() }) .exceptionHandler { // wrk resets the connections when benchmarking is finished. - if ( - // for epoll - /*(it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") - || (it is SocketException && it.message == "Connection reset")*/ - // for io_uring - it is NativeIoException && it.message == "io_uring read(..) failed: Connection reset by peer" + if ((/* for native transport */it is NativeIoException && it.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE) || + (/* for Java NIO */ it is SocketException && it.message == "Connection reset") ) return@exceptionHandler @@ -93,15 +104,17 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup } @Suppress("NOTHING_TO_INLINE") - inline fun HttpServerResponse.putCommonHeaders() { - putHeader(HttpHeaders.SERVER, "Vert.x-Web") - putHeader(HttpHeaders.DATE, date) + inline fun MultiMap.addCommonHeaders() { + add(HttpHeaders.SERVER, HttpHeaderValues.vertxWeb) + add(HttpHeaders.DATE, date) } @Suppress("NOTHING_TO_INLINE") - inline fun HttpServerResponse.putJsonResponseHeader() { - putCommonHeaders() - putHeader(HttpHeaders.CONTENT_TYPE, "application/json") + inline fun HttpServerResponse.addJsonResponseHeaders() { + headers().run { + addCommonHeaders() + add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.applicationJson) + } } @@ -117,15 +130,15 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup ) = coHandlerUnconfined { it.response().run { - putJsonResponseHeader() + addJsonResponseHeaders() /* - // approach 1 + // Approach 1 end(Json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/ */ /* - // approach 2 + // Approach 2 // java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding. toRawSink().buffered().use { bufferedSink -> @OptIn(ExperimentalSerializationApi::class) @@ -133,7 +146,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup } */ - // approach 3 + // Approach 3 end(Buffer.buffer().apply { toRawSink().buffered().use { bufferedSink -> @OptIn(ExperimentalSerializationApi::class) @@ -197,12 +210,15 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup } it.response().run { - putCommonHeaders() - putHeader(HttpHeaders.CONTENT_TYPE, "text/html; charset=utf-8") + headers().run { + addCommonHeaders() + add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textHtmlCharsetUtf8) + } end(htmlString)/*.coAwait()*/ } } + // Some changes to this part in the `vertx` portion in #9142 are not ported. get("/updates").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() val worlds = selectRandomWorlds(queries) @@ -210,7 +226,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup // Approach 1 // The updated worlds need to be sorted first to avoid deadlocks. - updateWordQuery + updateWorldQuery .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).coAwait() /* @@ -225,8 +241,10 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSup get("/plaintext").coHandlerUnconfined { it.response().run { - putCommonHeaders() - putHeader(HttpHeaders.CONTENT_TYPE, "text/plain") + headers().run { + addCommonHeaders() + add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textPlain) + } end("Hello, World!")/*.coAwait()*/ } } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt index d6230fef7f7..88240185856 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt @@ -2,4 +2,4 @@ import io.vertx.core.Future import io.vertx.kotlin.coroutines.coAwait suspend fun List>.awaitAll(): List = - Future.all(this).coAwait().list() + Future.all(this).coAwait().list() diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile index 17b43ebcb5c..148962d7948 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.10.2-jdk21 +FROM gradle:9.2.1-jdk25 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts @@ -10,18 +10,24 @@ RUN gradle --no-daemon installDist EXPOSE 8080 CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ -server \ -XX:+UseNUMA \ -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ - -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ - -Dvertx.flashPolicyHandler=false \ - -Dvertx.threadChecks=false \ -Dvertx.disableContextTimings=true \ - -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ " && \ build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile index 4bdc993707d..86382573446 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.10.2-jdk21 +FROM gradle:9.2.1-jdk25 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts @@ -10,18 +10,24 @@ RUN gradle --no-daemon installDist EXPOSE 8080 CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ -server \ -XX:+UseNUMA \ -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ - -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ - -Dvertx.flashPolicyHandler=false \ - -Dvertx.threadChecks=false \ -Dvertx.disableContextTimings=true \ - -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ " && \ build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false From 907770ce3084c65f3a14065541d3b5254d9fbf29 Mon Sep 17 00:00:00 2001 From: Yongshun Ye Date: Thu, 11 Dec 2025 01:30:01 +0800 Subject: [PATCH 120/130] Increase `io.netty.iouring.ringSize` for some Vert.x benchmarks that use io_uring (#10384) I see the following warnings when running these benchmarks on my device: ``` io.netty.channel.uring.IoUringIoHandler processCompletionsAndHandleOverflow vertx: WARNING: CompletionQueue overflow detected, consider increasing size: 4096 ``` --- frameworks/Java/vertx/vertx-postgres.dockerfile | 1 + frameworks/Java/vertx/vertx.dockerfile | 2 +- .../vertx-web-kotlin-dsljson-postgresql.dockerfile | 2 +- .../vertx-web-kotlin-dsljson.dockerfile | 3 +-- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/Java/vertx/vertx-postgres.dockerfile b/frameworks/Java/vertx/vertx-postgres.dockerfile index fe4477726c8..a444c3541ee 100644 --- a/frameworks/Java/vertx/vertx-postgres.dockerfile +++ b/frameworks/Java/vertx/vertx-postgres.dockerfile @@ -30,6 +30,7 @@ CMD export DBIP=`getent hosts tfb-database | awk '{ print $1 }'` && \ -Dio.netty.noUnsafe=false \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ -jar \ target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar \ src/main/conf/config.json diff --git a/frameworks/Java/vertx/vertx.dockerfile b/frameworks/Java/vertx/vertx.dockerfile index ae194f4c7f8..1920ebc0228 100644 --- a/frameworks/Java/vertx/vertx.dockerfile +++ b/frameworks/Java/vertx/vertx.dockerfile @@ -6,4 +6,4 @@ RUN mvn package -q EXPOSE 8080 -CMD ["java", "--enable-native-access=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "--add-opens=java.base/java.lang=ALL-UNNAMED", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints", "-Djava.lang.Integer.IntegerCache.high=10000", "-Dvertx.disableMetrics=true", "-Dvertx.disableWebsockets=true", "-Dvertx.disableContextTimings=true", "-Dvertx.disableHttpHeadersValidation=true", "-Dvertx.cacheImmutableHttpResponseHeaders=true", "-Dvertx.internCommonHttpRequestHeadersToLowerCase=true", "-Dio.netty.noUnsafe=false", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-jar", "target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar", "src/main/conf/config.json"] +CMD ["java", "--enable-native-access=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "--add-opens=java.base/java.lang=ALL-UNNAMED", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints", "-Djava.lang.Integer.IntegerCache.high=10000", "-Dvertx.disableMetrics=true", "-Dvertx.disableWebsockets=true", "-Dvertx.disableContextTimings=true", "-Dvertx.disableHttpHeadersValidation=true", "-Dvertx.cacheImmutableHttpResponseHeaders=true", "-Dvertx.internCommonHttpRequestHeadersToLowerCase=true", "-Dio.netty.noUnsafe=false", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.iouring.ringSize=16384", "-jar", "target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar", "src/main/conf/config.json"] diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile index b7157b37da2..e75d7fbdb8a 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile @@ -51,6 +51,6 @@ CMD java \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.leakDetection.level=disabled \ -Dio.netty.iouring.ringSize=4096 \ - -Dio.netty.iouring.cqSize=8192 \ + -Dio.netty.iouring.ringSize=16384 \ -Dtfb.type=postgres \ -jar /app/vertx-web-kotlin-dsljson.jar diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile index c69e49fbbfd..d1548a76ae9 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile @@ -50,7 +50,6 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.leakDetection.level=disabled \ - -Dio.netty.iouring.ringSize=4096 \ - -Dio.netty.iouring.cqSize=8192 \ + -Dio.netty.iouring.ringSize=16384 \ -Dtfb.type=basic \ -jar /app/vertx-web-kotlin-dsljson.jar From 549e3f01e224e7d82405573acaa344ac3467bce9 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 10 Dec 2025 18:31:36 +0100 Subject: [PATCH 121/130] [ruby/padrino] Update to Ruby 4.0-rc (#10385) --- frameworks/Ruby/hanami/Gemfile | 2 +- frameworks/Ruby/padrino/Gemfile | 1 + frameworks/Ruby/padrino/Gemfile.lock | 2 ++ frameworks/Ruby/padrino/padrino.dockerfile | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frameworks/Ruby/hanami/Gemfile b/frameworks/Ruby/hanami/Gemfile index 4220b7be74f..2065c222246 100644 --- a/frameworks/Ruby/hanami/Gemfile +++ b/frameworks/Ruby/hanami/Gemfile @@ -16,4 +16,4 @@ gem "rake" gem "rom", "~> 5.3" gem "rom-sql", "~> 3.6" gem "pg" -gem "ostruct" # required for Ruby 3.5 +gem "ostruct" # required for Ruby 4.0 diff --git a/frameworks/Ruby/padrino/Gemfile b/frameworks/Ruby/padrino/Gemfile index 18ff5f9566c..4e9aa2922ea 100644 --- a/frameworks/Ruby/padrino/Gemfile +++ b/frameworks/Ruby/padrino/Gemfile @@ -7,6 +7,7 @@ gem 'activerecord', '~> 8.1.0', :require => 'active_record' gem 'slim' gem 'padrino', '0.16.0' gem 'rack' +gem 'ostruct' # required for Ruby 3.5 group :iodine, optional: true do gem "iodine", "~> 0.7", require: false diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock index e0e649da789..b62ac92b5c5 100644 --- a/frameworks/Ruby/padrino/Gemfile.lock +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -56,6 +56,7 @@ GEM timeout net-smtp (0.5.1) net-protocol + ostruct (0.6.3) padrino (0.16.0) padrino-admin (= 0.16.0) padrino-cache (= 0.16.0) @@ -128,6 +129,7 @@ DEPENDENCIES iodine (~> 0.7) json mysql2 (> 0.5) + ostruct padrino (= 0.16.0) rack slim diff --git a/frameworks/Ruby/padrino/padrino.dockerfile b/frameworks/Ruby/padrino/padrino.dockerfile index 57fe29b1034..50cdbe55042 100644 --- a/frameworks/Ruby/padrino/padrino.dockerfile +++ b/frameworks/Ruby/padrino/padrino.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.4 +FROM ruby:4.0-rc WORKDIR /padrino COPY app app From d874a2e7bc6477a829a68116312c8f9a386fc5d0 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 10 Dec 2025 18:31:51 +0100 Subject: [PATCH 122/130] [ruby/sinatra-sequel] Update sinatra to 4.2 (#10386) --- frameworks/Ruby/sinatra-sequel/Gemfile.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile.lock b/frameworks/Ruby/sinatra-sequel/Gemfile.lock index 6560b48de8d..5d1d43e6228 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile.lock +++ b/frameworks/Ruby/sinatra-sequel/Gemfile.lock @@ -1,13 +1,13 @@ GEM remote: https://rubygems.org/ specs: - base64 (0.2.0) + base64 (0.3.0) bigdecimal (3.3.1) concurrent-ruby (1.3.5) iodine (0.7.58) json (2.16.0) - logger (1.6.6) - mustermann (3.0.3) + logger (1.7.0) + mustermann (3.0.4) ruby2_keywords (~> 0.0.1) nio4r (2.7.4) pg (1.6.2) @@ -15,12 +15,12 @@ GEM pg (1.6.2-x86_64-linux) puma (7.1.0) nio4r (~> 2.0) - rack (3.2.0) - rack-protection (4.1.1) + rack (3.2.4) + rack-protection (4.2.1) base64 (>= 0.1.0) logger (>= 1.6.0) rack (>= 3.0.0, < 4) - rack-session (2.1.0) + rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) ruby2_keywords (0.0.5) @@ -29,14 +29,14 @@ GEM sequel_pg (1.17.2) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) - sinatra (4.1.1) + sinatra (4.2.1) logger (>= 1.6.0) mustermann (~> 3.0) rack (>= 3.0.0, < 4) - rack-protection (= 4.1.1) + rack-protection (= 4.2.1) rack-session (>= 2.0.0, < 3) tilt (~> 2.0) - tilt (2.6.0) + tilt (2.6.1) trilogy (2.9.0) PLATFORMS From 94a84493775a873b9a4885633e851b37665fca35 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 10 Dec 2025 18:32:05 +0100 Subject: [PATCH 123/130] [ruby/grape] Upgrade to Ruby 4.0-rc (#10387) --- frameworks/Ruby/grape/grape-iodine.dockerfile | 2 +- frameworks/Ruby/grape/grape.dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/Ruby/grape/grape-iodine.dockerfile b/frameworks/Ruby/grape/grape-iodine.dockerfile index e103f724274..8db72a592f6 100644 --- a/frameworks/Ruby/grape/grape-iodine.dockerfile +++ b/frameworks/Ruby/grape/grape-iodine.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/grape/grape.dockerfile b/frameworks/Ruby/grape/grape.dockerfile index cbaa7fc385e..83c98fcb4e7 100644 --- a/frameworks/Ruby/grape/grape.dockerfile +++ b/frameworks/Ruby/grape/grape.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0-rc ENV RUBY_YJIT_ENABLE=1 From b3ccafd0582f0f38d3124886f402517fd64e980c Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 10 Dec 2025 18:32:20 +0100 Subject: [PATCH 124/130] [ruby/rack] Hardcode Puma to 5 threads (#10388) This should also improve the performance of JRuby where previously the threads were hardcoded to 512: +---------------------+-----+-----+-----+------+-------+---------+--------------+ | branch_name| json| db|query|update|fortune|plaintext|weighted_score| +---------------------+-----+-----+-----+------+-------+---------+--------------+ | master|15415|14528|12212| 11690| 13936| 144433| 1185| | threads = processors|30345|45011|32726| 22101| 39920| 112966| 2512| |rack/puma-max-threads|29204|50077|45459| 25358| 41560| 117562| 3026| +---------------------+-----+-----+-----+------+-------+---------+--------------+ --- frameworks/Ruby/rack/config/puma.rb | 20 +++++++------------- frameworks/Ruby/rack/hello_world.rb | 4 ++-- frameworks/Ruby/rack/pg_db.rb | 2 -- frameworks/Ruby/rack/rack-jruby.dockerfile | 6 ++++-- frameworks/Ruby/rack/rack.dockerfile | 4 +++- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/frameworks/Ruby/rack/config/puma.rb b/frameworks/Ruby/rack/config/puma.rb index 5f6c878f757..18a4851a761 100644 --- a/frameworks/Ruby/rack/config/puma.rb +++ b/frameworks/Ruby/rack/config/puma.rb @@ -1,17 +1,11 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune - -if RUBY_PLATFORM == 'java' - num_threads = 512 - num_workers = 0 -end - -threads num_threads - -if num_workers > 0 +if ENV.fetch('WEB_CONCURRENCY') == 'auto' before_fork do Sequel::DATABASES.each(&:disconnect) end +else + workers ENV.fetch('WEB_CONCURRENCY') + require 'concurrent/utility/processor_counter' + threads = (::Concurrent.available_processor_count * 1.5).to_i + threads threads + ENV['MAX_THREADS'] = threads.to_s end diff --git a/frameworks/Ruby/rack/hello_world.rb b/frameworks/Ruby/rack/hello_world.rb index 2a806461fa2..9944ac45d40 100644 --- a/frameworks/Ruby/rack/hello_world.rb +++ b/frameworks/Ruby/rack/hello_world.rb @@ -43,8 +43,8 @@ class HelloWorld ' def initialize - if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - max_connections = threads + if defined?(Puma) + max_connections = ENV.fetch('MAX_THREADS') elsif defined?(Itsi) require_relative 'config/auto_tune' _num_workers, num_threads = auto_tune diff --git a/frameworks/Ruby/rack/pg_db.rb b/frameworks/Ruby/rack/pg_db.rb index 51a38cadc85..c7b2c78cc6d 100644 --- a/frameworks/Ruby/rack/pg_db.rb +++ b/frameworks/Ruby/rack/pg_db.rb @@ -7,8 +7,6 @@ Jdbc::Postgres.load_driver end - - class PgDb QUERY_RANGE = (1..10_000).freeze # range of IDs in the Fortune DB ALL_IDS = QUERY_RANGE.to_a # enumeration of all the IDs in fortune DB diff --git a/frameworks/Ruby/rack/rack-jruby.dockerfile b/frameworks/Ruby/rack/rack-jruby.dockerfile index 062547508ca..3e786c1a2e5 100644 --- a/frameworks/Ruby/rack/rack-jruby.dockerfile +++ b/frameworks/Ruby/rack/rack-jruby.dockerfile @@ -6,13 +6,15 @@ WORKDIR /rack COPY Gemfile* ./ +#RUN echo $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) + RUN bundle config set with 'puma' RUN bundle install --jobs=8 COPY . . -EXPOSE 8080 +ENV WEB_CONCURRENCY=0 -CMD config/java_tune.sh +EXPOSE 8080 CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index b91c8e10c11..dea3795b187 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -17,7 +17,9 @@ RUN bundle install --jobs=8 COPY . . -EXPOSE 8080 ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + +EXPOSE 8080 CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production From a417041e2a7adfcaf699989ffbc51452748578d6 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Wed, 10 Dec 2025 19:41:20 +0100 Subject: [PATCH 125/130] [ruby/grape] Hardcode Puma to 5 threads (#10389) Also extract most logic to a boot.rb, similarly to other Ruby frameworks. --- frameworks/Ruby/grape/boot.rb | 91 ++++++++++++++++++ frameworks/Ruby/grape/config.ru | 94 +------------------ frameworks/Ruby/grape/config/database.yml | 2 +- frameworks/Ruby/grape/config/puma.rb | 13 --- frameworks/Ruby/grape/grape-iodine.dockerfile | 3 +- frameworks/Ruby/grape/grape.dockerfile | 6 +- 6 files changed, 99 insertions(+), 110 deletions(-) create mode 100644 frameworks/Ruby/grape/boot.rb delete mode 100644 frameworks/Ruby/grape/config/puma.rb diff --git a/frameworks/Ruby/grape/boot.rb b/frameworks/Ruby/grape/boot.rb new file mode 100644 index 00000000000..dd2ffda7f0e --- /dev/null +++ b/frameworks/Ruby/grape/boot.rb @@ -0,0 +1,91 @@ +require 'erb' +require 'active_record' +require 'yaml' + +MAX_PK = 10_000 +ID_RANGE = (1..MAX_PK).freeze +ALL_IDS = ID_RANGE.to_a +QUERIES_MIN = 1 +QUERIES_MAX = 500 + +Bundler.require :default + +db_config = YAML.load(ERB.new(File.read('config/database.yml')).result)[ENV['RACK_ENV']] +ActiveRecord::Base.establish_connection(db_config) + +class World < ActiveRecord::Base + self.table_name = 'World' +end + +module Acme + class HelloWorld < Grape::API + get '/json' do + {message:'Hello, World!'} + end + end + + class PlainText < Grape::API + content_type :plain, 'text/plain' + format :plain + + get '/plaintext' do + 'Hello, World!' + end + end + + class DatabaseQueries < Grape::API + logger nil + helpers do + def bounded_queries + queries = params[:queries].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end + + # Return a random number between 1 and MAX_PK + def rand1 + rand(MAX_PK).succ + end + end + + get '/db' do + ActiveRecord::Base.with_connection do + World.find(rand1).attributes + end + end + + get '/query' do + ActiveRecord::Base.with_connection do + ALL_IDS.sample(bounded_queries).map do |id| + World.find(id) + end + end + end + + get '/updates' do + worlds = + ActiveRecord::Base.with_connection do + ALL_IDS.sample(bounded_queries).map do |id| + world = World.find(id) + new_value = rand1 + new_value = rand1 while new_value == world.randomNumber + world.update_columns(randomNumber: new_value) + world + end + end + end + end + + class API < Grape::API + before do + header 'Date', Time.now.httpdate if defined?(Puma) + header 'Server', 'grape' + end + logger nil + content_type :json, 'application/json' + format :json + + mount ::Acme::HelloWorld + mount ::Acme::PlainText + mount ::Acme::DatabaseQueries + end +end diff --git a/frameworks/Ruby/grape/config.ru b/frameworks/Ruby/grape/config.ru index c06dc281e5d..54d0ce8ca74 100644 --- a/frameworks/Ruby/grape/config.ru +++ b/frameworks/Ruby/grape/config.ru @@ -1,94 +1,2 @@ -require 'erb' -require 'active_record' -require 'yaml' -require_relative 'config/auto_tune' - -MAX_PK = 10_000 -ID_RANGE = (1..MAX_PK).freeze -ALL_IDS = ID_RANGE.to_a -QUERIES_MIN = 1 -QUERIES_MAX = 500 - -Bundler.require :default - -db_config = YAML.load(ERB.new(File.read('config/database.yml')).result)[ENV['RACK_ENV']] -ActiveRecord::Base.establish_connection(db_config) - -class World < ActiveRecord::Base - self.table_name = 'World' -end - -module Acme - class HelloWorld < Grape::API - get '/json' do - {message:'Hello, World!'} - end - end - - class PlainText < Grape::API - content_type :plain, 'text/plain' - format :plain - - get '/plaintext' do - 'Hello, World!' - end - end - - class DatabaseQueries < Grape::API - logger nil - helpers do - def bounded_queries - queries = params[:queries].to_i - queries.clamp(QUERIES_MIN, QUERIES_MAX) - end - - # Return a random number between 1 and MAX_PK - def rand1 - rand(MAX_PK).succ - end - end - - get '/db' do - ActiveRecord::Base.with_connection do - World.find(rand1).attributes - end - end - - get '/query' do - ActiveRecord::Base.with_connection do - ALL_IDS.sample(bounded_queries).map do |id| - World.find(id) - end - end - end - - get '/updates' do - worlds = - ActiveRecord::Base.with_connection do - ALL_IDS.sample(bounded_queries).map do |id| - world = World.find(id) - new_value = rand1 - new_value = rand1 while new_value == world.randomNumber - world.update_columns(randomNumber: new_value) - world - end - end - end - end - - class API < Grape::API - before do - header 'Date', Time.now.httpdate if defined?(Puma) - header 'Server', 'grape' - end - logger nil - content_type :json, 'application/json' - format :json - - mount ::Acme::HelloWorld - mount ::Acme::PlainText - mount ::Acme::DatabaseQueries - end -end - +require_relative 'boot' run Acme::API diff --git a/frameworks/Ruby/grape/config/database.yml b/frameworks/Ruby/grape/config/database.yml index 9be8d7d851a..32ce75b69bf 100644 --- a/frameworks/Ruby/grape/config/database.yml +++ b/frameworks/Ruby/grape/config/database.yml @@ -5,5 +5,5 @@ production: database: hello_world username: benchmarkdbuser password: benchmarkdbpass - pool: 3 + pool: <%= ENV.fetch('MAX_THREADS') %> timeout: 5000 diff --git a/frameworks/Ruby/grape/config/puma.rb b/frameworks/Ruby/grape/config/puma.rb deleted file mode 100644 index a489e1af89d..00000000000 --- a/frameworks/Ruby/grape/config/puma.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -_, num_threads = auto_tune - -threads num_threads - -# Use the `preload_app!` method when specifying a `workers` number. -# This directive tells Puma to first boot the application and load code -# before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. -# -preload_app! diff --git a/frameworks/Ruby/grape/grape-iodine.dockerfile b/frameworks/Ruby/grape/grape-iodine.dockerfile index 8db72a592f6..4e20c95ba1c 100644 --- a/frameworks/Ruby/grape/grape-iodine.dockerfile +++ b/frameworks/Ruby/grape/grape-iodine.dockerfile @@ -14,9 +14,10 @@ ADD ./ /grape WORKDIR /grape RUN bundle config set with 'iodine' -RUN bundle install --jobs=4 --gemfile=/grape/Gemfile +RUN bundle install --jobs=8 --gemfile=/grape/Gemfile ENV RACK_ENV=production +ENV MAX_THREADS=1 EXPOSE 8080 diff --git a/frameworks/Ruby/grape/grape.dockerfile b/frameworks/Ruby/grape/grape.dockerfile index 83c98fcb4e7..2ef47fcaed2 100644 --- a/frameworks/Ruby/grape/grape.dockerfile +++ b/frameworks/Ruby/grape/grape.dockerfile @@ -12,9 +12,11 @@ ADD ./ /grape WORKDIR /grape RUN bundle config set with 'puma' -RUN bundle install --jobs=4 --gemfile=/grape/Gemfile +RUN bundle install --jobs=8 --gemfile=/grape/Gemfile ENV WEB_CONCURRENCY=auto +ENV MAX_THREADS=5 + EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -b tcp://0.0.0.0:8080 -e production From 597b2d03165cd1ce65de48c3c2b4f53833eaeebe Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 11 Dec 2025 20:49:00 +0100 Subject: [PATCH 126/130] [php] CakePHP update to PHP 8.5 (#10337) * [php] CakePHP update to PHP 8.5 * Fix deprecated RFC * Update error reporting settings for PHP 8.5 * Quiet composer * Update benchmark_config.json for CakePHP [skip] --- frameworks/PHP/cakephp/benchmark_config.json | 3 ++- frameworks/PHP/cakephp/cakephp-workerman.dockerfile | 13 +++++++------ frameworks/PHP/cakephp/cakephp.dockerfile | 10 +++++----- frameworks/PHP/cakephp/deploy/conf/cli-php.ini | 3 +++ frameworks/PHP/cakephp/server.php | 6 +++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/frameworks/PHP/cakephp/benchmark_config.json b/frameworks/PHP/cakephp/benchmark_config.json index 351a5d119b4..723b55e35b0 100644 --- a/frameworks/PHP/cakephp/benchmark_config.json +++ b/frameworks/PHP/cakephp/benchmark_config.json @@ -43,9 +43,10 @@ "webserver": "none", "os": "Linux", "database_os": "Linux", - "display_name": "CakePHP-workerman", + "display_name": "CakePHP [workerman]", "notes": "", "versus": "php" } }] } + diff --git a/frameworks/PHP/cakephp/cakephp-workerman.dockerfile b/frameworks/PHP/cakephp/cakephp-workerman.dockerfile index ce77247eb6c..776e55f1252 100644 --- a/frameworks/PHP/cakephp/cakephp-workerman.dockerfile +++ b/frameworks/PHP/cakephp/cakephp-workerman.dockerfile @@ -7,24 +7,25 @@ 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 git unzip \ - php8.4-cli php8.4-mysql php8.4-mbstring php8.4-intl php8.4-xml php8.4-curl > /dev/null + php8.5-cli php8.5-mysql php8.5-mbstring php8.5-intl php8.5-xml php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini EXPOSE 8080 ADD ./ /cakephp WORKDIR /cakephp -RUN composer require joanhey/adapterman:^0.7 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer require joanhey/adapterman:^0.7 --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod -R 777 /cakephp -#COPY deploy/conf/cli-php.ini /etc/php/8.4/cli/php.ini +#COPY deploy/conf/cli-php.ini /etc/php/8.5/cli/php.ini CMD php -c deploy/conf/cli-php.ini \ server.php start + diff --git a/frameworks/PHP/cakephp/cakephp.dockerfile b/frameworks/PHP/cakephp/cakephp.dockerfile index d5d39a7ea65..efd5894a928 100644 --- a/frameworks/PHP/cakephp/cakephp.dockerfile +++ b/frameworks/PHP/cakephp/cakephp.dockerfile @@ -7,22 +7,22 @@ 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 nginx git unzip \ - php8.4-fpm php8.4-mysql php8.4-xml php8.4-mbstring php8.4-intl php8.4-dev php8.4-curl > /dev/null + php8.5-fpm php8.5-mysql php8.5-xml php8.5-mbstring php8.5-intl php8.5-dev php8.5-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.4/fpm/ -COPY deploy/conf/* /etc/php/8.4/cli/ +COPY deploy/conf/* /etc/php/8.5/fpm/ +COPY deploy/conf/* /etc/php/8.5/cli/ ADD ./ /cakephp WORKDIR /cakephp -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod -R 777 /cakephp -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /cakephp/deploy/nginx.conf diff --git a/frameworks/PHP/cakephp/deploy/conf/cli-php.ini b/frameworks/PHP/cakephp/deploy/conf/cli-php.ini index e03b6e352a9..d2c550c65ee 100644 --- a/frameworks/PHP/cakephp/deploy/conf/cli-php.ini +++ b/frameworks/PHP/cakephp/deploy/conf/cli-php.ini @@ -14,3 +14,6 @@ opcache.jit_buffer_size = 128M opcache.jit = tracing disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit + +#php 8.5 +error_reporting = E_ALL & ~E_DEPRECATED diff --git a/frameworks/PHP/cakephp/server.php b/frameworks/PHP/cakephp/server.php index 820e178205d..ce502ed9bee 100644 --- a/frameworks/PHP/cakephp/server.php +++ b/frameworks/PHP/cakephp/server.php @@ -26,7 +26,7 @@ class HeaderDate { - const NAME = 'Date: '; + const DATE_FORMAT = 'D, d M Y H:i:s \G\M\T'; /** * Date header @@ -37,9 +37,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME.gmdate(DATE_RFC7231); + self::$date = 'Date: '.gmdate(self::DATE_FORMAT); Timer::add(1, static function () { - self::$date = self::NAME.gmdate(DATE_RFC7231); + self::$date = 'Date: '.gmdate(self::DATE_FORMAT); }); } } From 55edd012f6e600e5ef435fa8a2337858913bcfb3 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 11 Dec 2025 20:49:17 +0100 Subject: [PATCH 127/130] [crystal] Update to 1.18.2 (#10390) --- .../Crystal/crystal/crystal-radix.dockerfile | 2 +- frameworks/Crystal/crystal/crystal.dockerfile | 2 +- frameworks/Crystal/lucky/lucky.dockerfile | 2 +- frameworks/Crystal/lucky/shard.lock | 2 +- frameworks/Crystal/spider-gazelle/shard.lock | 24 +++++++------------ .../spider-gazelle/spider-gazelle.dockerfile | 2 +- 6 files changed, 13 insertions(+), 21 deletions(-) diff --git a/frameworks/Crystal/crystal/crystal-radix.dockerfile b/frameworks/Crystal/crystal/crystal-radix.dockerfile index deda5e21148..fb3f1325da6 100644 --- a/frameworks/Crystal/crystal/crystal-radix.dockerfile +++ b/frameworks/Crystal/crystal/crystal-radix.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.12.1 +FROM crystallang/crystal:1.18.2 WORKDIR /crystal COPY shard.yml shard.yml diff --git a/frameworks/Crystal/crystal/crystal.dockerfile b/frameworks/Crystal/crystal/crystal.dockerfile index 678dd214cd4..a775fc07e66 100644 --- a/frameworks/Crystal/crystal/crystal.dockerfile +++ b/frameworks/Crystal/crystal/crystal.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.12.1 +FROM crystallang/crystal:1.18.2 WORKDIR /crystal COPY shard.yml shard.yml diff --git a/frameworks/Crystal/lucky/lucky.dockerfile b/frameworks/Crystal/lucky/lucky.dockerfile index 1f352cf53bd..f2c38af3c71 100644 --- a/frameworks/Crystal/lucky/lucky.dockerfile +++ b/frameworks/Crystal/lucky/lucky.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.14.0 +FROM crystallang/crystal:1.18.2 WORKDIR /lucky COPY shard.lock shard.lock diff --git a/frameworks/Crystal/lucky/shard.lock b/frameworks/Crystal/lucky/shard.lock index 34f8bfcfea6..fe77e4ef539 100644 --- a/frameworks/Crystal/lucky/shard.lock +++ b/frameworks/Crystal/lucky/shard.lock @@ -6,7 +6,7 @@ shards: backtracer: git: https://github.com/sija/backtracer.cr.git - version: 1.2.2 + version: 1.2.4 cadmium_transliterator: git: https://github.com/cadmiumcr/transliterator.git diff --git a/frameworks/Crystal/spider-gazelle/shard.lock b/frameworks/Crystal/spider-gazelle/shard.lock index a73d29d085c..bc26543af7e 100644 --- a/frameworks/Crystal/spider-gazelle/shard.lock +++ b/frameworks/Crystal/spider-gazelle/shard.lock @@ -2,7 +2,7 @@ version: 2.0 shards: action-controller: git: https://github.com/spider-gazelle/action-controller.git - version: 7.4.3 + version: 7.6.1 active-model: git: https://github.com/spider-gazelle/active-model.git @@ -10,7 +10,7 @@ shards: backtracer: git: https://github.com/sija/backtracer.cr.git - version: 1.2.2 + version: 1.2.4 db: git: https://github.com/crystal-lang/crystal-db.git @@ -18,7 +18,7 @@ shards: eventbus: git: https://github.com/spider-gazelle/eventbus.git - version: 1.0.0+git.commit.af63536d718348885a553dc4aa6debccc2946289 + version: 1.0.1+git.commit.a707ac06aba16ba6070ff4972acfd839f1f05e15 exception_page: git: https://github.com/crystal-loot/exception_page.git @@ -30,7 +30,7 @@ shards: hot_topic: git: https://github.com/jgaskins/hot_topic.git - version: 0.1.0+git.commit.3c901e77b6e000930398738260a2944b6f5785dc + version: 0.1.0+git.commit.4eafc046ed4d98bbab7a4534da57e163ea16b6c6 http-params-serializable: git: https://github.com/place-labs/http-params-serializable.git @@ -38,7 +38,7 @@ shards: json-schema: git: https://github.com/spider-gazelle/json-schema.git - version: 1.3.1 + version: 1.3.2 kilt: git: https://github.com/jeromegn/kilt.git @@ -46,21 +46,13 @@ shards: lucky_router: git: https://github.com/luckyframework/lucky_router.git - version: 0.6.0 + version: 0.6.1 pg: git: https://github.com/will/crystal-pg.git - version: 0.28.0 + version: 0.29.0 pg-orm: git: https://github.com/spider-gazelle/pg-orm.git - version: 1.1.2+git.commit.9b340ee269cd4a10ed6c5b51235cbaf45fc380e1 - - pool: - git: https://github.com/ysbaddaden/pool.git - version: 0.2.4 - - redis: - git: https://github.com/stefanwille/crystal-redis.git - version: 2.9.1 + version: 2.1.0 diff --git a/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile b/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile index c836b434c44..8f811eead03 100644 --- a/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile +++ b/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.14.0 +FROM crystallang/crystal:1.18.2 WORKDIR /usr/src/app From 883c4fbab17e098bdb278c1410697c1a414703d7 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 11 Dec 2025 20:49:40 +0100 Subject: [PATCH 128/130] Remove Onyx framework (#10391) Onyx had the last commit 6 years ago. --- frameworks/Crystal/onyx/README.md | 11 ---- frameworks/Crystal/onyx/benchmark_config.json | 29 ----------- frameworks/Crystal/onyx/config.toml | 18 ------- frameworks/Crystal/onyx/onyx.dockerfile | 16 ------ frameworks/Crystal/onyx/run.sh | 5 -- frameworks/Crystal/onyx/shard.lock | 50 ------------------- frameworks/Crystal/onyx/shard.yml | 24 --------- .../Crystal/onyx/src/endpoints/random_id.cr | 5 -- .../Crystal/onyx/src/endpoints/worlds/many.cr | 25 ---------- .../onyx/src/endpoints/worlds/random.cr | 11 ---- .../onyx/src/endpoints/worlds/update.cr | 28 ----------- frameworks/Crystal/onyx/src/models/world.cr | 8 --- .../Crystal/onyx/src/server_postgres.cr | 37 -------------- frameworks/Crystal/onyx/src/views/world.cr | 13 ----- frameworks/Crystal/onyx/src/views/worlds.cr | 8 --- 15 files changed, 288 deletions(-) delete mode 100755 frameworks/Crystal/onyx/README.md delete mode 100755 frameworks/Crystal/onyx/benchmark_config.json delete mode 100644 frameworks/Crystal/onyx/config.toml delete mode 100644 frameworks/Crystal/onyx/onyx.dockerfile delete mode 100644 frameworks/Crystal/onyx/run.sh delete mode 100644 frameworks/Crystal/onyx/shard.lock delete mode 100644 frameworks/Crystal/onyx/shard.yml delete mode 100644 frameworks/Crystal/onyx/src/endpoints/random_id.cr delete mode 100644 frameworks/Crystal/onyx/src/endpoints/worlds/many.cr delete mode 100644 frameworks/Crystal/onyx/src/endpoints/worlds/random.cr delete mode 100644 frameworks/Crystal/onyx/src/endpoints/worlds/update.cr delete mode 100644 frameworks/Crystal/onyx/src/models/world.cr delete mode 100644 frameworks/Crystal/onyx/src/server_postgres.cr delete mode 100644 frameworks/Crystal/onyx/src/views/world.cr delete mode 100644 frameworks/Crystal/onyx/src/views/worlds.cr diff --git a/frameworks/Crystal/onyx/README.md b/frameworks/Crystal/onyx/README.md deleted file mode 100755 index df04ff51c00..00000000000 --- a/frameworks/Crystal/onyx/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Crystal-Onyx - -This is the [Onyx](https://github.com/onyxframework/) test of the Framework Benchmarks. Crystal is a new language that closely resembles Ruby with a goal of removing typed variables and parameters (instead inferencing), whilst maintaining top speed through bindings into C. - -The framework consists of multiple components: - -[Onyx::HTTP](https://github.com/onyxframework/http) is a collection of HTTP handlers, which essentially are building blocks for your web application -[Onyx::REST](https://github.com/onyxframework/rest) is a REST layer on top of Onyx::HTTP which implements splitting business and rendering logic into Actions and Views, inspired by Hanami -[Onyx::SQL](https://github.com/onyxframework/rest) is a database-agnostic SQL ORM - -Onyx Framework is designed to be both powerful and adoptable by Crystal newcomers. It utilizes complex concepts like annotations and generics, but hides it under beautiful DSL. Such an approach makes it possible to write less code, thus reducing the possibility of bugs, but still make it easy to extend the framework’s functionality. diff --git a/frameworks/Crystal/onyx/benchmark_config.json b/frameworks/Crystal/onyx/benchmark_config.json deleted file mode 100755 index a0646d4084c..00000000000 --- a/frameworks/Crystal/onyx/benchmark_config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "framework": "onyx", - "tests": [ - { - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Onyx", - "language": "Crystal", - "flavor": "None", - "orm": "Full", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Onyx (PostgreSQL)", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Crystal/onyx/config.toml b/frameworks/Crystal/onyx/config.toml deleted file mode 100644 index 8f7a33c7863..00000000000 --- a/frameworks/Crystal/onyx/config.toml +++ /dev/null @@ -1,18 +0,0 @@ -[framework] -name = "onyx" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/Crystal/onyx/onyx.dockerfile b/frameworks/Crystal/onyx/onyx.dockerfile deleted file mode 100644 index c861ec9e072..00000000000 --- a/frameworks/Crystal/onyx/onyx.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM crystallang/crystal:0.27.2 - -WORKDIR /onyx -COPY run.sh run.sh -COPY src src -COPY shard.yml shard.yml - -ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_pool_size=56&max_idle_pool_size=56 -ENV TEST_HOST tfb-server -ENV CRYSTAL_ENV benchmarking - -RUN shards install -RUN crystal build --release --no-debug src/server_postgres.cr - -EXPOSE 8080 -CMD bash run.sh diff --git a/frameworks/Crystal/onyx/run.sh b/frameworks/Crystal/onyx/run.sh deleted file mode 100644 index f8f69e90674..00000000000 --- a/frameworks/Crystal/onyx/run.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -./server_postgres -p 8080 & - -wait diff --git a/frameworks/Crystal/onyx/shard.lock b/frameworks/Crystal/onyx/shard.lock deleted file mode 100644 index 952301ca654..00000000000 --- a/frameworks/Crystal/onyx/shard.lock +++ /dev/null @@ -1,50 +0,0 @@ -version: 1.0 -shards: - callbacks: - github: vladfaust/callbacks.cr - version: 0.2.0 - - db: - github: crystal-lang/crystal-db - version: 0.5.1 - - dotenv: - github: gdotdesign/cr-dotenv - version: 0.1.0 - - exception_page: - github: crystal-loot/exception_page - version: 0.1.2 - - http-params-serializable: - github: vladfaust/http-params-serializable - version: 0.3.0 - - kilt: - github: jeromegn/kilt - version: 0.4.0 - - onyx: - github: onyxframework/onyx - version: 0.3.1 - - onyx-http: - github: onyxframework/http - version: 0.7.1 - - onyx-sql: - github: onyxframework/sql - version: 0.7.1 - - pg: - github: will/crystal-pg - version: 0.15.0 - - radix: - github: luislavena/radix - version: 0.3.9 - - time_format: - github: vladfaust/time_format.cr - version: 0.1.1 - diff --git a/frameworks/Crystal/onyx/shard.yml b/frameworks/Crystal/onyx/shard.yml deleted file mode 100644 index 7f2f6d18bd3..00000000000 --- a/frameworks/Crystal/onyx/shard.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: onyx -version: 0.2.0 - -authors: - - Vlad Faust - - Carlos Donderis - -crystal: 0.27.2 - -license: MIT - -dependencies: - onyx: - github: onyxframework/onyx - version: ~> 0.3.0 - onyx-http: - github: onyxframework/http - version: ~> 0.7.0 - onyx-sql: - github: onyxframework/sql - version: ~> 0.7.0 - pg: - github: will/crystal-pg - version: ~> 0.15.0 diff --git a/frameworks/Crystal/onyx/src/endpoints/random_id.cr b/frameworks/Crystal/onyx/src/endpoints/random_id.cr deleted file mode 100644 index 51101ad470c..00000000000 --- a/frameworks/Crystal/onyx/src/endpoints/random_id.cr +++ /dev/null @@ -1,5 +0,0 @@ -module Endpoints::RandomID - def random_id - Random.rand(10_000).succ - end -end diff --git a/frameworks/Crystal/onyx/src/endpoints/worlds/many.cr b/frameworks/Crystal/onyx/src/endpoints/worlds/many.cr deleted file mode 100644 index 0904dcfc299..00000000000 --- a/frameworks/Crystal/onyx/src/endpoints/worlds/many.cr +++ /dev/null @@ -1,25 +0,0 @@ -struct Endpoints::Worlds::Many - include Onyx::HTTP::Endpoint - include RandomID - - QUERY = Models::World.where(id: 0).build(true)[0] - - params do - query do - type queries : String | Int32 = 1 - end - end - - def call - queries = params.query.queries.is_a?(String) ? 1 : params.query.queries.as(Int32) - - worlds = Array(Models::World).new - - queries.clamp(1..500).times.each do - world = Onyx.query(Models::World, QUERY, random_id).first - worlds << world - end - - return Views::Worlds.new(worlds) - end -end diff --git a/frameworks/Crystal/onyx/src/endpoints/worlds/random.cr b/frameworks/Crystal/onyx/src/endpoints/worlds/random.cr deleted file mode 100644 index e20ee671833..00000000000 --- a/frameworks/Crystal/onyx/src/endpoints/worlds/random.cr +++ /dev/null @@ -1,11 +0,0 @@ -struct Endpoints::Worlds::Random - include Onyx::HTTP::Endpoint - include RandomID - - QUERY = Models::World.where(id: 0).build(true)[0] - - def call - world = Onyx.query(Models::World, QUERY, random_id).first - return Views::World.new(world) - end -end diff --git a/frameworks/Crystal/onyx/src/endpoints/worlds/update.cr b/frameworks/Crystal/onyx/src/endpoints/worlds/update.cr deleted file mode 100644 index acf16a66267..00000000000 --- a/frameworks/Crystal/onyx/src/endpoints/worlds/update.cr +++ /dev/null @@ -1,28 +0,0 @@ -struct Endpoints::Worlds::Update - include Onyx::HTTP::Endpoint - include RandomID - - SELECT_QUERY = Models::World.where(id: 0).build(true)[0] - UPDATE_QUERY = Models::World.update.set(random_number: 0).where(id: 0).build[0] - - params do - query do - type queries : String | Int32 = 1 - end - end - - def call - queries = params.query.queries.is_a?(String) ? 1 : params.query.queries.as(Int32) - - worlds = Array(Models::World).new - - queries.clamp(1..500).times.each do - world = Onyx.query(Models::World, SELECT_QUERY, random_id).first - world.random_number = random_id - Onyx.exec(UPDATE_QUERY, world.random_number, world.id) - worlds << world - end - - return Views::Worlds.new(worlds) - end -end diff --git a/frameworks/Crystal/onyx/src/models/world.cr b/frameworks/Crystal/onyx/src/models/world.cr deleted file mode 100644 index a187eb97477..00000000000 --- a/frameworks/Crystal/onyx/src/models/world.cr +++ /dev/null @@ -1,8 +0,0 @@ -class Models::World - include Onyx::SQL::Model - - schema world do - pkey id : Int32 - type random_number : Int32, key: "randomnumber" - end -end diff --git a/frameworks/Crystal/onyx/src/server_postgres.cr b/frameworks/Crystal/onyx/src/server_postgres.cr deleted file mode 100644 index a0d51bb15f2..00000000000 --- a/frameworks/Crystal/onyx/src/server_postgres.cr +++ /dev/null @@ -1,37 +0,0 @@ -require "pg" -require "onyx/sql" -require "onyx/http" - -require "./models/*" -require "./views/*" -require "./endpoints/**" - -class CustomHandler - include HTTP::Handler - - def call(context) - context.response.headers["Server"] = "Onyx" - context.response.headers["Date"] = HTTP.format_time(Time.now) - call_next(context) - end -end - -Onyx.draw do - get "/json" do |env| - env.response.content_type = "application/json" - {message: "Hello, World!"}.to_json(env.response) - end - - get "/db", Endpoints::Worlds::Random - get "/queries", Endpoints::Worlds::Many - get "/updates", Endpoints::Worlds::Update - - get "/plaintext" do |env| - env.response.content_type = "text/plain" - env.response << "Hello, World!" - end -end - -Onyx.listen(ENV["TEST_HOST"], 8080) do - handlers.unshift(CustomHandler.new) -end diff --git a/frameworks/Crystal/onyx/src/views/world.cr b/frameworks/Crystal/onyx/src/views/world.cr deleted file mode 100644 index 06f8b989c9c..00000000000 --- a/frameworks/Crystal/onyx/src/views/world.cr +++ /dev/null @@ -1,13 +0,0 @@ -struct Views::World - include Onyx::HTTP::View - - def initialize(@world : Models::World) - end - - json do - object do - field "id", @world.id - field "randomnumber", @world.random_number - end - end -end diff --git a/frameworks/Crystal/onyx/src/views/worlds.cr b/frameworks/Crystal/onyx/src/views/worlds.cr deleted file mode 100644 index 64a02d282b3..00000000000 --- a/frameworks/Crystal/onyx/src/views/worlds.cr +++ /dev/null @@ -1,8 +0,0 @@ -struct Views::Worlds - include Onyx::HTTP::View - - def initialize(@worlds : Enumerable(Models::World)) - end - - json @worlds.map { |world| Views::World.new(world) } -end From 36f19be611b812a1ccdd6f21c3d5ccf2912509fb Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Thu, 11 Dec 2025 21:36:26 +0000 Subject: [PATCH 129/130] toolset: Tune the AIO parameters for PostgreSQL 18 (#10378) Signed-off-by: Anton Kirilov --- toolset/databases/postgres/config.sh | 9 ++++++++- toolset/databases/postgres/postgres.dockerfile | 6 ++---- toolset/databases/postgres/postgresql.conf | 5 +++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/toolset/databases/postgres/config.sh b/toolset/databases/postgres/config.sh index ea3d95e4b7c..8ed1efc94e3 100755 --- a/toolset/databases/postgres/config.sh +++ b/toolset/databases/postgres/config.sh @@ -2,4 +2,11 @@ set -e -cat /tmp/postgresql.conf >> "${PGDATA}/postgresql.conf" +cat /docker-entrypoint-initdb.d/postgresql.conf >> "${PGDATA}/postgresql.conf" + +IO_WORKERS="$(( (`nproc` + 3) / 4 ))" + +# The maximum valid value for the io_workers configuration parameter is 32. +if [[ "$IO_WORKERS" -lt 32 ]]; then + sed -i "s/io_workers = 32/io_workers = ${IO_WORKERS}/" "${PGDATA}/postgresql.conf" +fi diff --git a/toolset/databases/postgres/postgres.dockerfile b/toolset/databases/postgres/postgres.dockerfile index 0573b85b2ca..c5d1db814b3 100644 --- a/toolset/databases/postgres/postgres.dockerfile +++ b/toolset/databases/postgres/postgres.dockerfile @@ -1,10 +1,8 @@ FROM postgres:18-trixie -ENV PGDATA=/ssd/postgresql \ - POSTGRES_DB=hello_world \ +ENV POSTGRES_DB=hello_world \ POSTGRES_PASSWORD=benchmarkdbpass \ POSTGRES_USER=benchmarkdbuser COPY 60-postgresql-shm.conf /etc/sysctl.d/ -COPY config.sh create-postgres.sql /docker-entrypoint-initdb.d/ -COPY postgresql.conf /tmp/ +COPY config.sh create-postgres.sql postgresql.conf /docker-entrypoint-initdb.d/ diff --git a/toolset/databases/postgres/postgresql.conf b/toolset/databases/postgres/postgresql.conf index 72c94956692..5000f5193e5 100644 --- a/toolset/databases/postgres/postgresql.conf +++ b/toolset/databases/postgres/postgresql.conf @@ -5,6 +5,11 @@ listen_addresses = '*' max_connections = 2000 ssl = false +# Tuning AIO in PostgreSQL 18: +# https://vondra.me/posts/tuning-aio-in-postgresql-18 +# The config.sh script sets the actual value based on that article and the runtime environment. +io_workers = 32 + # values from: http://blog.pgaddict.com/posts/performance-since-postgresql-7-4-to-9-4-pgbench # details: http://www.postgresql.org/docs/9.4/static/runtime-config-resource.html # http://www.postgresql.org/docs/9.4/static/runtime-config-wal.html From 8892a4e2ede5c9c07d5861af98c8b4afa9559994 Mon Sep 17 00:00:00 2001 From: Petrik de Heus Date: Thu, 11 Dec 2025 22:37:09 +0100 Subject: [PATCH 130/130] [crystal/grip] Fix tests and update to Crystal 1.18.2 (#10392) --- frameworks/Crystal/grip/benchmark_config.json | 1 - frameworks/Crystal/grip/grip.cr | 69 +++++++++++-------- frameworks/Crystal/grip/grip.dockerfile | 2 +- frameworks/Crystal/grip/shard.yml | 4 +- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/frameworks/Crystal/grip/benchmark_config.json b/frameworks/Crystal/grip/benchmark_config.json index fbd828243a3..56cd319dfc9 100644 --- a/frameworks/Crystal/grip/benchmark_config.json +++ b/frameworks/Crystal/grip/benchmark_config.json @@ -23,7 +23,6 @@ "database_os": "Linux", "display_name": "Grip", "notes": "", - "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Crystal/grip/grip.cr b/frameworks/Crystal/grip/grip.cr index 1b8a64b6667..6acd519566b 100644 --- a/frameworks/Crystal/grip/grip.cr +++ b/frameworks/Crystal/grip/grip.cr @@ -32,8 +32,10 @@ private def sanitized_query_count(request) queries.clamp(1..500) end -class Json < Grip::Controllers::Http - def get(context) +class JsonController + include Grip::Controllers::HTTP + + def get(context : Context) context .put_resp_header("Server", "Grip") .put_resp_header("Date", HTTP.format_time(Time.utc)) @@ -45,8 +47,10 @@ class Json < Grip::Controllers::Http end end -class Plaintext < Grip::Controllers::Http - def get(context) +class PlaintextController + include Grip::Controllers::HTTP + + def get(context : Context) context .put_resp_header("Server", "Grip") .put_resp_header("Date", HTTP.format_time(Time.utc)) @@ -56,8 +60,10 @@ class Plaintext < Grip::Controllers::Http end end -class Db < Grip::Controllers::Http - def get(context) +class DbController + include Grip::Controllers::HTTP + + def get(context : Context) context .put_resp_header("Server", "Grip") .put_resp_header("Date", HTTP.format_time(Time.utc)) @@ -67,8 +73,10 @@ class Db < Grip::Controllers::Http end end -class Queries < Grip::Controllers::Http - def get(context) +class QueriesController + include Grip::Controllers::HTTP + + def get(context : Context) results = (1..sanitized_query_count(context.request)).map do random_world end @@ -82,8 +90,10 @@ class Queries < Grip::Controllers::Http end end -class Updates < Grip::Controllers::Http - def get(context) +class UpdatesController + include Grip::Controllers::HTTP + + def get(context : Context) updated = (1..sanitized_query_count(context.request)).map do set_world({id: random_world[:id], randomNumber: rand(1..ID_MAXIMUM)}) end @@ -97,8 +107,10 @@ class Updates < Grip::Controllers::Http end end -class Fortunes < Grip::Controllers::Http - def get(context) +class FortunesController + include Grip::Controllers::HTTP + + def get(context : Context) data = fortunes additional_fortune = { id: 0, @@ -119,26 +131,23 @@ class Fortunes < Grip::Controllers::Http end end -class Application < Grip::Application - def initialize - super(environment: "production") - - get "/json", Json - get "/plaintext", Plaintext - get "/db", Db - get "/queries", Queries - get "/updates", Updates - get "/fortunes", Fortunes - end +class Application + include Grip::Application - def router : Array(HTTP::Handler) - [ - @http_handler, - ] of HTTP::Handler - end + property handlers : Array(HTTP::Handler) = [ + Grip::Handlers::HTTP.new + ] of HTTP::Handler - def server : HTTP::Server - HTTP::Server.new(@router) + property environment : String = + ENV["ENVIRONMENT"]? || "PRODUCTION" + + def initialize + get "/json", JsonController + get "/plaintext", PlaintextController + get "/db", DbController + get "/queries", QueriesController + get "/updates", UpdatesController + get "/fortunes", FortunesController end def reuse_port diff --git a/frameworks/Crystal/grip/grip.dockerfile b/frameworks/Crystal/grip/grip.dockerfile index 4d98926effb..a5e1efb3305 100644 --- a/frameworks/Crystal/grip/grip.dockerfile +++ b/frameworks/Crystal/grip/grip.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.12.1 +FROM crystallang/crystal:1.18.2 WORKDIR /grip COPY views views diff --git a/frameworks/Crystal/grip/shard.yml b/frameworks/Crystal/grip/shard.yml index ed1f5ab0a2e..41ac7355622 100644 --- a/frameworks/Crystal/grip/shard.yml +++ b/frameworks/Crystal/grip/shard.yml @@ -4,11 +4,11 @@ version: 0.2.0 dependencies: grip: github: grip-framework/grip - version: 3.0.0 + version: 4.0.0 pg: github: will/crystal-pg - version: 0.28.0 + version: 0.29.0 targets: grip: main: grip.cr