Browse Source

Merge branch 'master' of https://github.com/TechEmpower/FrameworkBenchmarks

jaguililla 9 months ago
parent
commit
aa3dbc5975
100 changed files with 780 additions and 970 deletions
  1. 27 17
      frameworks/C/h2o/h2o.dockerfile
  2. 7 9
      frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs
  3. 54 33
      frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs
  4. 32 32
      frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs
  5. 61 0
      frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs
  6. 4 4
      frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs
  7. 5 5
      frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs
  8. 29 36
      frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs
  9. 2 2
      frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj
  10. 2 15
      frameworks/Elixir/phoenix/config/prod.exs
  11. 1 1
      frameworks/Elixir/phoenix/lib/hello/world_cache.ex
  12. 2 2
      frameworks/Elixir/phoenix/lib/hello_web.ex
  13. 43 33
      frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex
  14. 0 1
      frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex
  15. 0 6
      frameworks/Elixir/phoenix/lib/hello_web/router.ex
  16. 2 2
      frameworks/Elixir/phoenix/mix.lock
  17. 2 2
      frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex
  18. 2 4
      frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex
  19. 1 1
      frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex
  20. 3 11
      frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex
  21. 3 11
      frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex
  22. 1 0
      frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex
  23. 1 1
      frameworks/Go/chi/chi-gojay-prefork.dockerfile
  24. 1 1
      frameworks/Go/chi/chi-gojay.dockerfile
  25. 1 1
      frameworks/Go/chi/chi-prefork.dockerfile
  26. 3 4
      frameworks/Go/chi/chi-scratch.dockerfile
  27. 1 1
      frameworks/Go/chi/chi-sjson-prefork.dockerfile
  28. 1 1
      frameworks/Go/chi/chi-sjson.dockerfile
  29. 1 1
      frameworks/Go/chi/chi.dockerfile
  30. 5 3
      frameworks/Go/chi/src/chi-gojay/go.mod
  31. 6 4
      frameworks/Go/chi/src/chi-gojay/go.sum
  32. 5 3
      frameworks/Go/chi/src/chi-sjson/go.mod
  33. 6 4
      frameworks/Go/chi/src/chi-sjson/go.sum
  34. 7 4
      frameworks/Go/chi/src/chi/go.mod
  35. 6 4
      frameworks/Go/chi/src/chi/go.sum
  36. 8 4
      frameworks/Go/fiber/fiber-prefork.dockerfile
  37. 8 4
      frameworks/Go/fiber/fiber.dockerfile
  38. 2 2
      frameworks/Go/fiber/src/go.mod
  39. 4 4
      frameworks/Go/fiber/src/go.sum
  40. 2 2
      frameworks/Go/gnet/benchmark_config.json
  41. 1 1
      frameworks/Go/gnet/gnet.dockerfile
  42. 11 9
      frameworks/Go/gnet/src/go.mod
  43. 20 27
      frameworks/Go/gnet/src/go.sum
  44. 56 14
      frameworks/Go/gnet/src/main.go
  45. 1 1
      frameworks/Java/helidon/nima/pom.xml
  46. 92 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java
  47. 6 52
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java
  48. 0 19
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java
  49. 17 4
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java
  50. 45 60
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java
  51. 3 3
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java
  52. 12 19
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java
  53. 1 0
      frameworks/Java/helidon/nima/src/main/resources/application.yaml
  54. 1 1
      frameworks/Java/jetty/pom.xml
  55. 1 1
      frameworks/Java/jooby/jooby-jetty.dockerfile
  56. 1 1
      frameworks/Java/jooby/jooby-mvc.dockerfile
  57. 1 1
      frameworks/Java/jooby/jooby-netty.dockerfile
  58. 1 1
      frameworks/Java/jooby/jooby-pgclient.dockerfile
  59. 1 1
      frameworks/Java/jooby/jooby.dockerfile
  60. 4 4
      frameworks/Java/jooby/pom.xml
  61. 0 83
      frameworks/Java/redkale/BenchmarkService.java
  62. 0 45
      frameworks/Java/redkale/benchmark_config.json
  63. 1 1
      frameworks/Java/redkale/conf/application.xml
  64. 0 33
      frameworks/Java/redkale/config.toml
  65. 1 1
      frameworks/Java/redkale/pom-jdbc.xml
  66. 2 0
      frameworks/Java/redkale/pom.xml
  67. 0 16
      frameworks/Java/redkale/redkale-block.dockerfile
  68. 0 16
      frameworks/Java/redkale/redkale-graalvm.dockerfile
  69. 1 2
      frameworks/Java/redkale/redkale-jdbc.dockerfile
  70. 1 1
      frameworks/Java/redkale/redkale-pgclient.dockerfile
  71. 1 1
      frameworks/Java/redkale/redkale.dockerfile
  72. 1 7
      frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java
  73. 2 2
      frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java
  74. 1 1
      frameworks/Java/solon/README.md
  75. 3 5
      frameworks/Java/solon/pom.xml
  76. 24 6
      frameworks/Java/spring-webflux/pom.xml
  77. 1 1
      frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile
  78. 1 1
      frameworks/Java/spring-webflux/spring-webflux.dockerfile
  79. 2 3
      frameworks/Java/spring-webflux/src/main/java/benchmark/App.java
  80. 19 0
      frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java
  81. 6 7
      frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java
  82. 0 15
      frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java
  83. 1 0
      frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java
  84. 1 0
      frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java
  85. 0 63
      frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java
  86. 8 4
      frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java
  87. 20 23
      frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java
  88. 10 0
      frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java
  89. 3 1
      frameworks/Java/spring-webflux/src/main/resources/application.yml
  90. 0 0
      frameworks/Java/spring-webflux/src/main/resources/fortunes.mustache
  91. 1 3
      frameworks/Java/spring/README.md
  92. 0 21
      frameworks/Java/spring/benchmark_config.json
  93. 22 4
      frameworks/Java/spring/pom.xml
  94. 0 15
      frameworks/Java/spring/spring-jpa.dockerfile
  95. 2 19
      frameworks/Java/spring/src/main/java/hello/App.java
  96. 0 12
      frameworks/Java/spring/src/main/java/hello/JpaConfig.java
  97. 0 9
      frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java
  98. 0 43
      frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java
  99. 19 0
      frameworks/Java/spring/src/main/java/hello/Utils.java
  100. 0 12
      frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java

+ 27 - 17
frameworks/C/h2o/h2o.dockerfile

@@ -6,19 +6,28 @@ FROM "ubuntu:${UBUNTU_VERSION}" AS compile
 
 
 ARG DEBIAN_FRONTEND=noninteractive
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get -yqq update && \
 RUN apt-get -yqq update && \
+    apt-get -yqq install \
+      ca-certificates \
+      curl \
+      lsb-release && \
+    install -dm755 /usr/share/postgresql-common/pgdg && \
+    curl --fail -LSso /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
+      "https://www.postgresql.org/media/keys/ACCC4CF8.asc" && \
+    sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \
+      https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > \
+      /etc/apt/sources.list.d/pgdg.list' && \
+    apt-get -yqq update && \
     apt-get -yqq install \
     apt-get -yqq install \
       autoconf \
       autoconf \
       bison \
       bison \
       cmake \
       cmake \
-      curl \
       flex \
       flex \
       g++ \
       g++ \
       libbpfcc-dev \
       libbpfcc-dev \
       libbrotli-dev \
       libbrotli-dev \
       libcap-dev \
       libcap-dev \
-      libicu-dev \
       libnuma-dev \
       libnuma-dev \
-      libreadline-dev \
+      libpq-dev \
       libssl-dev \
       libssl-dev \
       libtool \
       libtool \
       libuv1-dev \
       libuv1-dev \
@@ -57,18 +66,6 @@ RUN curl -LSs "https://github.com/x86-64/mustache-c/archive/${MUSTACHE_C_REVISIO
     CFLAGS="-flto -march=native -mtune=native -O3" ./autogen.sh && \
     CFLAGS="-flto -march=native -mtune=native -O3" ./autogen.sh && \
     make -j "$(nproc)" install
     make -j "$(nproc)" install
 
 
-ARG POSTGRESQL_VERSION=a37bb7c13995b834095d9d064cad1023a6f99b10
-
-WORKDIR /tmp/postgresql-build
-RUN curl -LSs "https://github.com/postgres/postgres/archive/${POSTGRESQL_VERSION}.tar.gz" | \
-      tar --strip-components=1 -xz && \
-    CFLAGS="-flto -march=native -mtune=native -O3" ./configure \
-      --includedir=/usr/local/include/postgresql \
-      --prefix=/usr/local \
-      --with-ssl=openssl && \
-    make -j "$(nproc)" -C src/include install && \
-    make -j "$(nproc)" -C src/interfaces/libpq install
-
 ARG H2O_APP_PREFIX
 ARG H2O_APP_PREFIX
 WORKDIR /tmp/build
 WORKDIR /tmp/build
 COPY CMakeLists.txt ../
 COPY CMakeLists.txt ../
@@ -85,15 +82,28 @@ RUN cmake \
 
 
 FROM "ubuntu:${UBUNTU_VERSION}"
 FROM "ubuntu:${UBUNTU_VERSION}"
 
 
+ARG POSTGRESQL_VERSION=17
+
 ARG DEBIAN_FRONTEND=noninteractive
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get -yqq update && \
 RUN apt-get -yqq update && \
+    apt-get -yqq install \
+      ca-certificates \
+      curl \
+      lsb-release && \
+    install -dm755 /usr/share/postgresql-common/pgdg && \
+    curl --fail -LSso /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
+      "https://www.postgresql.org/media/keys/ACCC4CF8.asc" && \
+    sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \
+      https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > \
+      /etc/apt/sources.list.d/pgdg.list' && \
+    apt-get -yqq update && \
     apt-get -yqq install \
     apt-get -yqq install \
       libnuma1 \
       libnuma1 \
-      libyajl2
+      libyajl2 \
+      "postgresql-client-${POSTGRESQL_VERSION}"
 ARG H2O_APP_PREFIX
 ARG H2O_APP_PREFIX
 COPY --from=compile "${H2O_APP_PREFIX}" "${H2O_APP_PREFIX}/"
 COPY --from=compile "${H2O_APP_PREFIX}" "${H2O_APP_PREFIX}/"
 COPY --from=compile /usr/local/lib/libmustache_c.so "${H2O_APP_PREFIX}/lib/"
 COPY --from=compile /usr/local/lib/libmustache_c.so "${H2O_APP_PREFIX}/lib/"
-COPY --from=compile /usr/local/lib/libpq.so.5.17 "${H2O_APP_PREFIX}/lib/libpq.so.5"
 ENV LD_LIBRARY_PATH="${H2O_APP_PREFIX}/lib"
 ENV LD_LIBRARY_PATH="${H2O_APP_PREFIX}/lib"
 EXPOSE 8080
 EXPOSE 8080
 ARG BENCHMARK_ENV
 ARG BENCHMARK_ENV

+ 7 - 9
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs

@@ -20,12 +20,6 @@ namespace appMpower.Orm.Data
          _dbConnection = dbConnection;
          _dbConnection = dbConnection;
       }
       }
 
 
-      public DbCommand(string commandText, DbConnection dbConnection, bool keyed)
-      {
-         _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text, keyed);
-         _dbConnection = dbConnection;
-      }
-
       public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection)
       public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection)
       {
       {
          _odbcCommand = dbConnection.GetCommand(commandText, commandType);
          _odbcCommand = dbConnection.GetCommand(commandText, commandType);
@@ -175,7 +169,7 @@ namespace appMpower.Orm.Data
 
 
       public async Task<int> ExecuteNonQueryAsync()
       public async Task<int> ExecuteNonQueryAsync()
       {
       {
-         return await (_odbcCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync();
+         return await _odbcCommand.ExecuteNonQueryAsync();
       }
       }
 
 
       public IDataReader ExecuteReader(CommandBehavior behavior)
       public IDataReader ExecuteReader(CommandBehavior behavior)
@@ -183,6 +177,11 @@ namespace appMpower.Orm.Data
          return _odbcCommand.ExecuteReader(behavior);
          return _odbcCommand.ExecuteReader(behavior);
       }
       }
 
 
+      public async Task<System.Data.Common.DbDataReader> ExecuteReaderAsync(CommandBehavior behavior)
+      {
+         return await _odbcCommand.ExecuteReaderAsync(behavior);
+      }
+
 #nullable enable
 #nullable enable
       public object? ExecuteScalar()
       public object? ExecuteScalar()
       {
       {
@@ -197,8 +196,7 @@ namespace appMpower.Orm.Data
 
 
       public void Dispose()
       public void Dispose()
       {
       {
-         if (_dbConnection._keyed) _dbConnection._keyedOdbcCommands.TryAdd(_odbcCommand.CommandText, _odbcCommand);
-         else _dbConnection._odbcCommands.Push(_odbcCommand);
+         _dbConnection.Release(_odbcCommand);
       }
       }
    }
    }
 }
 }

+ 54 - 33
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs

@@ -1,26 +1,27 @@
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Data;
 using System.Data;
-using System.Data.Odbc; 
+using System.Data.Odbc;
 
 
 namespace appMpower.Orm.Data
 namespace appMpower.Orm.Data
 {
 {
    public class DbConnection : IDbConnection
    public class DbConnection : IDbConnection
    {
    {
       private string _connectionString;
       private string _connectionString;
-      internal bool _keyed = false; 
-      internal int _number; 
-      internal OdbcConnection _odbcConnection;
-      internal ConcurrentStack<OdbcCommand> _odbcCommands = new();
-      internal Dictionary<string, OdbcCommand> _keyedOdbcCommands;
+      private bool _keyed = false;
+      private int _number;
+      private OdbcConnection _odbcConnection;
+      private ConcurrentStack<OdbcCommand> _odbcCommands = new();
+      private Dictionary<string, OdbcCommand> _keyedOdbcCommands;
 
 
       public DbConnection()
       public DbConnection()
       {
       {
-         _connectionString = DbProviderFactory.ConnectionString;
       }
       }
 
 
-      public DbConnection(string connectionString)
+      public DbConnection(string connectionString, bool keyed = false)
       {
       {
-         _connectionString = connectionString;
+         _keyed = keyed;
+         _connectionString = connectionString; 
+         GetConnection();
       }
       }
 
 
       public IDbConnection Connection
       public IDbConnection Connection
@@ -43,7 +44,22 @@ namespace appMpower.Orm.Data
          }
          }
          set
          set
          {
          {
-            _odbcConnection.ConnectionString = value;
+            _connectionString = value; 
+            GetConnection();
+         }
+      }
+
+      private void GetConnection()
+      {
+         if (_keyed)
+         {
+            (_number, _odbcConnection, _keyedOdbcCommands) = 
+               DbConnectionsKeyed.GetConnectionBase(_connectionString).GetAwaiter().GetResult();
+         }
+         else
+         {
+            (_number, _odbcConnection, _odbcCommands) = 
+               DbConnections.GetConnectionBase(_connectionString).GetAwaiter().GetResult();
          }
          }
       }
       }
 
 
@@ -99,23 +115,33 @@ namespace appMpower.Orm.Data
 
 
       public void Open()
       public void Open()
       {
       {
-         if (_odbcConnection is null)
+         if (_odbcConnection.State == ConnectionState.Closed)
          {
          {
-            DbConnections.GetConnection(_connectionString, this);
+            _odbcConnection.Open();
          }
          }
+      }
 
 
+      public async Task OpenAsync()
+      {
          if (_odbcConnection.State == ConnectionState.Closed)
          if (_odbcConnection.State == ConnectionState.Closed)
          {
          {
-            _odbcConnection.Open();
+            await _odbcConnection.OpenAsync();
          }
          }
       }
       }
 
 
       public void Dispose()
       public void Dispose()
       {
       {
-         DbConnections.Release(this);
+         if (_keyed)
+         {
+            DbConnectionsKeyed.Release((Number: _number, OdbcConnection: _odbcConnection, KeyedOdbcCommands: _keyedOdbcCommands));
+         }
+         else
+         {
+            DbConnections.Release((Number: _number, OdbcConnection: _odbcConnection, OdbcCommands: _odbcCommands));
+         }
       }
       }
 
 
-      internal OdbcCommand GetCommand(string commandText, CommandType commandType, bool keyed = false)
+      internal OdbcCommand GetCommand(string commandText, CommandType commandType)
       {
       {
          OdbcCommand odbcCommand;
          OdbcCommand odbcCommand;
 
 
@@ -129,25 +155,20 @@ namespace appMpower.Orm.Data
 
 
             return odbcCommand; 
             return odbcCommand; 
          }
          }
-         else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand))
-         {
-            return odbcCommand; 
-         }
-         else
-         {
-            if (!_keyed && keyed) 
-            {
-               _keyedOdbcCommands = new();
-               _keyed = keyed; 
-            }
-            
-            odbcCommand = _odbcConnection.CreateCommand();
-            odbcCommand.CommandText = commandText;
-            odbcCommand.CommandType = commandType;
-            odbcCommand.Prepare();
+         else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) return odbcCommand; 
 
 
-            return odbcCommand;
-         }
+         odbcCommand = _odbcConnection.CreateCommand();
+         odbcCommand.CommandText = commandText;
+         odbcCommand.CommandType = commandType;
+         odbcCommand.Prepare();
+
+         return odbcCommand;
+      }
+
+      internal void Release(OdbcCommand odbcCommand)
+      {
+         if (_keyed) _keyedOdbcCommands.TryAdd(odbcCommand.CommandText, odbcCommand);
+         else _odbcCommands.Push(odbcCommand);
       }
       }
    }
    }
 }
 }

+ 32 - 32
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs

@@ -1,61 +1,61 @@
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
+using System.Data.Odbc;
 
 
 namespace appMpower.Orm.Data
 namespace appMpower.Orm.Data
 {
 {
-   public static class DbConnections
+   internal static class DbConnections
    {
    {
+      private static bool _maxConnectionsCreated = false;
       private static short _createdConnections = 0;
       private static short _createdConnections = 0;
-      private static ConcurrentStack<DbConnection> _connectionsStack = new();
+      private static short _maxConnections = 500;
 
 
-      public static DbConnection GetConnection(string connectionString)
+      private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> _connectionsStack = new();
+      private static ConcurrentQueue<TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)>> _waitingQueue = new();
+      
+      internal static async Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> GetConnectionBase(string connectionString)
       {
       {
-         DbConnection popDbConnection; 
+         (int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) dbConnectionBase;
 
 
-         if (!_connectionsStack.TryPop(out popDbConnection))
+         if (!_connectionsStack.TryPop(out dbConnectionBase))
          {
          {
-            popDbConnection = new DbConnection();
-            popDbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString);
+            if (_maxConnectionsCreated)
+            {
+               dbConnectionBase = await GetDbConnectionBaseAsync();
+            }
+            else
+            {
+               _createdConnections++;
+               dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack<OdbcCommand>());
 
 
-            _createdConnections++;
-            popDbConnection._number = _createdConnections;
+               if (_createdConnections == _maxConnections) _maxConnectionsCreated = true;
 
 
-            if (_createdConnections % 25 == 0)
-            {
-               Console.WriteLine("Pooled connections created: " + _createdConnections.ToString());
+               //Console.WriteLine("opened connection number: " + dbConnectionBase._number);
             }
             }
          }
          }
 
 
-         return popDbConnection; 
+         return dbConnectionBase;
       }
       }
 
 
-
-      public static void GetConnection(string connectionString, DbConnection dbConnection)
+      internal static void Release((int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) dbConnectionBase)
       {
       {
-         DbConnection popDbConnection = null;
+         TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> taskCompletionSource;
 
 
-         if (_connectionsStack.TryPop(out popDbConnection))
+         if (_waitingQueue.TryDequeue(out taskCompletionSource))
          {
          {
-            dbConnection._odbcConnection = popDbConnection._odbcConnection; 
-            dbConnection._odbcCommands = popDbConnection._odbcCommands;
-            dbConnection._number = popDbConnection._number; 
+            taskCompletionSource.SetResult(dbConnectionBase);
          }
          }
          else
          else
          {
          {
-            dbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString);
-
-            _createdConnections++;
-            dbConnection._number = _createdConnections;
-
-           if (_createdConnections % 25 == 0)
-            {
-               Console.WriteLine("Pooled connections created: " + _createdConnections.ToString());
-            }
-          }
+            _connectionsStack.Push(dbConnectionBase);
+         }
       }
       }
 
 
-      public static void Release(DbConnection dbConnection)
+      private static Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> GetDbConnectionBaseAsync()
       {
       {
-         _connectionsStack.Push(dbConnection);
+         var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+         _waitingQueue.Enqueue(taskCompletionSource);
+         return taskCompletionSource.Task;
       }
       }
    }
    }
 }
 }

+ 61 - 0
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs

@@ -0,0 +1,61 @@
+using System.Collections.Concurrent;
+using System.Data.Odbc;
+
+namespace appMpower.Orm.Data
+{
+   internal static class DbConnectionsKeyed
+   {
+      private static bool _maxConnectionsCreated = false;
+      private static short _createdConnections = 0;
+      private static short _maxConnections = 500;
+
+      private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> _connectionsStack = new();
+      private static ConcurrentQueue<TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)>> _waitingQueue = new();
+
+      internal static async Task<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands)> GetConnectionBase(string connectionString)
+      {
+         (int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) dbConnectionBase;
+
+         if (!_connectionsStack.TryPop(out dbConnectionBase))
+         {
+            if (_maxConnectionsCreated)
+            {
+               dbConnectionBase = await GetDbConnectionBaseAsync();
+            }
+            else
+            {
+               _createdConnections++;
+               dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary<string, OdbcCommand>());
+
+               if (_createdConnections == _maxConnections) _maxConnectionsCreated = true;
+
+               //Console.WriteLine("opened connection number: " + dbConnectionBase._number);
+            }
+         }
+
+         return dbConnectionBase;
+      }
+
+      internal static void Release((int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) dbConnectionBase)
+      {
+         TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> taskCompletionSource;
+
+         if (_waitingQueue.TryDequeue(out taskCompletionSource))
+         {
+            taskCompletionSource.SetResult(dbConnectionBase);
+         }
+         else
+         {
+            _connectionsStack.Push(dbConnectionBase);
+         }
+      }
+
+      private static Task<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> GetDbConnectionBaseAsync()
+      {
+         var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+         _waitingQueue.Enqueue(taskCompletionSource);
+         return taskCompletionSource.Task;
+      }
+   }
+}

+ 4 - 4
frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs

@@ -21,7 +21,7 @@ public static class DotnetMethods
 
 
     public static byte[] Db()
     public static byte[] Db()
     {
     {
-        var world = RawDb.LoadSingleQueryRow();
+        var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -33,7 +33,7 @@ public static class DotnetMethods
 
 
     public static byte[] Query(int queries)
     public static byte[] Query(int queries)
     {
     {
-        World[] worlds = RawDb.ReadMultipleRows(queries);
+        World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -45,7 +45,7 @@ public static class DotnetMethods
 
 
     public static byte[] Updates(int count)
     public static byte[] Updates(int count)
     {
     {
-        World[] worlds = RawDb.LoadMultipleUpdatesRows(count);
+        World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -57,7 +57,7 @@ public static class DotnetMethods
 
 
     public static byte[] Fortunes()
     public static byte[] Fortunes()
     {
     {
-        List<Fortune> fortunes = RawDb.LoadFortunesRows(); 
+        List<Fortune> fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); 
         string fortunesView = FortunesView.Render(fortunes);
         string fortunesView = FortunesView.Render(fortunes);
         byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView);
         byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView);
 
 

+ 5 - 5
frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs

@@ -42,7 +42,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Db")]
     [UnmanagedCallersOnly(EntryPoint = "Db")]
     public static unsafe IntPtr Db(int* length, IntPtr* handlePointer)
     public static unsafe IntPtr Db(int* length, IntPtr* handlePointer)
     {
     {
-        var world = RawDb.LoadSingleQueryRow();
+        var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -69,7 +69,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Fortunes")]
     [UnmanagedCallersOnly(EntryPoint = "Fortunes")]
     public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer)
     public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer)
     {
     {
-        List<Fortune> fortunes = RawDb.LoadFortunesRows(); 
+        List<Fortune> fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); 
         string fortunesView = FortunesView.Render(fortunes);
         string fortunesView = FortunesView.Render(fortunes);
         byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView);
         byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView);
 
 
@@ -85,7 +85,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Query")]
     [UnmanagedCallersOnly(EntryPoint = "Query")]
     public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointer)
     public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointer)
     {
     {
-        World[] worlds = RawDb.ReadMultipleRows(queries);
+        World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -105,7 +105,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Updates")]
     [UnmanagedCallersOnly(EntryPoint = "Updates")]
     public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer)
     public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer)
     {
     {
-        World[] worlds = RawDb.LoadMultipleUpdatesRows(count);
+        World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -125,7 +125,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "DbById")]
     [UnmanagedCallersOnly(EntryPoint = "DbById")]
     public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer)
     public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer)
     {
     {
-        var world = RawDb.LoadSingleQueryRowById(id);
+        var world = RawDb.LoadSingleQueryRowById(id).GetAwaiter().GetResult();
 
 
         var memoryStream = new MemoryStream();
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);

+ 29 - 36
frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs

@@ -13,42 +13,42 @@ namespace appMpower.Orm
 
 
       private static string[] _queriesMultipleRows = new string[MaxBatch + 1];
       private static string[] _queriesMultipleRows = new string[MaxBatch + 1];
 
 
-      public static World LoadSingleQueryRow()
+      public static async Task<World> LoadSingleQueryRow()
       {
       {
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
 
          var (dbCommand, _) = CreateReadCommand(pooledConnection);
          var (dbCommand, _) = CreateReadCommand(pooledConnection);
 
 
          using (dbCommand)
          using (dbCommand)
          {
          {
-            World world = ReadSingleRow(dbCommand);
+            World world = await ReadSingleRow(dbCommand);
 
 
             return world;
             return world;
          }
          }
       }
       }
 
 
-      public static World LoadSingleQueryRowById(int id)
+      public static async Task<World> LoadSingleQueryRowById(int id)
       {
       {
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
 
          var (dbCommand, _) = CreateReadCommandById(pooledConnection, id);
          var (dbCommand, _) = CreateReadCommandById(pooledConnection, id);
 
 
          using (dbCommand)
          using (dbCommand)
          {
          {
-            World world = ReadSingleRow(dbCommand);
+            World world = await ReadSingleRow(dbCommand);
 
 
             return world;
             return world;
          }
          }
       }
       }
 
 
-      public static World[] LoadMultipleQueriesRows(int count)
+      public static async Task<World[]> LoadMultipleQueriesRows(int count)
       {
       {
          var worlds = new World[count];
          var worlds = new World[count];
 
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
 
          var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
          var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
 
@@ -56,7 +56,7 @@ namespace appMpower.Orm
          {
          {
             for (int i = 0; i < count; i++)
             for (int i = 0; i < count; i++)
             {
             {
-               worlds[i] = ReadSingleRow(dbCommand);
+               worlds[i] = await ReadSingleRow(dbCommand);
                dbDataParameter.Value = _random.Next(1, 10001);
                dbDataParameter.Value = _random.Next(1, 10001);
             }
             }
          }
          }
@@ -64,18 +64,18 @@ namespace appMpower.Orm
          return worlds;
          return worlds;
       }
       }
 
 
-      public static List<Fortune> LoadFortunesRows()
+      public static async Task<List<Fortune>> LoadFortunesRows()
       {
       {
          var fortunes = new List<Fortune>();
          var fortunes = new List<Fortune>();
 
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
 
          var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection);
          var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection);
 
 
          using (dbCommand)
          using (dbCommand)
          {
          {
-            IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess);
+            IDataReader dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess);
 
 
             while (dataReader.Read())
             while (dataReader.Read())
             {
             {
@@ -97,25 +97,25 @@ namespace appMpower.Orm
          return fortunes;
          return fortunes;
       }
       }
 
 
-      public static World[] LoadMultipleUpdatesRows(int count)
+      public static async Task<World[]> LoadMultipleUpdatesRows(int count)
       {
       {
          var worlds = new World[count];
          var worlds = new World[count];
 
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString, true);
+         await pooledConnection.OpenAsync();
 
 
-         var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection, true);
+         var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
 
          using (queryCommand)
          using (queryCommand)
          {
          {
             for (int i = 0; i < count; i++)
             for (int i = 0; i < count; i++)
             {
             {
-               worlds[i] = ReadSingleRow(queryCommand);
+               worlds[i] = await ReadSingleRow(queryCommand);
                dbDataParameter.Value = _random.Next(1, 10001);
                dbDataParameter.Value = _random.Next(1, 10001);
             }
             }
          }
          }
 
 
-         using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection, true);
+         using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection);
 
 
          var ids = BatchUpdateString.Ids;
          var ids = BatchUpdateString.Ids;
          var randoms = BatchUpdateString.Randoms;
          var randoms = BatchUpdateString.Randoms;
@@ -152,13 +152,6 @@ namespace appMpower.Orm
          return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001)));
          return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001)));
       }
       }
 
 
-      internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection, bool keyed)
-      {
-         DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection, keyed);
-
-         return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001)));
-      }
-
       internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommandById(DbConnection pooledConnection, int id)
       internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommandById(DbConnection pooledConnection, int id)
       {
       {
          DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection);
          DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection);
@@ -166,9 +159,9 @@ namespace appMpower.Orm
          return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id));
          return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id));
       }
       }
 
 
-      internal static World ReadSingleRow(DbCommand dbCommand)
+      internal static async Task<World> ReadSingleRow(DbCommand dbCommand)
       {
       {
-         var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess);
+         var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess);
 
 
          dataReader.Read();
          dataReader.Read();
 
 
@@ -183,7 +176,7 @@ namespace appMpower.Orm
          return world;
          return world;
       }
       }
 
 
-      public static World[] ReadMultipleRows(int count)
+      public static async Task<World[]> ReadMultipleRows(int count)
       {
       {
          int j = 0;
          int j = 0;
          var ids = BatchUpdateString.Ids;
          var ids = BatchUpdateString.Ids;
@@ -206,8 +199,8 @@ namespace appMpower.Orm
             queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder);
             queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder);
          }
          }
 
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
 
          using var dbCommand = new DbCommand(queryString, pooledConnection);
          using var dbCommand = new DbCommand(queryString, pooledConnection);
 
 
@@ -216,7 +209,7 @@ namespace appMpower.Orm
             dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001));
             dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001));
          }
          }
 
 
-         var dataReader = dbCommand.ExecuteReader(CommandBehavior.Default & CommandBehavior.SequentialAccess);
+         var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess);
 
 
          do
          do
          {
          {
@@ -229,7 +222,7 @@ namespace appMpower.Orm
             };
             };
 
 
             j++;
             j++;
-         } while (dataReader.NextResult());
+         } while (await dataReader.NextResultAsync());
 
 
          dataReader.Close();
          dataReader.Close();
 
 

+ 2 - 2
frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj

@@ -9,10 +9,10 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="BeetleX.Light" Version="0.28.24.614" />
     <PackageReference Include="BeetleX.Light" Version="0.28.24.614" />
-    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
     <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
     <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
     <PackageReference Include="Npgsql" Version="8.0.3" />
     <PackageReference Include="Npgsql" Version="8.0.3" />
-    <PackageReference Include="System.Runtime.Caching" Version="8.0.0" />
+    <PackageReference Include="System.Runtime.Caching" Version="8.0.1" />
   </ItemGroup>
   </ItemGroup>
 
 
 </Project>
 </Project>

+ 2 - 15
frameworks/Elixir/phoenix/config/prod.exs

@@ -21,7 +21,8 @@ config :hello, Hello.Repo,
   password: "benchmarkdbpass",
   password: "benchmarkdbpass",
   database: "hello_world",
   database: "hello_world",
   hostname: "tfb-database",
   hostname: "tfb-database",
-  pool_size: 50,
+  pool_count: 56,
+  pool_size: 15,
   queue_target: 5000,
   queue_target: 5000,
   log: false
   log: false
 
 
@@ -33,17 +34,3 @@ config :logger,
   ],
   ],
   level: :error,
   level: :error,
   backends: []
   backends: []
-
-# ## SSL Support
-#
-# To get SSL working, you will need to add the `https` key
-# to the previous section:
-#
-#  config:hello, Hello.Endpoint,
-#    ...
-#    https: [port: 443,
-#            keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
-#            certfile: System.get_env("SOME_APP_SSL_CERT_PATH")]
-#
-# Where those two env variables point to a file on
-# disk for the key and cert.

+ 1 - 1
frameworks/Elixir/phoenix/lib/hello/world_cache.ex

@@ -23,9 +23,9 @@ defmodule Hello.WorldCache do
         world = Repo.get(World, id)
         world = Repo.get(World, id)
         :ok = __MODULE__.put(id, world)
         :ok = __MODULE__.put(id, world)
         world
         world
+
       world ->
       world ->
         world
         world
     end
     end
   end
   end
-
 end
 end

+ 2 - 2
frameworks/Elixir/phoenix/lib/hello_web.ex

@@ -95,8 +95,8 @@ defmodule HelloWeb do
   end
   end
 
 
   @doc """
   @doc """
-    When used, dispatch to the appropriate controller/view/etc.
-    """
+  When used, dispatch to the appropriate controller/view/etc.
+  """
   defmacro __using__(which) when is_atom(which) do
   defmacro __using__(which) when is_atom(which) do
     apply(__MODULE__, which, [])
     apply(__MODULE__, which, [])
   end
   end

+ 43 - 33
frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex

@@ -1,5 +1,4 @@
 defmodule HelloWeb.PageController do
 defmodule HelloWeb.PageController do
-
   use HelloWeb, :controller
   use HelloWeb, :controller
 
 
   alias Hello.Models.Fortune
   alias Hello.Models.Fortune
@@ -9,6 +8,8 @@ defmodule HelloWeb.PageController do
 
 
   @random_max 10_000
   @random_max 10_000
 
 
+  plug :accepts, ~w(html json) when action == :fortunes
+
   def index(conn, _params) do
   def index(conn, _params) do
     json(conn, %{"TE Benchmarks\n" => "Started"})
     json(conn, %{"TE Benchmarks\n" => "Started"})
   end
   end
@@ -25,13 +26,12 @@ defmodule HelloWeb.PageController do
   end
   end
 
 
   def queries(conn, params) do
   def queries(conn, params) do
-    :rand.seed(:exsp)
-
     worlds =
     worlds =
-      Stream.repeatedly(&random_id/0)
-      |> Stream.uniq()
-      |> Stream.map(&Repo.get(World, &1))
-      |> Enum.take(size(params["queries"]))
+      Repo.checkout(fn ->
+        params["queries"]
+        |> random_ids_sample()
+        |> Enum.map(&Repo.get(World, &1))
+      end)
 
 
     json(conn, worlds)
     json(conn, worlds)
   end
   end
@@ -44,49 +44,53 @@ defmodule HelloWeb.PageController do
 
 
     fortunes =
     fortunes =
       [additional_fortune | Repo.all(Fortune)]
       [additional_fortune | Repo.all(Fortune)]
-      |> Enum.sort_by(& &1.message)
+      |> Enum.sort(fn a, b -> a.message < b.message end)
 
 
     render(conn, :fortunes, fortunes: fortunes)
     render(conn, :fortunes, fortunes: fortunes)
   end
   end
 
 
   def updates(conn, params) do
   def updates(conn, params) do
-    :rand.seed(:exsp)
-
-    worlds =
-      Stream.repeatedly(&random_id/0)
-      |> Stream.uniq()
-      |> Stream.map(&Repo.get(World, &1))
-      |> Stream.map(fn world -> %{id: world.id, randomnumber: :rand.uniform(@random_max)} end)
-      |> Enum.take(size(params["queries"]))
-      # If this is not sorted it sometimes generates
-      #  FAIL for http://tfb-server:8080/updates/20
-      #  Only 20470 executed queries in the database out of roughly 20480 expected.
-      |> Enum.sort_by(& &1.id)
+    world_updates =
+      Repo.checkout(fn ->
+        params["queries"]
+        |> random_ids_sample()
+        |> Enum.sort()
+        #
+        # If this is not sorted it will intermittently generate:
+        #
+        #   FAIL for http://tfb-server:8080/updates/20
+        #   Only 20470 executed queries in the database out of roughly 20480 expected.
+        #
+        |> Enum.map(fn id ->
+          world = Repo.get(World, id)
+          %{id: world.id, randomnumber: :rand.uniform(@random_max)}
+        end)
+      end)
 
 
     Repo.insert_all(
     Repo.insert_all(
       World,
       World,
-      worlds,
+      world_updates,
       on_conflict: {:replace_all_except, [:id]},
       on_conflict: {:replace_all_except, [:id]},
       conflict_target: [:id],
       conflict_target: [:id],
       returning: false
       returning: false
     )
     )
 
 
-    json(conn, worlds)
+    json(conn, world_updates)
   end
   end
 
 
-  def plaintext(conn, _params) do
-    text(conn, "Hello, World!")
+   def plaintext(conn, _params) do
+    conn
+    |> put_resp_header("content-type", "text/plain")
+    |> send_resp(200, "Hello, World!")
   end
   end
 
 
   def cached(conn, params) do
   def cached(conn, params) do
-    :rand.seed(:exsp)
     WorldCache.seed()
     WorldCache.seed()
 
 
     worlds =
     worlds =
-      Stream.repeatedly(&random_id/0)
-      |> Stream.uniq()
-      |> Stream.map(&WorldCache.fetch(&1))
-      |> Enum.take(size(params["count"]))
+      params["count"]
+      |> random_ids_sample()
+      |> Enum.map(&WorldCache.fetch(&1))
 
 
     json(conn, worlds)
     json(conn, worlds)
   end
   end
@@ -95,11 +99,17 @@ defmodule HelloWeb.PageController do
     :rand.uniform(@random_max)
     :rand.uniform(@random_max)
   end
   end
 
 
-  defp size(nil), do: 1
-  defp size(""), do: 1
+  defp random_ids_sample(count) do
+    # Use the fastest rand algorithm
+    :rand.seed(:exsp)
+
+    Stream.repeatedly(&random_id/0)
+    |> Stream.uniq()
+    |> Enum.take(size(count))
+  end
 
 
-  defp size(queries) when is_bitstring(queries) do
-    case Integer.parse(queries) do
+  defp size(param_count) when is_bitstring(param_count) do
+    case Integer.parse(param_count) do
       {count, _} -> max(1, min(500, count))
       {count, _} -> max(1, min(500, count))
       _ -> 1
       _ -> 1
     end
     end

+ 0 - 1
frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex

@@ -20,4 +20,3 @@ defmodule HelloWeb.Endpoint do
   plug HelloWeb.HeadersPlug
   plug HelloWeb.HeadersPlug
   plug HelloWeb.Router
   plug HelloWeb.Router
 end
 end
-

+ 0 - 6
frameworks/Elixir/phoenix/lib/hello_web/router.ex

@@ -1,13 +1,7 @@
 defmodule HelloWeb.Router do
 defmodule HelloWeb.Router do
   use HelloWeb, :router
   use HelloWeb, :router
 
 
-  pipeline :browser do
-    plug :accepts, ~w(html json)
-  end
-
   scope "/", HelloWeb do
   scope "/", HelloWeb do
-    pipe_through [:browser]
-
     get "/json", PageController, :_json
     get "/json", PageController, :_json
     get "/db", PageController, :db
     get "/db", PageController, :db
     get "/queries", PageController, :queries
     get "/queries", PageController, :queries

+ 2 - 2
frameworks/Elixir/phoenix/mix.lock

@@ -6,8 +6,8 @@
   "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
   "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
   "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
   "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
   "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
   "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
-  "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
-  "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"},
+  "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"},
+  "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
   "expo": {:hex, :expo, "1.0.0", "647639267e088717232f4d4451526e7a9de31a3402af7fcbda09b27e9a10395a", [:mix], [], "hexpm", "18d2093d344d97678e8a331ca0391e85d29816f9664a25653fd7e6166827827c"},
   "expo": {:hex, :expo, "1.0.0", "647639267e088717232f4d4451526e7a9de31a3402af7fcbda09b27e9a10395a", [:mix], [], "hexpm", "18d2093d344d97678e8a331ca0391e85d29816f9664a25653fd7e6166827827c"},
   "gettext": {:hex, :gettext, "0.25.0", "98a95a862a94e2d55d24520dd79256a15c87ea75b49673a2e2f206e6ebc42e5d", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "38e5d754e66af37980a94fb93bb20dcde1d2361f664b0a19f01e87296634051f"},
   "gettext": {:hex, :gettext, "0.25.0", "98a95a862a94e2d55d24520dd79256a15c87ea75b49673a2e2f206e6ebc42e5d", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "38e5d754e66af37980a94fb93bb20dcde1d2361f664b0a19f01e87296634051f"},
   "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
   "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},

+ 2 - 2
frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex

@@ -11,10 +11,10 @@ defmodule FrameworkBenchmarks.Handlers.CachedWorld do
         :rand.uniform(10_000)
         :rand.uniform(10_000)
       end)
       end)
 
 
-    {:ok, json} =
+    json =
       ids
       ids
       |> Enum.map(&FrameworkBenchmarks.CachedWorld.get/1)
       |> Enum.map(&FrameworkBenchmarks.CachedWorld.get/1)
-      |> Jason.encode()
+      |> Jason.encode_to_iodata!()
 
 
     conn
     conn
     |> Plug.Conn.put_resp_content_type("application/json")
     |> Plug.Conn.put_resp_content_type("application/json")

+ 2 - 4
frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex

@@ -5,11 +5,9 @@ defmodule FrameworkBenchmarks.Handlers.DB do
   def handle(conn) do
   def handle(conn) do
     id = :rand.uniform(10_000)
     id = :rand.uniform(10_000)
 
 
-    {:ok, json} =
+    json =
       FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, id)
       FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, id)
-      |> Map.from_struct()
-      |> Map.drop([:__meta__])
-      |> Jason.encode()
+      |> Jason.encode_to_iodata!()
 
 
     conn
     conn
     |> Plug.Conn.put_resp_content_type("application/json")
     |> Plug.Conn.put_resp_content_type("application/json")

+ 1 - 1
frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex

@@ -3,7 +3,7 @@ defmodule FrameworkBenchmarks.Handlers.JSON do
   This is the handle for the /json route
   This is the handle for the /json route
   """
   """
   def handle(conn) do
   def handle(conn) do
-    {:ok, json} = Jason.encode(%{message: "Hello, World!"})
+    json = Jason.encode_to_iodata!(%{message: "Hello, World!"})
 
 
     conn
     conn
     |> Plug.Conn.put_resp_content_type("application/json")
     |> Plug.Conn.put_resp_content_type("application/json")

+ 3 - 11
frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex

@@ -5,7 +5,7 @@ defmodule FrameworkBenchmarks.Handlers.Query do
   def handle(conn) do
   def handle(conn) do
     number_of_queries = FrameworkBenchmarks.Handlers.Helpers.parse_queries(conn, "queries")
     number_of_queries = FrameworkBenchmarks.Handlers.Helpers.parse_queries(conn, "queries")
 
 
-    records =
+    json =
       1..number_of_queries
       1..number_of_queries
       |> Enum.map(fn _ ->
       |> Enum.map(fn _ ->
         :rand.uniform(10_000)
         :rand.uniform(10_000)
@@ -15,16 +15,8 @@ defmodule FrameworkBenchmarks.Handlers.Query do
           FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, &1)
           FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, &1)
         end)
         end)
       )
       )
-      |> Enum.map(&Task.await(&1))
-
-    {:ok, json} =
-      records
-      |> Enum.map(fn record ->
-        record
-        |> Map.from_struct()
-        |> Map.drop([:__meta__])
-      end)
-      |> Jason.encode()
+      |> Enum.map(&Task.await(&1, :infinity))
+      |> Jason.encode_to_iodata!()
 
 
     conn
     conn
     |> Plug.Conn.put_resp_content_type("application/json")
     |> Plug.Conn.put_resp_content_type("application/json")

+ 3 - 11
frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex

@@ -22,7 +22,7 @@ defmodule FrameworkBenchmarks.Handlers.Update do
         :rand.uniform(10_000)
         :rand.uniform(10_000)
       end)
       end)
 
 
-    records =
+    json =
       ids
       ids
       |> Enum.map(
       |> Enum.map(
         &Task.async(fn ->
         &Task.async(fn ->
@@ -38,16 +38,8 @@ defmodule FrameworkBenchmarks.Handlers.Update do
           |> FrameworkBenchmarks.Repo.update!()
           |> FrameworkBenchmarks.Repo.update!()
         end)
         end)
       )
       )
-      |> Enum.map(&Task.await(&1))
-
-    {:ok, json} =
-      records
-      |> Enum.map(fn record ->
-        record
-        |> Map.from_struct()
-        |> Map.drop([:__meta__])
-      end)
-      |> Jason.encode()
+      |> Enum.map(&Task.await(&1, :infinity))
+      |> Jason.encode_to_iodata!()
 
 
     conn
     conn
     |> Plug.Conn.put_resp_content_type("application/json")
     |> Plug.Conn.put_resp_content_type("application/json")

+ 1 - 0
frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex

@@ -1,6 +1,7 @@
 defmodule FrameworkBenchmarks.Models.World do
 defmodule FrameworkBenchmarks.Models.World do
   use Ecto.Schema
   use Ecto.Schema
 
 
+  @derive {Jason.Encoder, only: [:id, :randomnumber]}
   schema "world" do
   schema "world" do
     field(:randomnumber, :integer)
     field(:randomnumber, :integer)
   end
   end

+ 1 - 1
frameworks/Go/chi/chi-gojay-prefork.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.23.1
 
 
 ADD ./src/chi-gojay /chi
 ADD ./src/chi-gojay /chi
 WORKDIR /chi
 WORKDIR /chi

+ 1 - 1
frameworks/Go/chi/chi-gojay.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.23.1
 
 
 ADD ./src/chi-gojay /chi
 ADD ./src/chi-gojay /chi
 WORKDIR /chi
 WORKDIR /chi

+ 1 - 1
frameworks/Go/chi/chi-prefork.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.23.1
 
 
 ADD ./src/chi /chi
 ADD ./src/chi /chi
 WORKDIR /chi
 WORKDIR /chi

+ 3 - 4
frameworks/Go/chi/chi-scratch.dockerfile

@@ -1,13 +1,12 @@
 # build layer
 # build layer
-FROM docker.io/golang:1.19-alpine as builder
+FROM docker.io/golang:1.23.1-alpine as builder
 
 
 ADD ./src/chi /chi
 ADD ./src/chi /chi
 WORKDIR /chi
 WORKDIR /chi
 
 
 RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 \
 RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 \
-    go build -ldflags="-w -s" -o server
-
-RUN apk --no-cache add --update ca-certificates
+    go build -ldflags="-w -s" -o server && \
+    apk --no-cache add --update ca-certificates
 
 
 # release layer
 # release layer
 FROM scratch
 FROM scratch

+ 1 - 1
frameworks/Go/chi/chi-sjson-prefork.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.23.1
 
 
 ADD ./src/chi-sjson /chi
 ADD ./src/chi-sjson /chi
 WORKDIR /chi
 WORKDIR /chi

+ 1 - 1
frameworks/Go/chi/chi-sjson.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.23.1
 
 
 ADD ./src/chi-sjson /chi
 ADD ./src/chi-sjson /chi
 WORKDIR /chi
 WORKDIR /chi

+ 1 - 1
frameworks/Go/chi/chi.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.23.1
 
 
 ADD ./src/chi /chi
 ADD ./src/chi /chi
 WORKDIR /chi
 WORKDIR /chi

+ 5 - 3
frameworks/Go/chi/src/chi-gojay/go.mod

@@ -1,8 +1,10 @@
 module chi/server
 module chi/server
 
 
-go 1.19
+go 1.23.1
 
 
 require (
 require (
-	github.com/go-chi/chi/v5 v5.0.7
-	github.com/go-sql-driver/mysql v1.6.0
+	github.com/go-chi/chi/v5 v5.1.0
+	github.com/go-sql-driver/mysql v1.8.1
 )
 )
+
+require filippo.io/edwards25519 v1.1.0 // indirect

+ 6 - 4
frameworks/Go/chi/src/chi-gojay/go.sum

@@ -1,4 +1,6 @@
-github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
-github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
+github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=

+ 5 - 3
frameworks/Go/chi/src/chi-sjson/go.mod

@@ -1,8 +1,10 @@
 module chi/server
 module chi/server
 
 
-go 1.19
+go 1.23.1
 
 
 require (
 require (
-	github.com/go-chi/chi/v5 v5.0.7
-	github.com/go-sql-driver/mysql v1.6.0
+	github.com/go-chi/chi/v5 v5.1.0
+	github.com/go-sql-driver/mysql v1.8.1
 )
 )
+
+require filippo.io/edwards25519 v1.1.0 // indirect

+ 6 - 4
frameworks/Go/chi/src/chi-sjson/go.sum

@@ -1,4 +1,6 @@
-github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
-github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
+github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=

+ 7 - 4
frameworks/Go/chi/src/chi/go.mod

@@ -1,11 +1,14 @@
 module chi/server
 module chi/server
 
 
-go 1.19
+go 1.23.1
 
 
 require (
 require (
-	github.com/go-chi/chi/v5 v5.0.7
-	github.com/go-sql-driver/mysql v1.6.0
+	github.com/go-chi/chi/v5 v5.1.0
+	github.com/go-sql-driver/mysql v1.8.1
 	github.com/mailru/easyjson v0.7.7
 	github.com/mailru/easyjson v0.7.7
 )
 )
 
 
-require github.com/josharian/intern v1.0.0 // indirect
+require (
+	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
+)

+ 6 - 4
frameworks/Go/chi/src/chi/go.sum

@@ -1,7 +1,9 @@
-github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
-github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
+github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=

+ 8 - 4
frameworks/Go/fiber/fiber-prefork.dockerfile

@@ -1,14 +1,18 @@
-FROM docker.io/golang:1.23
+FROM golang:1.23-alpine as builder
 
 
 WORKDIR /fiber
 WORKDIR /fiber
 
 
 COPY ./src /fiber
 COPY ./src /fiber
 
 
-RUN go mod download
+RUN go mod download && \
+    go generate -x ./templates && \
+    GOAMD64=v3 go build -ldflags="-s -w" -o app .
 
 
-RUN go generate -x ./templates
+FROM alpine:latest
 
 
-RUN GOAMD64=v3 go build -ldflags="-s -w" -o app .
+WORKDIR /fiber
+
+COPY --from=builder /fiber/app .
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 

+ 8 - 4
frameworks/Go/fiber/fiber.dockerfile

@@ -1,14 +1,18 @@
-FROM docker.io/golang:1.23
+FROM golang:1.23-alpine as builder
 
 
 WORKDIR /fiber
 WORKDIR /fiber
 
 
 COPY ./src /fiber
 COPY ./src /fiber
 
 
-RUN go mod download
+RUN go mod download && \
+    go generate -x ./templates && \
+    GOAMD64=v3 go build -ldflags="-s -w" -o app .
 
 
-RUN go generate -x ./templates
+FROM alpine:latest
 
 
-RUN GOAMD64=v3 go build -ldflags="-s -w" -o app .
+WORKDIR /fiber
+
+COPY --from=builder /fiber/app .
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 

+ 2 - 2
frameworks/Go/fiber/src/go.mod

@@ -5,7 +5,7 @@ go 1.23
 require (
 require (
 	github.com/goccy/go-json v0.10.3
 	github.com/goccy/go-json v0.10.3
 	github.com/gofiber/fiber/v2 v2.52.5
 	github.com/gofiber/fiber/v2 v2.52.5
-	github.com/jackc/pgx/v5 v5.6.0
+	github.com/jackc/pgx/v5 v5.7.1
 	github.com/valyala/quicktemplate v1.8.0
 	github.com/valyala/quicktemplate v1.8.0
 )
 )
 
 
@@ -14,7 +14,7 @@ require (
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/jackc/pgpassfile v1.0.0 // indirect
 	github.com/jackc/pgpassfile v1.0.0 // indirect
 	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
 	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
-	github.com/jackc/puddle/v2 v2.2.1 // indirect
+	github.com/jackc/puddle/v2 v2.2.2 // indirect
 	github.com/klauspost/compress v1.17.9 // indirect
 	github.com/klauspost/compress v1.17.9 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect

+ 4 - 4
frameworks/Go/fiber/src/go.sum

@@ -13,10 +13,10 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
 github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
-github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
-github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
-github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
+github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
+github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
+github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
 github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
 github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=

+ 2 - 2
frameworks/Go/gnet/benchmark_config.json

@@ -4,8 +4,8 @@
     "default": {
     "default": {
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "port": 8080,
-      "approach": "stripped",
-      "classification": "Micro",
+      "approach": "Realistic",
+      "classification": "Platform",
       "database": "None",
       "database": "None",
       "framework": "gnet",
       "framework": "gnet",
       "language": "Go",
       "language": "Go",

+ 1 - 1
frameworks/Go/gnet/gnet.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:latest
 
 
 WORKDIR /gnet
 WORKDIR /gnet
 
 

+ 11 - 9
frameworks/Go/gnet/src/go.mod

@@ -1,17 +1,19 @@
 module gnet
 module gnet
 
 
-go 1.19
+go 1.23.1
 
 
 require (
 require (
-	github.com/panjf2000/gnet/v2 v2.1.2
-	go.uber.org/multierr v1.8.0 // indirect
-	golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
+	github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567
+	github.com/panjf2000/gnet/v2 v2.5.7
 )
 )
 
 
 require (
 require (
-	github.com/josharian/intern v1.0.0 // indirect
-	github.com/mailru/easyjson v0.7.7 // indirect
-	go.uber.org/atomic v1.10.0 // indirect
-	go.uber.org/zap v1.23.0 // indirect
-	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
+	github.com/valyala/bytebufferpool v1.0.0 // indirect
+	github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a // indirect
+	go.uber.org/atomic v1.7.0 // indirect
+	go.uber.org/multierr v1.6.0 // indirect
+	go.uber.org/zap v1.21.0 // indirect
+	golang.org/x/sync v0.7.0 // indirect
+	golang.org/x/sys v0.21.0 // indirect
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 )
 )

+ 20 - 27
frameworks/Go/gnet/src/go.sum

@@ -1,46 +1,39 @@
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567 h1:7+oQw6YjB/kk9x27AEC7DMXudqERHD583hZpno18lRw=
+github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567/go.mod h1:XNGflD53X+hfdCAt1NGeBUgiUpe9QmweW/zI1gV26Zw=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/panjf2000/ants/v2 v2.4.8 h1:JgTbolX6K6RreZ4+bfctI0Ifs+3mrE5BIHudQxUDQ9k=
-github.com/panjf2000/ants/v2 v2.4.8/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
-github.com/panjf2000/gnet/v2 v2.1.2 h1:WJ/PkbfV6G0wcGOng2pyCwv8oadKiqtP8p+38smN7ao=
-github.com/panjf2000/gnet/v2 v2.1.2/go.mod h1:unWr2B4jF0DQPJH3GsXBGQiDcAamM6+Pf5FiK705kc4=
+github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8=
+github.com/panjf2000/ants/v2 v2.10.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
+github.com/panjf2000/gnet/v2 v2.5.7 h1:EGGIfLYEVAp2l5WSYT2XddSjpQ642PjwphbWhcJ0WBY=
+github.com/panjf2000/gnet/v2 v2.5.7/go.mod h1:ppopMJ8VrDbJu8kDsqFQTgNmpMS8Le5CmPxISf+Sauk=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a h1:lUVfiMMY/te9icPKBqOKkBIMZNxSpM90dxokDeCcfBg=
+github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a/go.mod h1:KUxJS71XlMs+ztT+RzsLRoWUQRUpECo/+Rb0EBk8/Wc=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
-go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
-go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
 go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
-go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
-go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -51,14 +44,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
-golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -71,12 +65,11 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 56 - 14
frameworks/Go/gnet/src/main.go

@@ -7,9 +7,11 @@ import (
 	"fmt"
 	"fmt"
 	"log"
 	"log"
 	"runtime"
 	"runtime"
+	"strconv"
 	"sync/atomic"
 	"sync/atomic"
 	"time"
 	"time"
 
 
+	"github.com/evanphx/wildcat"
 	"github.com/panjf2000/gnet/v2"
 	"github.com/panjf2000/gnet/v2"
 )
 )
 
 
@@ -22,30 +24,68 @@ type httpServer struct {
 }
 }
 
 
 type httpCodec struct {
 type httpCodec struct {
-	delimiter []byte
-	buf       []byte
+	parser        *wildcat.HTTPParser
+	contentLength int
+	buf           []byte
 }
 }
 
 
-func (hc *httpCodec) appendResponse() {
-	hc.buf = append(hc.buf, "HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: "...)
-	//hc.buf = time.Now().AppendFormat(hc.buf, "Mon, 02 Jan 2006 15:04:05 GMT")
-	hc.buf = append(hc.buf, NowTimeFormat()...)
-	hc.buf = append(hc.buf, "\r\nContent-Length: 13\r\n\r\nHello, World!"...)
-}
-
-var errCRLFNotFound = errors.New("CRLF not found")
+var CRLF = []byte("\r\n\r\n")
 
 
 func (hc *httpCodec) parse(data []byte) (int, error) {
 func (hc *httpCodec) parse(data []byte) (int, error) {
-	if idx := bytes.Index(data, hc.delimiter); idx != -1 {
+	// Perform a legit HTTP request parsing.
+	bodyOffset, err := hc.parser.Parse(data)
+	if err != nil {
+		return 0, err
+	}
+
+	// First check if the Content-Length header is present.
+	contentLength := hc.getContentLength()
+	if contentLength > -1 {
+		return bodyOffset + contentLength, nil
+	}
+
+	// If the Content-Length header is not found,
+	// we need to find the end of the body section.
+	if idx := bytes.Index(data, CRLF); idx != -1 {
 		return idx + 4, nil
 		return idx + 4, nil
 	}
 	}
-	return -1, errCRLFNotFound
+
+	return 0, errors.New("invalid http request")
+}
+
+var contentLengthKey = []byte("Content-Length")
+
+func (hc *httpCodec) getContentLength() int {
+	if hc.contentLength != -1 {
+		return hc.contentLength
+	}
+
+	val := hc.parser.FindHeader(contentLengthKey)
+	if val != nil {
+		i, err := strconv.ParseInt(string(val), 10, 0)
+		if err == nil {
+			hc.contentLength = int(i)
+		}
+	}
+
+	return hc.contentLength
+}
+
+func (hc *httpCodec) resetParser() {
+	hc.contentLength = -1
 }
 }
 
 
 func (hc *httpCodec) reset() {
 func (hc *httpCodec) reset() {
+	hc.resetParser()
 	hc.buf = hc.buf[:0]
 	hc.buf = hc.buf[:0]
 }
 }
 
 
+func (hc *httpCodec) appendResponse() {
+	hc.buf = append(hc.buf, "HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: "...)
+	hc.buf = append(hc.buf, NowTimeFormat()...)
+	hc.buf = append(hc.buf, "\r\nContent-Length: 13\r\n\r\nHello, World!"...)
+}
+
 func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action {
 func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action {
 	hs.eng = eng
 	hs.eng = eng
 	log.Printf("echo server with multi-core=%t is listening on %s\n", hs.multicore, hs.addr)
 	log.Printf("echo server with multi-core=%t is listening on %s\n", hs.multicore, hs.addr)
@@ -53,18 +93,20 @@ func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action {
 }
 }
 
 
 func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
 func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
-	c.SetContext(&httpCodec{delimiter: []byte("\r\n\r\n")})
+	c.SetContext(&httpCodec{parser: wildcat.NewHTTPParser()})
 	return nil, gnet.None
 	return nil, gnet.None
 }
 }
 
 
 func (hs *httpServer) OnTraffic(c gnet.Conn) gnet.Action {
 func (hs *httpServer) OnTraffic(c gnet.Conn) gnet.Action {
-	buf, _ := c.Next(-1)
 	hc := c.Context().(*httpCodec)
 	hc := c.Context().(*httpCodec)
+	buf, _ := c.Next(-1)
+
 pipeline:
 pipeline:
 	nextOffset, err := hc.parse(buf)
 	nextOffset, err := hc.parse(buf)
 	if err != nil {
 	if err != nil {
 		goto response
 		goto response
 	}
 	}
+	hc.resetParser()
 	hc.appendResponse()
 	hc.appendResponse()
 	buf = buf[nextOffset:]
 	buf = buf[nextOffset:]
 	if len(buf) > 0 {
 	if len(buf) > 0 {

+ 1 - 1
frameworks/Java/helidon/nima/pom.xml

@@ -21,7 +21,7 @@
     <parent>
     <parent>
         <groupId>io.helidon.applications</groupId>
         <groupId>io.helidon.applications</groupId>
         <artifactId>helidon-se</artifactId>
         <artifactId>helidon-se</artifactId>
-        <version>4.0.3</version>
+        <version>4.1.2</version>
         <relativePath/>
         <relativePath/>
     </parent>
     </parent>
 
 

+ 92 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java

@@ -0,0 +1,92 @@
+package io.helidon.benchmark.nima;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.List;
+
+import com.jsoniter.output.JsonStream;
+import com.jsoniter.output.JsonStreamPool;
+import com.jsoniter.spi.JsonException;
+
+public class JsonSerializer {
+
+    private JsonSerializer() {
+    }
+
+    /**
+     * Serialize an instance into a JSON object and return it as a byte array.
+     *
+     * @param obj the instance
+     * @return the byte array
+     */
+    public static byte[] serialize(Object obj) {
+        JsonStream stream = JsonStreamPool.borrowJsonStream();
+        try {
+            stream.reset(null);
+            stream.writeVal(obj.getClass(), obj);
+            return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
+        } catch (IOException e) {
+            throw new JsonException(e);
+        } finally {
+            JsonStreamPool.returnJsonStream(stream);
+        }
+    }
+
+    /**
+     * Serialize a map of strings into a JSON object and return it as a byte array.
+     *
+     * @param map the map
+     * @return the byte array
+     */
+    public static byte[] serialize(Map<String, String> map) {
+        JsonStream stream = JsonStreamPool.borrowJsonStream();
+        try {
+            stream.reset(null);
+            stream.writeObjectStart();
+            map.forEach((k, v) -> {
+                try {
+                    stream.writeObjectField(k);
+                    stream.writeVal(v);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            });
+            stream.writeObjectEnd();
+            return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
+        } catch (IOException e) {
+            throw new JsonException(e);
+        } finally {
+            JsonStreamPool.returnJsonStream(stream);
+        }
+    }
+
+    /**
+     * Serialize a list of objects into a JSON array and return it as a byte array.
+     *
+     * @param objs the list of objects
+     * @return the byte array
+     */
+    public static byte[] serialize(List<?> objs) {
+        JsonStream stream = JsonStreamPool.borrowJsonStream();
+        try {
+            stream.reset(null);
+            stream.writeArrayStart();
+            int i = 0;
+            int n = objs.size();
+            for (Object obj : objs) {
+                stream.writeVal(obj.getClass(), obj);
+                if (i++ < n - 1) {
+                    stream.writeMore();
+                }
+
+            }
+            stream.writeArrayEnd();
+            return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
+        } catch (IOException e) {
+            throw new JsonException(e);
+        } finally {
+            JsonStreamPool.returnJsonStream(stream);
+        }
+    }
+}

+ 6 - 52
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java

@@ -16,14 +16,9 @@
 
 
 package io.helidon.benchmark.nima;
 package io.helidon.benchmark.nima;
 
 
-import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
-import com.jsoniter.output.JsonStream;
-import com.jsoniter.output.JsonStreamPool;
-import com.jsoniter.spi.JsonException;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.HikariJdbcRepository;
 import io.helidon.benchmark.nima.models.HikariJdbcRepository;
 import io.helidon.benchmark.nima.models.PgClientRepository;
 import io.helidon.benchmark.nima.models.PgClientRepository;
@@ -41,6 +36,8 @@ import io.helidon.webserver.http.HttpRules;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerResponse;
 import io.helidon.webserver.http.ServerResponse;
 
 
+import static io.helidon.benchmark.nima.JsonSerializer.serialize;
+
 /**
 /**
  * Main class of the benchmark.
  * Main class of the benchmark.
  * Opens server on localhost:8080 and exposes {@code /plaintext} and {@code /json} endpoints adhering to the
  * Opens server on localhost:8080 and exposes {@code /plaintext} and {@code /json} endpoints adhering to the
@@ -90,29 +87,14 @@ public final class Main {
 
 
         rules.get("/plaintext", new PlaintextHandler())
         rules.get("/plaintext", new PlaintextHandler())
                 .get("/json", new JsonHandler())
                 .get("/json", new JsonHandler())
-                .get("/10k", new JsonKHandler(10))
                 .get("/fortunes", new FortuneHandler(repository))
                 .get("/fortunes", new FortuneHandler(repository))
                 .register("/", new DbService(repository));
                 .register("/", new DbService(repository));
     }
     }
 
 
-    private static byte[] serializeMsg(Message obj) {
-        JsonStream stream = JsonStreamPool.borrowJsonStream();
-        try {
-            stream.reset(null);
-            stream.writeVal(Message.class, obj);
-            return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail());
-        } catch (IOException e) {
-            throw new JsonException(e);
-        } finally {
-            JsonStreamPool.returnJsonStream(stream);
-        }
-    }
-
     static class PlaintextHandler implements Handler {
     static class PlaintextHandler implements Handler {
         static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE,
         static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE,
-                "text/plain; charset=UTF-8");
+                                                                     "text/plain; charset=UTF-8");
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13");
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13");
-
         private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8);
         private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8);
 
 
         @Override
         @Override
@@ -126,44 +108,16 @@ public final class Main {
 
 
     static class JsonHandler implements Handler {
     static class JsonHandler implements Handler {
         private static final String MESSAGE = "Hello, World!";
         private static final String MESSAGE = "Hello, World!";
-        private static final int JSON_LENGTH = serializeMsg(new Message(MESSAGE)).length;
+        private static final int JSON_LENGTH = serialize(new Message(MESSAGE)).length;
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH,
         static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH,
-                String.valueOf(JSON_LENGTH));
+                                                                       String.valueOf(JSON_LENGTH));
 
 
         @Override
         @Override
         public void handle(ServerRequest req, ServerResponse res) {
         public void handle(ServerRequest req, ServerResponse res) {
             res.header(CONTENT_LENGTH);
             res.header(CONTENT_LENGTH);
             res.header(HeaderValues.CONTENT_TYPE_JSON);
             res.header(HeaderValues.CONTENT_TYPE_JSON);
             res.header(Main.SERVER);
             res.header(Main.SERVER);
-            res.send(serializeMsg(newMsg()));
-        }
-
-        private static Message newMsg() {
-            return new Message("Hello, World!");
-        }
-    }
-
-    static class JsonKHandler implements Handler {
-        private final Header contentLength;
-        private final String message;
-
-        JsonKHandler(int kilobytes) {
-            this.message = "a".repeat(1024 * kilobytes);
-            int length = serializeMsg(new Message(message)).length;
-            this.contentLength = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH,
-                    String.valueOf(length));
-        }
-
-        @Override
-        public void handle(ServerRequest req, ServerResponse res) {
-            res.header(contentLength);
-            res.header(HeaderValues.CONTENT_TYPE_JSON);
-            res.header(Main.SERVER);
-            res.send(serializeMsg(newMsg()));
-        }
-
-        private Message newMsg() {
-            return new Message(message);
+            res.send(serialize(new Message(MESSAGE)));
         }
         }
     }
     }
 
 

+ 0 - 19
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java

@@ -6,35 +6,16 @@ import java.util.List;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 
 
 import jakarta.json.Json;
 import jakarta.json.Json;
-import jakarta.json.JsonArray;
-import jakarta.json.JsonArrayBuilder;
 import jakarta.json.JsonBuilderFactory;
 import jakarta.json.JsonBuilderFactory;
-import jakarta.json.JsonObject;
 
 
 public interface DbRepository {
 public interface DbRepository {
 
 
     JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
     JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
 
 
-    default World getWorld() {
-        return getWorld(randomWorldNumber());
-    }
-
     World getWorld(int id);
     World getWorld(int id);
 
 
-    default JsonObject getWorldAsJson(int id) {
-        return getWorld().toJson();
-    }
-
     List<World> getWorlds(int count);
     List<World> getWorlds(int count);
 
 
-    default JsonArray getWorldsAsJson(int count) {
-        JsonArrayBuilder result = JSON.createArrayBuilder();
-        for (World world : getWorlds(count)) {
-            result.add(world.toJson());
-        }
-        return result.build();
-    }
-
     World updateWorld(World world);
     World updateWorld(World world);
 
 
     List<World> updateWorlds(int count);
     List<World> updateWorlds(int count);

+ 17 - 4
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java

@@ -7,6 +7,8 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 import com.zaxxer.hikari.HikariConfig;
 import com.zaxxer.hikari.HikariConfig;
@@ -22,20 +24,31 @@ public class HikariJdbcRepository implements DbRepository {
     private final HikariConfig hikariConfig;
     private final HikariConfig hikariConfig;
 
 
     public HikariJdbcRepository(Config config) {
     public HikariJdbcRepository(Config config) {
+        // hikari connection configuration
         String url = "jdbc:postgresql://" +
         String url = "jdbc:postgresql://" +
                 config.get("host").asString().orElse("tfb-database") +
                 config.get("host").asString().orElse("tfb-database") +
                 ":" + config.get("port").asString().orElse("5432") +
                 ":" + config.get("port").asString().orElse("5432") +
                 "/" + config.get("db").asString().orElse("hello_world");
                 "/" + config.get("db").asString().orElse("hello_world");
-
         hikariConfig = new HikariConfig();
         hikariConfig = new HikariConfig();
         hikariConfig.setJdbcUrl(url);
         hikariConfig.setJdbcUrl(url);
         hikariConfig.setUsername(config.get("username").asString().orElse("benchmarkdbuser"));
         hikariConfig.setUsername(config.get("username").asString().orElse("benchmarkdbuser"));
         hikariConfig.setPassword(config.get("password").asString().orElse("benchmarkdbpass"));
         hikariConfig.setPassword(config.get("password").asString().orElse("benchmarkdbpass"));
-        hikariConfig.addDataSourceProperty("cachePrepStmts", "true");
 
 
+        // hikari additional configuration
         int poolSize = config.get("sql-pool-size").asInt().orElse(64);
         int poolSize = config.get("sql-pool-size").asInt().orElse(64);
-        hikariConfig.addDataSourceProperty("maximumPoolSize", poolSize);
-        LOGGER.info("Db pool size is set to " + poolSize);
+        hikariConfig.setMaximumPoolSize(poolSize);
+        LOGGER.info("Hikari pool size is set to " + poolSize);
+        ThreadFactory vtThreadFactory = Thread.ofVirtual().factory();
+        hikariConfig.setThreadFactory(vtThreadFactory);
+        hikariConfig.setScheduledExecutor(Executors.newScheduledThreadPool(poolSize, vtThreadFactory));
+        LOGGER.info("Set thread factory to VTs");
+
+        // data source properties
+        hikariConfig.addDataSourceProperty("cachePrepStmts","true");
+        hikariConfig.addDataSourceProperty("prepStmtCacheSize","250");
+        hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit","2048");
+        hikariConfig.addDataSourceProperty("ssl", "false");
+        hikariConfig.addDataSourceProperty("tcpKeepAlive", "true");
     }
     }
 
 
     private Connection getConnection() throws SQLException {
     private Connection getConnection() throws SQLException {

+ 45 - 60
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java

@@ -8,27 +8,25 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeoutException;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
-import io.helidon.common.reactive.Multi;
-import io.helidon.common.reactive.Single;
 import io.helidon.config.Config;
 import io.helidon.config.Config;
+
 import io.vertx.core.Vertx;
 import io.vertx.core.Vertx;
 import io.vertx.core.VertxOptions;
 import io.vertx.core.VertxOptions;
+import io.vertx.core.Future;
 import io.vertx.pgclient.PgConnectOptions;
 import io.vertx.pgclient.PgConnectOptions;
 import io.vertx.pgclient.PgPool;
 import io.vertx.pgclient.PgPool;
 import io.vertx.sqlclient.PoolOptions;
 import io.vertx.sqlclient.PoolOptions;
+import io.vertx.sqlclient.PreparedQuery;
 import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.Row;
+import io.vertx.sqlclient.RowSet;
 import io.vertx.sqlclient.SqlClient;
 import io.vertx.sqlclient.SqlClient;
 import io.vertx.sqlclient.Tuple;
 import io.vertx.sqlclient.Tuple;
-import jakarta.json.JsonArray;
-import jakarta.json.JsonArrayBuilder;
-import jakarta.json.JsonObject;
 
 
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
 
 
 public class PgClientRepository implements DbRepository {
 public class PgClientRepository implements DbRepository {
     private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName());
     private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName());
 
 
-
     private final SqlClient queryPool;
     private final SqlClient queryPool;
     private final SqlClient updatePool;
     private final SqlClient updatePool;
 
 
@@ -36,9 +34,13 @@ public class PgClientRepository implements DbRepository {
     private final long updateTimeout;
     private final long updateTimeout;
     private final int maxRetries;
     private final int maxRetries;
 
 
+    private final PreparedQuery<RowSet<Row>> getFortuneQuery;
+    private final PreparedQuery<RowSet<Row>> getWorldQuery;
+    private final PreparedQuery<RowSet<Row>> updateWorldQuery;
+
     public PgClientRepository(Config config) {
     public PgClientRepository(Config config) {
         Vertx vertx = Vertx.vertx(new VertxOptions()
         Vertx vertx = Vertx.vertx(new VertxOptions()
-                .setPreferNativeTransport(true));
+                                          .setPreferNativeTransport(true));
         PgConnectOptions connectOptions = new PgConnectOptions()
         PgConnectOptions connectOptions = new PgConnectOptions()
                 .setPort(config.get("port").asInt().orElse(5432))
                 .setPort(config.get("port").asInt().orElse(5432))
                 .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true))
                 .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true))
@@ -59,31 +61,20 @@ public class PgClientRepository implements DbRepository {
 
 
         queryPool = PgPool.client(vertx, connectOptions, clientOptions);
         queryPool = PgPool.client(vertx, connectOptions, clientOptions);
         updatePool = PgPool.client(vertx, connectOptions, clientOptions);
         updatePool = PgPool.client(vertx, connectOptions, clientOptions);
-    }
 
 
-    @Override
-    public JsonObject getWorldAsJson(int id) {
-        return getWorld(id, queryPool).map(World::toJson).await();
+        getWorldQuery = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1");
+        updateWorldQuery = queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2");
+        getFortuneQuery = queryPool.preparedQuery("SELECT id, message FROM fortune");
     }
     }
 
 
     @Override
     @Override
     public World getWorld(int id) {
     public World getWorld(int id) {
         try {
         try {
-            return getWorld(id, queryPool).toCompletableFuture().get();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public JsonArray getWorldsAsJson(int count) {
-        try {
-            return Multi.range(0, count)
-                    .flatMap(i -> getWorld(randomWorldNumber(), queryPool))
-                    .map(World::toJson)
-                    .reduce(JSON::createArrayBuilder, JsonArrayBuilder::add)
-                    .map(JsonArrayBuilder::build)
-                    .await();
+            return getWorldQuery.execute(Tuple.of(id))
+                    .map(rows -> {
+                        Row r = rows.iterator().next();
+                        return new World(r.getInteger(0), r.getInteger(1));
+                    }).toCompletionStage().toCompletableFuture().get();
         } catch (Exception e) {
         } catch (Exception e) {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
@@ -92,17 +83,15 @@ public class PgClientRepository implements DbRepository {
     @Override
     @Override
     public List<World> getWorlds(int count) {
     public List<World> getWorlds(int count) {
         try {
         try {
-            List<World> result = new ArrayList<>(count);
+            List<Future<?>> futures = new ArrayList<>();
             for (int i = 0; i < count; i++) {
             for (int i = 0; i < count; i++) {
-                World world = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1")
-                        .execute(Tuple.of(randomWorldNumber()))
-                        .map(rows -> {
-                            Row r = rows.iterator().next();
-                            return new World(r.getInteger(0), r.getInteger(1));
-                        }).toCompletionStage().toCompletableFuture().get();
-                result.add(world);
+                futures.add(getWorldQuery.execute(Tuple.of(randomWorldNumber()))
+                                    .map(rows -> {
+                                        Row r = rows.iterator().next();
+                                        return new World(r.getInteger(0), r.getInteger(1));
+                                    }));
             }
             }
-            return result;
+            return Future.all(futures).toCompletionStage().toCompletableFuture().get().list();
         } catch (Exception e) {
         } catch (Exception e) {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
@@ -110,10 +99,14 @@ public class PgClientRepository implements DbRepository {
 
 
     @Override
     @Override
     public World updateWorld(World world) {
     public World updateWorld(World world) {
-        return Single.create(queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2")
-                .execute(Tuple.of(world.id, world.id))
-                .toCompletionStage()
-                .thenApply(rows -> world)).await();
+        try {
+            return updateWorldQuery.execute(Tuple.of(world.id, world.id))
+                    .toCompletionStage()
+                    .thenApply(rows -> world)
+                    .toCompletableFuture().get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
     }
 
 
     @Override
     @Override
@@ -165,25 +158,18 @@ public class PgClientRepository implements DbRepository {
 
 
     @Override
     @Override
     public List<Fortune> getFortunes() {
     public List<Fortune> getFortunes() {
-        return Single.create(queryPool.preparedQuery("SELECT id, message FROM fortune")
-                .execute()
-                .map(rows -> {
-                    List<Fortune> fortunes = new ArrayList<>(rows.size() + 1);
-                    for (Row r : rows) {
-                        fortunes.add(new Fortune(r.getInteger(0), r.getString(1)));
-                    }
-                    return fortunes;
-                }).toCompletionStage()).await();
-    }
-
-    private static Single<World> getWorld(int id, SqlClient pool) {
-        return Single.create(pool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1")
-                .execute(Tuple.of(id))
-                .map(rows -> {
-                    Row r = rows.iterator().next();
-                    return new World(r.getInteger(0), r.getInteger(1));
-                }).toCompletionStage());
-
+        try {
+            return getFortuneQuery.execute()
+                    .map(rows -> {
+                        List<Fortune> fortunes = new ArrayList<>(rows.size() + 1);
+                        for (Row r : rows) {
+                            fortunes.add(new Fortune(r.getInteger(0), r.getString(1)));
+                        }
+                        return fortunes;
+                    }).toCompletionStage().toCompletableFuture().get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
     }
 
 
     private CompletableFuture<List<World>> updateWorlds(List<World> worlds, int from, SqlClient pool) {
     private CompletableFuture<List<World>> updateWorlds(List<World> worlds, int from, SqlClient pool) {
@@ -193,8 +179,7 @@ public class PgClientRepository implements DbRepository {
             World w = worlds.get(i);
             World w = worlds.get(i);
             tuples.add(Tuple.of(w.randomNumber, w.id));
             tuples.add(Tuple.of(w.randomNumber, w.id));
         }
         }
-        return pool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2")
-                .executeBatch(tuples)
+        return updateWorldQuery.executeBatch(tuples)
                 .toCompletionStage()
                 .toCompletionStage()
                 .thenApply(rows -> worlds)
                 .thenApply(rows -> worlds)
                 .toCompletableFuture();
                 .toCompletableFuture();

+ 3 - 3
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java

@@ -9,9 +9,9 @@ import jakarta.json.JsonObject;
 
 
 public final class World {
 public final class World {
 
 
-    private static final String ID_KEY = "id";
-    private static final String ID_RANDOM_NUMBER = "randomNumber";
-    private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
+    static final String ID_KEY = "id";
+    static final String ID_RANDOM_NUMBER = "randomNumber";
+    static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
 
 
     public int id;
     public int id;
     public int randomNumber;
     public int randomNumber;

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

@@ -1,27 +1,23 @@
 
 
 package io.helidon.benchmark.nima.services;
 package io.helidon.benchmark.nima.services;
 
 
-import java.util.Collections;
 import java.util.List;
 import java.util.List;
 
 
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.DbRepository;
 import io.helidon.benchmark.nima.models.World;
 import io.helidon.benchmark.nima.models.World;
 import io.helidon.common.parameters.Parameters;
 import io.helidon.common.parameters.Parameters;
+import io.helidon.http.HeaderValues;
 import io.helidon.webserver.http.HttpRules;
 import io.helidon.webserver.http.HttpRules;
 import io.helidon.webserver.http.HttpService;
 import io.helidon.webserver.http.HttpService;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerRequest;
 import io.helidon.webserver.http.ServerResponse;
 import io.helidon.webserver.http.ServerResponse;
-
-import jakarta.json.Json;
-import jakarta.json.JsonArrayBuilder;
-import jakarta.json.JsonBuilderFactory;
-import jakarta.json.JsonObject;
+import io.helidon.common.mapper.OptionalValue;
 
 
 import static io.helidon.benchmark.nima.Main.SERVER;
 import static io.helidon.benchmark.nima.Main.SERVER;
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
 import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
+import static io.helidon.benchmark.nima.JsonSerializer.serialize;
 
 
 public class DbService implements HttpService {
 public class DbService implements HttpService {
-    private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
 
 
     private final DbRepository repository;
     private final DbRepository repository;
 
 
@@ -38,36 +34,33 @@ public class DbService implements HttpService {
 
 
     private void db(ServerRequest req, ServerResponse res) {
     private void db(ServerRequest req, ServerResponse res) {
         res.header(SERVER);
         res.header(SERVER);
-        res.send(repository.getWorldAsJson(randomWorldNumber()));
+        res.header(HeaderValues.CONTENT_TYPE_JSON);
+        res.send(serialize(repository.getWorld(randomWorldNumber())));
     }
     }
 
 
     private void queries(ServerRequest req, ServerResponse res) {
     private void queries(ServerRequest req, ServerResponse res) {
         res.header(SERVER);
         res.header(SERVER);
+        res.header(HeaderValues.CONTENT_TYPE_JSON);
         int count = parseQueryCount(req.query());
         int count = parseQueryCount(req.query());
-        res.send(repository.getWorldsAsJson(count));
+        res.send(serialize(repository.getWorlds(count)));
     }
     }
 
 
     private void updates(ServerRequest req, ServerResponse res) {
     private void updates(ServerRequest req, ServerResponse res) {
         res.header(SERVER);
         res.header(SERVER);
+        res.header(HeaderValues.CONTENT_TYPE_JSON);
         int count = parseQueryCount(req.query());
         int count = parseQueryCount(req.query());
         List<World> worlds = repository.updateWorlds(count);
         List<World> worlds = repository.updateWorlds(count);
-        JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder();
-        for (World world : worlds) {
-            JsonObject json = world.toJson();
-            arrayBuilder.add(json);
-        }
-        res.send(arrayBuilder.build());
+        res.send(serialize(worlds));
     }
     }
 
 
     private int parseQueryCount(Parameters parameters) {
     private int parseQueryCount(Parameters parameters) {
-        List<String> values = parameters.all("queries");
-        if (values.isEmpty()) {
+        OptionalValue<String> value = parameters.first("queries");
+        if (value.isEmpty()) {
             return 1;
             return 1;
         }
         }
-        String first = values.get(0);
         int parsedValue;
         int parsedValue;
         try {
         try {
-            parsedValue = Integer.parseInt(first, 10);
+            parsedValue = Integer.parseInt(value.get(), 10);
         } catch (NumberFormatException e) {
         } catch (NumberFormatException e) {
             return 1;
             return 1;
         }
         }

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

@@ -19,6 +19,7 @@ server:
   port: 8080
   port: 8080
   backlog: 8192
   backlog: 8192
   write-queue-length: 8192
   write-queue-length: 8192
+  smart-async-writes: true
   connection-options:
   connection-options:
     read-timeout: PT0S
     read-timeout: PT0S
     connect-timeout: PT0S
     connect-timeout: PT0S

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

@@ -11,7 +11,7 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.target>11</maven.compiler.target>
         <maven.compiler.target>11</maven.compiler.target>
-        <jetty.version>10.0.14</jetty.version>
+        <jetty.version>10.0.24</jetty.version>
         <main.class>hello.handler.HelloWebServer</main.class>
         <main.class>hello.handler.HelloWebServer</main.class>
     </properties>
     </properties>
 
 

+ 1 - 1
frameworks/Java/jooby/jooby-jetty.dockerfile

@@ -1,4 +1,4 @@
-FROM maven:3.9.6-eclipse-temurin-21-jammy
+FROM maven:3.9.9-eclipse-temurin-22-alpine
 WORKDIR /jooby
 WORKDIR /jooby
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 COPY src src
 COPY src src

+ 1 - 1
frameworks/Java/jooby/jooby-mvc.dockerfile

@@ -1,4 +1,4 @@
-FROM maven:3.9.6-eclipse-temurin-21-jammy
+FROM maven:3.9.9-eclipse-temurin-22-alpine
 WORKDIR /jooby
 WORKDIR /jooby
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 COPY src src
 COPY src src

+ 1 - 1
frameworks/Java/jooby/jooby-netty.dockerfile

@@ -1,4 +1,4 @@
-FROM maven:3.9.6-eclipse-temurin-21-jammy
+FROM maven:3.9.9-eclipse-temurin-22-alpine
 WORKDIR /jooby
 WORKDIR /jooby
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 COPY src src
 COPY src src

+ 1 - 1
frameworks/Java/jooby/jooby-pgclient.dockerfile

@@ -1,4 +1,4 @@
-FROM maven:3.9.6-eclipse-temurin-21-jammy
+FROM maven:3.9.9-eclipse-temurin-22-alpine
 WORKDIR /jooby
 WORKDIR /jooby
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 COPY src src
 COPY src src

+ 1 - 1
frameworks/Java/jooby/jooby.dockerfile

@@ -1,4 +1,4 @@
-FROM maven:3.9.6-eclipse-temurin-21-jammy
+FROM maven:3.9.9-eclipse-temurin-22-alpine
 WORKDIR /jooby
 WORKDIR /jooby
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 COPY src src
 COPY src src

+ 4 - 4
frameworks/Java/jooby/pom.xml

@@ -11,13 +11,13 @@
   <name>jooby</name>
   <name>jooby</name>
 
 
   <properties>
   <properties>
-    <jooby.version>3.2.9</jooby.version>
-    <netty.version>4.1.112.Final</netty.version>
+    <jooby.version>3.4.0</jooby.version>
+    <netty.version>4.1.113.Final</netty.version>
     <dsl-json.version>2.0.2</dsl-json.version>
     <dsl-json.version>2.0.2</dsl-json.version>
     <postgresql.version>42.7.4</postgresql.version>
     <postgresql.version>42.7.4</postgresql.version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <maven.compiler.source>21</maven.compiler.source>
-    <maven.compiler.target>21</maven.compiler.target>
+    <maven.compiler.source>22</maven.compiler.source>
+    <maven.compiler.target>22</maven.compiler.target>
 
 
     <!-- Startup class -->
     <!-- Startup class -->
     <application.class>com.techempower.App</application.class>
     <application.class>com.techempower.App</application.class>

+ 0 - 83
frameworks/Java/redkale/BenchmarkService.java

@@ -1,83 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.redkalex.benchmark;
-
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.stream.Stream;
-import org.redkale.annotation.*;
-import org.redkale.net.http.*;
-import org.redkale.service.AbstractService;
-import org.redkale.source.DataSource;
-import org.redkale.util.AnyValue;
-
-/**
- * 测试redkale-jdbc, 需要覆盖到原BenchmarkService
- *
- * @author zhangjx
- */
-@RestService(name = " ", repair = false)
-public class BenchmarkService extends AbstractService {
-
-    private static final byte[] helloBytes = "Hello, world!".getBytes();
-
-    @Resource
-    private DataSource source;
-
-    public void init(AnyValue conf) {
-        source.finds(CachedWorld.class, 1);
-    }
-    
-    @NonBlocking
-    @RestMapping(auth = false)
-    public byte[] plaintext() {
-        return helloBytes;
-    }
-
-    @NonBlocking
-    @RestMapping(auth = false)
-    public Message json() {
-        return new Message("Hello, World!");
-    }
-
-    @RestMapping(auth = false)
-    public World db() {
-        return source.find(World.class, ThreadLocalRandom.current().nextInt(10000) + 1);
-    }
-
-    @RestMapping(auth = false)
-    public List<World> queries(int q) {
-        return source.findsList(World.class, random(q));
-    }
-
-    @RestMapping(auth = false)
-    public List<World> updates(int q) {
-        int size = Math.min(500, Math.max(1, q));
-        int[] newNumbers = ThreadLocalRandom.current().ints(size, 1, 10001).toArray();
-        List<World> words = source.findsList(World.class, random(q));
-        source.update(World.updateNewNumbers(words, newNumbers));
-        return words;
-    }
-
-    @RestMapping(auth = false)
-    public HttpScope fortunes() {
-        List<Fortune> fortunes = source.queryList(Fortune.class);
-        fortunes.add(new Fortune(0, "Additional fortune added at request time."));
-        Collections.sort(fortunes);
-        return HttpScope.refer("").referObj(fortunes);
-    }
-
-    @NonBlocking
-    @RestMapping(name = "cached-worlds", auth = false)
-    public CachedWorld[] cachedWorlds(int q) {
-        return source.finds(CachedWorld.class, random(q));
-    }
-
-    private Stream<Integer> random(int q) {
-        int size = Math.min(500, Math.max(1, q));
-        return ThreadLocalRandom.current().ints(size, 1, 10001).boxed();
-    }
-}

+ 0 - 45
frameworks/Java/redkale/benchmark_config.json

@@ -26,30 +26,6 @@
                 "notes": "",
                 "notes": "",
                 "versus": "Redkale"
                 "versus": "Redkale"
             },
             },
-            "graalvm": {
-                "plaintext_url": "/plaintext",
-                "json_url": "/json",
-                "db_url": "/db",
-                "query_url": "/queries?q=", 
-                "fortune_url": "/fortunes",
-                "update_url": "/updates?q=",
-                "cached_query_url": "/cached-worlds?q=",
-                "port": 8080,
-                "approach": "Realistic",
-                "classification": "Fullstack",
-                "database": "Postgres",
-                "framework": "Redkale",
-                "language": "Java",
-                "flavor": "None",
-                "orm": "Raw",
-                "platform": "Redkale",
-                "webserver": "Redkale",
-                "os": "Linux",
-                "database_os": "Linux",
-                "display_name": "redkale-graalvm",
-                "notes": "",
-                "versus": "Redkale"
-            },
             "native": {
             "native": {
                 "plaintext_url": "/plaintext",
                 "plaintext_url": "/plaintext",
                 "json_url": "/json",
                 "json_url": "/json",
@@ -95,27 +71,6 @@
                 "notes": "",
                 "notes": "",
                 "versus": "Redkale"
                 "versus": "Redkale"
             },
             },
-            "block": {
-                "db_url": "/db",
-                "query_url": "/queries?q=", 
-                "fortune_url": "/fortunes",
-                "update_url": "/updates?q=",
-                "port": 8080,
-                "approach": "Realistic",
-                "classification": "Fullstack",
-                "database": "Postgres",
-                "framework": "Redkale",
-                "language": "Java",
-                "flavor": "None",
-                "orm": "Raw",
-                "platform": "Redkale",
-                "webserver": "Redkale",
-                "os": "Linux",
-                "database_os": "Linux",
-                "display_name": "redkale-block",
-                "notes": "",
-                "versus": "Redkale"
-            },
             "pgclient": {
             "pgclient": {
                 "db_url": "/db",
                 "db_url": "/db",
                 "query_url": "/queries?q=", 
                 "query_url": "/queries?q=", 

+ 1 - 1
frameworks/Java/redkale/conf/application.xml

@@ -8,7 +8,7 @@
         <property name="system.property.redkale.http.response.header.connection" value="none"/>
         <property name="system.property.redkale.http.response.header.connection" value="none"/>
     </properties>
     </properties>
         
         
-    <server protocol="HTTP" port="8080" shareio="true">    
+    <server protocol="HTTP" port="8080">    
         <response>
         <response>
             <content-type plain="text/plain" json="application/json"/>  
             <content-type plain="text/plain" json="application/json"/>  
             <date period="1000"/>
             <date period="1000"/>

+ 0 - 33
frameworks/Java/redkale/config.toml

@@ -19,24 +19,6 @@ platform = "Redkale"
 webserver = "Redkale"
 webserver = "Redkale"
 versus = "Redkale"
 versus = "Redkale"
 
 
-[graalvm]
-urls.plaintext = "/plaintext"
-urls.json = "/json"
-urls.db = "/db"
-urls.fortune = "/fortunes"
-urls.query = "/queries?q="
-urls.update = "/updates?q="
-urls.cached_query = "/cached-worlds?q="
-approach = "Realistic"
-classification = "Fullstack"
-database = "Postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Raw"
-platform = "Redkale"
-webserver = "Redkale"
-versus = "Redkale"
-
 [native]
 [native]
 urls.plaintext = "/plaintext"
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
@@ -70,21 +52,6 @@ platform = "Redkale"
 webserver = "Redkale"
 webserver = "Redkale"
 versus = "Redkale"
 versus = "Redkale"
 
 
-[block]
-urls.db = "/db"
-urls.fortune = "/fortunes"
-urls.query = "/queries?q="
-urls.update = "/updates?q="
-approach = "Realistic"
-classification = "Fullstack"
-database = "Postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Raw"
-platform = "Redkale"
-webserver = "Redkale"
-versus = "Redkale"
-
 [pgclient]
 [pgclient]
 urls.db = "/db"
 urls.db = "/db"
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"

+ 1 - 1
frameworks/Java/redkale/pom-jdbc.xml

@@ -8,7 +8,7 @@
     <properties>
     <properties>
         <main.class>org.redkale.boot.Application</main.class>
         <main.class>org.redkale.boot.Application</main.class>
         <redkale.version>2.8.0-SNAPSHOT</redkale.version>
         <redkale.version>2.8.0-SNAPSHOT</redkale.version>
-        <redkale-maven.version>1.3.0-SNAPSHOT</redkale-maven.version>
+        <redkale-maven.version>1.2.0-SNAPSHOT</redkale-maven.version>
         <postgresql.version>42.7.2</postgresql.version>
         <postgresql.version>42.7.2</postgresql.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <maven.compiler.source>21</maven.compiler.source>
         <maven.compiler.source>21</maven.compiler.source>

+ 2 - 0
frameworks/Java/redkale/pom.xml

@@ -79,6 +79,8 @@
                 <configuration>		
                 <configuration>		
                     <nativeimageArgs>
                     <nativeimageArgs>
                         <arg>--no-fallback</arg>
                         <arg>--no-fallback</arg>
+                        <arg>-J-XX:+UseNUMA</arg>
+                        <arg>-J-XX:+UseParallelGC</arg>
                     </nativeimageArgs>
                     </nativeimageArgs>
                 </configuration>                                    
                 </configuration>                                    
                 <executions>
                 <executions>

+ 0 - 16
frameworks/Java/redkale/redkale-block.dockerfile

@@ -1,16 +0,0 @@
-FROM maven:3.9.6-amazoncorretto-21-debian as maven
-WORKDIR /redkale
-COPY src src
-COPY conf conf
-COPY pom.xml pom.xml
-COPY BenchmarkService.java src/main/java/org/redkalex/benchmark/BenchmarkService.java
-RUN mvn package -q
-
-FROM openjdk:23-jdk-slim
-WORKDIR /redkale
-COPY conf conf
-COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar
-
-EXPOSE 8080
-
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]

+ 0 - 16
frameworks/Java/redkale/redkale-graalvm.dockerfile

@@ -1,16 +0,0 @@
-FROM maven:3.9.6-amazoncorretto-21-debian as maven
-WORKDIR /redkale
-COPY src src
-COPY conf conf
-COPY pom.xml pom.xml
-RUN mvn package -q
-
-
-FROM ghcr.io/graalvm/jdk-community:22.0.2
-WORKDIR /redkale
-COPY conf conf
-COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar
-
-EXPOSE 8080
-
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]

+ 1 - 2
frameworks/Java/redkale/redkale-jdbc.dockerfile

@@ -3,7 +3,6 @@ WORKDIR /redkale
 COPY src src
 COPY src src
 COPY conf conf
 COPY conf conf
 COPY pom-jdbc.xml pom.xml
 COPY pom-jdbc.xml pom.xml
-COPY BenchmarkService.java src/main/java/org/redkalex/benchmark/BenchmarkService.java
 RUN mvn package -q
 RUN mvn package -q
 
 
 FROM openjdk:23-jdk-slim
 FROM openjdk:23-jdk-slim
@@ -13,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]
+CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]

+ 1 - 1
frameworks/Java/redkale/redkale-pgclient.dockerfile

@@ -12,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]
+CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]

+ 1 - 1
frameworks/Java/redkale/redkale.dockerfile

@@ -12,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]
+CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]

+ 1 - 7
frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java

@@ -7,13 +7,11 @@ package org.redkalex.benchmark;
 
 
 import java.util.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.*;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
+import java.util.stream.*;
 import org.redkale.annotation.*;
 import org.redkale.annotation.*;
 import org.redkale.net.http.*;
 import org.redkale.net.http.*;
 import org.redkale.service.AbstractService;
 import org.redkale.service.AbstractService;
 import org.redkale.source.DataSource;
 import org.redkale.source.DataSource;
-import org.redkale.util.AnyValue;
 
 
 /**
 /**
  *
  *
@@ -28,10 +26,6 @@ public class BenchmarkService extends AbstractService {
     @Resource
     @Resource
     private DataSource source;
     private DataSource source;
 
 
-    public void init(AnyValue conf) {
-        source.finds(CachedWorld.class, 1);
-    }
-
     @RestMapping(auth = false)
     @RestMapping(auth = false)
     public byte[] plaintext() {
     public byte[] plaintext() {
         return helloBytes;
         return helloBytes;

+ 2 - 2
frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java

@@ -6,7 +6,7 @@
 package org.redkalex.benchmark;
 package org.redkalex.benchmark;
 
 
 import org.redkale.annotation.Serial;
 import org.redkale.annotation.Serial;
-import org.redkale.convert.ConvertSmallString;
+import org.redkale.convert.ConvertStandardString;
 import org.redkale.convert.json.JsonConvert;
 import org.redkale.convert.json.JsonConvert;
 
 
 /**
 /**
@@ -16,7 +16,7 @@ import org.redkale.convert.json.JsonConvert;
 @Serial
 @Serial
 public final class Message {
 public final class Message {
 
 
-    @ConvertSmallString
+    @ConvertStandardString
     private String message;
     private String message;
 
 
     public Message() {}
     public Message() {}

+ 1 - 1
frameworks/Java/solon/README.md

@@ -10,7 +10,7 @@ This is the solon portion of a [benchmarking test suite](../) comparing a variet
 ## Versions
 ## Versions
 
 
 * [Java OpenJDK 21](http://openjdk.java.net/)
 * [Java OpenJDK 21](http://openjdk.java.net/)
-* [solon 2.9.1](https://github.com/noear/solon)
+* [solon 3.0.2](https://github.com/noear/solon)
 
 
 ## Test URLs
 ## Test URLs
 
 

+ 3 - 5
frameworks/Java/solon/pom.xml

@@ -5,7 +5,7 @@
     <parent>
     <parent>
         <groupId>org.noear</groupId>
         <groupId>org.noear</groupId>
         <artifactId>solon-parent</artifactId>
         <artifactId>solon-parent</artifactId>
-        <version>2.9.2</version>
+        <version>3.0.2</version>
     </parent>
     </parent>
 
 
     <groupId>hello</groupId>
     <groupId>hello</groupId>
@@ -20,14 +20,12 @@
     <dependencies>
     <dependencies>
         <dependency>
         <dependency>
             <groupId>org.noear</groupId>
             <groupId>org.noear</groupId>
-            <artifactId>solon.boot.smarthttp</artifactId>
-            <version>${solon.version}</version>
+            <artifactId>solon-boot-smarthttp</artifactId>
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
             <groupId>org.noear</groupId>
             <groupId>org.noear</groupId>
-            <artifactId>solon.serialization.fastjson2</artifactId>
-            <version>${solon.version}</version>
+            <artifactId>solon-serialization-snack3</artifactId>
         </dependency>
         </dependency>
     </dependencies>
     </dependencies>
 
 

+ 24 - 6
frameworks/Java/spring-webflux/pom.xml

@@ -13,13 +13,14 @@
     <parent>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.3.3</version>
+        <version>3.3.4</version>
     </parent>
     </parent>
 
 
     <properties>
     <properties>
-        <maven.compiler.source>21</maven.compiler.source>
-        <maven.compiler.target>21</maven.compiler.target>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <java.version>21</java.version>
+        <jstachio.version>1.3.6</jstachio.version>
+        <r2dbc-pool.version>1.0.2.RELEASE</r2dbc-pool.version>
+        <r2dbc-postgresql.version>1.0.7.RELEASE</r2dbc-postgresql.version>
     </properties>
     </properties>
 
 
     <dependencies>
     <dependencies>
@@ -36,8 +37,16 @@
             <artifactId>r2dbc-postgresql</artifactId>
             <artifactId>r2dbc-postgresql</artifactId>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-mustache</artifactId>
+            <groupId>io.jstach</groupId>
+            <artifactId>jstachio</artifactId>
+            <version>${jstachio.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jstach</groupId>
+            <artifactId>jstachio-apt</artifactId>
+            <version>${jstachio.version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <groupId>org.springframework.boot</groupId>
@@ -55,6 +64,15 @@
             <plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.jstach</groupId>
+                            <artifactId>jstachio-apt</artifactId>
+                            <version>${jstachio.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
             </plugin>
             </plugin>
         </plugins>
         </plugins>
     </build>
     </build>

+ 1 - 1
frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile

@@ -13,4 +13,4 @@ RUN java -Djarmode=tools -jar app.jar extract
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD ["java", "-Dlogging.level.root=OFF", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=mongo"]
+CMD ["java", "-Dlogging.level.root=OFF", "-Dio.netty.leakDetection.level=disabled", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=mongo"]

+ 1 - 1
frameworks/Java/spring-webflux/spring-webflux.dockerfile

@@ -12,4 +12,4 @@ RUN java -Djarmode=tools -jar app.jar extract
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD ["java", "-Dlogging.level.root=OFF", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=r2dbc"]
+CMD ["java", "-Dlogging.level.root=OFF", "-Dio.netty.leakDetection.level=disabled", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=r2dbc"]

+ 2 - 3
frameworks/Java/spring-webflux/src/main/java/benchmark/App.java

@@ -11,7 +11,6 @@ import org.springframework.web.reactive.function.server.HandlerStrategies;
 import org.springframework.web.reactive.function.server.RouterFunction;
 import org.springframework.web.reactive.function.server.RouterFunction;
 import org.springframework.web.reactive.function.server.RouterFunctions;
 import org.springframework.web.reactive.function.server.RouterFunctions;
 import org.springframework.web.reactive.function.server.ServerResponse;
 import org.springframework.web.reactive.function.server.ServerResponse;
-import org.springframework.web.reactive.result.view.ViewResolver;
 import org.springframework.web.server.WebHandler;
 import org.springframework.web.server.WebHandler;
 import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
 import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
 
 
@@ -20,8 +19,8 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
 public class App  {
 public class App  {
 
 
     @Bean
     @Bean
-    public HttpHandler httpHandler(RouterFunction<ServerResponse> route, ServerFilter serverFilter, ViewResolver viewResolver) {
-        WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().viewResolver(viewResolver).build());
+    public HttpHandler httpHandler(RouterFunction<ServerResponse> route, ServerFilter serverFilter) {
+        WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().build());
         return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build();
         return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build();
     }
     }
 
 

+ 19 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java

@@ -0,0 +1,19 @@
+package benchmark;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.IntStream;
+
+abstract public class Utils {
+
+	private static final int MIN_WORLD_NUMBER = 1;
+	private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001;
+
+	public static int randomWorldNumber() {
+		return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE);
+	}
+
+	public static IntStream randomWorldNumbers() {
+		return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE).distinct();
+	}
+
+}

+ 6 - 7
frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java

@@ -4,9 +4,11 @@ import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.mapping.Document;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 
 @Document
 @Document
-public final class Fortune {
+public final class Fortune implements Comparable<Fortune> {
+
     @Id
     @Id
     public int id;
     public int id;
+
     public String message;
     public String message;
 
 
     public Fortune(int id, String message) {
     public Fortune(int id, String message) {
@@ -14,11 +16,8 @@ public final class Fortune {
         this.message = message;
         this.message = message;
     }
     }
 
 
-    public int getId() {
-        return id;
-    }
-
-    public String getMessage() {
-        return message;
+    @Override
+    public int compareTo(final Fortune other) {
+        return message.compareTo(other.message);
     }
     }
 }
 }

+ 0 - 15
frameworks/Java/spring-webflux/src/main/java/benchmark/model/Message.java

@@ -1,15 +0,0 @@
-package benchmark.model;
-
-public class Message {
-
-	private final String message;
-
-	public Message(String message) {
-		this.message = message;
-	}
-
-	public String getMessage() {
-		return message;
-	}
-
-}

+ 1 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java

@@ -9,6 +9,7 @@ public final class World {
 
 
     @Id
     @Id
     public int id;
     public int id;
+
     @Field("randomNumber")
     @Field("randomNumber")
     public int randomnumber;
     public int randomnumber;
 
 

+ 1 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java

@@ -6,6 +6,7 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
 public interface DbRepository {
 public interface DbRepository {
+
     Mono<World> getWorld(int id);
     Mono<World> getWorld(int id);
 
 
     Mono<World> findAndUpdateWorld(int id, int randomNumber);
     Mono<World> findAndUpdateWorld(int id, int randomNumber);

+ 0 - 63
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java

@@ -1,63 +0,0 @@
-package benchmark.repository;
-
-import benchmark.model.Fortune;
-import benchmark.model.World;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.annotation.Profile;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.stereotype.Component;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Scheduler;
-
-@Component
-@Profile("jdbc")
-public class JdbcDbRepository implements DbRepository {
-    private final Logger log = LoggerFactory.getLogger(getClass());
-    private final JdbcTemplate jdbcTemplate;
-    private final Scheduler scheduler;
-
-    public JdbcDbRepository(JdbcTemplate jdbcTemplate, Scheduler scheduler) {
-        this.jdbcTemplate = jdbcTemplate;
-        this.scheduler = scheduler;
-    }
-
-    @Override
-    public Mono<World> getWorld(int id) {
-        log.debug("getWorld({})", id);
-        return Mono.fromCallable(() -> {
-            return jdbcTemplate.queryForObject(
-                    "SELECT * FROM world WHERE id = ?",
-                    (rs, rn) -> new World(rs.getInt("id"), rs.getInt("randomnumber")),
-                    id);
-        }).subscribeOn(scheduler);
-    }
-
-    private Mono<World> updateWorld(World world) {
-        return Mono.fromCallable(() -> {
-            jdbcTemplate.update(
-                    "UPDATE world SET randomnumber = ? WHERE id = ?",
-                    world.randomnumber,
-                    world.id);
-            return world;
-        }).subscribeOn(scheduler);
-    }
-
-    @Override
-    public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
-        return getWorld(id).flatMap(world -> {
-            world.randomnumber = randomNumber;
-            return updateWorld(world);
-        });
-    }
-
-    @Override
-    public Flux<Fortune> fortunes() {
-        return Mono.fromCallable(() -> {
-            return jdbcTemplate.query(
-                    "SELECT * FROM fortune",
-                    (rs, rn) -> new Fortune(rs.getInt("id"), rs.getString("message")));
-        }).subscribeOn(scheduler).flatMapIterable(fortunes -> fortunes);
-    }
-}

+ 8 - 4
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java

@@ -1,16 +1,18 @@
 package benchmark.repository;
 package benchmark.repository;
 
 
-import benchmark.model.Fortune;
-import benchmark.model.World;
 import org.springframework.context.annotation.Profile;
 import org.springframework.context.annotation.Profile;
 import org.springframework.r2dbc.core.DatabaseClient;
 import org.springframework.r2dbc.core.DatabaseClient;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
+
+import benchmark.model.Fortune;
+import benchmark.model.World;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
 @Component
 @Component
 @Profile("r2dbc")
 @Profile("r2dbc")
 public class R2dbcDbRepository implements DbRepository {
 public class R2dbcDbRepository implements DbRepository {
+
     private final DatabaseClient databaseClient;
     private final DatabaseClient databaseClient;
 
 
     public R2dbcDbRepository(DatabaseClient databaseClient) {
     public R2dbcDbRepository(DatabaseClient databaseClient) {
@@ -24,10 +26,9 @@ public class R2dbcDbRepository implements DbRepository {
                 .bind("$1", id)
                 .bind("$1", id)
                 .mapProperties(World.class)
                 .mapProperties(World.class)
                 .first();
                 .first();
-
     }
     }
 
 
-    public Mono<World> updateWorld(World world) {
+    private Mono<World> updateWorld(World world) {
         return databaseClient
         return databaseClient
                 .sql("UPDATE world SET randomnumber=$2 WHERE id = $1")
                 .sql("UPDATE world SET randomnumber=$2 WHERE id = $1")
                 .bind("$1", world.id)
                 .bind("$1", world.id)
@@ -37,6 +38,8 @@ public class R2dbcDbRepository implements DbRepository {
                 .map(count -> world);
                 .map(count -> world);
     }
     }
 
 
+
+    @Override
     public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
     public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
         return getWorld(id).flatMap(world -> {
         return getWorld(id).flatMap(world -> {
             world.randomnumber = randomNumber;
             world.randomnumber = randomNumber;
@@ -51,4 +54,5 @@ public class R2dbcDbRepository implements DbRepository {
                 .mapProperties(Fortune.class)
                 .mapProperties(Fortune.class)
                 .all();
                 .all();
     }
     }
+
 }
 }

+ 20 - 23
frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java

@@ -1,26 +1,27 @@
 package benchmark.web;
 package benchmark.web;
 
 
-import java.util.Collections;
 import java.util.List;
 import java.util.List;
-import java.util.concurrent.ThreadLocalRandom;
 
 
+import benchmark.Utils;
 import benchmark.model.Fortune;
 import benchmark.model.Fortune;
 import benchmark.model.World;
 import benchmark.model.World;
 import benchmark.repository.DbRepository;
 import benchmark.repository.DbRepository;
+import io.jstach.jstachio.JStachio;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import org.springframework.web.reactive.function.server.ServerRequest;
 import org.springframework.web.reactive.function.server.ServerRequest;
 import org.springframework.web.reactive.function.server.ServerResponse;
 import org.springframework.web.reactive.function.server.ServerResponse;
 
 
-import static java.util.Comparator.comparing;
-
 @Component
 @Component
 public class DbHandler {
 public class DbHandler {
 
 
+    private static final String CONTENT_TYPE_VALUE = "text/html; charset=utf-8";
+
     private final DbRepository dbRepository;
     private final DbRepository dbRepository;
 
 
     public DbHandler(DbRepository dbRepository) {
     public DbHandler(DbRepository dbRepository) {
@@ -28,24 +29,24 @@ public class DbHandler {
     }
     }
 
 
     public Mono<ServerResponse> db(ServerRequest request) {
     public Mono<ServerResponse> db(ServerRequest request) {
-        int id = randomWorldNumber();
+        int id = Utils.randomWorldNumber();
         Mono<World> world = dbRepository.getWorld(id)
         Mono<World> world = dbRepository.getWorld(id)
                 .switchIfEmpty(Mono.error(new Exception("No World found with Id: " + id)));
                 .switchIfEmpty(Mono.error(new Exception("No World found with Id: " + id)));
 
 
         return ServerResponse.ok()
         return ServerResponse.ok()
-                .contentType(MediaType.APPLICATION_JSON)
+                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                 .body(world, World.class);
                 .body(world, World.class);
     }
     }
 
 
     public Mono<ServerResponse> queries(ServerRequest request) {
     public Mono<ServerResponse> queries(ServerRequest request) {
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
 
 
-        Mono<List<World>> worlds = Flux.range(0, queries)
-                .flatMap(i -> dbRepository.getWorld(randomWorldNumber()))
+        Mono<List<World>> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed())
+                .flatMap(dbRepository::getWorld)
                 .collectList();
                 .collectList();
 
 
         return ServerResponse.ok()
         return ServerResponse.ok()
-                .contentType(MediaType.APPLICATION_JSON)
+                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                 .body(worlds, new ParameterizedTypeReference<List<World>>() {
                 .body(worlds, new ParameterizedTypeReference<List<World>>() {
                 });
                 });
     }
     }
@@ -66,28 +67,24 @@ public class DbHandler {
     public Mono<ServerResponse> updates(ServerRequest request) {
     public Mono<ServerResponse> updates(ServerRequest request) {
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
 
 
-        Mono<List<World>> worlds = Flux.range(0, queries)
-                .flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber()))
+        Mono<List<World>> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed())
+                .flatMap(i -> dbRepository.findAndUpdateWorld(i, Utils.randomWorldNumber()))
                 .collectList();
                 .collectList();
 
 
         return ServerResponse.ok()
         return ServerResponse.ok()
-                .contentType(MediaType.APPLICATION_JSON)
+                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                 .body(worlds, new ParameterizedTypeReference<List<World>>() {
                 .body(worlds, new ParameterizedTypeReference<List<World>>() {
                 });
                 });
     }
     }
 
 
     public Mono<ServerResponse> fortunes(ServerRequest request) {
     public Mono<ServerResponse> fortunes(ServerRequest request) {
-        Mono<List<Fortune>> result = dbRepository.fortunes().collectList().flatMap(fortunes -> {
-            fortunes.add(new Fortune(0, "Additional fortune added at request time."));
-            fortunes.sort(comparing(fortune -> fortune.message));
-            return Mono.just(fortunes);
-        });
-
-        return ServerResponse.ok()
-                .render("fortunes", Collections.singletonMap("fortunes", result));
+        return dbRepository.fortunes()
+                .concatWith(Mono.just(new Fortune(0, "Additional fortune added at request time.")))
+                .collectSortedList()
+                .flatMap(fortunes ->
+                        ServerResponse.ok()
+                                .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_VALUE)
+                                .bodyValue(JStachio.render(new Fortunes(fortunes))));
     }
     }
 
 
-    private static int randomWorldNumber() {
-        return 1 + ThreadLocalRandom.current().nextInt(10000);
-    }
 }
 }

+ 10 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java

@@ -0,0 +1,10 @@
+package benchmark.web;
+
+import java.util.List;
+
+import benchmark.model.Fortune;
+import io.jstach.jstache.JStache;
+
+@JStache(path = "fortunes.mustache")
+public record Fortunes(List<Fortune> fortunes) {
+}

+ 3 - 1
frameworks/Java/spring-webflux/src/main/resources/application.yml

@@ -15,7 +15,9 @@ spring:
   r2dbc:
   r2dbc:
     username: ${database.username}
     username: ${database.username}
     password: ${database.password}
     password: ${database.password}
-    url: r2dbc:postgresql://${database.host}:${database.port}/${database.name}
+    url: r2dbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable
+    pool:
+      max-size: 256
 
 
 ---
 ---
 spring:
 spring:

+ 0 - 0
frameworks/Java/spring-webflux/src/main/resources/templates/fortunes.mustache → frameworks/Java/spring-webflux/src/main/resources/fortunes.mustache


+ 1 - 3
frameworks/Java/spring/README.md

@@ -2,9 +2,7 @@
 
 
 This is the Spring MVC portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 This is the Spring MVC portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
 
-An embedded undertow is used for the web server, with nearly everything configured with default settings.
-The only thing changed is Hikari can use up to (2 * cores count) connections (the default is 10).
-See [About-Pool-Sizing](https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing)
+An embedded undertow is used for the web server.
 
 
 There are two implementations :
 There are two implementations :
 * For postgresql access, JdbcTemplate is used. See [JdbcDbRepository](src/main/java/hello/JdbcDbRepository.java).
 * For postgresql access, JdbcTemplate is used. See [JdbcDbRepository](src/main/java/hello/JdbcDbRepository.java).

+ 0 - 21
frameworks/Java/spring/benchmark_config.json

@@ -24,27 +24,6 @@
       "notes": "",
       "notes": "",
       "versus": ""
       "versus": ""
     },
     },
-    "jpa": {
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Fullstack",
-      "database": "Postgres",
-      "framework": "spring",
-      "language": "Java",
-      "flavor": "None",
-      "orm": "Full",
-      "platform": "Servlet",
-      "webserver": "Undertow",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "spring-jpa",
-      "notes": "",
-      "versus": "spring"
-    },
     "mongo": {
     "mongo": {
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "query_url": "/queries?queries=",

+ 22 - 4
frameworks/Java/spring/pom.xml

@@ -11,11 +11,12 @@
 	<parent>
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>3.3.3</version>
+		<version>3.3.4</version>
 	</parent>
 	</parent>
 
 
 	<properties>
 	<properties>
 		<java.version>21</java.version>
 		<java.version>21</java.version>
+		<jstachio.version>1.3.6</jstachio.version>
 	</properties>
 	</properties>
 
 
 	<dependencies>
 	<dependencies>
@@ -35,15 +36,23 @@
 		</dependency>
 		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-data-jpa</artifactId>
+			<artifactId>spring-boot-starter-jdbc</artifactId>
 		</dependency>
 		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-data-mongodb</artifactId>
 			<artifactId>spring-boot-starter-data-mongodb</artifactId>
 		</dependency>
 		</dependency>
 		<dependency>
 		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-mustache</artifactId>
+			<groupId>io.jstach</groupId>
+			<artifactId>jstachio</artifactId>
+			<version>${jstachio.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>io.jstach</groupId>
+			<artifactId>jstachio-apt</artifactId>
+			<version>${jstachio.version}</version>
+			<scope>provided</scope>
+			<optional>true</optional>
 		</dependency>
 		</dependency>
 
 
 		<dependency>
 		<dependency>
@@ -61,6 +70,15 @@
 			<plugin>
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-compiler-plugin</artifactId>
 				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<annotationProcessorPaths>
+						<path>
+							<groupId>io.jstach</groupId>
+							<artifactId>jstachio-apt</artifactId>
+							<version>${jstachio.version}</version>
+						</path>
+					</annotationProcessorPaths>
+				</configuration>
 			</plugin>
 			</plugin>
 		</plugins>
 		</plugins>
 	</build>
 	</build>

+ 0 - 15
frameworks/Java/spring/spring-jpa.dockerfile

@@ -1,15 +0,0 @@
-FROM maven:3.9.5-eclipse-temurin-21 as maven
-WORKDIR /spring
-COPY src src
-COPY pom.xml pom.xml
-RUN mvn package -q
-
-FROM bellsoft/liberica-openjre-debian:21
-WORKDIR /spring
-COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
-# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html
-RUN java -Djarmode=tools -jar app.jar extract
-
-EXPOSE 8080
-
-CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jpa"]

+ 2 - 19
frameworks/Java/spring/src/main/java/hello/App.java

@@ -1,17 +1,10 @@
 package hello;
 package hello;
 
 
-import javax.sql.DataSource;
-
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.boot.context.event.ApplicationReadyEvent;
 import org.springframework.boot.context.event.ApplicationReadyEvent;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Profile;
 import org.springframework.context.event.EventListener;
 import org.springframework.context.event.EventListener;
 
 
-import com.zaxxer.hikari.HikariDataSource;
-
 @SpringBootApplication
 @SpringBootApplication
 public class App {
 public class App {
 
 
@@ -20,18 +13,8 @@ public class App {
 	}
 	}
 
 
 	@EventListener(ApplicationReadyEvent.class)
 	@EventListener(ApplicationReadyEvent.class)
-    public void runAfterStartup() {
-        System.out.println("Application is ready");
-    }
-
-	@Bean
-	@Profile({ "jdbc", "jpa" })
-	DataSource datasource(DataSourceProperties dataSourceProperties) {
-		HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class)
-				.build();
-		dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2);
-
-		return dataSource;
+	public void runAfterStartup() {
+		System.out.println("Application is ready");
 	}
 	}
 
 
 }
 }

+ 0 - 12
frameworks/Java/spring/src/main/java/hello/JpaConfig.java

@@ -1,12 +0,0 @@
-package hello;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Profile;
-import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
-
-@Profile("jpa")
-@Configuration
-@EnableJpaRepositories(basePackages = "hello.jpa")
-public class JpaConfig {
-
-}

+ 0 - 9
frameworks/Java/spring/src/main/java/hello/UpdateWorldService.java

@@ -1,9 +0,0 @@
-package hello;
-
-import hello.model.World;
-
-public interface UpdateWorldService {
-
-	World updateWorld(int worldId);
-
-}

+ 0 - 43
frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java

@@ -1,43 +0,0 @@
-package hello;
-
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import hello.web.DbHandler;
-import hello.web.WebmvcRouter;
-import hello.model.World;
-import hello.repository.DbRepository;
-
-@Service
-public class UpdateWorldServiceImpl implements UpdateWorldService {
-
-	private DbRepository dbRepository;
-	
-	public UpdateWorldServiceImpl(DbRepository dbRepository) {
-		this.dbRepository = dbRepository;
-	}
-
-	@Override
-	@Transactional
-	public World updateWorld(int worldId) {
-		var world = dbRepository.getWorld(worldId);
-		// Ensure that the new random number is not equal to the old one.
-		// That would cause the JPA-based implementation to avoid sending the
-		// UPDATE query to the database, which would violate the test
-		// requirements.
-
-		// Locally the records doesn't exist, maybe in the yours is ok but we need to
-		// make this check
-		if (world == null) {
-			return null;
-		}
-
-		int newRandomNumber;
-		do {
-			newRandomNumber = DbHandler.randomWorldNumber();
-		} while (newRandomNumber == world.randomnumber);
-
-		return dbRepository.updateWorld(world, newRandomNumber);
-	}
-
-}

+ 19 - 0
frameworks/Java/spring/src/main/java/hello/Utils.java

@@ -0,0 +1,19 @@
+package hello;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.IntStream;
+
+abstract public class Utils {
+
+	private static final int MIN_WORLD_NUMBER = 1;
+	private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001;
+
+	public static int randomWorldNumber() {
+		return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE);
+	}
+
+	public static IntStream randomWorldNumbers() {
+		return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE).distinct();
+	}
+
+}

+ 0 - 12
frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java

@@ -1,12 +0,0 @@
-package hello.jpa;
-
-import org.springframework.context.annotation.Profile;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import hello.model.Fortune;
-
-@Repository
-@Profile("jpa")
-public interface FortuneRepository extends JpaRepository<Fortune, Integer> {
-}

Some files were not shown because too many files changed in this diff