Browse Source

Merge branch 'TechEmpower:master' into master

Huang ziquan 1 year ago
parent
commit
0805d9acdb
100 changed files with 991 additions and 658 deletions
  1. 1 1
      Dockerfile
  2. 120 79
      frameworks/C/h2o/src/database.c
  3. 1 1
      frameworks/C/h2o/src/database.h
  4. 4 3
      frameworks/C/h2o/src/handlers/world.c
  5. 1 0
      frameworks/FSharp/oxpecker/README.md
  6. 4 1
      frameworks/FSharp/oxpecker/benchmark_config.json
  7. 3 0
      frameworks/FSharp/oxpecker/config.toml
  8. 4 7
      frameworks/FSharp/oxpecker/src/App/App.fsproj
  9. 140 24
      frameworks/FSharp/oxpecker/src/App/Program.fs
  10. 0 7
      frameworks/FSharp/oxpecker/src/App/runtimeconfig.template.json
  11. 29 2
      frameworks/Java/jooby/pom.xml
  12. 1 1
      frameworks/Java/jooby/src/main/java/com/techempower/App.java
  13. 4 8
      frameworks/Java/jooby/src/main/java/com/techempower/Json.java
  14. 4 7
      frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java
  15. 24 24
      frameworks/Java/micronaut/benchmark_config.json
  16. 6 12
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java
  17. 0 3
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java
  18. 4 1
      frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java
  19. 1 0
      frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml
  20. 3 2
      frameworks/Java/micronaut/common/src/main/resources/application-common.yml
  21. 2 2
      frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile
  22. 2 2
      frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile
  23. 2 2
      frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile
  24. 2 2
      frameworks/Java/micronaut/micronaut-jdbc.dockerfile
  25. 2 2
      frameworks/Java/micronaut/micronaut-r2dbc.dockerfile
  26. 7 9
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java
  27. 140 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java
  28. 0 58
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java
  29. 0 5
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java
  30. 1 6
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java
  31. 2 2
      frameworks/Java/micronaut/micronaut.dockerfile
  32. 0 1
      frameworks/Java/micronaut/run_benchmark.sh
  33. 3 4
      frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile
  34. 3 4
      frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile
  35. 1 1
      frameworks/PHP/laravel/.env
  36. 5 4
      frameworks/PHP/laravel/deploy/roadrunner/.rr.yaml
  37. 9 10
      frameworks/PHP/laravel/laravel-roadrunner.dockerfile
  38. 2 1
      frameworks/PHP/php-ngx/benchmark_config.json
  39. 6 5
      frameworks/PHP/php-ngx/php-ngx-async.dockerfile
  40. 7 4
      frameworks/PHP/php-ngx/php-ngx-mysql.dockerfile
  41. 8 5
      frameworks/PHP/php-ngx/php-ngx-pgsql.dockerfile
  42. 6 4
      frameworks/PHP/php-ngx/php-ngx.dockerfile
  43. 10 1
      frameworks/PHP/php/deploy/nginx-unit.json
  44. 4 3
      frameworks/PHP/php/php-franken.dockerfile
  45. 12 5
      frameworks/PHP/php/php-unit.dockerfile
  46. 0 17
      frameworks/PHP/spiral/php/install-composer.sh
  47. 5 0
      frameworks/PHP/spiral/php/php.ini
  48. 14 11
      frameworks/PHP/spiral/spiral.dockerfile
  49. 25 0
      frameworks/PHP/symfony/.rr.yaml
  50. 24 0
      frameworks/PHP/symfony/benchmark_config.json
  51. 2 2
      frameworks/PHP/symfony/deploy/Caddyfile
  52. 1 1
      frameworks/PHP/symfony/deploy/conf/php.ini
  53. 1 1
      frameworks/PHP/symfony/public/runtime.php
  54. 13 18
      frameworks/PHP/symfony/symfony-franken.dockerfile
  55. 4 10
      frameworks/PHP/symfony/symfony-mysql.dockerfile
  56. 4 8
      frameworks/PHP/symfony/symfony-raw.dockerfile
  57. 25 0
      frameworks/PHP/symfony/symfony-roadrunner.dockerfile
  58. 7 15
      frameworks/PHP/symfony/symfony-swoole.dockerfile
  59. 10 13
      frameworks/PHP/symfony/symfony-workerman.dockerfile
  60. 4 7
      frameworks/PHP/symfony/symfony.dockerfile
  61. 8 4
      frameworks/PHP/workerman/app-pg.php
  62. 1 1
      frameworks/PHP/workerman/server.php
  63. 6 6
      frameworks/PHP/workerman/workerman-async.dockerfile
  64. 7 6
      frameworks/PHP/workerman/workerman-pgsql.dockerfile
  65. 6 6
      frameworks/PHP/workerman/workerman-php8-jit.dockerfile
  66. 6 6
      frameworks/PHP/workerman/workerman.dockerfile
  67. 2 0
      frameworks/Pascal/mormot/mormot.dockerfile
  68. 2 2
      frameworks/Python/api_hour/requirements.txt
  69. 0 1
      frameworks/Ruby/agoo/.ruby-gemset
  70. 0 1
      frameworks/Ruby/agoo/.ruby-version
  71. 6 4
      frameworks/Ruby/grape/config.ru
  72. 5 5
      frameworks/Ruby/rack-sequel/Gemfile
  73. 2 0
      frameworks/Ruby/rack-sequel/boot.rb
  74. 5 5
      frameworks/Ruby/rack-sequel/hello_world.rb
  75. 1 1
      frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile
  76. 1 1
      frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile
  77. 1 1
      frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile
  78. 1 1
      frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile
  79. 1 1
      frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile
  80. 1 1
      frameworks/Ruby/rack-sequel/rack-sequel.dockerfile
  81. 4 4
      frameworks/Ruby/rack/Gemfile
  82. 74 57
      frameworks/Ruby/rack/Gemfile.lock
  83. 2 4
      frameworks/Ruby/rails/Gemfile
  84. 82 86
      frameworks/Ruby/rails/Gemfile.lock
  85. 3 3
      frameworks/Ruby/rails/app/controllers/hello_world_controller.rb
  86. 0 9
      frameworks/Ruby/rails/app/controllers/plaintext_controller.rb
  87. 3 0
      frameworks/Ruby/rails/config/database.yml
  88. 9 1
      frameworks/Ruby/rails/config/routes.rb
  89. 1 1
      frameworks/Ruby/sinatra-sequel/Gemfile
  90. 5 0
      frameworks/Ruby/sinatra-sequel/boot.rb
  91. 4 4
      frameworks/Ruby/sinatra-sequel/hello_world.rb
  92. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile
  93. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile
  94. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile
  95. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile
  96. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile
  97. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile
  98. 1 1
      frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile
  99. 1 1
      frameworks/Ruby/sinatra/Gemfile
  100. 5 0
      frameworks/Ruby/sinatra/boot.rb

+ 1 - 1
Dockerfile

@@ -31,7 +31,7 @@ RUN apt-get -yqq update && \
       colorama==0.3.1 \
       docker==7.0.0 \
       mysqlclient==2.2.4 \
-      pymongo==3.13.0
+      pymongo==4.7.2
 
 # Collect resource usage statistics
 ARG DOOL_VERSION=v1.3.1

+ 120 - 79
frameworks/C/h2o/src/database.c

@@ -75,7 +75,7 @@ static void on_database_write_ready(h2o_socket_t *sock, const char *err);
 static void on_process_queries(void *arg);
 static void poll_database_connection(h2o_socket_t *sock, const char *err);
 static void prepare_statements(db_conn_t *conn);
-static void process_queries(db_conn_t *conn, bool removed);
+static void process_queries(db_conn_pool_t *pool);
 static void remove_connection(db_conn_t *conn);
 static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn);
 
@@ -237,7 +237,10 @@ static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err)
 					h2o_timer_unlink(&conn->timer);
 					h2o_socket_read_stop(conn->sock);
 					h2o_socket_read_start(conn->sock, on_database_read_ready);
-					process_queries(conn, true);
+					*conn->pool->conn.tail = &conn->l;
+					conn->pool->conn.tail = &conn->l.next;
+					conn->l.next = NULL;
+					process_queries(conn->pool);
 					return;
 				default:
 					LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
@@ -370,7 +373,13 @@ static void on_database_read_ready(h2o_socket_t *sock, const char *err)
 	for (PGnotify *notify = PQnotifies(conn->conn); notify; notify = PQnotifies(conn->conn))
 		PQfreemem(notify);
 
-	process_queries(conn, removed);
+	if (removed && conn->query_num) {
+		*conn->pool->conn.tail = &conn->l;
+		conn->pool->conn.tail = &conn->l.next;
+		conn->l.next = NULL;
+	}
+
+	process_queries(conn->pool);
 }
 
 static void on_database_timeout(h2o_timer_t *timer)
@@ -405,20 +414,83 @@ static void on_database_write_ready(h2o_socket_t *sock, const char *err)
 
 static void on_process_queries(void *arg)
 {
+	list_t *iter = NULL;
 	db_conn_pool_t * const pool = arg;
+	size_t query_num = 0;
 
-	while (pool->queries.head && pool->conn) {
-		db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn);
+	while (pool->queries.head && pool->conn.head) {
+		db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn.head);
+		db_query_param_t * const param = H2O_STRUCT_FROM_MEMBER(db_query_param_t,
+		                                                        l,
+		                                                        conn->pool->queries.head);
 
-		pool->conn = conn->l.next;
 		assert(conn->query_num);
-		process_queries(conn, true);
+		assert(pool->query_num < pool->config->max_query_num);
+		pool->conn.head = conn->l.next;
+		pool->queries.head = param->l.next;
+
+		if (!pool->conn.head) {
+			assert(pool->conn.tail == &conn->l.next);
+			pool->conn.tail = &pool->conn.head;
+		}
+
+		if (++pool->query_num == pool->config->max_query_num) {
+			assert(!pool->queries.head);
+			assert(pool->queries.tail == &param->l.next);
+			pool->queries.tail = &pool->queries.head;
+		}
+
+		if (do_execute_query(conn, param)) {
+			param->on_error(param, DB_ERROR);
+			on_database_error(conn, DB_ERROR);
+		}
+		else {
+			query_num++;
+
+			if (conn->query_num) {
+				*pool->conn.tail = &conn->l;
+				pool->conn.tail = &conn->l.next;
+				conn->l.next = NULL;
+			}
+			else {
+				conn->l.next = iter;
+				iter = &conn->l;
+			}
+		}
 	}
 
-	if (pool->queries.head && pool->conn_num)
-		start_database_connect(pool, NULL);
+	if (iter)
+		do {
+			db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, iter);
+
+			iter = conn->l.next;
+
+			if (flush_connection(on_database_write_ready, conn))
+				on_database_error(conn, DB_ERROR);
+		} while (iter);
 
+	pool->conn.tail = &pool->conn.head;
 	pool->process_queries = false;
+	query_num += pool->config->max_query_num - pool->query_num;
+
+	for (iter = pool->conn.head; iter;) {
+		db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, iter);
+
+		iter = conn->l.next;
+
+		if (flush_connection(on_database_write_ready, conn)) {
+			*pool->conn.tail = iter;
+			on_database_error(conn, DB_ERROR);
+		}
+		else
+			pool->conn.tail = &conn->l.next;
+	}
+
+	const size_t conn_num = pool->config->max_db_conn_num - pool->conn_num;
+
+	if (query_num > conn_num)
+		for (query_num -= conn_num; pool->conn_num && query_num; query_num--)
+			start_database_connect(pool, NULL);
 }
 
 static void poll_database_connection(h2o_socket_t *sock, const char *err)
@@ -536,54 +608,44 @@ static void prepare_statements(db_conn_t *conn)
 	}
 	else {
 		h2o_socket_read_start(conn->sock, on_database_read_ready);
-		process_queries(conn, true);
+		*conn->pool->conn.tail = &conn->l;
+		conn->pool->conn.tail = &conn->l.next;
+		conn->l.next = NULL;
+		process_queries(conn->pool);
 	}
 }
 
-static void process_queries(db_conn_t *conn, bool removed)
+static void process_queries(db_conn_pool_t *pool)
 {
-	const bool flush = conn->query_num && conn->pool->queries.head;
-
-	while (conn->query_num && conn->pool->queries.head) {
-		db_query_param_t * const param = H2O_STRUCT_FROM_MEMBER(db_query_param_t,
-		                                                        l,
-		                                                        conn->pool->queries.head);
-
-		if (++conn->pool->query_num == conn->pool->config->max_query_num) {
-			assert(conn->pool->queries.tail == &param->l.next);
-			conn->pool->queries.tail = &conn->pool->queries.head;
-		}
-
-		conn->pool->queries.head = param->l.next;
-
-		if (do_execute_query(conn, param)) {
-			param->on_error(param, DB_ERROR);
-			on_database_error(conn, DB_ERROR);
-			return;
-		}
-	}
-
-	if (flush && flush_connection(on_database_write_ready, conn))
-		on_database_error(conn, DB_ERROR);
-	else if (conn->query_num && removed) {
-		conn->l.next = conn->pool->conn;
-		conn->pool->conn = &conn->l;
+	if (!pool->process_queries && pool->queries.head) {
+		task_message_t * const msg = h2o_mem_alloc(sizeof(*msg));
+
+		assert(pool->query_num < pool->config->max_query_num);
+		memset(msg, 0, sizeof(*msg));
+		msg->arg = pool;
+		msg->super.type = TASK;
+		msg->task = on_process_queries;
+		pool->process_queries = true;
+		send_local_message(&msg->super, pool->local_messages);
 	}
-	else if (!conn->query_num && !removed)
-		// This call should not be problematic, assuming a relatively low number of connections.
-		remove_connection(conn);
 }
 
 static void remove_connection(db_conn_t *conn)
 {
-	list_t *iter = conn->pool->conn;
-	list_t **prev = &conn->pool->conn;
+	list_t *iter = conn->pool->conn.head;
+	list_t **prev = &conn->pool->conn.head;
 
 	for (; iter && iter != &conn->l; iter = iter->next)
 		prev = &iter->next;
 
-	if (iter)
+	if (iter) {
 		*prev = iter->next;
+
+		if (!conn->pool->conn.head) {
+			assert(conn->pool->conn.tail == &iter->next);
+			conn->pool->conn.tail = &conn->pool->conn.head;
+		}
+	}
 }
 
 static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn)
@@ -661,37 +723,15 @@ int execute_database_query(db_conn_pool_t *pool, db_query_param_t *param)
 	int ret = 1;
 
 	if (pool->query_num) {
-		if (pool->conn) {
-			// Delay sending the database queries to the server, so that if there is a rapid
-			// succession of calls to this function, all resultant queries would be inserted
-			// into a command pipeline with a smaller number of system calls.
-			if (!pool->process_queries) {
-				task_message_t * const msg = h2o_mem_alloc(sizeof(*msg));
-
-				memset(msg, 0, sizeof(*msg));
-				msg->arg = pool;
-				msg->super.type = TASK;
-				msg->task = on_process_queries;
-				send_local_message(&msg->super, pool->local_messages);
-				pool->process_queries = true;
-			}
-
-			ret = 0;
-		}
-		else {
-			if (pool->conn_num)
-				start_database_connect(pool, NULL);
-
-			if (pool->conn_num < pool->config->max_db_conn_num && pool->query_num)
-				ret = 0;
-		}
-
-		if (!ret) {
-			param->l.next = NULL;
-			*pool->queries.tail = &param->l;
-			pool->queries.tail = &param->l.next;
-			pool->query_num--;
-		}
+		// Delay sending the database queries to the server, so that if there is a rapid
+		// succession of calls to this function, all resultant queries would be inserted
+		// into a command pipeline with a smaller number of system calls.
+		param->l.next = NULL;
+		*pool->queries.tail = &param->l;
+		pool->queries.tail = &param->l.next;
+		pool->query_num--;
+		process_queries(pool);
+		ret = 0;
 	}
 
 	return ret;
@@ -704,9 +744,9 @@ void free_database_connection_pool(db_conn_pool_t *pool)
 
 	size_t num = 0;
 
-	if (pool->conn)
+	if (pool->conn.head)
 		do {
-			db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn);
+			db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn.head);
 
 			assert(!conn->queries.head);
 			assert(conn->query_num == pool->config->max_pipeline_query_num);
@@ -715,10 +755,10 @@ void free_database_connection_pool(db_conn_pool_t *pool)
 			h2o_socket_read_stop(conn->sock);
 			h2o_socket_close(conn->sock);
 			PQfinish(conn->conn);
-			pool->conn = pool->conn->next;
-			free(conn);
+			pool->conn.head = conn->l.next;
 			num++;
-		} while (pool->conn);
+			free(conn);
+		} while (pool->conn.head);
 
 	assert(num + pool->conn_num == pool->config->max_db_conn_num);
 }
@@ -732,6 +772,7 @@ void initialize_database_connection_pool(const char *conninfo,
 {
 	memset(pool, 0, sizeof(*pool));
 	pool->config = config;
+	pool->conn.tail = &pool->conn.head;
 	pool->conninfo = conninfo ? conninfo : "";
 	pool->local_messages = local_messages;
 	pool->loop = loop;

+ 1 - 1
frameworks/C/h2o/src/database.h

@@ -60,7 +60,7 @@ typedef struct db_query_param_t {
 
 typedef struct {
 	const struct config_t *config;
-	list_t *conn;
+	queue_t conn;
 	const char *conninfo;
 	h2o_linklist_t *local_messages;
 	h2o_loop_t *loop;

+ 4 - 3
frameworks/C/h2o/src/handlers/world.c

@@ -416,7 +416,7 @@ static void fetch_from_cache(uint64_t now,
 		h2o_cache_ref_t * const r = h2o_cache_fetch(data->world_cache, now, key, 0);
 
 		if (r) {
-			const uint32_t * const table = (const uint32_t *) r->value.base;
+			const uint16_t * const table = (const uint16_t *) r->value.base;
 
 			for (size_t i = 0; i < query_ctx->num_query; i++) {
 				const uint32_t id = query_ctx->res[i].id;
@@ -440,7 +440,7 @@ static void fetch_from_cache(uint64_t now,
 			memset(ctx, 0, sizeof(*ctx));
 			ctx->data = data;
 			ctx->loop = query_ctx->ctx->event_loop.h2o_ctx.loop;
-			ctx->table.len = (MAX_ID + 1) * sizeof(uint32_t);
+			ctx->table.len = (MAX_ID + 1) * sizeof(uint16_t);
 			ctx->table.base = h2o_mem_alloc(ctx->table.len);
 			memset(ctx->table.base, 0, ctx->table.len);
 			ctx->param.command = POPULATE_CACHE_QUERY;
@@ -605,10 +605,11 @@ static result_return_t on_populate_cache_result(db_query_param_t *param, PGresul
 		                                                                param,
 		                                                                param);
 		query_result_t r = {.id = 0};
-		uint32_t * const table = (uint32_t *) query_ctx->table.base;
+		uint16_t * const table = (uint16_t *) query_ctx->table.base;
 
 		for (size_t i = 0; i < num_rows; i++) {
 			process_result(result, i, &r);
+			assert(r.random_number <= UINT16_MAX);
 			table[r.id] = r.random_number;
 		}
 

+ 1 - 0
frameworks/FSharp/oxpecker/README.md

@@ -19,6 +19,7 @@ This includes tests for plaintext, json, and fortunes HTML serialization.
 
 * [Oxpecker](https://github.com/Lanayx/Oxpecker)
 * [Dapper](https://github.com/DapperLib/Dapper)
+* [SpanJson](https://github.com/Tornhoof/SpanJson)
 * ASP.NET Core
 
 ## Paths & Source for Tests

+ 4 - 1
frameworks/FSharp/oxpecker/benchmark_config.json

@@ -6,6 +6,9 @@
         "plaintext_url": "/plaintext",
         "json_url": "/json",
         "fortune_url": "/fortunes",
+        "db_url": "/db",
+        "query_url": "/queries/",
+        "update_url": "/updates/",
         "port": 8080,
         "approach": "Realistic",
         "classification": "Micro",
@@ -18,7 +21,7 @@
         "webserver": "Kestrel",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "Oxpecker, Dapper",
+        "display_name": "Oxpecker",
         "notes": "",
         "versus": "aspcore"
       }

+ 3 - 0
frameworks/FSharp/oxpecker/config.toml

@@ -5,6 +5,9 @@ name = "oxpecker"
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.fortune = "/fortunes"
+urls.db = "/db"
+urls.query = "/queries/"
+urls.update = "/updates/"
 approach = "Realistic"
 classification = "fullstack"
 database = "Postgres"

+ 4 - 7
frameworks/FSharp/oxpecker/src/App/App.fsproj

@@ -1,8 +1,8 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
     <TargetFramework>net8.0</TargetFramework>
-    <OutputType>Exe</OutputType>
+    <EnableDefaultContentItems>false</EnableDefaultContentItems>
   </PropertyGroup>
 
   <ItemGroup>
@@ -10,13 +10,10 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Update="FSharp.Core" Version="8.0.200" />
+    <PackageReference Update="FSharp.Core" Version="8.0.300" />
     <PackageReference Include="Dapper" Version="2.1.44" />
     <PackageReference Include="Oxpecker" Version="0.10.1" />
     <PackageReference Include="Npgsql" Version="8.0.3" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <None Include="runtimeconfig.template.json" />
+    <PackageReference Include="SpanJson" Version="4.0.1" />
   </ItemGroup>
 </Project>

+ 140 - 24
frameworks/FSharp/oxpecker/src/App/Program.fs

@@ -1,8 +1,12 @@
 namespace App
 
+open System
+open System.Collections.Generic
+open System.Threading.Tasks
+open Oxpecker
+
 [<AutoOpen>]
 module Common =
-    open System
 
     [<CLIMutable>]
     type Fortune =
@@ -14,8 +18,10 @@ module Common =
     [<Literal>]
     let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"
 
-    let fortuneComparer a b =
-        String.CompareOrdinal(a.message, b.message)
+    let FortuneComparer = {
+        new IComparer<Fortune> with
+            member self.Compare(a,b) = String.CompareOrdinal(a.message, b.message)
+    }
 
 [<RequireQualifiedAccess>]
 module HtmlViews =
@@ -50,9 +56,10 @@ module HtmlViews =
 
 [<RequireQualifiedAccess>]
 module HttpHandlers =
-    open Oxpecker
     open Dapper
     open Npgsql
+    open System.Text
+    open Microsoft.AspNetCore.Http
 
     let private extra =
         {
@@ -60,53 +67,162 @@ module HttpHandlers =
             message = "Additional fortune added at request time."
         }
 
+    let private renderFortunes (ctx: HttpContext) dbFortunes =
+        let augmentedData = [|
+            yield! dbFortunes
+            extra
+        |]
+        Array.Sort(augmentedData, FortuneComparer)
+        augmentedData |> HtmlViews.fortunes |> ctx.WriteHtmlView
+
     let private fortunes : EndpointHandler =
         fun ctx ->
             task {
                 use conn = new NpgsqlConnection(ConnectionString)
-                let! data = conn.QueryAsync<Fortune>("SELECT id, message FROM fortune")
-                let augmentedData = [|
-                    yield! data
-                    extra
-                |]
-                augmentedData |> Array.sortInPlaceWith fortuneComparer
-                let view = HtmlViews.fortunes augmentedData
-                return! ctx.WriteHtmlView view
+                let! dbFortunes = conn.QueryAsync<Fortune>("SELECT id, message FROM fortune")
+                return! renderFortunes ctx dbFortunes
+            }
+
+    [<Struct>]
+    [<CLIMutable>]
+    type World =
+        {
+            id: int
+            randomnumber: int
+        }
+
+    let private readSingleRow (conn: NpgsqlConnection) =
+        conn.QueryFirstOrDefaultAsync<World>(
+            "SELECT id, randomnumber FROM world WHERE id = @Id",
+            {| Id = Random.Shared.Next(1, 10001) |}
+        )
+
+    let private parseQueries (ctx: HttpContext) =
+        match ctx.TryGetRouteValue<string>("count") with
+        | Some q ->
+            match Int32.TryParse q with
+            | true, q when q > 1 -> if q < 500 then q else 500
+            | _, _ -> 1
+        | _ -> 1
+
+    let private singleQuery : EndpointHandler =
+        fun ctx ->
+            task {
+                use conn = new NpgsqlConnection(ConnectionString)
+                let! result = readSingleRow conn
+                return! ctx.WriteJsonChunked result
             }
 
-    let endpoints : Endpoint[] =
+    let private multipleQueries : EndpointHandler =
+        fun ctx ->
+            let count = parseQueries ctx
+            let results = Array.zeroCreate<World> count
+            task {
+                use conn = new NpgsqlConnection(ConnectionString)
+                do! conn.OpenAsync()
+                for i in 0..results.Length-1 do
+                    let! result = readSingleRow conn
+                    results[i] <- result
+                return! ctx.WriteJsonChunked results
+            }
+
+    let private maxBatch = 500
+    let mutable private queries = Array.zeroCreate (maxBatch + 1)
+
+    let private batchUpdateString batchSize =
+        match queries[batchSize] with
+        | null ->
+            let lastIndex = batchSize - 1
+            let sb = StringBuilder()
+            sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ") |> ignore
+            for i in 0..lastIndex-1 do
+                sb.AppendFormat("(@Id_{0}, @Rn_{0}), ", i) |> ignore
+            sb.AppendFormat("(@Id_{0}, @Rn_{0}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id", lastIndex) |> ignore
+            let result = sb.ToString()
+            queries[batchSize] <- result
+            result
+        | q -> q
+
+    let private multipleUpdates : EndpointHandler =
+        fun ctx ->
+            let count = parseQueries ctx
+            let results = Array.zeroCreate<World> count
+            task {
+                use conn = new NpgsqlConnection(ConnectionString)
+                do! conn.OpenAsync()
+                for i in 0..results.Length-1 do
+                    let! result = readSingleRow conn
+                    results[i] <- result
+                let parameters = Dictionary<string,obj>()
+                for i in 0..results.Length-1 do
+                    let randomNumber = Random.Shared.Next(1, 10001)
+                    parameters[$"@Rn_{i}"] <- randomNumber
+                    parameters[$"@Id_{i}"] <- results[i].id
+                    results[i] <- { results[i] with randomnumber = randomNumber }
+                let! _ = conn.ExecuteAsync(batchUpdateString count, parameters)
+                return! ctx.WriteJsonChunked results
+            }
+
+    let utf8Const (s: string): EndpointHandler =
+        let result = s |> Encoding.UTF8.GetBytes
+        fun ctx ->
+            ctx.SetContentType("text/plain")
+            ctx.WriteBytes(result)
+
+    let endpoints =
         [|
-            route "/plaintext" <| text "Hello, World!"
+            route "/plaintext" <| utf8Const "Hello, World!"
             route "/json"<| jsonChunked {| message = "Hello, World!" |}
             route "/fortunes" fortunes
+            route "/db" singleQuery
+            route "/queries/{count?}" multipleQueries
+            route "/updates/{count?}" multipleUpdates
         |]
 
 
 module Main =
+    open SpanJson
+    open Microsoft.AspNetCore.Http
     open Microsoft.AspNetCore.Builder
     open Microsoft.AspNetCore.Hosting
     open Microsoft.Extensions.DependencyInjection
-    open Oxpecker
     open Microsoft.Extensions.Hosting
     open Microsoft.Extensions.Logging
+    open System.Buffers
+
+    type SpanJsonSerializer() =
+        interface Serializers.IJsonSerializer with
+            member this.Serialize(value, ctx, chunked) =
+                ctx.Response.ContentType <- "application/json"
+                if chunked then
+                    if ctx.Request.Method <> HttpMethods.Head then
+                        JsonSerializer.Generic.Utf8.SerializeAsync<_>(value, stream = ctx.Response.Body).AsTask()
+                    else
+                        Task.CompletedTask
+                else
+                    task {
+                        let buffer = JsonSerializer.Generic.Utf8.SerializeToArrayPool<_>(value)
+                        ctx.Response.Headers.ContentLength <- buffer.Count
+                        if ctx.Request.Method <> HttpMethods.Head then
+                            do! ctx.Response.Body.WriteAsync(buffer)
+                            ArrayPool<byte>.Shared.Return(buffer.Array)
+                        else
+                            return ()
+                    }
+            member this.Deserialize _ =
+                failwith "Not implemented"
 
     [<EntryPoint>]
     let main args =
-
         let builder = WebApplication.CreateBuilder(args)
-
         builder.Services
             .AddRouting()
-            .AddOxpecker() |> ignore
-
+            .AddOxpecker()
+            .AddSingleton<Serializers.IJsonSerializer>(SpanJsonSerializer())
+        |> ignore
         builder.Logging.ClearProviders() |> ignore
-        builder.WebHost.ConfigureKestrel(fun options -> options.AllowSynchronousIO <- true) |> ignore
-
         let app = builder.Build()
-
         app.UseRouting()
            .UseOxpecker HttpHandlers.endpoints |> ignore
-
         app.Run()
-
         0

+ 0 - 7
frameworks/FSharp/oxpecker/src/App/runtimeconfig.template.json

@@ -1,7 +0,0 @@
-{
-    "configProperties": {
-      "System.GC.Server": true,
-      "System.GC.NoAffinitize": true,
-      "System.GC.HeapCount": 2
-    }
-  }

+ 29 - 2
frameworks/Java/jooby/pom.xml

@@ -11,7 +11,8 @@
   <name>jooby</name>
 
   <properties>
-    <jooby.version>3.0.8</jooby.version>
+    <jooby.version>3.1.1</jooby.version>
+    <netty.version>4.1.109.Final</netty.version>
     <dsl-json.version>2.0.2</dsl-json.version>
     <postgresql.version>42.7.2</postgresql.version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -44,7 +45,6 @@
       <version>8.3.0</version>
     </dependency>
 
-
     <!-- postgresql -->
     <dependency>
       <groupId>org.postgresql</groupId>
@@ -166,6 +166,25 @@
   </build>
 
   <profiles>
+    <profile>
+      <id>mac</id>
+      <activation>
+        <os>
+          <family>mac</family>
+        </os>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>com.ongres.scram</groupId>
+          <artifactId>client</artifactId>
+          <version>2.1</version>
+        </dependency>
+        <dependency>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-resolver-dns-native-macos</artifactId>
+        </dependency>
+      </dependencies>
+    </profile>
     <profile>
       <id>undertow</id>
       <dependencies>
@@ -202,6 +221,14 @@
 
   <dependencyManagement>
     <dependencies>
+      <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-bom</artifactId>
+        <version>${netty.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+
       <dependency>
         <groupId>io.jooby</groupId>
         <artifactId>jooby-bom</artifactId>

+ 1 - 1
frameworks/Java/jooby/src/main/java/com/techempower/App.java

@@ -40,7 +40,7 @@ public class App extends Jooby {
     DataSource ds = require(DataSource.class);
 
     /** Template engine: */
-    install(new RockerModule().reuseBuffer(true));
+    install(new RockerModule());
 
     get("/plaintext", ctx ->
         ctx.send(MESSAGE_BUFFER.duplicate())

+ 4 - 8
frameworks/Java/jooby/src/main/java/com/techempower/Json.java

@@ -19,8 +19,7 @@ public class Json {
   public static ByteBuffer encode(Message data) {
     JsonWriter writer = pool.get();
     writer.reset();
-    _Message_DslJsonConverter.ObjectFormatConverter converter = new _Message_DslJsonConverter.ObjectFormatConverter(
-        dslJson);
+    var converter = new _Message_DslJsonConverter.ObjectFormatConverter(dslJson);
     converter.write(writer, data);
     return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
   }
@@ -28,8 +27,7 @@ public class Json {
   public static ByteBuffer encode(World data) {
     JsonWriter writer = pool.get();
     writer.reset();
-    _World_DslJsonConverter.ObjectFormatConverter converter = new _World_DslJsonConverter.ObjectFormatConverter(
-        dslJson);
+    var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson);
     converter.write(writer, data);
     return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
   }
@@ -37,8 +35,7 @@ public class Json {
   public static ByteBuffer encode(World[] data) {
     JsonWriter writer = pool.get();
     writer.reset();
-    _World_DslJsonConverter.ObjectFormatConverter converter = new _World_DslJsonConverter.ObjectFormatConverter(
-        dslJson);
+    var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson);
     writer.serialize(data, converter);
     return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
   }
@@ -46,8 +43,7 @@ public class Json {
   public static ByteBuffer encode(List<World> data) {
     JsonWriter writer = pool.get();
     writer.reset();
-    _World_DslJsonConverter.ObjectFormatConverter converter = new _World_DslJsonConverter.ObjectFormatConverter(
-        dslJson);
+    var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson);
     writer.serialize(data, converter);
     return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
   }

+ 4 - 7
frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java

@@ -4,17 +4,14 @@ import static com.techempower.Util.randomWorld;
 import static io.jooby.ExecutionMode.EVENT_LOOP;
 import static io.jooby.MediaType.JSON;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 
 import com.fizzed.rocker.RockerOutputFactory;
 import io.jooby.Context;
 import io.jooby.Jooby;
 import io.jooby.MediaType;
 import io.jooby.ServerOptions;
-import io.jooby.rocker.ByteBufferOutput;
+import io.jooby.rocker.DataBufferOutput;
 import io.jooby.rocker.RockerModule;
 import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.RowIterator;
@@ -34,7 +31,7 @@ public class ReactivePg extends Jooby {
     PgClient client = new PgClient(getConfig().getConfig("db"));
 
     /** Template engine: */
-    install(new RockerModule().reuseBuffer(true));
+    install(new RockerModule());
 
     /** Single query: */
     get("/db", ctx -> {
@@ -109,7 +106,7 @@ public class ReactivePg extends Jooby {
     }).setNonBlocking(true);
 
     /** Fortunes: */
-    RockerOutputFactory<ByteBufferOutput> factory = require(RockerOutputFactory.class);
+    RockerOutputFactory<DataBufferOutput> factory = require(RockerOutputFactory.class);
     get("/fortunes", ctx -> {
       client.fortunes(rsp -> {
         if (rsp.succeeded()) {

+ 24 - 24
frameworks/Java/micronaut/benchmark_config.json

@@ -16,9 +16,9 @@
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Raw",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut Vertx PG Client",
@@ -39,9 +39,9 @@
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Raw",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut Vertx PG Client GraalVM",
@@ -60,9 +60,9 @@
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Raw",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut JDBC",
@@ -81,9 +81,9 @@
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Raw",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut JDBC GraalVM",
@@ -102,9 +102,9 @@
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Raw",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut R2DBC",
@@ -123,9 +123,9 @@
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Raw",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut R2DBC GraalVM",
@@ -139,14 +139,14 @@
         "update_url": "/updates?queries=",
         "port": 8080,
         "approach": "Realistic",
-        "classification": "Micro",
+        "classification": "fullstack",
         "database": "Postgres",
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Micro",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut Data JDBC",
@@ -160,14 +160,14 @@
         "update_url": "/updates?queries=",
         "port": 8080,
         "approach": "Realistic",
-        "classification": "Micro",
+        "classification": "fullstack",
         "database": "Postgres",
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Micro",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut Data JDBC GraalVM",
@@ -181,14 +181,14 @@
         "update_url": "/updates?queries=",
         "port": 8080,
         "approach": "Realistic",
-        "classification": "Micro",
+        "classification": "fullstack",
         "database": "MongoDB",
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Micro",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut Data MongoDB",
@@ -202,14 +202,14 @@
         "update_url": "/updates?queries=",
         "port": 8080,
         "approach": "Realistic",
-        "classification": "Micro",
+        "classification": "fullstack",
         "database": "MongoDB",
         "framework": "Micronaut",
         "language": "Java",
         "flavor": "None",
-        "orm": "raw",
+        "orm": "Micro",
         "platform": "Netty",
-        "webserver": "None",
+        "webserver": "Netty",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Micronaut Data MongoDB GraalVM",

+ 6 - 12
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java

@@ -9,15 +9,12 @@ import io.micronaut.http.HttpResponse;
 import io.micronaut.http.annotation.Controller;
 import io.micronaut.http.annotation.Get;
 import io.micronaut.http.annotation.QueryValue;
-import io.micronaut.scheduling.TaskExecutors;
-import jakarta.inject.Named;
 import views.fortunes;
 
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.concurrent.CompletionStage;
-import java.util.concurrent.Executor;
 
 import static java.util.Comparator.comparing;
 
@@ -27,14 +24,11 @@ public class AsyncBenchmarkController extends AbstractBenchmarkController {
 
     private final AsyncWorldRepository worldRepository;
     private final AsyncFortuneRepository fortuneRepository;
-    private final Executor executor;
 
     public AsyncBenchmarkController(AsyncWorldRepository worldRepository,
-                                    AsyncFortuneRepository fortuneRepository,
-                                    @Named(TaskExecutors.BLOCKING) Executor executor) {
+                                    AsyncFortuneRepository fortuneRepository) {
         this.worldRepository = worldRepository;
         this.fortuneRepository = fortuneRepository;
-        this.executor = executor;
     }
 
     @Get("/prepare-data-for-test")
@@ -45,7 +39,7 @@ public class AsyncBenchmarkController extends AbstractBenchmarkController {
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#single-database-query
     @Get("/db")
     public CompletionStage<World> db() {
-        return worldRepository.findById(randomId()).thenApplyAsync(world -> world, executor);
+        return worldRepository.findById(randomId());
     }
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#multiple-database-queries
@@ -56,20 +50,20 @@ public class AsyncBenchmarkController extends AbstractBenchmarkController {
         for (int i = 0; i < count; i++) {
             ids.add(randomId());
         }
-        return worldRepository.findByIds(ids).thenApplyAsync(worlds -> worlds, executor);
+        return worldRepository.findByIds(ids);
     }
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes
     @Get(value = "/fortunes", produces = "text/html;charset=utf-8")
     public CompletionStage<HttpResponse<String>> fortune() {
-        return fortuneRepository.findAll().thenApplyAsync(fortuneList -> {
+        return fortuneRepository.findAll().thenApply(fortuneList -> {
             List<Fortune> all = new ArrayList<>(fortuneList.size() + 1);
             all.add(new Fortune(0, "Additional fortune added at request time."));
             all.addAll(fortuneList);
             all.sort(comparing(Fortune::message));
             String body = fortunes.template(all).render().toString();
             return HttpResponse.ok(body).contentType("text/html;charset=utf-8");
-        }, executor);
+        });
     }
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates
@@ -80,7 +74,7 @@ public class AsyncBenchmarkController extends AbstractBenchmarkController {
                 world.setRandomNumber(randomWorldNumber());
             }
             worlds.sort(Comparator.comparingInt(World::getId)); // Avoid deadlock
-            return worldRepository.updateAll(worlds).thenApplyAsync(ignore -> worlds, executor);
+            return worldRepository.updateAll(worlds).thenApply(ignore -> worlds);
         });
     }
 

+ 0 - 3
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java

@@ -9,8 +9,6 @@ import io.micronaut.http.HttpResponse;
 import io.micronaut.http.annotation.Controller;
 import io.micronaut.http.annotation.Get;
 import io.micronaut.http.annotation.QueryValue;
-import io.micronaut.scheduling.TaskExecutors;
-import io.micronaut.scheduling.annotation.ExecuteOn;
 import views.fortunes;
 
 import java.util.ArrayList;
@@ -20,7 +18,6 @@ import java.util.List;
 
 import static java.util.Comparator.comparing;
 
-@ExecuteOn(TaskExecutors.IO)
 @Requires(beans = {WorldRepository.class, FortuneRepository.class})
 @Controller
 public class BenchmarkController extends AbstractBenchmarkController {

+ 4 - 1
frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java

@@ -4,7 +4,9 @@ import io.micronaut.http.MutableHttpResponse;
 import io.micronaut.http.annotation.Filter;
 import io.micronaut.http.annotation.ResponseFilter;
 import io.micronaut.http.annotation.ServerFilter;
+import io.micronaut.http.netty.NettyHttpHeaders;
 import io.micronaut.scheduling.annotation.Scheduled;
+import io.netty.handler.codec.http.HttpHeaderNames;
 
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
@@ -25,7 +27,8 @@ public class ServerHeaderFilter {
 
     @ResponseFilter
     public void addDateHeader(MutableHttpResponse<?> mutableHttpResponse) {
-        mutableHttpResponse.header("Date", dateHeader);
+        NettyHttpHeaders nettyHttpHeaders = (NettyHttpHeaders) mutableHttpResponse.getHeaders();
+        nettyHttpHeaders.setUnsafe(HttpHeaderNames.DATE, dateHeader);
     }
 
 }

+ 1 - 0
frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml

@@ -5,6 +5,7 @@ micronaut:
     port: 8080
     server-header: Micronaut
     date-header: false
+    validate-url: false
   http:
     client:
       read-timeout: 60s

+ 3 - 2
frameworks/Java/micronaut/common/src/main/resources/application-common.yml

@@ -5,6 +5,7 @@ micronaut:
     port: 8080
     server-header: Micronaut
     date-header: false
+    validate-url: false
 
 netty:
   resource-leak-detector-level: DISABLED
@@ -17,7 +18,7 @@ datasources:
     driverClassName: org.postgresql.Driver
     db-type: postgresql
     dialect: POSTGRES
-    maximum-pool-size: 48
+    maximum-pool-size: 512
     transaction-per-operation: false
     allow-connection-per-operation: true
 
@@ -29,7 +30,7 @@ r2dbc:
       options:
         protocol: postgres
         initialSize: 0 # https://github.com/micronaut-projects/micronaut-data/issues/2136
-        maxSize: 48
+        maxSize: 512
 
 mongodb:
   package-names:

+ 2 - 2
frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile

@@ -1,9 +1,9 @@
-FROM gradle:8.7.0-jdk17 as build
+FROM gradle:8.7.0-jdk21 as build
 COPY --chown=gradle:gradle . /home/gradle/src
 WORKDIR /home/gradle/src
 RUN gradle micronaut-data-jdbc:build -x test --no-daemon
 
-FROM openjdk:21
+FROM openjdk:22
 WORKDIR /micronaut
 COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/libs/micronaut-data-jdbc-all.jar micronaut.jar
 COPY run_benchmark.sh run_benchmark.sh

+ 2 - 2
frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile

@@ -1,9 +1,9 @@
-FROM gradle:8.7.0-jdk17 as build
+FROM gradle:8.7.0-jdk21 as build
 COPY --chown=gradle:gradle . /home/gradle/src
 WORKDIR /home/gradle/src
 RUN gradle micronaut-data-mongodb:build -x test --no-daemon
 
-FROM openjdk:21
+FROM openjdk:22
 WORKDIR /micronaut
 COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/libs/micronaut-data-mongodb-all.jar micronaut.jar
 COPY run_benchmark.sh run_benchmark.sh

+ 2 - 2
frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile

@@ -1,9 +1,9 @@
-FROM gradle:8.7.0-jdk17 as build
+FROM gradle:8.7.0-jdk21 as build
 COPY --chown=gradle:gradle . /home/gradle/src
 WORKDIR /home/gradle/src
 RUN gradle micronaut-data-r2dbc:build -x test --no-daemon
 
-FROM openjdk:21
+FROM openjdk:22
 WORKDIR /micronaut
 COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/libs/micronaut-data-r2dbc-all.jar micronaut.jar
 COPY run_benchmark.sh run_benchmark.sh

+ 2 - 2
frameworks/Java/micronaut/micronaut-jdbc.dockerfile

@@ -1,9 +1,9 @@
-FROM gradle:8.7.0-jdk17 as build
+FROM gradle:8.7.0-jdk21 as build
 COPY --chown=gradle:gradle . /home/gradle/src
 WORKDIR /home/gradle/src
 RUN gradle micronaut-jdbc:build -x test --no-daemon
 
-FROM openjdk:21
+FROM openjdk:22
 WORKDIR /micronaut
 COPY --from=build /home/gradle/src/micronaut-jdbc/build/libs/micronaut-jdbc-all.jar micronaut.jar
 COPY run_benchmark.sh run_benchmark.sh

+ 2 - 2
frameworks/Java/micronaut/micronaut-r2dbc.dockerfile

@@ -1,9 +1,9 @@
-FROM gradle:8.7.0-jdk17 as build
+FROM gradle:8.7.0-jdk21 as build
 COPY --chown=gradle:gradle . /home/gradle/src
 WORKDIR /home/gradle/src
 RUN gradle micronaut-r2dbc:build -x test --no-daemon
 
-FROM openjdk:21
+FROM openjdk:22
 WORKDIR /micronaut
 COPY --from=build /home/gradle/src/micronaut-r2dbc/build/libs/micronaut-r2dbc-all.jar micronaut.jar
 COPY run_benchmark.sh run_benchmark.sh

+ 7 - 9
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java

@@ -7,6 +7,7 @@ import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.RowSet;
 import io.vertx.sqlclient.SqlClient;
 import io.vertx.sqlclient.Tuple;
+import jakarta.inject.Inject;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -15,23 +16,20 @@ import java.util.function.Function;
 
 public class AbstractVertxSqlClientRepository {
 
-    protected final Pool client;
-
-    public AbstractVertxSqlClientRepository(Pool client) {
-        this.client = client;
-    }
+    @Inject
+    protected ConnectionHolder holder;
 
     protected CompletionStage<?> execute(String sql) {
-        return client.preparedQuery(sql).execute().toCompletionStage();
+        return holder.get().flatMap(conn->conn.preparedQuery(sql).execute()).toCompletionStage();
     }
 
     protected <T> CompletionStage<T> executeAndCollectOne(String sql, Tuple tuple, Function<Row, T> mapper) {
-        return client.preparedQuery(sql).execute(tuple).map(rows -> mapper.apply(rows.iterator().next()))
+        return holder.get().flatMap(conn->conn.preparedQuery(sql).execute(tuple).map(rows -> mapper.apply(rows.iterator().next())))
                 .toCompletionStage();
     }
 
     protected <T> CompletionStage<List<T>> executeAndCollectList(String sql, Function<Row, T> mapper) {
-        return client.preparedQuery(sql).execute().map(rows -> {
+        return holder.get().flatMap(conn->conn.preparedQuery(sql).execute()).map(rows -> {
             List<T> result = new ArrayList<>(rows.size());
             for (Row row : rows) {
                 result.add(mapper.apply(row));
@@ -52,7 +50,7 @@ public class AbstractVertxSqlClientRepository {
     }
 
     protected CompletionStage<?> executeBatch(String sql, List<Tuple> data) {
-        return client.preparedQuery(sql).executeBatch(data).toCompletionStage();
+        return holder.get().flatMap(conn->conn.preparedQuery(sql).executeBatch(data)).toCompletionStage();
     }
 
 }

+ 140 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java

@@ -0,0 +1,140 @@
+package benchmark;
+
+import io.micronaut.context.annotation.Property;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFactory;
+import io.netty.channel.EventLoop;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.ServerChannel;
+import io.netty.channel.socket.DatagramChannel;
+import io.netty.channel.socket.InternetProtocolFamily;
+import io.netty.util.concurrent.FastThreadLocal;
+import io.netty.util.internal.ThreadExecutorMap;
+import io.vertx.core.Future;
+import io.vertx.core.Vertx;
+import io.vertx.core.datagram.DatagramSocketOptions;
+import io.vertx.core.impl.VertxBuilder;
+import io.vertx.core.net.ClientOptionsBase;
+import io.vertx.core.net.NetServerOptions;
+import io.vertx.core.spi.transport.Transport;
+import io.vertx.pgclient.PgConnectOptions;
+import io.vertx.pgclient.PgConnection;
+import io.vertx.sqlclient.PoolOptions;
+import jakarta.inject.Singleton;
+
+import java.net.SocketAddress;
+import java.util.concurrent.ThreadFactory;
+
+@Singleton
+public class ConnectionHolder {
+    private final FastThreadLocal<Future<PgConnection>> conn = new FastThreadLocal<>();
+
+    @Property(name = "datasources.default.url") String url;
+    @Property(name = "datasources.default.username") String user;
+    @Property(name = "datasources.default.password") String password;
+    @Property(name = "datasources.default.maximum-pool-size") int maxPoolSize;
+
+    public Future<PgConnection> get() {
+        Future<PgConnection> c = conn.get();
+        if (c == null) {
+
+            PgConnectOptions connectOptions = PgConnectOptions.fromUri(url.substring(5))
+                    .setUser(user)
+                    .setPassword(password)
+                    .setCachePreparedStatements(true)
+                    .setTcpNoDelay(true)
+                    .setTcpQuickAck(true)
+                    .setPipeliningLimit(1024);
+            PoolOptions poolOptions = new PoolOptions();
+            poolOptions.setMaxSize(maxPoolSize);
+
+            VertxBuilder builder = new VertxBuilder()
+                    .init();
+
+            EventLoop loop = (EventLoop) ThreadExecutorMap.currentExecutor();
+
+            Vertx vertx = builder
+                    .findTransport(new ExistingTransport(builder.findTransport(), loop))
+                    .vertx();
+
+            c = PgConnection.connect(vertx, connectOptions);
+            conn.set(c);
+        }
+        return c;
+    }
+
+    private record ExistingTransport(Transport transport, EventLoop loop) implements Transport {
+
+        @Override
+            public boolean supportsDomainSockets() {
+                return transport.supportsDomainSockets();
+            }
+
+            @Override
+            public boolean supportFileRegion() {
+                return transport.supportFileRegion();
+            }
+
+            @Override
+            public boolean isAvailable() {
+                return transport.isAvailable();
+            }
+
+            @Override
+            public Throwable unavailabilityCause() {
+                return transport.unavailabilityCause();
+            }
+
+            @Override
+            public SocketAddress convert(io.vertx.core.net.SocketAddress address) {
+                return transport.convert(address);
+            }
+
+            @Override
+            public io.vertx.core.net.SocketAddress convert(SocketAddress address) {
+                return transport.convert(address);
+            }
+
+            @Override
+            public EventLoopGroup eventLoopGroup(int type, int nThreads, ThreadFactory threadFactory, int ignoredIoRatio) {
+                return loop;
+            }
+
+            @Override
+            public DatagramChannel datagramChannel() {
+                return transport.datagramChannel();
+            }
+
+            @Override
+            public DatagramChannel datagramChannel(InternetProtocolFamily family) {
+                return transport.datagramChannel(family);
+            }
+
+            @Override
+            public ChannelFactory<? extends Channel> channelFactory(boolean domainSocket) {
+                return transport.channelFactory(domainSocket);
+            }
+
+            @Override
+            public ChannelFactory<? extends ServerChannel> serverChannelFactory(boolean domainSocket) {
+                return transport.serverChannelFactory(domainSocket);
+            }
+
+            @Override
+            public void configure(DatagramChannel channel, DatagramSocketOptions options) {
+                transport.configure(channel, options);
+            }
+
+            @Override
+            public void configure(ClientOptionsBase options, boolean domainSocket, Bootstrap bootstrap) {
+                transport.configure(options, domainSocket, bootstrap);
+            }
+
+            @Override
+            public void configure(NetServerOptions options, boolean domainSocket, ServerBootstrap bootstrap) {
+                transport.configure(options, domainSocket, bootstrap);
+            }
+        }
+}

+ 0 - 58
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java

@@ -1,58 +0,0 @@
-/*
- * Copyright 2017-2020 original authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package benchmark;
-
-import io.micronaut.context.annotation.Bean;
-import io.micronaut.context.annotation.Factory;
-import io.micronaut.context.annotation.Property;
-import io.vertx.core.Vertx;
-import io.vertx.core.VertxOptions;
-import io.vertx.core.impl.VertxBuilder;
-import io.vertx.pgclient.PgConnectOptions;
-import io.vertx.pgclient.PgPool;
-import io.vertx.sqlclient.PoolOptions;
-import jakarta.inject.Singleton;
-
-/**
- * The Factory for creating Vertx PG client.
- */
-@Factory
-public class PgClientFactory {
-
-    @Singleton
-    @Bean(preDestroy = "close")
-    public PgPool client(@Property(name = "datasources.default.url") String url,
-                         @Property(name = "datasources.default.username") String user,
-                         @Property(name = "datasources.default.password") String password,
-                         @Property(name = "datasources.default.maximum-pool-size") int maxPoolSize) {
-
-        VertxOptions vertxOptions = new VertxOptions()
-                .setPreferNativeTransport(true);
-
-        PgConnectOptions connectOptions = PgConnectOptions.fromUri(url.substring(5))
-                .setUser(user)
-                .setPassword(password)
-                .setCachePreparedStatements(true)
-                .setTcpNoDelay(true)
-                .setTcpQuickAck(true)
-                .setPipeliningLimit(1024);
-        PoolOptions poolOptions = new PoolOptions();
-        poolOptions.setMaxSize(maxPoolSize);
-
-        Vertx vertx = new VertxBuilder(vertxOptions).init().vertx();
-        return PgPool.pool(vertx, connectOptions, poolOptions);
-    }
-}

+ 0 - 5
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java

@@ -2,7 +2,6 @@ package benchmark;
 
 import benchmark.model.Fortune;
 import benchmark.repository.AsyncFortuneRepository;
-import io.vertx.sqlclient.Pool;
 import io.vertx.sqlclient.Tuple;
 import jakarta.inject.Singleton;
 
@@ -14,10 +13,6 @@ import java.util.stream.Collectors;
 @Singleton
 public class VertxPgFortuneRepository extends AbstractVertxSqlClientRepository implements AsyncFortuneRepository {
 
-    public VertxPgFortuneRepository(Pool client) {
-        super(client);
-    }
-
     private CompletionStage<?> createTable() {
         return execute("DROP TABLE IF EXISTS Fortune;")
                 .thenCompose(ignore -> execute("CREATE TABLE Fortune (id INTEGER NOT NULL,message VARCHAR(255) NOT NULL);"));

+ 1 - 6
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java

@@ -2,7 +2,6 @@ package benchmark;
 
 import benchmark.model.World;
 import benchmark.repository.AsyncWorldRepository;
-import io.vertx.sqlclient.Pool;
 import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.Tuple;
 import jakarta.inject.Singleton;
@@ -19,10 +18,6 @@ public class VertxPgWorldRepository extends AbstractVertxSqlClientRepository imp
 
     private static final Function<Row, World> ROW_TO_WORLD_MAPPER = row -> new World(row.getInteger(0), row.getInteger(1));
 
-    public VertxPgWorldRepository(Pool client) {
-        super(client);
-    }
-
     private CompletionStage<?> createTable() {
         return execute("DROP TABLE IF EXISTS World;").thenCompose(ignore -> execute("CREATE TABLE World (id INTEGER NOT NULL,randomNumber INTEGER NOT NULL);"));
     }
@@ -44,7 +39,7 @@ public class VertxPgWorldRepository extends AbstractVertxSqlClientRepository imp
         for (Integer id : ids) {
             data.add(Tuple.of(id));
         }
-        return client.withConnection(sqlConnection ->
+        return holder.get().flatMap(sqlConnection ->
                 executeMany(sqlConnection, "SELECT * FROM world WHERE id = $1", data, ROW_TO_WORLD_MAPPER))
                 .toCompletionStage();
     }

+ 2 - 2
frameworks/Java/micronaut/micronaut.dockerfile

@@ -1,9 +1,9 @@
-FROM gradle:8.7.0-jdk17 as build
+FROM gradle:8.7.0-jdk21 as build
 COPY --chown=gradle:gradle . /home/gradle/src
 WORKDIR /home/gradle/src
 RUN gradle micronaut-vertx-pg-client:build -x test --no-daemon
 
-FROM openjdk:21
+FROM openjdk:22
 WORKDIR /micronaut
 COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/libs/micronaut-vertx-pg-client-all.jar micronaut.jar
 COPY run_benchmark.sh run_benchmark.sh

+ 0 - 1
frameworks/Java/micronaut/run_benchmark.sh

@@ -3,7 +3,6 @@
 JAVA_OPTIONS="-server \
   -XX:+UseParallelGC \
   -XX:+UseNUMA \
-  -XX:+UseStringDeduplication \
   -XX:-StackTraceInThrowable \
   -Dio.netty.buffer.checkBounds=false \
   -Dio.netty.buffer.checkAccessible=false \

+ 3 - 4
frameworks/PHP/kumbiaphp/kumbiaphp-raw.dockerfile

@@ -9,12 +9,11 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 RUN apt-get install -yqq nginx git unzip \
     php8.3-fpm php8.3-mysql > /dev/null
 
-COPY deploy/conf/* /etc/php/8.3/fpm/
-
-ADD ./ /kumbiaphp
+COPY --link deploy/conf/* /etc/php/8.3/fpm/
 WORKDIR /kumbiaphp
+COPY --link . .
 
-RUN git clone -b v1.1.4 --single-branch --depth 1 -q https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia
+RUN git clone -b v1.2.1 --single-branch --depth 1 -q https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia
 
 RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi;
 

+ 3 - 4
frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile

@@ -9,12 +9,11 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 RUN apt-get install -yqq nginx git unzip \
     php8.3-fpm php8.3-mysql > /dev/null
 
-COPY deploy/conf/* /etc/php/8.3/fpm/
-
-ADD ./ /kumbiaphp
+COPY --link deploy/conf/* /etc/php/8.3/fpm/
 WORKDIR /kumbiaphp
+COPY --link . .
 
-RUN git clone -b v1.1.4 --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia
+RUN git clone -b v1.2.1 --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia
 RUN git clone -b dev --single-branch --depth 1 https://github.com/KumbiaPHP/ActiveRecord.git vendor/Kumbia/ActiveRecord
 
 RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi;

+ 1 - 1
frameworks/PHP/laravel/.env

@@ -1,5 +1,5 @@
 APP_NAME=Laravel
-APP_ENV=local
+APP_ENV=production
 APP_KEY=base64:JRW3D/imCqern1eNGYaRTmP8wixsi3gWRXTSIT1LGTQ=
 APP_DEBUG=false
 APP_URL=http://localhost

+ 5 - 4
frameworks/PHP/laravel/deploy/roadrunner/.rr.yaml

@@ -1,4 +1,7 @@
 # see https://roadrunner.dev/docs/intro-config
+version: "3"
+#https://github.com/roadrunner-server/roadrunner/blob/master/.rr.yaml
+
 server:
   command: "php ./vendor/bin/rr-worker start --relay-dsn unix:///usr/local/var/run/rr-rpc.sock"
   relay: "unix:///usr/local/var/run/rr-rpc.sock"
@@ -7,7 +10,7 @@ logs:
   level: error
 http:
   address: 0.0.0.0:8080
-  middleware: ["headers", "static", "gzip"]
+  middleware: ["headers"]
   pool:
     #max_jobs: 64 # feel free to change this
     supervisor:
@@ -15,8 +18,6 @@ http:
   headers:
     response:
       Server: "RoadRunner"
-  static:
-    dir: "public"
-    forbid: [".php"]
+
 
 

+ 9 - 10
frameworks/PHP/laravel/laravel-roadrunner.dockerfile

@@ -6,30 +6,29 @@ RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opca
 #RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
 #RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
 
-ADD ./ /laravel
 WORKDIR /laravel
+COPY --link . .
 
 RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache
-RUN chmod -R 777 /laravel
 
 RUN apt-get update > /dev/null && \
-    apt-get install -yqq git unzip > /dev/null
-RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');"
-RUN mv composer.phar /usr/local/bin/composer
+    apt-get install -yqq curl unzip > /dev/null
 
-COPY deploy/roadrunner/composer.json ./
-COPY deploy/roadrunner/.rr.yaml ./
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+COPY --link deploy/roadrunner/composer.json .
+COPY --link deploy/roadrunner/.rr.yaml .
 
 RUN composer install -a --no-dev --quiet
 RUN php artisan optimize
 
 # install roadrunner
-COPY --from=ghcr.io/roadrunner-server/roadrunner:2.12.1 /usr/bin/rr ./rr
+COPY --from=ghcr.io/roadrunner-server/roadrunner:2023.3 --link /usr/bin/rr /usr/local/bin/rr
 
 RUN php artisan vendor:publish --provider='Spiral\RoadRunnerLaravel\ServiceProvider' --tag=config
+RUN rr -v
 
 EXPOSE 8080
 
 # CMD bash
-CMD ./rr serve -c ./.rr.yaml
-
+CMD rr serve -c .rr.yaml

+ 2 - 1
frameworks/PHP/php-ngx/benchmark_config.json

@@ -81,7 +81,8 @@
       "database_os": "Linux",
       "display_name": "ngx-php async",
       "notes": "ngx_php async",
-      "versus": "php"
+      "versus": "php",
+      "tags": ["broken"]
     }
   }]
 }

+ 6 - 5
frameworks/PHP/php-ngx/php-ngx-async.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -9,12 +9,10 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get update -yqq > /dev/null && \
     apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \
-                    zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev libkrb5-dev \
+                    zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \
                     php8.3-cli php8.3-dev libphp8.3-embed php8.3-mysql > /dev/null
 
-ADD . .
-
-ENV NGINX_VERSION 1.25.4
+ENV NGINX_VERSION 1.26.0
 
 RUN git clone -b v0.0.29 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null
 
@@ -28,8 +26,11 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
             --add-module=/ngx-php/third_party/ngx_devel_kit \
             --add-module=/ngx-php > /dev/null && \
     make > /dev/null && make install > /dev/null
+
 RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.3/embed/conf.d/10-opcache.ini
 
+COPY --link . .
+
 EXPOSE 8080
 
 CMD /nginx/sbin/nginx -c /deploy/nginx_async.conf

+ 7 - 4
frameworks/PHP/php-ngx/php-ngx-mysql.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -9,11 +9,10 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get update -yqq > /dev/null && \
     apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \
-                    zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev libkrb5-dev \
+                    zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \
                     php8.3-cli php8.3-dev libphp8.3-embed php8.3-mysql > /dev/null
-ADD . .
 
-ENV NGINX_VERSION 1.25.4
+ENV NGINX_VERSION 1.26.0
 
 RUN git clone -b v0.0.29 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null
 
@@ -28,6 +27,10 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
             --add-module=/ngx-php > /dev/null && \
     make > /dev/null && make install > /dev/null
 
+RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.3/embed/conf.d/10-opcache.ini
+
+COPY --link . .
+
 RUN export WORKERS=$(( 4 * $(nproc) )) && \
     sed -i "s/worker_processes  auto/worker_processes $WORKERS/g" /deploy/nginx.conf
 

+ 8 - 5
frameworks/PHP/php-ngx/php-ngx-pgsql.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -9,11 +9,10 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get update -yqq > /dev/null && \
     apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \
-                    zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev libkrb5-dev \
+                    zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \
                     php8.3-cli php8.3-dev libphp8.3-embed php8.3-pgsql > /dev/null
-ADD . .
 
-ENV NGINX_VERSION 1.25.4
+ENV NGINX_VERSION 1.26.0
 
 RUN git clone -b v0.0.29 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null
 
@@ -28,11 +27,15 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
             --add-module=/ngx-php > /dev/null && \
     make > /dev/null && make install > /dev/null
 
+RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.3/embed/conf.d/10-opcache.ini
+
+COPY --link . .
+
 RUN sed -i "s|app.php|app-pg.php|g" /deploy/nginx.conf
 
 RUN export WORKERS=$(( 4 * $(nproc) )) && \
     sed -i "s|worker_processes  auto|worker_processes $WORKERS|g" /deploy/nginx.conf
-RUN sed -i "s|opcache.jit=off|opcache.jit=function|g" /etc/php/8.3/embed/conf.d/10-opcache.ini
+
 EXPOSE 8080
 
 CMD /nginx/sbin/nginx -c /deploy/nginx.conf

+ 6 - 4
frameworks/PHP/php-ngx/php-ngx.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -9,11 +9,10 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get update -yqq > /dev/null && \
     apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \
-                    zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev libkrb5-dev \
+                    zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \
                     php8.3-cli php8.3-dev libphp8.3-embed php8.3-mysql > /dev/null
-ADD . .
 
-ENV NGINX_VERSION 1.25.4
+ENV NGINX_VERSION 1.26.0
 
 RUN git clone -b v0.0.29 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null
 
@@ -27,8 +26,11 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
             --add-module=/ngx-php/third_party/ngx_devel_kit \
             --add-module=/ngx-php > /dev/null && \
     make > /dev/null && make install > /dev/null
+
 RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.3/embed/conf.d/10-opcache.ini
 
+COPY --link . .
+
 EXPOSE 8080
 
 CMD /nginx/sbin/nginx -c /deploy/nginx_default.conf 

+ 10 - 1
frameworks/PHP/php/deploy/nginx-unit.json

@@ -8,7 +8,11 @@
     "applications": {
         "benchmark": {
             "type": "php",
-            "processes": 84,
+            "processes": {
+                "max": 224,
+                "spare": 168,
+                "idle_timeout": 20
+              },
             "user": "www-data",
             "group": "www-data",
             "root": "/php/",
@@ -19,5 +23,10 @@
                 "requests": 10000000
             }
         }
+    },
+    "settings": {
+        "http": {
+          "server_version": false
+        }
     }
 }

+ 4 - 3
frameworks/PHP/php/php-franken.dockerfile

@@ -4,12 +4,13 @@ FROM dunglas/frankenphp
 RUN install-php-extensions \
     pdo_mysql \
     zip \
-    opcache
+    opcache > /dev/null
 
 
-COPY deploy/franken/Caddyfile /etc/caddy/Caddyfile
+COPY --link deploy/franken/Caddyfile /etc/caddy/Caddyfile
+COPY --link deploy/conf/php.ini /usr/local/etc/php/
 
-ADD . /php
+COPY --link . /php
 
 # Worker mode 
 #ENV FRANKENPHP_CONFIG="worker ./public/index.php"

+ 12 - 5
frameworks/PHP/php/php-unit.dockerfile

@@ -1,13 +1,20 @@
 FROM unit:php8.3
 
-ADD . /php
+RUN docker-php-ext-install pdo_mysql opcache > /dev/null
+
 WORKDIR /php
+COPY --link . .
 
-RUN docker-php-ext-install pdo_mysql opcache > /dev/null
-RUN if [ $(nproc) = 2 ]; then sed -i "s|\"processes\": 84,|\"processes\": 64,|g" /php/deploy/nginx-unit.json ; fi;
+RUN if [ $(nproc) = 2 ]; then sed -i "s|\"spare\": 168,|\"spare\": 64,|g" /php/deploy/nginx-unit.json ; fi;
 
-EXPOSE 8080
+#RUN more /php/deploy/nginx-unit.json
 
-COPY deploy/nginx-unit.json /docker-entrypoint.d/nginx-unit.json
+RUN unitd && \
+    curl -X PUT --data-binary @/php/deploy/nginx-unit.json --unix-socket \
+        /var/run/control.unit.sock http://localhost/config
+
+ENTRYPOINT [ ]
+
+EXPOSE 8080
 
 CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"]

+ 0 - 17
frameworks/PHP/spiral/php/install-composer.sh

@@ -1,17 +0,0 @@
-#!/bin/sh
-
-EXPECTED_SIGNATURE="$(curl -s https://composer.github.io/installer.sig)"
-php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
-ACTUAL_SIGNATURE="$(php -r "echo hash_file('SHA384', 'composer-setup.php');")"
-
-if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
-then
-    >&2 echo 'ERROR: Invalid installer signature'
-    rm composer-setup.php
-    exit 1
-fi
-
-php composer-setup.php --quiet
-RESULT=$?
-rm composer-setup.php
-exit $RESULT

+ 5 - 0
frameworks/PHP/spiral/php/php.ini

@@ -1909,6 +1909,11 @@ opcache.huge_code_pages=1
 ; SSL stream context option.
 ;openssl.capath=
 
+
+
+opcache.jit_buffer_size=128M
+opcache.jit=tracing
+
 ; Local Variables:
 ; tab-width: 4
 ; End:

+ 14 - 11
frameworks/PHP/spiral/spiral.dockerfile

@@ -1,21 +1,24 @@
 FROM php:8.3-cli
 
-RUN docker-php-ext-install pdo_mysql > /dev/null
+RUN apt-get update -yqq > /dev/null && apt-get install -yqq git unzip > /dev/null
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+RUN docker-php-ext-install \
+    opcache \
+    pdo_mysql \
+    sockets > /dev/null
 
-# Workaround solution for installing ext-sockets for PHP 8.0
-# See https://github.com/docker-library/php/issues/1245
-RUN CFLAGS="$CFLAGS -D_GNU_SOURCE" docker-php-ext-install sockets > /dev/null
+# RoadRunner >= 2024.x.x requires protobuf extensions to be installed
+ARG PROTOBUF_VERSION="4.26.1"
+RUN pecl channel-update pecl.php.net
+RUN MAKEFLAGS="-j $(nproc)" pecl install protobuf-${PROTOBUF_VERSION} > /dev/null
 
-ADD ./ /spiral
 WORKDIR /spiral
+COPY --link . .
 
 # composer and opcache settings
-COPY php/* /usr/local/etc/php/
-RUN chmod +x /usr/local/etc/php/install-composer.sh && /usr/local/etc/php/install-composer.sh
-
-# install dependencies
-RUN apt-get update -yqq > /dev/null && apt-get install -yqq git unzip > /dev/null
-RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev
+COPY --link php/php.ini /usr/local/etc/php/
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
 
 # pre-configure
 RUN ./vendor/bin/rr get-binary > /dev/null 2>&1

+ 25 - 0
frameworks/PHP/symfony/.rr.yaml

@@ -0,0 +1,25 @@
+version: "3"
+#https://github.com/roadrunner-server/roadrunner/blob/master/.rr.yaml
+
+server:
+  command: "php /symfony/public/runtime.php"
+  env:
+    - APP_RUNTIME: Runtime\RoadRunnerSymfonyNyholm\Runtime
+
+http:
+  address: "0.0.0.0:8080"
+
+  middleware: ["headers"]
+  headers:
+    response:
+      Server: "RoadRunner"
+  #pool:
+    #num_workers: 0
+    #max_jobs: 500
+  
+logs:
+  mode: production
+  level: error
+#rpc:
+#  listen: tcp://127.0.0.1:6001
+

+ 24 - 0
frameworks/PHP/symfony/benchmark_config.json

@@ -116,6 +116,30 @@
       "versus": "php",
       "tags": []
     },
+    "roadrunner": {
+      "plaintext_url": "/plaintext",
+      "json_url": "/json",
+      "db_url": "/db",
+      "update_url": "/updates?queries=",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "symfony",
+      "language": "PHP",
+      "flavor": "PHP8",
+      "orm": "Full",
+      "platform": "roadrunner",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "symfony-roadrunner",
+      "notes": "",
+      "versus": "php",
+      "tags": []
+    },
     "franken": {
       "plaintext_url": "/plaintext",
       "json_url": "/json",

+ 2 - 2
frameworks/PHP/symfony/deploy/Caddyfile

@@ -3,7 +3,7 @@
     {$CADDY_DEBUG}
 
 	frankenphp {
-		#worker /path/to/your/worker.php
+		#worker /path/to/your/runtime.php
 		{$FRANKENPHP_CONFIG}
 	}
 }
@@ -15,7 +15,7 @@ route {
 
     # If the requested file does not exist, try index files
     @indexFiles file {
-        try_files {path} {path}/worker.php worker.php
+        try_files {path} {path}/runtime.php runtime.php
         split_path .php
     }
     rewrite @indexFiles {http.matchers.file.relative}

+ 1 - 1
frameworks/PHP/symfony/deploy/conf/php.ini

@@ -1767,7 +1767,7 @@ ldap.max_links = -1
 opcache.enable=1
 
 ; Determines if Zend OPCache is enabled for the CLI version of PHP
-;opcache.enable_cli=0
+opcache.enable_cli=1
 
 ; The OPcache shared memory storage size.
 opcache.memory_consumption=256

+ 1 - 1
frameworks/PHP/symfony/public/worker.php → frameworks/PHP/symfony/public/runtime.php

@@ -4,6 +4,6 @@ use App\Kernel;
 
 require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
 
-return function (array $context) {
+return function (array $context): Kernel {
     return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
 };

+ 13 - 18
frameworks/PHP/symfony/symfony-franken.dockerfile

@@ -2,30 +2,25 @@ FROM dunglas/frankenphp
 
 # add additional extensions here:
 RUN install-php-extensions \
-    pdo_pgsql \
     intl \
-    opcache
-
-RUN apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null && \
-    apt-get install unzip > /dev/null
-
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+    opcache \
+    pdo_pgsql \
+    zip > /dev/null
 
-EXPOSE 8080
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-COPY deploy/Caddyfile /etc/caddy/Caddyfile
+COPY --link deploy/Caddyfile /etc/caddy/Caddyfile
+COPY --link deploy/conf/php.ini /usr/local/etc/php/
 
-ADD . /symfony
 WORKDIR /symfony
+COPY --link . .
 
-RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log
-
-ENV COMPOSER_ALLOW_SUPERUSER=1
-RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts
+ENV FRANKENPHP_CONFIG="worker /symfony/public/runtime.php"
+ENV APP_RUNTIME="Runtime\FrankenPhpSymfony\Runtime"
+#ENV CADDY_DEBUG=debug
+RUN composer require runtime/frankenphp-symfony --update-no-dev --no-scripts --quiet
 RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
 
-RUN composer require runtime/frankenphp-symfony
-ENV FRANKENPHP_CONFIG="worker ./public/worker.php"
-ENV APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime
+EXPOSE 8080
 
-#ENV CADDY_DEBUG=debug
+RUN frankenphp -v

+ 4 - 10
frameworks/PHP/symfony/symfony-mysql.dockerfile

@@ -1,4 +1,3 @@
-FROM composer/composer:2-bin AS composer
 FROM ubuntu:22.04
 
 ARG DEBIAN_FRONTEND=noninteractive
@@ -11,24 +10,19 @@ RUN apt-get install -yqq nginx git unzip curl \
     php8.3-cli php8.3-fpm php8.3-mysql  \
     php8.3-mbstring php8.3-xml php8.3-curl php8.3-dev > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-COPY deploy/conf/* /etc/php/8.3/fpm/
-
-ADD . /symfony
+COPY --link deploy/conf/* /etc/php/8.3/fpm/
 WORKDIR /symfony
+COPY --link . .
 
 RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi;
 
-RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log
-
-ENV COMPOSER_ALLOW_SUPERUSER=1
-RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet
 RUN cp deploy/mysql/.env . && composer dump-env prod && bin/console cache:clear
 
 RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.3/fpm/php.ini
 
-
 EXPOSE 8080
 
 # Uncomment next line for Laravel console error logging to be viewable in docker logs

+ 4 - 8
frameworks/PHP/symfony/symfony-raw.dockerfile

@@ -10,19 +10,15 @@ RUN apt-get install -yqq nginx git unzip curl \
     php8.3-cli php8.3-fpm php8.3-pgsql  \
     php8.3-mbstring php8.3-xml php8.3-curl > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-COPY deploy/conf/* /etc/php/8.3/fpm/
-
-ADD . /symfony
+COPY --link deploy/conf/* /etc/php/8.3/fpm/
 WORKDIR /symfony
+COPY --link . .
 
 RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi;
 
-RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log
-
-ENV COMPOSER_ALLOW_SUPERUSER=1
-RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet
 RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
 
 RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.3/fpm/php.ini

+ 25 - 0
frameworks/PHP/symfony/symfony-roadrunner.dockerfile

@@ -0,0 +1,25 @@
+FROM php:8.3-cli
+
+COPY --from=ghcr.io/roadrunner-server/roadrunner:2023.3 --link /usr/bin/rr /usr/local/bin/rr
+COPY --from=mlocati/php-extension-installer --link /usr/bin/install-php-extensions /usr/local/bin/
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+RUN install-php-extensions \
+    intl \
+    opcache \
+    pdo_pgsql \
+    sockets \
+    zip > /dev/null
+
+COPY --link deploy/conf/php.ini /usr/local/etc/php/
+WORKDIR /symfony
+COPY --link . .
+
+ENV APP_RUNTIME="Runtime\RoadRunnerSymfonyNyholm\Runtime"
+RUN composer require runtime/roadrunner-symfony-nyholm --update-no-dev --no-scripts --quiet
+RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
+
+EXPOSE 8080
+
+RUN rr -v
+ENTRYPOINT ["rr", "serve"]

+ 7 - 15
frameworks/PHP/symfony/symfony-swoole.dockerfile

@@ -10,25 +10,17 @@ RUN apt-get update -yqq && \
     apt-get install -yqq libpq-dev libicu-dev git unzip > /dev/null && \ 
     docker-php-ext-install pdo_pgsql opcache intl > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-COPY deploy/swoole/php.ini /usr/local/etc/php/
-
-ADD . /symfony
+COPY --link deploy/swoole/php.ini /usr/local/etc/php/
 WORKDIR /symfony
-RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log
-#RUN mkdir -m 777 -p /symfony/var/cache/swoole /symfony/var/log
-RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --no-scripts --quiet
-RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
-
-ENV APP_RUNTIME=Runtime\\Swoole\\Runtime
-RUN composer require runtime/swoole
-
-RUN COMPOSER_ALLOW_SUPERUSER=1 composer dump-autoload --no-dev --classmap-authoritative
-RUN COMPOSER_ALLOW_SUPERUSER=1 composer dump-env prod
+COPY --link . .
 
 #ENV APP_DEBUG=1
+ENV APP_RUNTIME="Runtime\Swoole\Runtime"
+RUN composer require runtime/swoole --update-no-dev --no-scripts --quiet
+RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
 
 EXPOSE 8080
 
-CMD php /symfony/public/swoole.php
+ENTRYPOINT [ "php", "/symfony/public/swoole.php" ]

+ 10 - 13
frameworks/PHP/symfony/symfony-workerman.dockerfile

@@ -6,25 +6,22 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de
 RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
     apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null
 
-RUN apt-get install -yqq git unzip \
+RUN apt-get install -yqq unzip \
     php8.3-cli php8.3-pgsql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null
-RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
+RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null && \
+    pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
 
-EXPOSE 8080
-
-ADD . /symfony
 WORKDIR /symfony
+COPY --link . .
 
-RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log
-
-ENV COMPOSER_ALLOW_SUPERUSER=1
-RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet
 RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
 
-COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini
+COPY --link deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini
+
+EXPOSE 8080
 
-CMD php server.php start
+ENTRYPOINT [ "php", "server.php", "start" ]

+ 4 - 7
frameworks/PHP/symfony/symfony.dockerfile

@@ -10,19 +10,16 @@ RUN apt-get install -yqq nginx git unzip curl \
     php8.3-cli php8.3-fpm php8.3-pgsql  \
     php8.3-mbstring php8.3-xml php8.3-curl php8.3-dev > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-COPY deploy/conf/* /etc/php/8.3/fpm/
+COPY --link deploy/conf/* /etc/php/8.3/fpm/
 
-ADD . /symfony
 WORKDIR /symfony
+COPY --link . .
 
 RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi;
 
-RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log
-
-ENV COMPOSER_ALLOW_SUPERUSER=1
-RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet
 RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear
 
 RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.3/fpm/php.ini

+ 8 - 4
frameworks/PHP/workerman/app-pg.php

@@ -47,6 +47,8 @@ function db()
 
 function query($request)
 {
+    $random = DbRaw::$random;
+
     $query_count = 1;
     $q = (int) $request->get('q');
     if ($q > 1) {
@@ -54,8 +56,8 @@ function query($request)
     }
 
     while ($query_count--) {
-        DbRaw::$random->execute([mt_rand(1, 10000)]);
-        $arr[] = DbRaw::$random->fetch();
+        $random->execute([mt_rand(1, 10000)]);
+        $arr[] = $random->fetch();
     }
 
     return new Response(200, [
@@ -66,6 +68,8 @@ function query($request)
 
 function updateraw($request)
 {
+    $random = DbRaw::$random;
+
     $query_count = 1;
     $q = (int) $request->get('q');
     if ($q > 1) {
@@ -74,8 +78,8 @@ function updateraw($request)
 
     while ($query_count--) {
 
-        DbRaw::$random->execute([mt_rand(1, 10000)]);
-        $row = DbRaw::$random->fetch();
+        $random->execute([mt_rand(1, 10000)]);
+        $row = $random->fetch();
         $row['randomNumber'] = mt_rand(1, 10000);
 
         $worlds[] = $row;

+ 1 - 1
frameworks/PHP/workerman/server.php

@@ -7,7 +7,7 @@ use Workerman\Timer;
 
 $http_worker                = new Worker('http://0.0.0.0:8080');
 $http_worker->count         = (int) shell_exec('nproc') * 4;
-$http_worker->onWorkerStart = function () {
+$http_worker->onWorkerStart = static function () {
     Header::$date = gmdate('D, d M Y H:i:s').' GMT';
     Timer::add(1, function() {
         Header::$date = gmdate('D, d M Y H:i:s').' GMT';

+ 6 - 6
frameworks/PHP/workerman/workerman-async.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -8,15 +8,15 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get install -yqq php8.3-cli php8.3-mysql  > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-RUN apt-get install -y php-pear php8.3-dev php8.3-xml libevent-dev git > /dev/null
-RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
+RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \
+    pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
 
-COPY php.ini /etc/php/8.3/cli/php.ini
+COPY --link php.ini /etc/php/8.3/cli/php.ini
 
-ADD ./ /workerman
 WORKDIR /workerman
+COPY --link . .
 
 RUN composer require react/mysql "^0.6" --quiet
 RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet

+ 7 - 6
frameworks/PHP/workerman/workerman-pgsql.dockerfile

@@ -1,4 +1,5 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
+
 ARG DEBIAN_FRONTEND=noninteractive
 
 RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null
@@ -7,15 +8,15 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null
-RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
+RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \
+    pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
 
-COPY php.ini /etc/php/8.3/cli/php.ini
+COPY --link php.ini /etc/php/8.3/cli/php.ini
 
-ADD ./ /workerman
 WORKDIR /workerman
+COPY --link . .
 
 RUN sed -i "s|'/app.php|'/app-pg.php|g" server.php
 RUN sed -i "s|init()|DbRaw::init()|g" server.php

+ 6 - 6
frameworks/PHP/workerman/workerman-php8-jit.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -8,15 +8,15 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null
-RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
+RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \
+    pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
  
-COPY php-jit.ini /etc/php/8.3/cli/php.ini
+COPY --link php-jit.ini /etc/php/8.3/cli/php.ini
 
-ADD ./ /workerman
 WORKDIR /workerman
+COPY --link . .
 
 RUN sed -i "s|'/app.php|'/app-pg.php|g" server.php
 RUN sed -i "s|init()|DbRaw::init()|g" server.php

+ 6 - 6
frameworks/PHP/workerman/workerman.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:24.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -8,15 +8,15 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
 
 RUN apt-get install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null
 
-COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
 
-RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null
-RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
+RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null && \
+    pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini
  
-COPY php-jit.ini /etc/php/8.3/cli/php.ini 
+COPY --link php-jit.ini /etc/php/8.3/cli/php.ini 
 
-ADD ./ /workerman
 WORKDIR /workerman
+COPY --link . .
 
 RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
 

+ 2 - 0
frameworks/Pascal/mormot/mormot.dockerfile

@@ -10,6 +10,7 @@ COPY setup_and_build.sh .
 RUN /bin/bash -c ./setup_and_build.sh
 
 FROM ubuntu:22.04
+RUN apt-get update -yqq && apt-get install -yqq libmimalloc2.0
 
 ARG TFB_TEST_NAME
 
@@ -17,6 +18,7 @@ COPY --from=builder /build/bin/fpc-x86_64-linux/raw /usr/local/bin/raw
 COPY --from=builder /build/libpq.so.5.16 /usr/lib/x86_64-linux-gnu/libpq.so.5
 
 ENV TFB_TEST_NAME=$TFB_TEST_NAME
+ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libmimalloc.so.2.0
 
 EXPOSE 8080
 CMD ["raw"]

+ 2 - 2
frameworks/Python/api_hour/requirements.txt

@@ -11,9 +11,9 @@ MarkupSafe==0.23
 piprot==0.9.1
 psycopg2==2.7.5
 PyYAML==5.4
-requests==2.31.0
+requests==2.32.0
 requests-futures==0.9.5
 setproctitle==1.1.8
 ujson==1.33
 aiomysql==0.0.7
-PyMySQL==0.6.7
+PyMySQL==1.1.1

+ 0 - 1
frameworks/Ruby/agoo/.ruby-gemset

@@ -1 +0,0 @@
-agoo

+ 0 - 1
frameworks/Ruby/agoo/.ruby-version

@@ -1 +0,0 @@
-ruby-2.6.3

+ 6 - 4
frameworks/Ruby/grape/config.ru

@@ -4,6 +4,8 @@ require 'yaml'
 require_relative 'config/auto_tune'
 
 MAX_PK = 10_000
+ID_RANGE = (1..MAX_PK).freeze
+ALL_IDS = ID_RANGE.to_a
 QUERIES_MIN = 1
 QUERIES_MAX = 500
 
@@ -53,8 +55,8 @@ module Acme
 
     get '/query' do
       ActiveRecord::Base.connection_pool.with_connection do
-        Array.new(bounded_queries) do
-          World.find(rand1)
+        ALL_IDS.sample(bounded_queries).map do |id|
+          World.find(id)
         end
       end
     end
@@ -62,8 +64,8 @@ module Acme
     get '/updates' do
       worlds =
         ActiveRecord::Base.connection_pool.with_connection do
-          Array.new(bounded_queries) do
-            world = World.find(rand1)
+          ALL_IDS.sample(bounded_queries).map do |id|
+            world = World.find(id)
             new_value = rand1
             new_value = rand1 while new_value == world.randomNumber
             world.update_columns(randomNumber: new_value)

+ 5 - 5
frameworks/Ruby/rack-sequel/Gemfile

@@ -1,19 +1,19 @@
 source 'https://rubygems.org'
 
 gem 'json', '~> 2.0'
-gem 'passenger', '~> 5.1', :platforms=>[:ruby, :mswin], :require=>false
+gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false
 gem 'puma', '~> 6.4', :require=>false
 gem 'sequel', '~> 5.0'
-gem 'rack', '2.0.8'
-gem 'unicorn', '~> 5.2', :platforms=>[:ruby, :mswin], :require=>false
+gem 'rack', '~> 3.0'
+gem 'unicorn', '~> 6.1', :platforms=>[:ruby, :mswin], :require=>false
 
 group :mysql do
   gem 'jdbc-mysql', '~> 5.1', :platforms=>:jruby, :require=>'jdbc/mysql'
-  gem 'mysql2', '~> 0.4', :platforms=>[:ruby, :mswin]
+  gem 'mysql2', '~> 0.5', :platforms=>[:ruby, :mswin]
 end
 
 group :postgresql do
   gem 'jdbc-postgres', '~> 9.4', :platforms=>:jruby, :require=>'jdbc/postgres'
-  gem 'pg', '~> 0.19', :platforms=>[:ruby, :mswin]
+  gem 'pg', '~> 1.5', :platforms=>[:ruby, :mswin]
   gem 'sequel_pg', '~> 1.6', :platforms=>:ruby, :require=>false
 end

+ 2 - 0
frameworks/Ruby/rack-sequel/boot.rb

@@ -3,6 +3,8 @@ require 'bundler/setup'
 require 'time'
 
 MAX_PK = 10_000
+ID_RANGE = (1..10_000).freeze
+ALL_IDS = ID_RANGE.to_a
 QUERIES_MIN = 1
 QUERIES_MAX = 500
 SEQUEL_NO_ASSOCIATIONS = true

+ 5 - 5
frameworks/Ruby/rack-sequel/hello_world.rb

@@ -29,8 +29,8 @@ class HelloWorld
 
   def queries(env)
     DB.synchronize do
-      Array.new(bounded_queries(env)) do
-        WORLD_BY_ID.(:id=>rand1)
+      ALL_IDS.sample(bounded_queries(env)).map do |id|
+        WORLD_BY_ID.(id: id)
       end
     end
   end
@@ -78,9 +78,9 @@ class HelloWorld
 
   def updates(env)
     DB.synchronize do
-      Array.new(bounded_queries(env)) do
-        world = WORLD_BY_ID.(:id=>rand1)
-        WORLD_UPDATE.(:id=>world[:id], :randomnumber=>(world[:randomnumber] = rand1))
+      ALL_IDS.sample(bounded_queries(env)).map do |id|
+        world = WORLD_BY_ID.(id: id)
+        WORLD_UPDATE.(id: world[:id], randomnumber: (world[:randomnumber] = rand1))
         world
       end
     end

+ 1 - 1
frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile

@@ -11,7 +11,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends libjemalloc2
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
 
-RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile
 
 # TODO: https://github.com/phusion/passenger/issues/1916
 ENV _PASSENGER_FORCE_HTTP_SESSION=true

+ 1 - 1
frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile

@@ -11,7 +11,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends libjemalloc2
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
 
-RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile
 
 # TODO: https://github.com/phusion/passenger/issues/1916
 ENV _PASSENGER_FORCE_HTTP_SESSION=true

+ 1 - 1
frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile

@@ -11,7 +11,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends libjemalloc2
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
 
-RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile
 
 ENV DBTYPE=postgresql
 

+ 1 - 1
frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile

@@ -11,7 +11,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends libjemalloc2
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
 
-RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile
 
 ENV DBTYPE=postgresql
 

+ 1 - 1
frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile

@@ -11,7 +11,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends libjemalloc2
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
 
-RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile
 
 ENV DBTYPE=mysql
 

+ 1 - 1
frameworks/Ruby/rack-sequel/rack-sequel.dockerfile

@@ -11,7 +11,7 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends libjemalloc2
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
 
-RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile
 
 ENV DBTYPE=mysql
 

+ 4 - 4
frameworks/Ruby/rack/Gemfile

@@ -2,13 +2,13 @@
 
 source 'https://rubygems.org'
 
-gem 'rack', '~>3.0'
-gem 'connection_pool', '~>2.4'
-gem 'falcon', '~>0.42', platforms: %i[ruby mswin]
+gem 'rack', '~> 3.0'
+gem 'connection_pool', '~> 2.4'
+gem 'falcon', '~> 0.47', platforms: %i[ruby mswin]
 gem 'jdbc-postgres', '~> 42.2', platforms: :jruby, require: 'jdbc/postgres'
 gem 'json', '~> 2.6', platforms: :jruby
 gem 'oj', '~> 3.14', platforms: %i[ruby mswin]
-gem 'pg', '~>1.5', platforms: %i[ruby mswin]
+gem 'pg', '~> 1.5', platforms: %i[ruby mswin]
 gem 'puma', '~> 6.4'
 gem 'sequel'
 gem 'sequel_pg', platforms: %i[ruby mswin]

+ 74 - 57
frameworks/Ruby/rack/Gemfile.lock

@@ -2,118 +2,135 @@ GEM
   remote: https://rubygems.org/
   specs:
     ast (2.4.2)
-    async (2.5.0)
-      console (~> 1.10)
-      io-event (~> 1.1)
+    async (2.11.0)
+      console (~> 1.25, >= 1.25.2)
+      fiber-annotation
+      io-event (~> 1.5, >= 1.5.1)
       timers (~> 4.1)
-    async-container (0.16.12)
-      async
-      async-io
-    async-http (0.60.1)
-      async (>= 1.25)
-      async-io (>= 1.28)
-      async-pool (>= 0.2)
-      protocol-http (~> 0.24.0)
-      protocol-http1 (~> 0.15.0)
-      protocol-http2 (~> 0.15.0)
-      traces (>= 0.8.0)
+    async-container (0.18.2)
+      async (~> 2.10)
+    async-http (0.66.3)
+      async (>= 2.10.2)
+      async-pool (>= 0.6.1)
+      io-endpoint (~> 0.10, >= 0.10.3)
+      io-stream (~> 0.4)
+      protocol-http (~> 0.26.0)
+      protocol-http1 (~> 0.19.0)
+      protocol-http2 (~> 0.17.0)
+      traces (>= 0.10.0)
     async-http-cache (0.4.3)
       async-http (~> 0.56)
-    async-io (1.34.3)
-      async
-    async-pool (0.4.0)
+    async-pool (0.6.1)
       async (>= 1.25)
-    build-environment (1.13.0)
-    concurrent-ruby (1.2.2)
-    connection_pool (2.4.0)
-    console (1.16.2)
-      fiber-local
-    falcon (0.42.3)
+    async-service (0.12.0)
       async
-      async-container (~> 0.16.0)
-      async-http (~> 0.57)
+      async-container (~> 0.16)
+    bigdecimal (3.1.8)
+    concurrent-ruby (1.2.3)
+    connection_pool (2.4.1)
+    console (1.25.2)
+      fiber-annotation
+      fiber-local (~> 1.1)
+      json
+    falcon (0.47.6)
+      async
+      async-container (~> 0.18)
+      async-http (~> 0.66, >= 0.66.3)
       async-http-cache (~> 0.4.0)
-      async-io (~> 1.22)
-      build-environment (~> 1.13)
+      async-service (~> 0.10)
       bundler
       localhost (~> 1.1)
       openssl (~> 3.0)
       process-metrics (~> 0.2.0)
-      protocol-rack (~> 0.1)
-      samovar (~> 2.1)
-    fiber-local (1.0.0)
-    io-event (1.1.7)
-    json (2.6.3)
+      protocol-rack (~> 0.5)
+      samovar (~> 2.3)
+    fiber-annotation (0.2.0)
+    fiber-local (1.1.0)
+      fiber-storage
+    fiber-storage (0.1.0)
+    io-endpoint (0.10.3)
+    io-event (1.5.1)
+    io-stream (0.4.0)
+    json (2.7.2)
     kgio (2.11.4)
-    localhost (1.1.10)
+    language_server-protocol (3.17.0.3)
+    localhost (1.3.1)
     mapping (1.1.1)
-    nio4r (2.7.0)
-    oj (3.14.2)
-    openssl (3.1.0)
-    parallel (1.23.0)
-    parser (3.2.2.1)
+    nio4r (2.7.3)
+    oj (3.16.3)
+      bigdecimal (>= 3.0)
+    openssl (3.2.0)
+    parallel (1.24.0)
+    parser (3.3.1.0)
       ast (~> 2.4.1)
-    pg (1.5.3)
+      racc
+    pg (1.5.6)
     process-metrics (0.2.1)
       console (~> 1.8)
       samovar (~> 2.1)
-    protocol-hpack (1.4.2)
-    protocol-http (0.24.7)
-    protocol-http1 (0.15.1)
+    protocol-hpack (1.4.3)
+    protocol-http (0.26.5)
+    protocol-http1 (0.19.1)
       protocol-http (~> 0.22)
-    protocol-http2 (0.15.1)
+    protocol-http2 (0.17.0)
       protocol-hpack (~> 1.4)
       protocol-http (~> 0.18)
-    protocol-rack (0.2.4)
+    protocol-rack (0.5.1)
       protocol-http (~> 0.23)
       rack (>= 1.0)
     puma (6.4.2)
       nio4r (~> 2.0)
-    rack (3.0.9.1)
+    racc (1.7.3)
+    rack (3.0.11)
     rack-test (2.1.0)
       rack (>= 1.3)
     rainbow (3.1.1)
     raindrops (0.20.1)
-    regexp_parser (2.8.0)
-    rexml (3.2.5)
-    rubocop (1.51.0)
+    regexp_parser (2.9.1)
+    rexml (3.2.8)
+      strscan (>= 3.0.9)
+    rubocop (1.63.5)
       json (~> 2.3)
+      language_server-protocol (>= 3.17.0)
       parallel (~> 1.10)
-      parser (>= 3.2.0.0)
+      parser (>= 3.3.0.2)
       rainbow (>= 2.2.2, < 4.0)
       regexp_parser (>= 1.8, < 3.0)
       rexml (>= 3.2.5, < 4.0)
-      rubocop-ast (>= 1.28.0, < 2.0)
+      rubocop-ast (>= 1.31.1, < 2.0)
       ruby-progressbar (~> 1.7)
       unicode-display_width (>= 2.4.0, < 3.0)
-    rubocop-ast (1.28.1)
-      parser (>= 3.2.1.0)
+    rubocop-ast (1.31.3)
+      parser (>= 3.3.1.0)
     ruby-progressbar (1.13.0)
-    samovar (2.1.4)
+    samovar (2.3.0)
       console (~> 1.0)
       mapping (~> 1.0)
-    sequel (5.68.0)
+    sequel (5.80.0)
+      bigdecimal
     sequel_pg (1.17.1)
       pg (>= 0.18.0, != 1.2.0)
       sequel (>= 4.38.0)
+    strscan (3.1.0)
     timers (4.3.5)
-    traces (0.9.1)
+    traces (0.11.1)
     tzinfo (2.0.6)
       concurrent-ruby (~> 1.0)
     tzinfo-data (1.2023.3)
       tzinfo (>= 1.0.0)
-    unicode-display_width (2.4.2)
+    unicode-display_width (2.5.0)
     unicorn (6.1.0)
       kgio (~> 2.6)
       raindrops (~> 0.7)
 
 PLATFORMS
   x86_64-darwin-20
+  x86_64-darwin-22
   x86_64-linux
 
 DEPENDENCIES
   connection_pool (~> 2.4)
-  falcon (~> 0.42)
+  falcon (~> 0.47)
   jdbc-postgres (~> 42.2)
   json (~> 2.6)
   oj (~> 3.14)

+ 2 - 4
frameworks/Ruby/rails/Gemfile

@@ -1,11 +1,9 @@
-ruby '~> 3.2'
-
 source 'https://rubygems.org'
 
-gem 'trilogy', group: :mysql
 gem 'oj', '~> 3.16'
-gem 'pg', '1.5.4', group: :postgresql
+gem 'pg', '~> 1.5', group: :postgresql
 gem 'puma', '~> 6.4'
 gem 'rails', '~> 7.1.3'
 gem 'redis', '~> 5.0'
+gem 'trilogy', '~> 2.8.1', group: :mysql
 gem 'tzinfo-data'

+ 82 - 86
frameworks/Ruby/rails/Gemfile.lock

@@ -1,35 +1,35 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    actioncable (7.1.3.1)
-      actionpack (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    actioncable (7.1.3.3)
+      actionpack (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       nio4r (~> 2.0)
       websocket-driver (>= 0.6.1)
       zeitwerk (~> 2.6)
-    actionmailbox (7.1.3.1)
-      actionpack (= 7.1.3.1)
-      activejob (= 7.1.3.1)
-      activerecord (= 7.1.3.1)
-      activestorage (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    actionmailbox (7.1.3.3)
+      actionpack (= 7.1.3.3)
+      activejob (= 7.1.3.3)
+      activerecord (= 7.1.3.3)
+      activestorage (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       mail (>= 2.7.1)
       net-imap
       net-pop
       net-smtp
-    actionmailer (7.1.3.1)
-      actionpack (= 7.1.3.1)
-      actionview (= 7.1.3.1)
-      activejob (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    actionmailer (7.1.3.3)
+      actionpack (= 7.1.3.3)
+      actionview (= 7.1.3.3)
+      activejob (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       mail (~> 2.5, >= 2.5.4)
       net-imap
       net-pop
       net-smtp
       rails-dom-testing (~> 2.2)
-    actionpack (7.1.3.1)
-      actionview (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    actionpack (7.1.3.3)
+      actionview (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       nokogiri (>= 1.8.5)
       racc
       rack (>= 2.2.4)
@@ -37,35 +37,35 @@ GEM
       rack-test (>= 0.6.3)
       rails-dom-testing (~> 2.2)
       rails-html-sanitizer (~> 1.6)
-    actiontext (7.1.3.1)
-      actionpack (= 7.1.3.1)
-      activerecord (= 7.1.3.1)
-      activestorage (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    actiontext (7.1.3.3)
+      actionpack (= 7.1.3.3)
+      activerecord (= 7.1.3.3)
+      activestorage (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       globalid (>= 0.6.0)
       nokogiri (>= 1.8.5)
-    actionview (7.1.3.1)
-      activesupport (= 7.1.3.1)
+    actionview (7.1.3.3)
+      activesupport (= 7.1.3.3)
       builder (~> 3.1)
       erubi (~> 1.11)
       rails-dom-testing (~> 2.2)
       rails-html-sanitizer (~> 1.6)
-    activejob (7.1.3.1)
-      activesupport (= 7.1.3.1)
+    activejob (7.1.3.3)
+      activesupport (= 7.1.3.3)
       globalid (>= 0.3.6)
-    activemodel (7.1.3.1)
-      activesupport (= 7.1.3.1)
-    activerecord (7.1.3.1)
-      activemodel (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    activemodel (7.1.3.3)
+      activesupport (= 7.1.3.3)
+    activerecord (7.1.3.3)
+      activemodel (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       timeout (>= 0.4.0)
-    activestorage (7.1.3.1)
-      actionpack (= 7.1.3.1)
-      activejob (= 7.1.3.1)
-      activerecord (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    activestorage (7.1.3.3)
+      actionpack (= 7.1.3.3)
+      activejob (= 7.1.3.3)
+      activerecord (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       marcel (~> 1.0)
-    activesupport (7.1.3.1)
+    activesupport (7.1.3.3)
       base64
       bigdecimal
       concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -76,22 +76,21 @@ GEM
       mutex_m
       tzinfo (~> 2.0)
     base64 (0.2.0)
-    bigdecimal (3.1.6)
+    bigdecimal (3.1.8)
     builder (3.2.4)
     concurrent-ruby (1.2.3)
     connection_pool (2.4.1)
     crass (1.0.6)
     date (3.3.4)
-    drb (2.2.0)
-      ruby2_keywords
+    drb (2.2.1)
     erubi (1.12.0)
     globalid (1.2.1)
       activesupport (>= 6.1)
-    i18n (1.14.1)
+    i18n (1.14.5)
       concurrent-ruby (~> 1.0)
     io-console (0.7.2)
-    irb (1.11.2)
-      rdoc
+    irb (1.13.1)
+      rdoc (>= 4.0.0)
       reline (>= 0.4.2)
     loofah (2.22.0)
       crass (~> 1.0.2)
@@ -101,36 +100,37 @@ GEM
       net-imap
       net-pop
       net-smtp
-    marcel (1.0.2)
+    marcel (1.0.4)
     mini_mime (1.1.5)
-    mini_portile2 (2.8.5)
-    minitest (5.22.2)
+    mini_portile2 (2.8.6)
+    minitest (5.23.1)
     mutex_m (0.2.0)
-    net-imap (0.4.10)
+    net-imap (0.4.11)
       date
       net-protocol
     net-pop (0.1.2)
       net-protocol
     net-protocol (0.2.2)
       timeout
-    net-smtp (0.4.0.1)
+    net-smtp (0.5.0)
       net-protocol
-    nio4r (2.7.0)
-    nokogiri (1.16.2)
+    nio4r (2.7.3)
+    nokogiri (1.16.5)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
-    nokogiri (1.16.2-arm64-darwin)
+    nokogiri (1.16.5-arm64-darwin)
       racc (~> 1.4)
-    nokogiri (1.16.2-x86_64-linux)
+    nokogiri (1.16.5-x86_64-linux)
       racc (~> 1.4)
-    oj (3.16.1)
-    pg (1.5.4)
+    oj (3.16.3)
+      bigdecimal (>= 3.0)
+    pg (1.5.6)
     psych (5.1.2)
       stringio
     puma (6.4.2)
       nio4r (~> 2.0)
-    racc (1.7.3)
-    rack (3.0.9.1)
+    racc (1.8.0)
+    rack (3.0.11)
     rack-session (2.0.0)
       rack (>= 3.0.0)
     rack-test (2.1.0)
@@ -138,20 +138,20 @@ GEM
     rackup (2.1.0)
       rack (>= 3)
       webrick (~> 1.8)
-    rails (7.1.3.1)
-      actioncable (= 7.1.3.1)
-      actionmailbox (= 7.1.3.1)
-      actionmailer (= 7.1.3.1)
-      actionpack (= 7.1.3.1)
-      actiontext (= 7.1.3.1)
-      actionview (= 7.1.3.1)
-      activejob (= 7.1.3.1)
-      activemodel (= 7.1.3.1)
-      activerecord (= 7.1.3.1)
-      activestorage (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    rails (7.1.3.3)
+      actioncable (= 7.1.3.3)
+      actionmailbox (= 7.1.3.3)
+      actionmailer (= 7.1.3.3)
+      actionpack (= 7.1.3.3)
+      actiontext (= 7.1.3.3)
+      actionview (= 7.1.3.3)
+      activejob (= 7.1.3.3)
+      activemodel (= 7.1.3.3)
+      activerecord (= 7.1.3.3)
+      activestorage (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       bundler (>= 1.15.0)
-      railties (= 7.1.3.1)
+      railties (= 7.1.3.3)
     rails-dom-testing (2.2.0)
       activesupport (>= 5.0.0)
       minitest
@@ -159,37 +159,36 @@ GEM
     rails-html-sanitizer (1.6.0)
       loofah (~> 2.21)
       nokogiri (~> 1.14)
-    railties (7.1.3.1)
-      actionpack (= 7.1.3.1)
-      activesupport (= 7.1.3.1)
+    railties (7.1.3.3)
+      actionpack (= 7.1.3.3)
+      activesupport (= 7.1.3.3)
       irb
       rackup (>= 1.0.0)
       rake (>= 12.2)
       thor (~> 1.0, >= 1.2.2)
       zeitwerk (~> 2.6)
-    rake (13.1.0)
+    rake (13.2.1)
     rdoc (6.6.3.1)
       psych (>= 4.0.0)
-    redis (5.0.7)
-      redis-client (>= 0.9.0)
-    redis-client (0.17.0)
+    redis (5.2.0)
+      redis-client (>= 0.22.0)
+    redis-client (0.22.2)
       connection_pool
-    reline (0.4.3)
+    reline (0.5.7)
       io-console (~> 0.5)
-    ruby2_keywords (0.0.5)
     stringio (3.1.0)
     thor (1.3.1)
     timeout (0.4.1)
-    trilogy (2.6.0)
+    trilogy (2.8.1)
     tzinfo (2.0.6)
       concurrent-ruby (~> 1.0)
-    tzinfo-data (1.2021.5)
+    tzinfo-data (1.2024.1)
       tzinfo (>= 1.0.0)
     webrick (1.8.1)
     websocket-driver (0.7.6)
       websocket-extensions (>= 0.1.0)
     websocket-extensions (0.1.5)
-    zeitwerk (2.6.13)
+    zeitwerk (2.6.14)
 
 PLATFORMS
   arm64-darwin-20
@@ -198,15 +197,12 @@ PLATFORMS
 
 DEPENDENCIES
   oj (~> 3.16)
-  pg (= 1.5.4)
+  pg (~> 1.5)
   puma (~> 6.4)
   rails (~> 7.1.3)
   redis (~> 5.0)
-  trilogy
+  trilogy (~> 2.8.1)
   tzinfo-data
 
-RUBY VERSION
-   ruby 3.2.2p53
-
 BUNDLED WITH
    2.3.3

+ 3 - 3
frameworks/Ruby/rails/app/controllers/hello_world_controller.rb

@@ -7,7 +7,7 @@ class HelloWorldController < ApplicationController
   MAX_QUERIES = 500          # max number of records that can be retrieved
 
   def db
-    render json: World.find(random_id)
+    render json: World.find(random_id).attributes
   end
 
   def query
@@ -37,9 +37,9 @@ class HelloWorldController < ApplicationController
       world = World.find(id)
       new_value = random_id
       new_value = random_id until new_value != world.randomNumber
-      world.update_columns(randomNumber: new_value)
-      world
+      { id: id, randomNumber: new_value }
     end
+    World.upsert_all(worlds.sort_by!{_1[:id]})
 
     render json: worlds
   end

+ 0 - 9
frameworks/Ruby/rails/app/controllers/plaintext_controller.rb

@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-class PlaintextController < ApplicationControllerMetal
-  def index
-    add_headers
-    self.content_type = 'text/plain'
-    self.response_body = 'Hello, World!'
-  end
-end

+ 3 - 0
frameworks/Ruby/rails/config/database.yml

@@ -16,6 +16,9 @@ test:
 production_mysql:
   <<: *default
   adapter: trilogy
+  ssl: true
+  ssl_mode: 4 <%# Trilogy::SSL_PREFERRED_NOVERIFY %>
+  tls_min_version: 3 <%# Trilogy::TLS_VERSION_12 %>
 
 production_postgresql:
   <<: *default

+ 9 - 1
frameworks/Ruby/rails/config/routes.rb

@@ -6,6 +6,14 @@ Rails.application.routes.draw do
   get "queries", to: "hello_world#query"
   get "fortunes", to: "hello_world#fortune"
   get "updates", to: "hello_world#update"
-  get "plaintext", to: PlaintextController.action(:index)
+  get "plaintext", to: ->(env) do
+    [200,
+     {
+       'Content-Type' => 'text/plain',
+       'Date' => Time.now.httpdate,
+       'Server' => 'Rails'
+     },
+     ['Hello, World!']]
+  end
   get "cached", to: "hello_world#cached_query"
 end

+ 1 - 1
frameworks/Ruby/sinatra-sequel/Gemfile

@@ -1,6 +1,6 @@
 source 'https://rubygems.org'
 
-gem 'json', '~> 2.0'
+gem 'oj'
 gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false
 gem 'puma', '~> 6.4', :require=>false
 gem 'sequel', '~> 5.0'

+ 5 - 0
frameworks/Ruby/sinatra-sequel/boot.rb

@@ -1,8 +1,11 @@
 # frozen_string_literal: true
 require 'bundler/setup'
 require 'time'
+require 'oj'
 
 MAX_PK = 10_000
+ID_RANGE = (1..MAX_PK).freeze
+ALL_IDS = ID_RANGE.to_a
 QUERIES_MIN = 1
 QUERIES_MAX = 500
 SEQUEL_NO_ASSOCIATIONS = true
@@ -21,6 +24,8 @@ SERVER_STRING =
 
 Bundler.require(:default) # Load core modules
 
+Oj.mimic_JSON
+
 def connect(dbtype)
   Bundler.require(dbtype) # Load database-specific modules
 

+ 4 - 4
frameworks/Ruby/sinatra-sequel/hello_world.rb

@@ -56,8 +56,8 @@ class HelloWorld < Sinatra::Base
   get '/queries' do
     worlds =
       DB.synchronize do
-        Array.new(bounded_queries) do
-          World.with_pk(rand1)
+        ALL_IDS.sample(bounded_queries).map do |id|
+          World.with_pk(id)
         end
       end
 
@@ -80,8 +80,8 @@ class HelloWorld < Sinatra::Base
   get '/updates' do
     worlds =
       DB.synchronize do
-        Array.new(bounded_queries) do
-          world = World.with_pk(rand1)
+        ALL_IDS.sample(bounded_queries).map do |id|
+          world = World.with_pk(id)
           new_value = rand1
           new_value = rand1 while new_value == world.randomnumber
           world.update(randomnumber: new_value)

+ 1 - 1
frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile

@@ -5,4 +5,4 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile

+ 1 - 1
frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile

@@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile
 
 # TODO: https://github.com/phusion/passenger/issues/1916
 ENV _PASSENGER_FORCE_HTTP_SESSION=true

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

@@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile
 
 # TODO: https://github.com/phusion/passenger/issues/1916
 ENV _PASSENGER_FORCE_HTTP_SESSION=true

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

@@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile
 
 ENV DBTYPE=postgresql
 

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

@@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile
 
 ENV DBTYPE=postgresql
 

+ 1 - 1
frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile

@@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile
 
 ENV DBTYPE=mysql
 

+ 1 - 1
frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile

@@ -5,7 +5,7 @@ ENV RUBY_YJIT_ENABLE=1
 ADD ./ /sinatra-sequel
 WORKDIR /sinatra-sequel
 
-RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle
+RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile
 
 ENV DBTYPE=mysql
 

+ 1 - 1
frameworks/Ruby/sinatra/Gemfile

@@ -1,7 +1,7 @@
 source 'https://rubygems.org'
 
 gem 'activerecord', '~> 7.0', :require=>'active_record'
-gem 'json', '~> 2.0'
+gem 'oj'
 gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false
 gem 'puma', '~> 6.4', :require=>false
 gem 'sinatra', '~> 3.0', :require=>'sinatra/base'

+ 5 - 0
frameworks/Ruby/sinatra/boot.rb

@@ -1,8 +1,11 @@
 # frozen_string_literal: true
 require 'bundler/setup'
 require 'time'
+require 'oj'
 
 MAX_PK = 10_000
+ID_RANGE = (1..MAX_PK).freeze
+ALL_IDS = ID_RANGE.to_a
 QUERIES_MIN = 1
 QUERIES_MAX = 500
 
@@ -20,6 +23,8 @@ SERVER_STRING =
 
 Bundler.require(:default) # Load core modules
 
+Oj.mimic_JSON
+
 def connect(dbtype)
   Bundler.require(dbtype) # Load database-specific modules
 

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