Browse Source

Merge pull request #37 from TechEmpower/master

aa
三刀 8 months ago
parent
commit
6a839e8c6c
34 changed files with 432 additions and 70 deletions
  1. 1 1
      frameworks/Go/goravel/src/fiber/go.mod
  2. 2 1
      frameworks/Go/goravel/src/fiber/go.sum
  3. 1 1
      frameworks/Java/redkale/redkale-pgclient.dockerfile
  4. 1 3
      frameworks/Java/spring-webflux/pom.xml
  5. 1 1
      frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile
  6. 1 1
      frameworks/Java/spring-webflux/spring-webflux.dockerfile
  7. 3 1
      frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java
  8. 8 9
      frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java
  9. 20 17
      frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java
  10. 11 2
      frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java
  11. 1 1
      frameworks/Java/spring-webflux/src/main/resources/application.yml
  12. 1 1
      frameworks/Java/spring/pom.xml
  13. 1 1
      frameworks/Java/spring/spring-mongo.dockerfile
  14. 1 1
      frameworks/Java/spring/spring.dockerfile
  15. 1 1
      frameworks/Java/spring/src/main/resources/application.yml
  16. 75 0
      frameworks/PHP/ripple/README.md
  17. 29 0
      frameworks/PHP/ripple/benchmark_config.json
  18. 9 0
      frameworks/PHP/ripple/composer.json
  19. 18 0
      frameworks/PHP/ripple/fortunes.php
  20. 32 0
      frameworks/PHP/ripple/ripple.dockerfile
  21. 200 0
      frameworks/PHP/ripple/server.php
  22. 1 1
      frameworks/Python/api_hour/requirements.txt
  23. 0 1
      frameworks/Ruby/rails/Gemfile
  24. 1 6
      frameworks/Ruby/rails/Gemfile.lock
  25. 1 1
      frameworks/Ruby/rails/app/controllers/json_controller.rb
  26. 0 1
      frameworks/Ruby/rails/config/initializers/oj.rb
  27. 1 1
      frameworks/Ruby/roda-sequel/Gemfile
  28. 0 1
      frameworks/Ruby/roda-sequel/boot.rb
  29. 4 4
      frameworks/Ruby/roda-sequel/hello_world.rb
  30. 1 1
      frameworks/Ruby/sinatra-sequel/Gemfile
  31. 0 3
      frameworks/Ruby/sinatra-sequel/boot.rb
  32. 1 1
      frameworks/Ruby/sinatra/Gemfile
  33. 0 3
      frameworks/Ruby/sinatra/boot.rb
  34. 5 4
      frameworks/Rust/astra/Cargo.lock

+ 1 - 1
frameworks/Go/goravel/src/fiber/go.mod

@@ -65,7 +65,7 @@ require (
 	github.com/gofiber/template v1.8.3 // indirect
 	github.com/gofiber/template v1.8.3 // indirect
 	github.com/gofiber/template/html/v2 v2.1.1 // indirect
 	github.com/gofiber/template/html/v2 v2.1.1 // indirect
 	github.com/gofiber/utils v1.1.0 // indirect
 	github.com/gofiber/utils v1.1.0 // indirect
-	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+	github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
 	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
 	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
 	github.com/golang-migrate/migrate/v4 v4.17.1 // indirect
 	github.com/golang-migrate/migrate/v4 v4.17.1 // indirect
 	github.com/golang-module/carbon/v2 v2.3.12 // indirect
 	github.com/golang-module/carbon/v2 v2.3.12 // indirect

+ 2 - 1
frameworks/Go/goravel/src/fiber/go.sum

@@ -285,8 +285,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
+github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
 github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
 github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=

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

@@ -12,4 +12,4 @@ COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]
+CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dvertx.disableURIValidation=true", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"]

+ 1 - 3
frameworks/Java/spring-webflux/pom.xml

@@ -13,14 +13,12 @@
     <parent>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.3.4</version>
+        <version>3.3.5</version>
     </parent>
     </parent>
 
 
     <properties>
     <properties>
         <java.version>21</java.version>
         <java.version>21</java.version>
         <jstachio.version>1.3.6</jstachio.version>
         <jstachio.version>1.3.6</jstachio.version>
-        <r2dbc-pool.version>1.0.2.RELEASE</r2dbc-pool.version>
-        <r2dbc-postgresql.version>1.0.7.RELEASE</r2dbc-postgresql.version>
     </properties>
     </properties>
 
 
     <dependencies>
     <dependencies>

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

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 RUN mvn package -q
 RUN mvn package -q
 
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 WORKDIR /spring
 COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar
 COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

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

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 RUN mvn package -q
 RUN mvn package -q
 
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 WORKDIR /spring
 COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar
 COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

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

@@ -1,5 +1,7 @@
 package benchmark.repository;
 package benchmark.repository;
 
 
+import java.util.List;
+
 import benchmark.model.Fortune;
 import benchmark.model.Fortune;
 import benchmark.model.World;
 import benchmark.model.World;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
@@ -9,7 +11,7 @@ public interface DbRepository {
 
 
     Mono<World> getWorld(int id);
     Mono<World> getWorld(int id);
 
 
-    Mono<World> findAndUpdateWorld(int id, int randomNumber);
+    Mono<Void> updateWorlds(List<World> worlds);
 
 
     Flux<Fortune> fortunes();
     Flux<Fortune> fortunes();
 }
 }

+ 8 - 9
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java

@@ -1,16 +1,16 @@
 package benchmark.repository;
 package benchmark.repository;
 
 
+import java.util.List;
+
 import benchmark.model.Fortune;
 import benchmark.model.Fortune;
 import benchmark.model.World;
 import benchmark.model.World;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
 import org.springframework.context.annotation.Profile;
 import org.springframework.context.annotation.Profile;
 import org.springframework.data.mongodb.core.ReactiveMongoOperations;
 import org.springframework.data.mongodb.core.ReactiveMongoOperations;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
-import static org.springframework.data.mongodb.core.FindAndModifyOptions.options;
 import static org.springframework.data.mongodb.core.query.Criteria.where;
 import static org.springframework.data.mongodb.core.query.Criteria.where;
 import static org.springframework.data.mongodb.core.query.Query.query;
 import static org.springframework.data.mongodb.core.query.Query.query;
 import static org.springframework.data.mongodb.core.query.Update.update;
 import static org.springframework.data.mongodb.core.query.Update.update;
@@ -31,12 +31,11 @@ public class MongoDbRepository implements DbRepository {
     }
     }
 
 
     @Override
     @Override
-    public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
-        return operations.findAndModify(
-                query(where("id").is(id)),
-                update("randomNumber", randomNumber),
-                options().returnNew(true),
-                World.class);
+    public Mono<Void> updateWorlds(List<World> worlds) {
+        return Flux.fromIterable(worlds).flatMap(world -> operations.findAndModify(
+                query(where("id").is(world.id)),
+                update("randomNumber", world.randomnumber),
+                World.class)).then();
     }
     }
 
 
     @Override
     @Override

+ 20 - 17
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java

@@ -1,11 +1,17 @@
 package benchmark.repository;
 package benchmark.repository;
 
 
+import java.util.List;
+
 import org.springframework.context.annotation.Profile;
 import org.springframework.context.annotation.Profile;
 import org.springframework.r2dbc.core.DatabaseClient;
 import org.springframework.r2dbc.core.DatabaseClient;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
 import benchmark.model.Fortune;
 import benchmark.model.Fortune;
 import benchmark.model.World;
 import benchmark.model.World;
+import io.r2dbc.spi.Connection;
+import io.r2dbc.spi.ConnectionFactory;
+import io.r2dbc.spi.Result;
+import io.r2dbc.spi.Statement;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Mono;
 
 
@@ -23,28 +29,25 @@ public class R2dbcDbRepository implements DbRepository {
     public Mono<World> getWorld(int id) {
     public Mono<World> getWorld(int id) {
         return databaseClient
         return databaseClient
                 .sql("SELECT id, randomnumber FROM world WHERE id = $1")
                 .sql("SELECT id, randomnumber FROM world WHERE id = $1")
-                .bind("$1", id)
+                .bind(0, id)
                 .mapProperties(World.class)
                 .mapProperties(World.class)
                 .first();
                 .first();
     }
     }
 
 
-    private Mono<World> updateWorld(World world) {
-        return databaseClient
-                .sql("UPDATE world SET randomnumber=$2 WHERE id = $1")
-                .bind("$1", world.id)
-                .bind("$2", world.randomnumber)
-                .fetch()
-                .rowsUpdated()
-                .map(count -> world);
-    }
-
-
     @Override
     @Override
-    public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
-        return getWorld(id).flatMap(world -> {
-            world.randomnumber = randomNumber;
-            return updateWorld(world);
-        });
+    public Mono<Void> updateWorlds(List<World> worlds) {
+        return databaseClient.inConnectionMany(con -> {
+            Statement statement = con.createStatement("UPDATE world SET randomnumber=$2 WHERE id = $1");
+            for (int i = 0; i < worlds.size(); i++) {
+                World world = worlds.get(i);
+                statement.bind(0, world.randomnumber)
+                        .bind(1, world.id);
+                if (i < worlds.size() - 1) {
+                    statement.add();
+                }
+            }
+            return Flux.from(statement.execute());
+        }).flatMap(Result::getRowsUpdated).then();
     }
     }
 
 
     @Override
     @Override

+ 11 - 2
frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java

@@ -1,5 +1,6 @@
 package benchmark.web;
 package benchmark.web;
 
 
+import java.util.Comparator;
 import java.util.List;
 import java.util.List;
 
 
 import benchmark.Utils;
 import benchmark.Utils;
@@ -68,8 +69,16 @@ public class DbHandler {
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
 
 
         Mono<List<World>> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed())
         Mono<List<World>> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed())
-                .flatMap(i -> dbRepository.findAndUpdateWorld(i, Utils.randomWorldNumber()))
-                .collectList();
+                .flatMap(id -> dbRepository.getWorld(id).map(world -> {
+                    int randomNumber;
+                    do {
+                        randomNumber = Utils.randomWorldNumber();
+                    } while (randomNumber == world.randomnumber);
+                    world.randomnumber = randomNumber;
+                    return world;
+                }))
+                .collectSortedList(Comparator.comparingInt(w -> w.id))
+                .flatMap(list -> dbRepository.updateWorlds(list).thenReturn(list));
 
 
         return ServerResponse.ok()
         return ServerResponse.ok()
                 .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                 .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)

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

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

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

@@ -11,7 +11,7 @@
 	<parent>
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>3.3.4</version>
+		<version>3.3.5</version>
 	</parent>
 	</parent>
 
 
 	<properties>
 	<properties>

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

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 RUN mvn package -q
 RUN mvn package -q
 
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 WORKDIR /spring
 COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
 COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

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

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
 RUN mvn package -q
 RUN mvn package -q
 
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 WORKDIR /spring
 COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
 COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

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

@@ -15,7 +15,7 @@ spring:
     username: ${database.username}
     username: ${database.username}
     password: ${database.password}
     password: ${database.password}
     hikari:
     hikari:
-      maximum-pool-size: 256
+      maximum-pool-size: 512
 database:
 database:
   name: hello_world
   name: hello_world
   host: tfb-database
   host: tfb-database

+ 75 - 0
frameworks/PHP/ripple/README.md

@@ -0,0 +1,75 @@
+<p align="center">
+<img src="https://raw.githubusercontent.com/cloudtay/ripple/refs/heads/main/assets/images/logo.png" width="420" alt="Logo">
+</p>
+<p align="center">
+<a href="#"><img src="https://img.shields.io/badge/PHP-%3E%3D%208.1-blue" alt="Build Status"></a>
+<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/dt/cloudtay/ripple" alt="Download statistics"> </a>
+<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/v/cloudtay/ripple" alt="Stable version"> </a>
+<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/l/cloudtay/ripple" alt="License"></a>
+</p>
+<p>
+Ripple is a modern, high-performance native PHP coroutine engine designed to solve PHP's challenges in high concurrency, complex network communication and data operations.
+The engine uses an innovative architecture and efficient programming model to provide powerful and flexible backend support for modern web and web applications.
+By using ripple, you will experience the advantages of managing tasks from a global view of the system and efficiently handling network traffic and data. </p>
+
+## Install
+
+````bash
+composer require cloudtay/ripple
+````
+
+## Latest documentation
+
+You can visit `ripple`’s [documentation](https://ripple.cloudtay.com/) to start reading
+
+We recommend that you start with [Manual Installation](https://ripple.cloudtay.com/docs/install/professional) to better
+understand the workflow of ripple
+
+If you want to quickly deploy and use `ripple` services, you can directly
+visit [Quick Deployment](https://ripple.cloudtay.com/docs/install/server)
+
+## Appendix
+
+### Applicable component library
+
+> We allow users to choose applicable component libraries by themselves. All components can be used as described in the
+> document without additional configuration.
+
+**🚀 [Guzzle](https://docs.guzzlephp.org/en/stable/)**
+PHP is the most widely used HTTP client
+
+**🔥 [AmPHP](https://amphp.org/)**
+Provides rich PHP asynchronous components for users to encapsulate by themselves
+
+**🚀 [Driver](https://github.com/cloudtay/ripple-driver)**
+The official high-performance driver library provides seamless access to your traditional applications.
+
+**🚀 [Webman-coroutine](https://github.com/workbunny/webman-coroutine)**
+The workbunny team's integrated webman coroutine extension provides coroutine support for Webman.
+
+**🟢[ripple](https://github.com/cloudtay/ripple)**
+Provides standard coroutine architecture and tools for rapid development or packaging of traditional applications
+
+### Event Library Guide
+
+| Extension Types | Recommended Use | Compatibility |                                                     Description                                                      |
+|:---------------:|:---------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------:|
+|     `libev`     |       🏅️       |      🟢️      | `Ev` is a more efficient event extension that performs consistently in various systems and is recommended to be used |
+|    `Native`     |        ️        |      🟢       |                                  Support the use of PHP's built-in select mechanism                                  |
+|     `event`     |                 |      🌗       |         The event characteristics under different systems are not uniform, and their use is not recommended          |
+
+## Special thanks
+
+<a href="https://www.jetbrains.com/?from=ripple" target="__blank">
+    <img src="https://www.jetbrains.com/company/brand/img/jetbrains_logo.png" width="200" alt="jetbrains">
+</a>
+
+[Jetbrains](https://www.jetbrains.com/?from=ripple) provides free development tools for this project
+
+### Contact information
+
+`Email` [email protected]
+
+`WeChat` jingnigg
+
+---

+ 29 - 0
frameworks/PHP/ripple/benchmark_config.json

@@ -0,0 +1,29 @@
+{
+  "framework": "ripple",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Fullstack",
+        "database": "MySQL",
+        "framework": "ripple",
+        "language": "PHP",
+        "flavor": "PHP8.3",
+        "orm": "Raw",
+        "platform": "ripple",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "ripple",
+        "notes": "",
+        "versus": "php"
+      }
+    }
+  ]
+}

+ 9 - 0
frameworks/PHP/ripple/composer.json

@@ -0,0 +1,9 @@
+{
+  "require": {
+    "ext-pdo": "*",
+    "cloudtay/ripple-http": "^1.0",
+    "cloudtay/ripple": "^1.0"
+  },
+  "minimum-stability": "beta",
+  "prefer-stable": true
+}

+ 18 - 0
frameworks/PHP/ripple/fortunes.php

@@ -0,0 +1,18 @@
+<?php /*** @var array $rows */?><!DOCTYPE html>
+<html lang="en">
+<head><title>Fortunes</title></head>
+<body>
+<table>
+    <tr>
+        <th>id</th>
+        <th>message</th>
+    </tr>
+    <?php foreach ($rows as $row): ?>
+        <tr>
+            <td><?= \htmlspecialchars($row['id']) ?></td>
+            <td><?= \htmlspecialchars($row['message']) ?></td>
+        </tr>
+    <?php endforeach; ?>
+</table>
+</body>
+</html>

+ 32 - 0
frameworks/PHP/ripple/ripple.dockerfile

@@ -0,0 +1,32 @@
+FROM php:8.3-cli
+
+RUN apt-get update -yqq >> /dev/null
+RUN apt-get install -y libevent-dev \
+    libssl-dev \
+    pkg-config \
+    build-essential \
+    unzip >> /dev/null
+
+RUN docker-php-ext-install pdo_mysql \
+    opcache \
+    posix \
+    pcntl \
+    sockets >> /dev/null
+
+RUN pecl install event >> /dev/null
+
+RUN docker-php-ext-enable posix pcntl sockets
+RUN docker-php-ext-enable --ini-name zz-event.ini event
+
+COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer
+
+# Initialize
+WORKDIR /ripple
+COPY --link . .
+
+# Configure
+RUN composer install --quiet
+
+# Start
+EXPOSE 8080
+ENTRYPOINT ["php","server.php"]

+ 200 - 0
frameworks/PHP/ripple/server.php

@@ -0,0 +1,200 @@
+<?php declare(strict_types=1);
+
+include __DIR__ . '/vendor/autoload.php';
+
+use Ripple\Http\Server;
+use Ripple\Worker\Manager;
+
+use function Co\repeat;
+use function Co\wait;
+
+class Setup
+{
+    public static PDO    $pdo;
+    public static string $dateFormatted;
+
+    public static PDOStatement $queryWorldWhereID;
+    public static PDOStatement $updateWorldRandomNumber;
+    public static PDOStatement $queryFortune;
+
+    public static function dateRefresh(): void
+    {
+        try {
+            $date = new DateTime('now', new DateTimeZone('GMT'));
+        } catch (Throwable $e) {
+            return;
+        }
+        Setup::$dateFormatted = $date->format('D, d M Y H:i:s T');
+    }
+
+
+    /**
+     * @return int
+     */
+    public static function randomInt(): int
+    {
+        try {
+            return \random_int(1, 10000);
+        } catch (Throwable $e) {
+            return mt_rand(1, 10000);
+        }
+    }
+
+    /**
+     * @param mixed $value
+     *
+     * @return int
+     */
+    public static function clamp(mixed $value): int
+    {
+        if (!\is_numeric($value) || $value < 1) {
+            return 1;
+        }
+        if ($value > 500) {
+            return 500;
+        }
+        return \intval($value);
+    }
+
+    /**
+     * @param string $template
+     * @param array  $data
+     *
+     * @return string
+     */
+    public static function render(string $template, array $data = []): string
+    {
+        foreach ($data as $key => $value) {
+            $$key = $value;
+        }
+
+        \ob_start();
+        include $template;
+        return \ob_get_clean();
+    }
+}
+
+$manager = new Manager();
+$worker  = new class() extends \Ripple\Worker {
+    /*** @var \Ripple\Http\Server */
+    public Server $server;
+
+    /**
+     * @param \Ripple\Worker\Manager $manager
+     *
+     * @return void
+     */
+    public function register(Manager $manager): void
+    {
+        $this->count  = 64;
+        $this->server = new Server('http://0.0.0.0:8080');
+    }
+
+    /**
+     * @return void
+     */
+    public function boot(): void
+    {
+        Setup::dateRefresh();
+        repeat(static fn () => Setup::dateRefresh(), 1);
+
+        Setup::$pdo = new \PDO(
+            'mysql:host=tfb-database;port=3306;dbname=hello_world',
+            'benchmarkdbuser',
+            'benchmarkdbpass',
+            [
+                \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
+                \PDO::ATTR_EMULATE_PREPARES   => false,
+                \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
+            ]
+        );
+
+        Setup::$queryWorldWhereID       = Setup::$pdo->prepare('SELECT id, randomNumber FROM World WHERE id = ?');
+        Setup::$updateWorldRandomNumber = Setup::$pdo->prepare('UPDATE World SET randomNumber = ? WHERE id = ?');
+        Setup::$queryFortune            = Setup::$pdo->prepare('SELECT * FROM `Fortune`');
+        $this->server->onRequest(fn (Server\Request $request) => $this->onRequest($request));
+        $this->server->listen();
+    }
+
+    /**
+     * @param \Ripple\Http\Server\Request $request
+     *
+     * @return void
+     */
+    public function onRequest(Server\Request $request): void
+    {
+        switch ($request->SERVER['REQUEST_URI']) {
+            case '/json':
+                $request->respondJson(
+                    ['message' => 'Hello, World!'],
+                    ['Date' => Setup::$dateFormatted]
+                );
+                break;
+
+            case '/db':
+                $statement = Setup::$queryWorldWhereID;
+                $statement->execute([Setup::randomInt()]);
+                $request->respondJson($statement->fetch(), ['Date' => Setup::$dateFormatted]);
+                break;
+
+            case '/queries':
+                $queries   = Setup::clamp($request->GET['queries'] ?? 1);
+                $results   = [];
+                $statement = Setup::$queryWorldWhereID;
+                while ($queries--) {
+                    $statement->execute([Setup::randomInt()]);
+                    $results[] = $statement->fetch();
+                }
+                $request->respondJson($results, ['Date' => Setup::$dateFormatted]);
+
+                break;
+            case '/fortunes':
+                $rows   = Setup::$pdo->query('SELECT * FROM `Fortune`')?->fetchAll();
+                $rows[] = ['id' => 0, 'message' => 'Additional fortune added at request time.'];
+                \usort($rows, function ($a, $b) {
+                    return $a['message'] <=> $b['message'];
+                });
+
+                $request->respondHtml(
+                    Setup::render('fortunes.php', ['rows' => $rows]),
+                    [
+                        'Date'         => Setup::$dateFormatted,
+                        'Content-Type' => 'text/html; charset=UTF-8'
+                    ]
+                );
+                break;
+
+            case '/updates':
+                $queries   = Setup::clamp($request->GET['queries'] ?? 1);
+                $results   = [];
+                $statement = Setup::$queryWorldWhereID;
+                $update    = Setup::$updateWorldRandomNumber;
+                while ($queries--) {
+                    $statement->execute([Setup::randomInt()]);
+                    $row                 = $statement->fetch();
+                    $row['randomNumber'] = Setup::randomInt();
+                    $results[]           = $row;
+                    $update->execute([$row['randomNumber'], $row['id']]);
+                }
+                $request->respondJson($results, ['Date' => Setup::$dateFormatted]);
+                break;
+
+            case '/plaintext':
+                $request->respond(
+                    'Hello, World!',
+                    [
+                        'Content-Type' => 'text/plain; charset=utf-8',
+                        'Date'         => Setup::$dateFormatted
+                    ]
+                );
+                break;
+
+            default:
+                $request->respond('Not Found', [], 404);
+        }
+    }
+};
+
+$manager->addWorker($worker);
+$manager->run();
+wait();

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

@@ -1,4 +1,4 @@
-aiohttp==3.10.2
+aiohttp==3.10.11
 -e git+https://github.com/Eyepea/aiohttp_jinja2.git@c9675e5c1e1ee7741b30aea8d8fbffcde016c7a0#egg=aiohttp_jinja2-master
 -e git+https://github.com/Eyepea/aiohttp_jinja2.git@c9675e5c1e1ee7741b30aea8d8fbffcde016c7a0#egg=aiohttp_jinja2-master
 aiopg==0.7.0
 aiopg==0.7.0
 -e git+https://github.com/Eyepea/API-Hour.git@577abbdcbb8cc2810dad46e260b338b15db4d0e3#egg=api_hour-master
 -e git+https://github.com/Eyepea/API-Hour.git@577abbdcbb8cc2810dad46e260b338b15db4d0e3#egg=api_hour-master

+ 0 - 1
frameworks/Ruby/rails/Gemfile

@@ -1,6 +1,5 @@
 source 'https://rubygems.org'
 source 'https://rubygems.org'
 
 
-gem 'oj', '~> 3.16'
 gem 'rails', '~> 7.2.0'
 gem 'rails', '~> 7.2.0'
 gem 'redis', '~> 5.0'
 gem 'redis', '~> 5.0'
 gem 'tzinfo-data'
 gem 'tzinfo-data'

+ 1 - 6
frameworks/Ruby/rails/Gemfile.lock

@@ -137,7 +137,7 @@ GEM
     irb (1.14.1)
     irb (1.14.1)
       rdoc (>= 4.0.0)
       rdoc (>= 4.0.0)
       reline (>= 0.4.2)
       reline (>= 0.4.2)
-    json (2.7.2)
+    json (2.8.1)
     kgio (2.11.4)
     kgio (2.11.4)
     localhost (1.3.1)
     localhost (1.3.1)
     logger (1.6.1)
     logger (1.6.1)
@@ -172,11 +172,7 @@ GEM
       racc (~> 1.4)
       racc (~> 1.4)
     nokogiri (1.16.7-x86_64-linux)
     nokogiri (1.16.7-x86_64-linux)
       racc (~> 1.4)
       racc (~> 1.4)
-    oj (3.16.6)
-      bigdecimal (>= 3.0)
-      ostruct (>= 0.2)
     openssl (3.2.0)
     openssl (3.2.0)
-    ostruct (0.6.0)
     pg (1.5.8)
     pg (1.5.8)
     process-metrics (0.3.0)
     process-metrics (0.3.0)
       console (~> 1.8)
       console (~> 1.8)
@@ -275,7 +271,6 @@ PLATFORMS
 DEPENDENCIES
 DEPENDENCIES
   agoo
   agoo
   falcon (~> 0.47)
   falcon (~> 0.47)
-  oj (~> 3.16)
   pg (~> 1.5)
   pg (~> 1.5)
   puma (~> 6.4)
   puma (~> 6.4)
   rackup
   rackup

+ 1 - 1
frameworks/Ruby/rails/app/controllers/json_controller.rb

@@ -4,6 +4,6 @@ class JsonController < ApplicationControllerMetal
   def index
   def index
     add_headers
     add_headers
     self.content_type = 'application/json'
     self.content_type = 'application/json'
-    self.response_body = Oj.dump({ 'message' => 'Hello, World!' })
+    self.response_body = { 'message' => 'Hello, World!' }.to_json
   end
   end
 end
 end

+ 0 - 1
frameworks/Ruby/rails/config/initializers/oj.rb

@@ -1 +0,0 @@
-Oj.optimize_rails

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

@@ -2,13 +2,13 @@ source "https://rubygems.org"
 
 
 gem 'base64' # required by passenger on Ruby 3.4
 gem 'base64' # required by passenger on Ruby 3.4
 gem "erubi", "~> 1.12"
 gem "erubi", "~> 1.12"
+gem "json", "~> 2.8"
 gem "passenger", "~> 6.0", platforms: %i[ruby mswin], require: false
 gem "passenger", "~> 6.0", platforms: %i[ruby mswin], require: false
 gem "puma", "~> 6.2", require: false
 gem "puma", "~> 6.2", require: false
 gem "sequel", "~> 5.67"
 gem "sequel", "~> 5.67"
 gem "roda", "~> 3.66"
 gem "roda", "~> 3.66"
 gem "tilt", "~> 2.1", require: "tilt/erb"
 gem "tilt", "~> 2.1", require: "tilt/erb"
 gem "unicorn", "~> 6.1", platforms: %i[ruby mswin], require: false
 gem "unicorn", "~> 6.1", platforms: %i[ruby mswin], require: false
-gem "rapidjson"
 
 
 group :mysql do
 group :mysql do
   gem "mysql2", "~> 0.5", platforms: %i[ruby mswin]
   gem "mysql2", "~> 0.5", platforms: %i[ruby mswin]

+ 0 - 1
frameworks/Ruby/roda-sequel/boot.rb

@@ -1,7 +1,6 @@
 # frozen_string_literal: true
 # frozen_string_literal: true
 require "bundler/setup"
 require "bundler/setup"
 require "time"
 require "time"
-require "rapidjson"
 MAX_PK = 10_000
 MAX_PK = 10_000
 QUERY_RANGE = (1..MAX_PK).freeze
 QUERY_RANGE = (1..MAX_PK).freeze
 ALL_IDS = QUERY_RANGE.to_a
 ALL_IDS = QUERY_RANGE.to_a

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

@@ -22,13 +22,13 @@ class HelloWorld < Roda
     # Test type 1: JSON serialization
     # Test type 1: JSON serialization
     r.is "json" do
     r.is "json" do
       response[CONTENT_TYPE] = JSON_TYPE
       response[CONTENT_TYPE] = JSON_TYPE
-      RapidJSON.encode({ message: "Hello, World!" })
+      { message: "Hello, World!" }.to_json
     end
     end
 
 
     # Test type 2: Single database query
     # Test type 2: Single database query
     r.is "db" do
     r.is "db" do
       response[CONTENT_TYPE] = JSON_TYPE
       response[CONTENT_TYPE] = JSON_TYPE
-      RapidJSON.encode(World.with_pk(rand1).values)
+      World.with_pk(rand1).values.to_json
     end
     end
 
 
     # Test type 3: Multiple database queries
     # Test type 3: Multiple database queries
@@ -40,7 +40,7 @@ class HelloWorld < Roda
             World.with_pk(id).values
             World.with_pk(id).values
           end
           end
         end
         end
-      RapidJSON.encode(worlds)
+      worlds.to_json
     end
     end
 
 
     # Test type 4: Fortunes
     # Test type 4: Fortunes
@@ -70,7 +70,7 @@ class HelloWorld < Roda
           end
           end
         World.batch_update(worlds)
         World.batch_update(worlds)
       end
       end
-      RapidJSON.encode(worlds.map!(&:values))
+      worlds.map!(&:values).to_json
     end
     end
 
 
     # Test type 6: Plaintext
     # Test type 6: Plaintext

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

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

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

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

+ 1 - 1
frameworks/Ruby/sinatra/Gemfile

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

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

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

+ 5 - 4
frameworks/Rust/astra/Cargo.lock

@@ -268,11 +268,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 
 [[package]]
 [[package]]
 name = "libmimalloc-sys"
 name = "libmimalloc-sys"
-version = "0.1.24"
+version = "0.1.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7705fc40f6ed493f73584abbb324e74f96b358ff60dfe5659a0f8fc12c590a69"
+checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44"
 dependencies = [
 dependencies = [
  "cc",
  "cc",
+ "libc",
 ]
 ]
 
 
 [[package]]
 [[package]]
@@ -292,9 +293,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
 
 [[package]]
 [[package]]
 name = "mimalloc"
 name = "mimalloc"
-version = "0.1.28"
+version = "0.1.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0dfa131390c2f6bdb3242f65ff271fcdaca5ff7b6c08f28398be7f2280e3926"
+checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c"
 dependencies = [
 dependencies = [
  "libmimalloc-sys",
  "libmimalloc-sys",
 ]
 ]