Browse Source

Merge pull request #30 from TechEmpower/master

aa
三刀 1 year ago
parent
commit
0b41bd0ec9
100 changed files with 764 additions and 2678 deletions
  1. 2 2
      .github/workflows/build.yml
  2. 37 0
      .github/workflows/get-maintainers.yml
  3. 49 0
      .github/workflows/ping-maintainers.yml
  4. 3 1
      .gitignore
  5. 34 32
      Dockerfile
  6. 5 4
      entrypoint.sh
  7. 2 1
      frameworks/C++/cppcms/config-nginx-mysql.json
  8. 2 1
      frameworks/C++/cppcms/config-nginx-postgresql.json
  9. 6 15
      frameworks/C++/cppcms/nginx.conf
  10. 5 4
      frameworks/C++/cutelyst/build.sh
  11. 2 2
      frameworks/C++/cutelyst/src/CMakeLists.txt
  12. 3 3
      frameworks/C++/cutelyst/src/cachedqueries.cpp
  13. 18 23
      frameworks/C++/cutelyst/src/cutelyst-benchmarks.cpp
  14. 21 21
      frameworks/C++/cutelyst/src/databaseupdatestest.cpp
  15. 23 23
      frameworks/C++/cutelyst/src/fortunetest.cpp
  16. 1 1
      frameworks/C++/cutelyst/src/jsontest.cpp
  17. 11 11
      frameworks/C++/cutelyst/src/multipledatabasequeriestest.cpp
  18. 2 2
      frameworks/C++/cutelyst/src/plaintexttest.cpp
  19. 7 7
      frameworks/C++/cutelyst/src/singledatabasequerytest.cpp
  20. 9 0
      frameworks/C++/reactor/README.md
  21. 23 0
      frameworks/C++/reactor/benchmark_config.json
  22. 14 0
      frameworks/C++/reactor/config.toml
  23. 37 0
      frameworks/C++/reactor/reactor.dockerfile
  24. 120 0
      frameworks/C++/reactor/techempower.cpp
  25. 0 4
      frameworks/C++/treefrog/benchmark_config.json
  26. 8 4
      frameworks/C++/userver/userver-bare.dockerfile
  27. 8 4
      frameworks/C++/userver/userver.dockerfile
  28. 7 0
      frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp
  29. 11 0
      frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp
  30. 11 7
      frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp
  31. 4 0
      frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.hpp
  32. 20 20
      frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp
  33. 4 0
      frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp
  34. 3 2
      frameworks/C++/userver/userver_benchmark/controllers/plaintext/handler.cpp
  35. 16 8
      frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp
  36. 4 0
      frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp
  37. 27 23
      frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp
  38. 4 0
      frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp
  39. 6 3
      frameworks/C++/userver/userver_configs/dynamic_config_fallback.json
  40. 17 8
      frameworks/C++/userver/userver_configs/static_config.yaml
  41. 1 1
      frameworks/C/h2o/h2o.dockerfile
  42. 95 97
      frameworks/C/h2o/src/database.c
  43. 4 0
      frameworks/C/h2o/src/database.h
  44. 26 3
      frameworks/C/h2o/src/event_loop.c
  45. 11 1
      frameworks/C/h2o/src/event_loop.h
  46. 0 5
      frameworks/C/h2o/src/global_data.h
  47. 1 0
      frameworks/C/h2o/src/handlers/world.c
  48. 6 36
      frameworks/C/h2o/src/main.c
  49. 0 2
      frameworks/C/h2o/src/request_handler.c
  50. 0 1
      frameworks/C/h2o/src/request_handler.h
  51. 4 5
      frameworks/C/h2o/src/thread.c
  52. 30 10
      frameworks/CSharp/aspnetcore/Benchmarks.sln
  53. 0 23
      frameworks/CSharp/aspnetcore/Benchmarks/Benchmarks.csproj
  54. 0 22
      frameworks/CSharp/aspnetcore/Benchmarks/Benchmarks.sln
  55. 0 11
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/AppSettings.cs
  56. 0 14
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleArgs.cs
  57. 0 79
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleHostScenariosConfiguration.cs
  58. 0 17
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/EnabledScenario.cs
  59. 0 9
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/IScenariosConfiguration.cs
  60. 0 163
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/Scenarios.cs
  61. 0 32
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/FortunesController.cs
  62. 0 45
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/HomeController.cs
  63. 0 39
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/MultipleQueriesController.cs
  64. 0 39
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/MultipleUpdatesController.cs
  65. 0 38
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/SingleQueryController.cs
  66. 0 40
      frameworks/CSharp/aspnetcore/Benchmarks/Data/BatchUpdateString.cs
  67. 0 107
      frameworks/CSharp/aspnetcore/Benchmarks/Data/DapperDb.cs
  68. 0 30
      frameworks/CSharp/aspnetcore/Benchmarks/Data/Fortune.cs
  69. 0 15
      frameworks/CSharp/aspnetcore/Benchmarks/Data/IDb.cs
  70. 0 29
      frameworks/CSharp/aspnetcore/Benchmarks/Data/Random.cs
  71. 0 153
      frameworks/CSharp/aspnetcore/Benchmarks/Data/RawDb.cs
  72. 0 57
      frameworks/CSharp/aspnetcore/Benchmarks/Data/StringBuilderCache.cs
  73. 0 45
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesDapperMiddleware.cs
  74. 0 45
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesEfMiddleware.cs
  75. 0 45
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesRawMiddleware.cs
  76. 0 47
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/JsonMiddleware.cs
  77. 0 52
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MiddlewareHelpers.cs
  78. 0 52
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesDapperMiddleware.cs
  79. 0 52
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesEfMiddleware.cs
  80. 0 52
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesRawMiddleware.cs
  81. 0 51
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleUpdatesDapperMiddleware.cs
  82. 0 51
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleUpdatesEfMiddleware.cs
  83. 0 52
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleUpdatesRawMiddleware.cs
  84. 0 47
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/PlaintextMiddleware.cs
  85. 0 50
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryDapperMiddleware.cs
  86. 0 49
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryEfMiddleware.cs
  87. 0 50
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryRawMiddleware.cs
  88. 0 31
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.Designer.cs
  89. 0 32
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.cs
  90. 0 42
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.Designer.cs
  91. 0 32
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.cs
  92. 0 41
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/ApplicationDbContextModelSnapshot.cs
  93. 0 68
      frameworks/CSharp/aspnetcore/Benchmarks/Program.cs
  94. 0 208
      frameworks/CSharp/aspnetcore/Benchmarks/Startup.cs
  95. 0 5
      frameworks/CSharp/aspnetcore/Benchmarks/Views/Home/Index.cshtml
  96. 0 3
      frameworks/CSharp/aspnetcore/Benchmarks/appsettings.json
  97. 0 4
      frameworks/CSharp/aspnetcore/Benchmarks/appsettings.postgresql.updates.json
  98. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/1KB.txt
  99. 0 67
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs
  100. 0 46
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs

+ 2 - 2
.github/workflows/build.yml

@@ -48,7 +48,7 @@ jobs:
           echo "PREVIOUS_COMMIT=$(git log --format=%H -n 1 HEAD^2~1)" >> $GITHUB_ENV
       - uses: actions/setup-python@v4
         with:
-          python-version: '2.7'
+          python-version: '3.10'
           architecture: 'x64'
       - name: Get all changes vs master
         env:
@@ -115,7 +115,7 @@ jobs:
           fetch-depth: 10
       - uses: actions/setup-python@v4
         with:
-          python-version: '2.7'
+          python-version: '3.10'
           architecture: 'x64'
       - name: Get all changes vs master
         # Runs github_actions_diff, with the the output accessible in later steps

+ 37 - 0
.github/workflows/get-maintainers.yml

@@ -0,0 +1,37 @@
+name: get-maintainers
+on: 
+  pull_request:
+    types: [opened, reopened]
+permissions:
+  pull-requests: write
+jobs:
+  get_maintainers:
+    runs-on: ubuntu-22.04
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          fetch-depth: 10
+      - name: Get commit branch and commit message from PR
+        run: |
+          echo "BRANCH_NAME=$GITHUB_HEAD_REF" >> $GITHUB_ENV
+          echo "TARGET_BRANCH_NAME=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_ENV
+          echo "COMMIT_MESSAGE<<EOF" >> $GITHUB_ENV
+          echo "$(git log --format=%B -n 1 HEAD^2)" >> $GITHUB_ENV
+          echo "EOF" >> $GITHUB_ENV
+          echo "PREVIOUS_COMMIT=$(git log --format=%H -n 1 HEAD^2~1)" >> $GITHUB_ENV
+      - uses: actions/setup-python@v4
+        with:
+          python-version: '3.10'
+          architecture: 'x64'
+      - name: Save PR number
+        run: |
+          mkdir -p ./maintainers
+          echo ${{ github.event.number }} > ./maintainers/NR
+      - name: Get Maintainers
+        run: |
+          python ./toolset/github_actions/get_maintainers.py > ./maintainers/maintainers.md
+      - name: Save Maintainers
+        uses: actions/upload-artifact@v3
+        with:
+          name: maintainers
+          path: maintainers/

+ 49 - 0
.github/workflows/ping-maintainers.yml

@@ -0,0 +1,49 @@
+name: Ping Maintainers
+on:
+  workflow_run:
+    workflows: [ "get-maintainers"]
+    types:
+      - completed
+permissions:
+  pull-requests: write
+jobs:
+  ping_maintainers:
+    runs-on: ubuntu-22.04
+    steps:
+      - name: 'Download maintainers artifact'
+        uses: actions/github-script@v6
+        with:
+          script: |
+            let artifacts = await github.rest.actions.listWorkflowRunArtifacts({
+               owner: context.repo.owner,
+               repo: context.repo.repo,
+               run_id: ${{github.event.workflow_run.id }},
+            });
+            let matchArtifact = artifacts.data.artifacts.filter((artifact) => {
+              return artifact.name == "maintainers"
+            })[0];
+            let download = await github.rest.actions.downloadArtifact({
+               owner: context.repo.owner,
+               repo: context.repo.repo,
+               artifact_id: matchArtifact.id,
+               archive_format: 'zip',
+            });
+            let fs = require('fs');
+            fs.writeFileSync('${{github.workspace}}/maintainers.zip', Buffer.from(download.data));
+      - run: unzip maintainers.zip
+      - name: Ping maintainers
+        uses: actions/github-script@v6
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            let fs = require('fs');
+            let issue_number = Number(fs.readFileSync('./NR'));
+            let maintainers_comment = fs.readFileSync('./maintainers.md', 'utf8');
+            if (maintainers_comment) {
+              await github.rest.issues.createComment({
+                issue_number: issue_number,
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                body: maintainers_comment
+              });
+            }

+ 3 - 1
.gitignore

@@ -33,6 +33,7 @@ build/
 *.patch
 */bin/
 
+
 # intellij
 *.iml
 *.ipr
@@ -57,7 +58,8 @@ benchmark.cfg
 
 # Visual Studio Code
 .vscode
-.history
+.history/
+.devcontainer
 
 # vim
 .*.sw[a-p]

+ 34 - 32
Dockerfile

@@ -1,58 +1,60 @@
 FROM ubuntu:22.04
 
-ARG USER_ID
-ARG GROUP_ID
 ARG DEBIAN_FRONTEND=noninteractive
-
-#RUN add-apt-repository universe
 # WARNING: DON'T PUT A SPACE AFTER ANY BACKSLASH OR APT WILL BREAK
 # One -q produces output suitable for logging (mostly hides
 # progress indicators)
-RUN apt-get -yqq update && apt-get -yqq install \
-      -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \
+RUN apt-get -yqq update && \
+    apt-get -yqq install \
+      -o Dpkg::Options::="--force-confdef" \
+      -o Dpkg::Options::="--force-confold" \
       cloc \
       curl \
-      dstat                       `# Collect resource usage statistics` \
       gcc \
       git-core \
       gosu \
-      libmysqlclient-dev          `# Needed for MySQL-python` \
+      # Needed for mysqlclient
+      libmysqlclient-dev \
       libpq-dev \
-      python2 \
-      python2.7-dev \
+      pkg-config \
+      python3 \
+      python3-dev \
+      python3-pip \
       siege \
       software-properties-common
 
-RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
-RUN python2 get-pip.py
-
-RUN curl https://raw.githubusercontent.com/paulfitz/mysql-connector-c/master/include/my_config.h --output /usr/include/mysql/my_config.h
-
-RUN pip install \
+RUN pip3 install \
       colorama==0.3.1 \
       docker==4.0.2 \
-      MySQL-python \
+      mysqlclient \
       psutil \
       psycopg2-binary \
-      pymongo \
-      requests
-    # Fix for docker-py trying to import one package from the wrong location
-    #cp -r /usr/local/lib/python2.7/dist-packages/backports/ssl_match_hostname \
-    #  /usr/lib/python2.7/dist-packages/backports
+      pymongo==3.13.0 \
+      # urllib3 incompatibility:
+      # https://github.com/docker/docker-py/issues/3113#issuecomment-1525500104
+      requests==2.28.1
+
+# Collect resource usage statistics
+ARG DOOL_VERSION=v1.2.0
 
-ENV FWROOT=/FrameworkBenchmarks PYTHONPATH=/FrameworkBenchmarks
+WORKDIR /tmp
+RUN curl -LSs "https://github.com/scottchiefbaker/dool/archive/${DOOL_VERSION}.tar.gz" | \
+      tar --strip-components=1 -xz && \
+    ./install.py
 
-# Check if Group is already created
-RUN if ! getent group $GROUP_ID; then \
-      addgroup --gid $GROUP_ID user; \
+# Check if the group ID is already created
+ARG GROUP_ID
+RUN if ! getent group "$GROUP_ID"; then \
+      addgroup --gid "$GROUP_ID" user; \
     fi
 
-# Drop permissions of user to match those of the host system
-# Check if the User ID is already created
-RUN if ! getent passwd $USER_ID; then \
-      adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user; \
+# Check if the user ID is already created
+ARG USER_ID
+RUN if ! getent passwd "$USER_ID"; then \
+      adduser --disabled-password --gecos '' --gid "$GROUP_ID" --uid "$USER_ID" user; \
     fi
 
-ENV USER_ID=$USER_ID
+ENV FWROOT=/FrameworkBenchmarks USER_ID="$USER_ID"
+ENV PYTHONPATH="$FWROOT"
 
-ENTRYPOINT ["/bin/bash", "FrameworkBenchmarks/entrypoint.sh" ]
+ENTRYPOINT ["/FrameworkBenchmarks/entrypoint.sh"]

+ 5 - 4
entrypoint.sh

@@ -1,6 +1,7 @@
-#!/usr/bin/env bash
-set -euox pipefail
+#!/bin/bash
 
-chown -R $USER_ID /var/run/
+set -eo pipefail -u
 
-gosu $USER_ID python2 /FrameworkBenchmarks/toolset/run-tests.py "$@"
+chown -LR "$USER_ID" /var/run
+# Drop permissions of user to match those of the host system
+gosu "$USER_ID" python3 "${FWROOT}/toolset/run-tests.py" "$@"

+ 2 - 1
frameworks/C++/cppcms/config-nginx-mysql.json

@@ -4,7 +4,8 @@
     },
     "service": {
         "api": "fastcgi",
-        "socket": "/var/tmp/cppcms.sock"
+        "socket": "/var/tmp/cppcms.sock",
+        "backlog": 65535
     },
     "http": {
         "script": "/"

+ 2 - 1
frameworks/C++/cppcms/config-nginx-postgresql.json

@@ -4,7 +4,8 @@
     },
     "service": {
         "api": "fastcgi",
-        "socket": "/var/tmp/cppcms.sock"
+        "socket": "/var/tmp/cppcms.sock",
+        "backlog": 65535
     },
     "http": {
         "script": "/"

+ 6 - 15
frameworks/C++/cppcms/nginx.conf

@@ -7,32 +7,23 @@ error_log stderr error;
 events {
     # This needed to be increased because the nginx error log said so.
     # http://nginx.org/en/docs/ngx_core_module.html#worker_connections
-    worker_connections  65535;
+    worker_connections 65535;
     multi_accept on;
 }
 
 http {
     default_type  application/octet-stream;
     client_body_temp_path      /tmp;
-
-    # turn off request logging for performance
     access_log off;
+    server_tokens off;
 
-    # I think these only options affect static file serving
-    sendfile        on;
-    tcp_nopush      on;
+    sendfile on;
+    tcp_nopush on;
 
-    # Allow many HTTP Keep-Alive requests in a single TCP connection before
-    # closing it (the default is 100). This will minimize the total number
-    # of TCP connections opened/closed. The problem is that this may cause
-    # some worker processes to be handling too connections relative to the
-    # other workers based on an initial imbalance, so this is disabled for
-    # now.
+    keepalive_timeout 65;
+    keepalive_disable none;
     keepalive_requests 1000;
 
-    #keepalive_timeout  0;
-    keepalive_timeout  65;
-
     server {
         # For information on deferred, see:
         # http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

+ 5 - 4
frameworks/C++/cutelyst/build.sh

@@ -1,8 +1,9 @@
 #!/bin/bash
 
-export ASQL_VER=0.74.0
+export ASQL_VER=0.84.0
 export CUTELEE_VER=6.1.0
-export CUTELYST_VER=3.7.0
+export CUTELYST_TAG=v4.0.0-alpha1
+export CUTELYST_VER=4.0.0
 
 apt update -qq && \
     apt install -yqq --no-install-recommends \
@@ -21,8 +22,8 @@ wget -q https://github.com/cutelyst/cutelee/releases/download/v${CUTELEE_VER}/cu
 wget -q https://github.com/cutelyst/asql/releases/download/v${ASQL_VER}/libasql0-qt6_${ASQL_VER}_amd64.deb && \
     apt install -yqq ./libasql0-qt6_${ASQL_VER}_amd64.deb
 
-wget -q https://github.com/cutelyst/cutelyst/releases/download/v${CUTELYST_VER}/cutelyst3-qt6_${CUTELYST_VER}_amd64.deb && \
-    apt install -yqq ./cutelyst3-qt6_${CUTELYST_VER}_amd64.deb
+wget -q https://github.com/cutelyst/cutelyst/releases/download/${CUTELYST_TAG}/cutelyst4-qt6_${CUTELYST_VER}_amd64.deb && \
+    apt install -yqq ./cutelyst4-qt6_${CUTELYST_VER}_amd64.deb
 
 cd ${TROOT} && \
     mkdir -p build && \

+ 2 - 2
frameworks/C++/cutelyst/src/CMakeLists.txt

@@ -14,8 +14,8 @@ FetchContent_Declare(
 FetchContent_MakeAvailable(mimalloc)
 
 find_package(Qt6 6.2.0 REQUIRED COMPONENTS Core Network Sql)
-find_package(ASqlQt6 0.74 REQUIRED)
-find_package(Cutelyst3Qt6 3.6 REQUIRED)
+find_package(ASqlQt6 0.84 REQUIRED)
+find_package(Cutelyst4Qt6 3.6 REQUIRED)
 find_package(Cutelee6Qt6 6.1.0 REQUIRED)
 find_package(PostgreSQL REQUIRED)
 

+ 3 - 3
frameworks/C++/cutelyst/src/cachedqueries.cpp

@@ -20,7 +20,7 @@ CachedQueries::CachedQueries(QObject *parent)
 
 void CachedQueries::cached_queries(Context *c)
 {
-    int queries = c->request()->queryParam(QStringLiteral("count")).toInt();
+    int queries = c->request()->queryParam(u"count"_qs).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -48,8 +48,8 @@ void CachedQueries::cached_queries(Context *c)
                 auto it = result.begin();
                 int id = it[0].toInt();
                 auto obj = new QJsonObject({
-                                               {QStringLiteral("id"), id},
-                                               {QStringLiteral("randomNumber"), it[1].toInt()}
+                                               {u"id"_qs, id},
+                                               {u"randomNumber"_qs, it[1].toInt()}
                                            });
                 array->append(*obj);
                 cache.insert(id, obj, 1);

+ 18 - 23
frameworks/C++/cutelyst/src/cutelyst-benchmarks.cpp

@@ -40,7 +40,7 @@ cutelyst_benchmarks::~cutelyst_benchmarks()
 
 bool cutelyst_benchmarks::init()
 {
-    if (config(QStringLiteral("SendDate")).value<bool>()) {
+    if (config(u"SendDate"_qs).value<bool>()) {
         qDebug() << "Manually send date";
         auto dateT = new QTimer(this);
         dateT->setInterval(1000);
@@ -63,9 +63,9 @@ bool cutelyst_benchmarks::init()
     new CachedQueries(this);
 
     if (defaultHeaders().server().isEmpty()) {
-        defaultHeaders().setServer(QStringLiteral("Cutelyst"));
+        defaultHeaders().setServer("Cutelyst"_qba);
     }
-    defaultHeaders().removeHeader(QStringLiteral("X-Cutelyst"));
+    defaultHeaders().removeHeader("X-Cutelyst");
 
     return true;
 }
@@ -75,48 +75,43 @@ bool cutelyst_benchmarks::postFork()
     QMutexLocker locker(&mutex); // QSqlDatabase::addDatabase is not thread-safe
 
     QSqlDatabase db;
-    const auto driver = config(QStringLiteral("Driver")).toString();
+    const auto driver = config(u"Driver"_qs).toString();
     if (driver == u"QPSQL") {
-        db = QSqlDatabase::addDatabase(driver, Sql::databaseNameThread(QStringLiteral("postgres")));
-        db.setDatabaseName(QStringLiteral("hello_world"));
-        db.setUserName(QStringLiteral("benchmarkdbuser"));
-        db.setPassword(QStringLiteral("benchmarkdbpass"));
-        db.setHostName(config(QStringLiteral("DatabaseHostName")).toString());
+        db = QSqlDatabase::addDatabase(driver, Sql::databaseNameThread(u"postgres"_qs));
+        db.setDatabaseName(u"hello_world"_qs);
+        db.setUserName(u"benchmarkdbuser"_qs);
+        db.setPassword(u"benchmarkdbpass"_qs);
+        db.setHostName(config(u"DatabaseHostName"_qs).toString());
         if (!db.open()) {
             qDebug() << "Error opening PostgreSQL db:" << db << db.connectionName() << db.lastError().databaseText();
             return false;
         }
     } else if (driver == u"QMYSQL") {
-        db = QSqlDatabase::addDatabase(driver, Sql::databaseNameThread(QStringLiteral("mysql")));
-        db.setDatabaseName(QStringLiteral("hello_world"));
-        db.setUserName(QStringLiteral("benchmarkdbuser"));
-        db.setPassword(QStringLiteral("benchmarkdbpass"));
-        db.setHostName(config(QStringLiteral("DatabaseHostName")).toString());
+        db = QSqlDatabase::addDatabase(driver, Sql::databaseNameThread(u"mysql"_qs));
+        db.setDatabaseName(u"hello_world"_qs);
+        db.setUserName(u"benchmarkdbuser"_qs);
+        db.setPassword(u"benchmarkdbpass"_qs);
+        db.setHostName(config(u"DatabaseHostName"_qs).toString());
         if (!db.open()) {
             qDebug() << "Error opening MySQL db:" << db << db.connectionName() << db.lastError().databaseText();
             return false;
         }
     } else if (driver == u"postgres") {
-        QUrl uri(QStringLiteral("postgresql://benchmarkdbuser:benchmarkdbpass@server/hello_world"));
-        uri.setHost(config(QStringLiteral("DatabaseHostName")).toString());
+        QUrl uri(u"postgresql://benchmarkdbuser:benchmarkdbpass@server/hello_world"_qs);
+        uri.setHost(config(u"DatabaseHostName"_qs).toString());
         qDebug() << "ASql URI:" << uri.toString();
 
         APool::create(ASql::APg::factory(uri.toString()));
         APool::setMaxIdleConnections(128);
-        APool::setSetupCallback([](ADatabase &db) {
+        APool::setSetupCallback([](ADatabase db) {
             // Enable Pipeline mode
             db.enterPipelineMode(500);
         });
     }
 
     qDebug() << "Connections" << QCoreApplication::applicationPid() << QThread::currentThread() << QSqlDatabase::connectionNames();
-//    db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("sqlite"));
-//    if (!db.open()) {
-//        qDebug() << "Error opening db:" << db << db.lastError().databaseText();
-//        return false;
-//    }
 
     return true;
 }
 
-//#include "moc_cutelyst-benchmarks.cpp"
+#include "moc_cutelyst-benchmarks.cpp"

+ 21 - 21
frameworks/C++/cutelyst/src/databaseupdatestest.cpp

@@ -25,7 +25,7 @@ DatabaseUpdatesTest::DatabaseUpdatesTest(QObject *parent) : Controller(parent)
 
 void DatabaseUpdatesTest::updatep(Context *c)
 {
-    int queries = c->request()->queryParam(QStringLiteral("queries"), QStringLiteral("1")).toInt();
+    int queries = c->request()->queryParam(u"queries"_qs, u"1"_qs).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -66,7 +66,7 @@ void DatabaseUpdatesTest::updatep(Context *c)
 
 void DatabaseUpdatesTest::updateb(Context *c)
 {
-    int queries = c->request()->queryParam(QStringLiteral("queries"), QStringLiteral("1")).toInt();
+    int queries = c->request()->queryParam(u"queries"_qs, u"1"_qs).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -117,22 +117,22 @@ void DatabaseUpdatesTest::updateb(Context *c)
 void DatabaseUpdatesTest::updates_postgres(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, randomNumber FROM world WHERE id = :id"),
-                QStringLiteral("postgres"));
+                u"SELECT id, randomNumber FROM world WHERE id = :id"_qs,
+                u"postgres"_qs);
     QSqlQuery updateQuery = CPreparedSqlQueryThreadForDB(
-                QLatin1String("UPDATE world SET randomNumber = :randomNumber WHERE id = :id"),
-                QStringLiteral("postgres"));
+                u"UPDATE world SET randomNumber = :randomNumber WHERE id = :id"_qs,
+                u"postgres"_qs);
     processQuery(c, query, updateQuery);
 }
 
 void DatabaseUpdatesTest::updates_mysql(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT randomNumber, id FROM world WHERE id = :id"),
-                QStringLiteral("mysql"));
+                u"SELECT randomNumber, id FROM world WHERE id = :id"_qs,
+                u"mysql"_qs);
     QSqlQuery updateQuery = CPreparedSqlQueryThreadForDB(
-                QLatin1String("UPDATE world SET randomNumber = :randomNumber WHERE id = :id"),
-                QStringLiteral("mysql"));
+                u"UPDATE world SET randomNumber = :randomNumber WHERE id = :id"_qs,
+                u"mysql"_qs);
     processQuery(c, query, updateQuery);
 }
 
@@ -140,7 +140,7 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
 {
     QJsonArray array;
 
-    int queries = c->request()->queryParam(QStringLiteral("queries"), QStringLiteral("1")).toInt();
+    int queries = c->request()->queryParam(u"queries"_qs, u"1"_qs).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -153,7 +153,7 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
     for (int i = 0; i < queries; ++i) {
         int id = (rand() % 10000) + 1;
 
-        query.bindValue(QStringLiteral(":id"), id);
+        query.bindValue(u":id"_qs, id);
         if (Q_UNLIKELY(!query.exec() || !query.next())) {
             c->res()->setStatus(Response::InternalServerError);
             return;
@@ -164,13 +164,13 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
         randomNumbers.append(randomNumber);
 
         array.append(QJsonObject{
-                         {QStringLiteral("id"), id},
-                         {QStringLiteral("randomNumber"), randomNumber}
+                         {u"id"_qs, id},
+                         {u"randomNumber"_qs, randomNumber}
                      });
     }
 
-    updateQuery.bindValue(QStringLiteral(":id"), ids);
-    updateQuery.bindValue(QStringLiteral(":randomNumber"), randomNumbers);
+    updateQuery.bindValue(u":id"_qs, ids);
+    updateQuery.bindValue(u":randomNumber"_qs, randomNumbers);
     if (Q_LIKELY(updateQuery.execBatch())) {
         c->response()->setJsonArrayBody(array);
     } else {
@@ -182,24 +182,24 @@ APreparedQuery DatabaseUpdatesTest::getSql(int count)
 {
     auto iter = m_sqlMap.find(count);
     if (Q_UNLIKELY(iter == m_sqlMap.end())) {
-        QString sql = QStringLiteral("UPDATE WORLD SET randomnumber=CASE id ");
+        QString sql = u"UPDATE WORLD SET randomnumber=CASE id "_qs;
         sql.reserve(80 + count * 25);
         int placeholdersCounter = 1;
         for (int i = 0; i < count; i++) {
-            sql.append(QStringLiteral("WHEN $%1 THEN $%2 ").arg(placeholdersCounter).arg(placeholdersCounter + 1));
+            sql.append(u"WHEN $%1 THEN $%2 "_qs.arg(placeholdersCounter).arg(placeholdersCounter + 1));
             placeholdersCounter += 2;
         }
-        sql.append(QStringLiteral("ELSE randomnumber END WHERE id IN ("));
+        sql.append(u"ELSE randomnumber END WHERE id IN (");
 
         for (int i = 0; i < count; i++) {
-            sql.append(QLatin1Char('$') + QString::number(placeholdersCounter) + QLatin1Char(','));
+            sql.append(u'$' + QString::number(placeholdersCounter) + u',');
             ++placeholdersCounter;
         }
 
         if (count) {
             sql.remove(sql.size() - 1, 1);
         }
-        sql.append(QLatin1Char(')'));
+        sql.append(u')');
 
         iter = m_sqlMap.insert(count, APreparedQuery(sql));
     }

+ 23 - 23
frameworks/C++/cutelyst/src/fortunetest.cpp

@@ -33,7 +33,7 @@ void FortuneTest::fortunes_raw_p(Context *c)
             fortunes.emplace_back(Fortune{it[0].toInt(), it[1].toString()});
             ++it;
         }
-        fortunes.emplace_back(Fortune{0, QStringLiteral("Additional fortune added at request time.")});
+        fortunes.emplace_back(Fortune{0, u"Additional fortune added at request time."_qs});
 
         std::sort(fortunes.begin(), fortunes.end(), [] (const Fortune &a1, const Fortune &a2) {
             return a1.message < a2.message;
@@ -46,8 +46,8 @@ void FortuneTest::fortunes_raw_p(Context *c)
 void FortuneTest::fortunes_raw_postgres(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, message FROM fortune"),
-                QStringLiteral("postgres"));
+                u"SELECT id, message FROM fortune"_qs,
+                u"postgres"_qs);
     auto fortunes = processQuery(c, query);
     renderRaw(c, fortunes);
 }
@@ -55,8 +55,8 @@ void FortuneTest::fortunes_raw_postgres(Context *c)
 void FortuneTest::fortunes_raw_mysql(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, message FROM fortune"),
-                QStringLiteral("mysql"));
+                u"SELECT id, message FROM fortune"_qs,
+                u"mysql"_qs);
     auto fortunes = processQuery(c, query);
     renderRaw(c, fortunes);
 }
@@ -82,59 +82,59 @@ void FortuneTest::fortunes_c_p(Context *c)
         }
 
         fortunes.append(QVariant::fromValue(QVariantList{
-                            {0, QStringLiteral("Additional fortune added at request time.")},
+                            {0, u"Additional fortune added at request time."_qs},
                         }));
         std::sort(fortunes.begin(), fortunes.end(), [] (const QVariant &a1, const QVariant &a2) {
             return a1.toList()[1].toString() < a2.toList()[1].toString();
         });
 
-        c->setStash(QStringLiteral("template"), QStringLiteral("fortunes.html"));
-        c->setStash(QStringLiteral("fortunes"), fortunes);
+        c->setStash(u"template"_qs, u"fortunes.html"_qs);
+        c->setStash(u"fortunes"_qs, fortunes);
         static thread_local View *view = c->view();
         view->execute(c);
-        c->response()->setContentType(QStringLiteral("text/html; charset=UTF-8"));
+        c->response()->setContentType("text/html; charset=UTF-8"_qba);
     });
 }
 
 void FortuneTest::fortunes_cutelee_postgres(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, message FROM fortune"),
-                QStringLiteral("postgres"));
+                u"SELECT id, message FROM fortune"_qs,
+                u"postgres"_qs);
     if (query.exec()) {
         QVariantList fortunes = Sql::queryToList(query);
         fortunes.append(QVariant::fromValue(QVariantList{
-                            {0, QStringLiteral("Additional fortune added at request time.")},
+                            {0, u"Additional fortune added at request time."_qs},
                         }));
         std::sort(fortunes.begin(), fortunes.end(), [] (const QVariant &a1, const QVariant &a2) {
             return a1.toList()[1].toString() < a2.toList()[1].toString();
         });
-        c->setStash(QStringLiteral("template"), QStringLiteral("fortunes.html"));
-        c->setStash(QStringLiteral("fortunes"), fortunes);
+        c->setStash(u"template"_qs, u"fortunes.html"_qs);
+        c->setStash(u"fortunes"_qs, fortunes);
         static thread_local View *view = c->view();
         view->execute(c);
-        c->response()->setContentType(QStringLiteral("text/html; charset=UTF-8"));
+        c->response()->setContentType("text/html; charset=UTF-8"_qba);
     }
 }
 
 void FortuneTest::fortunes_cutelee_mysql(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, message FROM fortune"),
-                QStringLiteral("mysql"));
+                u"SELECT id, message FROM fortune"_qs,
+                u"mysql"_qs);
     if (query.exec()) {
         QVariantList fortunes = Sql::queryToList(query);
         fortunes.append(QVariant::fromValue(QVariantList{
-                            {0, QStringLiteral("Additional fortune added at request time.")},
+                            {0, u"Additional fortune added at request time."_qs},
                         }));
         std::sort(fortunes.begin(), fortunes.end(), [] (const QVariant &a1, const QVariant &a2) {
             return a1.toList()[1].toString() < a2.toList()[1].toString();
         });
-        c->setStash(QStringLiteral("template"), QStringLiteral("fortunes.html"));
-        c->setStash(QStringLiteral("fortunes"), fortunes);
+        c->setStash(u"template"_qs, u"fortunes.html"_qs);
+        c->setStash(u"fortunes"_qs, fortunes);
         static thread_local View *view = c->view();
         view->execute(c);
-        c->response()->setContentType(QStringLiteral("text/html; charset=UTF-8"));
+        c->response()->setContentType("text/html; charset=UTF-8"_qba);
     }
 }
 
@@ -151,7 +151,7 @@ FortuneList FortuneTest::processQuery(Context *c, QSqlQuery &query)
     while (query.next()) {
         fortunes.push_back({query.value(0).toInt(), query.value(1).toString()});
     }
-    fortunes.push_back({0, QStringLiteral("Additional fortune added at request time.")});
+    fortunes.push_back({0, u"Additional fortune added at request time."_qs});
 
     std::sort(fortunes.begin(), fortunes.end(), [] (const Fortune &a1, const Fortune &a2) {
         return a1.message < a2.message;
@@ -183,5 +183,5 @@ void FortuneTest::renderRaw(Context *c, const FortuneList &fortunes) const
 
     auto response = c->response();
     response->setBody(out);
-    response->setContentType(QStringLiteral("text/html; charset=UTF-8"));
+    response->setContentType("text/html; charset=UTF-8"_qba);
 }

+ 1 - 1
frameworks/C++/cutelyst/src/jsontest.cpp

@@ -12,7 +12,7 @@ JsonTest::JsonTest(QObject *parent) : Controller(parent)
 
 void JsonTest::json(Context *c)
 {
-    c->response()->setJsonObjectBody({ {QStringLiteral("message"), QStringLiteral("Hello, World!")} });
+    c->response()->setJsonObjectBody({ {u"message"_qs, u"Hello, World!"_qs} });
 }
 
 void JsonTest::pson(Context *c)

+ 11 - 11
frameworks/C++/cutelyst/src/multipledatabasequeriestest.cpp

@@ -21,7 +21,7 @@ MultipleDatabaseQueriesTest::MultipleDatabaseQueriesTest(QObject *parent) : Cont
 
 void MultipleDatabaseQueriesTest::queriesp(Context *c)
 {
-    int queries = c->request()->queryParam(QStringLiteral("queries")).toInt();
+    int queries = c->request()->queryParam(u"queries"_qs).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -39,8 +39,8 @@ void MultipleDatabaseQueriesTest::queriesp(Context *c)
             if (Q_LIKELY(!result.error() && result.size())) {
                 auto it = result.begin();
                 array->append(QJsonObject{
-                                  {QStringLiteral("id"), it[0].toInt()},
-                                  {QStringLiteral("randomNumber"), it[1].toInt()}
+                                  {u"id"_qs, it[0].toInt()},
+                                  {u"randomNumber"_qs, it[1].toInt()}
                               });
 
                 if (i + 1 == queries) {
@@ -57,16 +57,16 @@ void MultipleDatabaseQueriesTest::queriesp(Context *c)
 void MultipleDatabaseQueriesTest::query_postgres(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, randomNumber FROM world WHERE id = :id"),
-                QStringLiteral("postgres"));
+                u"SELECT id, randomNumber FROM world WHERE id = :id"_qs,
+                u"postgres"_qs);
     processQuery(c, query);
 }
 
 void MultipleDatabaseQueriesTest::query_mysql(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, randomNumber FROM world WHERE id = :id"),
-                QStringLiteral("mysql"));
+                u"SELECT id, randomNumber FROM world WHERE id = :id"_qs,
+                u"mysql"_qs);
     processQuery(c, query);
 }
 
@@ -74,7 +74,7 @@ void MultipleDatabaseQueriesTest::processQuery(Context *c, QSqlQuery &query)
 {
     QJsonArray array;
 
-    int queries = c->request()->queryParam(QStringLiteral("queries")).toInt();
+    int queries = c->request()->queryParam(u"queries"_qs).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -84,11 +84,11 @@ void MultipleDatabaseQueriesTest::processQuery(Context *c, QSqlQuery &query)
     for (int i = 0; i < queries; ++i) {
         const int id = (rand() % 10000) + 1;
 
-        query.bindValue(QStringLiteral(":id"), id);
+        query.bindValue(u":id"_qs, id);
         if (Q_LIKELY(query.exec() && query.next())) {
             array.append(QJsonObject{
-                             {QStringLiteral("id"), query.value(0).toInt()},
-                             {QStringLiteral("randomNumber"), query.value(1).toInt()}
+                             {u"id"_qs, query.value(0).toInt()},
+                             {u"randomNumber"_qs, query.value(1).toInt()}
                          });
         } else {
             c->res()->setStatus(Response::InternalServerError);

+ 2 - 2
frameworks/C++/cutelyst/src/plaintexttest.cpp

@@ -8,6 +8,6 @@ PlaintextTest::PlaintextTest(QObject *parent) : Controller(parent)
 void PlaintextTest::plaintext(Context *c)
 {
     Response *res = c->response();
-    res->setBody(QByteArrayLiteral("Hello, World!"));
-    res->setContentType(QStringLiteral("text/plain"));
+    res->setBody("Hello, World!"_qba);
+    res->setContentType("text/plain"_qba);
 }

+ 7 - 7
frameworks/C++/cutelyst/src/singledatabasequerytest.cpp

@@ -76,16 +76,16 @@ void SingleDatabaseQueryTest::db_asql_pipeline_pg(Context *c)
 void SingleDatabaseQueryTest::db_postgres(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, randomNumber FROM world WHERE id = :id"),
-                QStringLiteral("postgres"));
+                u"SELECT id, randomNumber FROM world WHERE id = :id"_qs,
+                u"postgres"_qs);
     processQuery(c, query);
 }
 
 void SingleDatabaseQueryTest::db_mysql(Context *c)
 {
     QSqlQuery query = CPreparedSqlQueryThreadForDB(
-                QLatin1String("SELECT id, randomNumber FROM world WHERE id = :id"),
-                QStringLiteral("mysql"));
+                u"SELECT id, randomNumber FROM world WHERE id = :id"_qs,
+                u"mysql"_qs);
     processQuery(c, query);
 }
 
@@ -93,14 +93,14 @@ void SingleDatabaseQueryTest::processQuery(Context *c, QSqlQuery &query)
 {
     int id = (rand() % 10000) + 1;
 
-    query.bindValue(QStringLiteral(":id"), id);
+    query.bindValue(u":id"_qs, id);
     if (Q_UNLIKELY(!query.exec() || !query.next())) {
         c->res()->setStatus(Response::InternalServerError);
         return;
     }
 
     c->response()->setJsonObjectBody({
-                                         {QStringLiteral("id"), query.value(0).toInt()},
-                                         {QStringLiteral("randomNumber"), query.value(1).toInt()}
+                                         {u"id"_qs, query.value(0).toInt()},
+                                         {u"randomNumber"_qs, query.value(1).toInt()}
                                      });
 }

+ 9 - 0
frameworks/C++/reactor/README.md

@@ -0,0 +1,9 @@
+# [reactor](https://github.com/shaovie/reactor) (c++) Benchmarking Test
+
+This is the go portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms.
+
+"reactor is a high-performance, lightweight, i/o event-driven network framework in c++."
+
+## Test URLs
+
+    http://localhost:8080/plaintext

+ 23 - 0
frameworks/C++/reactor/benchmark_config.json

@@ -0,0 +1,23 @@
+{
+  "framework": "reactor",
+  "tests": [{
+    "default": {
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "reactor",
+      "language": "C++",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Reactor",
+      "notes": "",
+      "versus": "c++"
+    }
+  }]
+}

+ 14 - 0
frameworks/C++/reactor/config.toml

@@ -0,0 +1,14 @@
+[framework]
+name = "reactor"
+
+[main]
+urls.plaintext = "/plaintext"
+approach = "Stripped"
+classification = "Platform"
+database = "None"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "None"
+webserver = "None"
+versus = "c++"

+ 37 - 0
frameworks/C++/reactor/reactor.dockerfile

@@ -0,0 +1,37 @@
+FROM ubuntu:22.04
+MAINTAINER [email protected]
+
+RUN apt-get update -yqq
+RUN apt-get install -yqq g++-11 gcc-11 make git
+
+RUN   update-alternatives --quiet --remove-all gcc \
+    ; update-alternatives --quiet --remove-all g++ \
+    ; update-alternatives --quiet --remove-all cc \
+    ; update-alternatives --quiet --remove-all cpp \
+    ; update-alternatives --quiet --install /usr/bin/gcc gcc /usr/bin/gcc-11 20 \
+    ; update-alternatives --quiet --install /usr/bin/cc cc /usr/bin/gcc-11 20 \
+    ; update-alternatives --quiet --install /usr/bin/g++ g++ /usr/bin/g++-11 20 \
+    ; update-alternatives --quiet --install /usr/bin/cpp cpp /usr/bin/g++-11 20 \
+    ; update-alternatives --quiet --config gcc \
+    ; update-alternatives --quiet --config cc \
+    ; update-alternatives --quiet --config g++ \
+    ; update-alternatives --quiet --config cpp
+
+
+WORKDIR /reactor-bench
+
+RUN git clone https://github.com/shaovie/reactor.git
+
+
+RUN cd reactor/ && make clean all
+COPY ./techempower.cpp /reactor-bench/reactor
+
+WORKDIR /reactor-bench/reactor
+RUN g++ techempower.cpp -O2 -std=c++11 -lreactor -L./bin -lpthread -o app
+
+ENV LD_LIBRARY_PATH=./bin:$LD_LIBRARY_PATH
+
+EXPOSE 8080
+
+RUN ulimit -n 100000
+CMD ./app

+ 120 - 0
frameworks/C++/reactor/techempower.cpp

@@ -0,0 +1,120 @@
+#include "src/reactor.h"
+#include "src/io_handle.h"
+#include "src/acceptor.h"
+#include "src/options.h"
+#include "src/poll_sync_opt.h"
+
+#include <string>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <thread>
+
+reactor *conn_reactor = nullptr;
+const char httpheaders1[] = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nServer: goev\r\nContent-Type: text/plain\r\nDate: ";
+const char httpheaders2[] = "\r\nContent-Length: 13\r\n\r\nHello, World!";
+
+const int pcache_data_t = 1;
+
+class http : public io_handle {
+public:
+    virtual bool on_open() {
+        // add_ev_handler 尽量放在最后, (on_open 和o_read可能不在一个线程)
+        if (conn_reactor->add_ev_handler(this, this->get_fd(), ev_handler::ev_read) != 0) {
+            fprintf(stderr, "add new conn to poller fail! %s\n", strerror(errno));
+            return false;
+        }
+        return true;
+    }
+    virtual bool on_read() {
+        char *buf = nullptr;
+        int ret = this->recv(buf);
+        if (ret == 0) // closed
+            return false;
+        else if (ret < 0)
+            return true;
+
+        if (::strstr(buf, "\r\n\r\n") == nullptr) {
+            // invliad msg
+            return false;
+        }
+
+        int writen = 0;
+        ::memcpy(buf, httpheaders1, sizeof(httpheaders1)-1);
+        writen += sizeof(httpheaders1)-1;
+
+        char *date = (char *)this->poll_cache_get(pcache_data_t);
+        ret = ::strlen(date);
+        ::memcpy(buf + writen, date, ret);
+        writen += ret;
+
+        ret = sizeof(httpheaders2)-1;
+        ::memcpy(buf + writen, httpheaders2, ret);
+        writen += ret;
+
+        this->send(buf, writen);
+        return true;
+    }
+    virtual void on_close() {
+        this->destroy();
+    }
+};
+ev_handler *gen_http() {
+    return new http();
+}
+void release_dates(void *p) {
+    delete[] (char *)p;
+}
+void sync_date(bool init) {
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    struct tm tmv;
+    ::localtime_r(&(now.tv_sec), &tmv);
+    char dates[32] = {0};
+    ::strftime(dates, 32, "%a, %d %b %Y %H:%M:%S GMT", &tmv);
+    void **args = new void *[conn_reactor->get_poller_num()];
+    for (int i = 0; i < conn_reactor->get_poller_num(); ++i) {
+        char *ds = new char[32]{0};
+        ::strcpy(ds, dates);
+        poll_sync_opt::sync_cache *arg = new poll_sync_opt::sync_cache();
+        arg->id = pcache_data_t;
+        arg->value = ds;
+        arg->free_func = release_dates;
+        args[i] = arg;
+    }
+    if (init)
+        conn_reactor->init_poll_sync_opt(poll_sync_opt::sync_cache_t, args);
+    else
+        conn_reactor->poll_sync_opt(poll_sync_opt::sync_cache_t, args);
+}
+void sync_date_timing() {
+    while (true) {
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+        sync_date(false);
+    }
+}
+int main (int argc, char *argv[]) {
+    options opt;
+    opt.set_cpu_affinity = true;
+    if (argc > 1)
+        opt.poller_num = atoi(argv[1]);
+
+    signal(SIGPIPE ,SIG_IGN);
+
+    conn_reactor = new reactor();
+    if (conn_reactor->open(opt) != 0)
+        ::exit(1);
+
+    sync_date(true);
+
+    std::thread thr(sync_date_timing);
+    thr.detach();
+
+    opt.reuse_addr = true;
+    acceptor acc(conn_reactor, gen_http);
+    if (acc.open(":8080", opt) != 0)
+        ::exit(1);
+    conn_reactor->run();
+}

+ 0 - 4
frameworks/C++/treefrog/benchmark_config.json

@@ -26,12 +26,10 @@
       "versus": ""
     },
     "mysql": {
-      "json_url": "/json/json",
       "db_url": "/world/random",
       "query_url": "/world/queries/",
       "fortune_url": "/fortune/index",
       "update_url": "/world/updates/",
-      "plaintext_url": "/world/plain",
       "cached_query_url": "/world/cached_queries/",
       "port": 8080,
       "approach": "Realistic",
@@ -73,12 +71,10 @@
       "versus": ""
     },
     "mongodb": {
-      "json_url": "/json/json",
       "db_url": "/world/mrandom",
       "query_url": "/world/mqueries/",
       "fortune_url": "/fortune/mindex",
       "update_url": "/world/mupdates/",
-      "plaintext_url": "/world/plain",
       "cached_query_url": "/world/cached_mqueries/",
       "port": 8080,
       "approach": "Realistic",

+ 8 - 4
frameworks/C++/userver/userver-bare.dockerfile

@@ -1,16 +1,20 @@
-FROM ghcr.io/userver-framework/docker-userver-build-base:v1a AS builder
-RUN apt install -y libnghttp2-dev
+FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v1 AS builder
+
+RUN apt update && \
+    apt install -y lsb-release wget software-properties-common gnupg && \
+        wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 16
 
 WORKDIR /src
 RUN git clone https://github.com/userver-framework/userver.git && \
-    cd userver && git checkout 040b0bd001a078ee023aabe987e5ec7cc8ed5b6c
+    cd userver && git checkout 73727ce95d24f18651fc018c45f50c492f858027
 COPY userver_benchmark/ ./
 RUN mkdir build && cd build && \
     cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \
           -DUSERVER_FEATURE_REDIS=0 -DUSERVER_FEATURE_CLICKHOUSE=0 -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_RABBITMQ=0 -DUSERVER_FEATURE_GRPC=0 \
           -DUSERVER_FEATURE_UTEST=0 \
           -DUSERVER_FEATURE_POSTGRESQL=1 \
-          -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" .. && \
+          -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" -DCMAKE_C_FLAGS="-march=native" \
+          -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 .. && \
     make -j $(nproc)
 
 FROM builder AS runner

+ 8 - 4
frameworks/C++/userver/userver.dockerfile

@@ -1,16 +1,20 @@
-FROM ghcr.io/userver-framework/docker-userver-build-base:v1a AS builder
-RUN apt install -y libnghttp2-dev
+FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v1 AS builder
+
+RUN apt update && \
+    apt install -y lsb-release wget software-properties-common gnupg && \
+        wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 16
 
 WORKDIR /src
 RUN git clone https://github.com/userver-framework/userver.git && \
-    cd userver && git checkout 040b0bd001a078ee023aabe987e5ec7cc8ed5b6c
+    cd userver && git checkout 73727ce95d24f18651fc018c45f50c492f858027
 COPY userver_benchmark/ ./
 RUN mkdir build && cd build && \
     cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \
           -DUSERVER_FEATURE_REDIS=0 -DUSERVER_FEATURE_CLICKHOUSE=0 -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_RABBITMQ=0 -DUSERVER_FEATURE_GRPC=0 \
           -DUSERVER_FEATURE_UTEST=0 \
           -DUSERVER_FEATURE_POSTGRESQL=1 \
-          -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" .. && \
+          -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" -DCMAKE_C_FLAGS="-march=native" \
+          -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 .. && \
     make -j $(nproc)
 
 FROM builder AS runner

+ 7 - 0
frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp

@@ -63,4 +63,11 @@ int ParseParamFromQuery(std::string_view url, std::string_view name) {
   return ParseFromQueryVal(url.substr(pos, len));
 }
 
+DatabasePoolSemaphore::DatabasePoolSemaphore(std::size_t initial_count)
+    : semaphore_{initial_count} {}
+
+userver::engine::SemaphoreLock DatabasePoolSemaphore::Acquire() const {
+  return userver::engine::SemaphoreLock{semaphore_};
+}
+
 }  // namespace userver_techempower::db_helpers

+ 11 - 0
frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <userver/engine/semaphore.hpp>
 #include <userver/formats/json/value.hpp>
 #include <userver/server/http/http_request.hpp>
 #include <userver/storages/postgres/cluster_types.hpp>
@@ -31,4 +32,14 @@ int ParseParamFromQuery(const userver::server::http::HttpRequest& request,
 
 int ParseParamFromQuery(std::string_view url, std::string_view name);
 
+class DatabasePoolSemaphore final {
+ public:
+  explicit DatabasePoolSemaphore(std::size_t initial_count);
+
+  userver::engine::SemaphoreLock Acquire() const;
+
+ private:
+  mutable userver::engine::Semaphore semaphore_;
+};
+
 }  // namespace userver_techempower::db_helpers

+ 11 - 7
frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp

@@ -2,8 +2,6 @@
 
 #include <vector>
 
-#include "../../common/db_helpers.hpp"
-
 #include <userver/components/component_context.hpp>
 #include <userver/storages/postgres/postgres.hpp>
 
@@ -124,6 +122,8 @@ std::string FormatFortunes(const std::vector<Fortune>& fortunes) {
   return result;
 }
 
+constexpr std::size_t kBestConcurrencyWildGuess = 256;
+
 }  // namespace
 
 Handler::Handler(const userver::components::ComponentConfig& config,
@@ -133,7 +133,8 @@ Handler::Handler(const userver::components::ComponentConfig& config,
               .FindComponent<userver::components::Postgres>(
                   db_helpers::kDbComponentName)
               .GetCluster()},
-      select_all_fortunes_query_{"SELECT id, message FROM Fortune"} {}
+      select_all_fortunes_query_{"SELECT id, message FROM Fortune"},
+      semaphore_{kBestConcurrencyWildGuess} {}
 
 std::string Handler::HandleRequestThrow(
     const userver::server::http::HttpRequest& request,
@@ -143,10 +144,13 @@ std::string Handler::HandleRequestThrow(
 }
 
 std::string Handler::GetResponse() const {
-  auto fortunes =
-      pg_->Execute(db_helpers::kClusterHostType, select_all_fortunes_query_)
-          .AsContainer<std::vector<Fortune>>(
-              userver::storages::postgres::kRowTag);
+  auto fortunes = [this] {
+    const auto lock = semaphore_.Acquire();
+    return pg_
+        ->Execute(db_helpers::kClusterHostType, select_all_fortunes_query_)
+        .AsContainer<std::vector<Fortune>>(
+            userver::storages::postgres::kRowTag);
+  }();
 
   fortunes.push_back({0, "Additional fortune added at request time."});
 

+ 4 - 0
frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include "../../common/db_helpers.hpp"
+
 #include <userver/server/handlers/http_handler_base.hpp>
 
 #include <userver/storages/postgres/postgres_fwd.hpp>
@@ -23,6 +25,8 @@ class Handler final : public userver::server::handlers::HttpHandlerBase {
  private:
   const userver::storages::postgres::ClusterPtr pg_;
   const userver::storages::postgres::Query select_all_fortunes_query_;
+
+  db_helpers::DatabasePoolSemaphore semaphore_;
 };
 
 }  // namespace userver_techempower::fortunes

+ 20 - 20
frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp

@@ -1,7 +1,5 @@
 #include "handler.hpp"
 
-#include "../../common/db_helpers.hpp"
-
 #include <userver/components/component_context.hpp>
 #include <userver/formats/serialize/common_containers.hpp>
 #include <userver/storages/postgres/postgres.hpp>
@@ -10,6 +8,12 @@
 
 namespace userver_techempower::multiple_queries {
 
+namespace {
+
+constexpr std::size_t kBestConcurrencyWildGuess = 256;
+
+}
+
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
     : userver::server::handlers::HttpHandlerJsonBase{config, context},
@@ -17,7 +21,8 @@ Handler::Handler(const userver::components::ComponentConfig& config,
               .FindComponent<userver::components::Postgres>(
                   db_helpers::kDbComponentName)
               .GetCluster()},
-      query_arg_name_{"queries"} {}
+      query_arg_name_{"queries"},
+      semaphore_{kBestConcurrencyWildGuess} {}
 
 userver::formats::json::Value Handler::HandleRequestJsonThrow(
     const userver::server::http::HttpRequest& request,
@@ -30,28 +35,23 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow(
 }
 
 userver::formats::json::Value Handler::GetResponse(int queries) const {
-  boost::container::small_vector<db_helpers::WorldTableRow, 500> result(
-      queries);
+  boost::container::small_vector<db_helpers::WorldTableRow, 20> result(queries);
   for (auto& value : result) {
     value.id = db_helpers::GenerateRandomId();
   }
 
-  // even though this adds a round-trip for Begin/Commit we expect this to be
-  // faster due to the pool semaphore contention reduction - now we have a
-  // connection for ourselves until we are done with it, otherwise we would
-  // likely wait on the semaphore with every new query.
-  auto transaction = pg_->Begin(
-      db_helpers::kClusterHostType,
-      userver::storages::postgres::TransactionOptions{
-          userver::storages::postgres::TransactionOptions::Mode::kReadOnly});
-  for (auto& value : result) {
-    value.random_number =
-        transaction.Execute(db_helpers::kSelectRowQuery, value.id)
-            .AsSingleRow<db_helpers::WorldTableRow>(
-                userver::storages::postgres::kRowTag)
-            .random_number;
+  {
+    const auto lock = semaphore_.Acquire();
+
+    auto trx = pg_->Begin(db_helpers::kClusterHostType, {});
+    for (auto& value : result) {
+      value.random_number = trx.Execute(db_helpers::kSelectRowQuery, value.id)
+                                .AsSingleRow<db_helpers::WorldTableRow>(
+                                    userver::storages::postgres::kRowTag)
+                                .random_number;
+    }
+    trx.Commit();
   }
-  transaction.Commit();
 
   return userver::formats::json::ValueBuilder{result}.ExtractValue();
 }

+ 4 - 0
frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include "../../common/db_helpers.hpp"
+
 #include <userver/server/handlers/http_handler_json_base.hpp>
 #include <userver/storages/postgres/postgres_fwd.hpp>
 
@@ -23,6 +25,8 @@ class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
   const userver::storages::postgres::ClusterPtr pg_;
 
   const std::string query_arg_name_;
+
+  db_helpers::DatabasePoolSemaphore semaphore_;
 };
 
 }  // namespace userver_techempower::multiple_queries

+ 3 - 2
frameworks/C++/userver/userver_benchmark/controllers/plaintext/handler.cpp

@@ -1,14 +1,15 @@
 #include "handler.hpp"
 
+#include <userver/http/common_headers.hpp>
+
 namespace userver_techempower::plaintext {
 
-const std::string kContentTypeHeader{"Content-Type"};
 const std::string kContentTypeTextPlain{"text/plain"};
 
 std::string Handler::HandleRequestThrow(
     const userver::server::http::HttpRequest& request,
     userver::server::request::RequestContext&) const {
-  request.GetHttpResponse().SetHeader(kContentTypeHeader,
+  request.GetHttpResponse().SetHeader(userver::http::headers::kContentType,
                                       kContentTypeTextPlain);
   return GetResponse();
 }

+ 16 - 8
frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp

@@ -1,19 +1,24 @@
 #include "handler.hpp"
 
-#include "../../common/db_helpers.hpp"
-
 #include <userver/components/component_context.hpp>
 #include <userver/storages/postgres/postgres.hpp>
 
 namespace userver_techempower::single_query {
 
+namespace {
+
+constexpr std::size_t kBestConcurrencyWildGuess = 256;
+
+}
+
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
     : userver::server::handlers::HttpHandlerJsonBase{config, context},
       pg_{context
               .FindComponent<userver::components::Postgres>(
                   db_helpers::kDbComponentName)
-              .GetCluster()} {}
+              .GetCluster()},
+      semaphore_{kBestConcurrencyWildGuess} {}
 
 userver::formats::json::Value Handler::HandleRequestJsonThrow(
     const userver::server::http::HttpRequest&,
@@ -23,11 +28,14 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow(
 }
 
 userver::formats::json::Value Handler::GetResponse() const {
-  const auto row =
-      pg_->Execute(db_helpers::kClusterHostType, db_helpers::kSelectRowQuery,
-                   db_helpers::GenerateRandomId())
-          .AsSingleRow<db_helpers::WorldTableRow>(
-              userver::storages::postgres::kRowTag);
+  const auto row = [this] {
+    const auto lock = semaphore_.Acquire();
+    return pg_
+        ->Execute(db_helpers::kClusterHostType, db_helpers::kSelectRowQuery,
+                  db_helpers::GenerateRandomId())
+        .AsSingleRow<db_helpers::WorldTableRow>(
+            userver::storages::postgres::kRowTag);
+  }();
 
   return db_helpers::Serialize(row, {});
 }

+ 4 - 0
frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include "../../common/db_helpers.hpp"
+
 #include <userver/server/handlers/http_handler_json_base.hpp>
 
 #include <userver/storages/postgres/postgres_fwd.hpp>
@@ -22,6 +24,8 @@ class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
 
  private:
   const userver::storages::postgres::ClusterPtr pg_;
+
+  db_helpers::DatabasePoolSemaphore semaphore_;
 };
 
 }  // namespace userver_techempower::single_query

+ 27 - 23
frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp

@@ -1,7 +1,5 @@
 #include "handler.hpp"
 
-#include "../../common/db_helpers.hpp"
-
 #include <userver/components/component_context.hpp>
 #include <userver/formats/serialize/common_containers.hpp>
 #include <userver/storages/postgres/postgres.hpp>
@@ -22,7 +20,9 @@ FROM ( SELECT
 WHERE w.id = new_numbers.id
 )"};
 
-}
+constexpr std::size_t kBestConcurrencyWildGuess = 128;
+
+}  // namespace
 
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
@@ -30,7 +30,8 @@ Handler::Handler(const userver::components::ComponentConfig& config,
       pg_{context.FindComponent<userver::components::Postgres>("hello-world-db")
               .GetCluster()},
       query_arg_name_{"queries"},
-      update_query_{kUpdateQueryStr} {}
+      update_query_{kUpdateQueryStr},
+      semaphore_{kBestConcurrencyWildGuess} {}
 
 userver::formats::json::Value Handler::HandleRequestJsonThrow(
     const userver::server::http::HttpRequest& request,
@@ -52,29 +53,32 @@ userver::formats::json::Value Handler::GetResponse(int queries) const {
   std::sort(values.begin(), values.end(),
             [](const auto& lhs, const auto& rhs) { return lhs.id < rhs.id; });
 
-  // even though this adds a round-trip for Begin/Commit we expect this to be
-  // faster due to the pool semaphore contention reduction - now we have a
-  // connection for ourselves until we are done with it, otherwise we would
-  // likely wait on the semaphore with every new query.
-  auto transaction = pg_->Begin(db_helpers::kClusterHostType, {});
-  for (auto& value : values) {
-    value.random_number =
-        transaction.Execute(db_helpers::kSelectRowQuery, value.id)
-            .AsSingleRow<db_helpers::WorldTableRow>(
-                userver::storages::postgres::kRowTag)
-            .random_number;
-  }
+  boost::container::small_vector<db_helpers::WorldTableRow, 20> result;
 
-  auto json_result =
-      userver::formats::json::ValueBuilder{values}.ExtractValue();
+  {
+    const auto lock = semaphore_.Acquire();
 
-  for (auto& value : values) {
-    value.random_number = db_helpers::GenerateRandomValue();
+    auto trx = pg_->Begin(db_helpers::kClusterHostType, {});
+    for (auto& value : values) {
+      value.random_number = trx.Execute(db_helpers::kSelectRowQuery, value.id)
+                                .AsSingleRow<db_helpers::WorldTableRow>(
+                                    userver::storages::postgres::kRowTag)
+                                .random_number;
+    }
+
+    // We copy values here (and hope compiler optimizes it into one memcpy call)
+    // to not serialize into json within transaction
+    result.assign(values.begin(), values.end());
+
+    for (auto& value : values) {
+      value.random_number = db_helpers::GenerateRandomValue();
+    }
+
+    trx.ExecuteDecomposeBulk(update_query_, values, values.size());
+    trx.Commit();
   }
-  transaction.ExecuteDecomposeBulk(update_query_, values, values.size());
-  transaction.Commit();
 
-  return json_result;
+  return userver::formats::json::ValueBuilder{values}.ExtractValue();
 }
 
 }  // namespace userver_techempower::updates

+ 4 - 0
frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include "../../common/db_helpers.hpp"
+
 #include <userver/server/handlers/http_handler_json_base.hpp>
 #include <userver/storages/postgres/postgres_fwd.hpp>
 #include <userver/storages/postgres/query.hpp>
@@ -25,6 +27,8 @@ class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
 
   const std::string query_arg_name_;
   const userver::storages::postgres::Query update_query_;
+
+  db_helpers::DatabasePoolSemaphore semaphore_;
 };
 
 }  // namespace userver_techempower::updates

+ 6 - 3
frameworks/C++/userver/userver_configs/dynamic_config_fallback.json

@@ -1,6 +1,9 @@
 {
   "USERVER_CACHES": {},
   "USERVER_CANCEL_HANDLE_REQUEST_BY_DEADLINE": false,
+  "POSTGRES_CONGESTION_CONTROL_SETTINGS": {},
+  "POSTGRES_DEADLINE_PROPAGATION_VERSION": 0,
+  "POSTGRES_CONNECTION_PIPELINE_EXPERIMENT": 5,
   "USERVER_CHECK_AUTH_IN_HANDLERS": false,
   "USERVER_DUMPS": {},
   "USERVER_HTTP_PROXY": "",
@@ -32,8 +35,8 @@
       "default-task-processor": {
         "wait_queue_overload": {
           "action": "ignore",
-          "length_limit": 16385,
-          "time_limit_us": 30000
+          "length_limit": 0,
+          "time_limit_us": 10000000
         }
       }
     }
@@ -41,7 +44,7 @@
 
   "POSTGRES_STATEMENT_METRICS_SETTINGS": {},
   "POSTGRES_CONNLIMIT_MODE_AUTO_ENABLED": false,
-  "POSTGRES_CONNECTION_PIPELINE_ENABLED": false,
+  "USERVER_DEADLINE_PROPAGATION_ENABLED": false,
   "POSTGRES_CONNECTION_POOL_SETTINGS": {},
   "POSTGRES_CONNECTION_SETTINGS": {},
   "POSTGRES_DEFAULT_COMMAND_CONTROL": {

+ 17 - 8
frameworks/C++/userver/userver_configs/static_config.yaml

@@ -1,17 +1,18 @@
 # yaml
 components_manager:
     event_thread_pool:
-        threads: 3
+        threads: 5
+        dedicated_timer_threads: 1
     coro_pool:
-        initial_size: 10000             # Preallocate 10000 coroutines at startup.
-        max_size: 65536                 # Do not keep more than 65536 preallocated coroutines.
-        stack_size: 66560               # 64Kb for coroutine stack
+        initial_size: 10000              # Preallocate 10000 coroutines at startup.
+        max_size: 300000                 # Do not keep more than 300000 preallocated coroutines.
+        stack_size: 66560                # 64Kb for coroutine stack
 
     task_processors:                    # Task processor is an executor for coroutine tasks
 
         main-task-processor:            # Make a task processor for CPU-bound couroutine tasks.
             thread_name: main-worker    # OS will show the threads of this task processor with 'main-worker' prefix.
-            worker_threads: 25
+            worker_threads: 23
             guess-cpu-limit: true
 
         fs-task-processor:              # Make a separate task processor for filesystem bound tasks.
@@ -65,49 +66,57 @@ components_manager:
         plaintext-handler:
             path: /plaintext
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 
         json-handler:
             path: /json
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 
         hello-world-db:
             dbalias: hello_world
             blocking_task_processor: fs-task-processor
-            min_pool_size: 75
-            max_pool_size: 125
+            min_pool_size: 80
+            max_pool_size: 260
             max_queue_size: 512
             connecting_limit: 15
 
         single-query-handler:
             path: /db
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 
         multiple-queries-handler:
             path: /queries
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 
         updates-handler:
             path: /updates
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 
         world-pg-cache:
             pgcomponent: hello-world-db
+            chunk-size: 0 # fetch all rows at once
             update-types: only-full
-            update-interval: 1s
+            update-interval: 60s
             update-correction: 50ms
 
         cached-queries-handler:
             path: /cached-queries
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 
         fortunes-handler:
             path: /fortunes
             method: GET
+            decompress_request: false
             task_processor: main-task-processor
 

+ 1 - 1
frameworks/C/h2o/h2o.dockerfile

@@ -106,7 +106,7 @@ CMD ["taskset", \
      "-a20", \
      "-d", \
      "dbname=hello_world host=tfb-database password=benchmarkdbpass sslmode=disable user=benchmarkdbuser", \
-     "-e64", \
+     "-e256", \
      "-f", \
      "/opt/h2o_app/share/h2o_app/template", \
      "-m1"]

+ 95 - 97
frameworks/C/h2o/src/database.c

@@ -30,6 +30,7 @@
 
 #include "database.h"
 #include "error.h"
+#include "event_loop.h"
 #include "global_data.h"
 #include "list.h"
 
@@ -37,9 +38,8 @@
 
 // Database connection state
 #define EXPECT_SYNC 1
-#define IDLE 2
-#define IGNORE_RESULT 4
-#define RESET 8
+#define IGNORE_RESULT 2
+#define RESET 4
 
 typedef struct {
 	list_t l;
@@ -61,8 +61,9 @@ typedef struct {
 } prepared_statement_t;
 
 static h2o_socket_t *create_socket(int sd, h2o_loop_t *loop);
-static int do_execute_query(db_conn_t *conn, db_query_param_t *param, bool flush);
+static int do_execute_query(db_conn_t *conn, db_query_param_t *param);
 static void error_notification(db_conn_pool_t *pool, bool timeout, const char *error_string);
+static int flush_connection(h2o_socket_cb cb, db_conn_t *conn);
 static void on_database_connect_error(db_conn_t *conn, bool timeout, const char *error_string);
 static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err);
 static void on_database_connect_timeout(h2o_timer_t *timer);
@@ -71,9 +72,11 @@ static void on_database_error(db_conn_t *conn, const char *error_string);
 static void on_database_read_ready(h2o_socket_t *sock, const char *err);
 static void on_database_timeout(h2o_timer_t *timer);
 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);
+static void process_queries(db_conn_t *conn, bool removed);
+static void remove_connection(db_conn_t *conn);
 static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn);
 
 static h2o_socket_t *create_socket(int sd, h2o_loop_t *loop)
@@ -104,7 +107,7 @@ static h2o_socket_t *create_socket(int sd, h2o_loop_t *loop)
 	return ret;
 }
 
-static int do_execute_query(db_conn_t *conn, db_query_param_t *param, bool flush)
+static int do_execute_query(db_conn_t *conn, db_query_param_t *param)
 {
 	assert(conn->query_num);
 	assert((conn->queries.head && conn->query_num < conn->pool->config->max_pipeline_query_num) ||
@@ -137,17 +140,6 @@ static int do_execute_query(db_conn_t *conn, db_query_param_t *param, bool flush
 		return 1;
 	}
 
-	if (flush) {
-		const int send_status = PQflush(conn->conn);
-
-		if (send_status < 0) {
-			LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
-			return 1;
-		}
-		else if (send_status)
-			h2o_socket_notify_write(conn->sock, on_database_write_ready);
-	}
-
 	if (!conn->queries.head && !(conn->flags & (EXPECT_SYNC | IGNORE_RESULT))) {
 		assert(!h2o_timer_is_linked(&conn->timer));
 		conn->timer.cb = on_database_timeout;
@@ -158,7 +150,6 @@ static int do_execute_query(db_conn_t *conn, db_query_param_t *param, bool flush
 	*conn->queries.tail = &param->l;
 	conn->queries.tail = &param->l.next;
 	conn->query_num--;
-	conn->flags &= ~IDLE;
 	return 0;
 }
 
@@ -189,6 +180,18 @@ static void error_notification(db_conn_pool_t *pool, bool timeout, const char *e
 	}
 }
 
+static int flush_connection(h2o_socket_cb cb, db_conn_t *conn)
+{
+	const int send_status = PQflush(conn->conn);
+
+	if (send_status < 0)
+		LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
+	else if (send_status)
+		h2o_socket_notify_write(conn->sock, cb);
+
+	return send_status < 0;
+}
+
 static void on_database_connect_error(db_conn_t *conn, bool timeout, const char *error_string)
 {
 	db_conn_pool_t * const pool = conn->pool;
@@ -217,17 +220,10 @@ static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err)
 		return;
 	}
 
-	const int send_status = PQflush(conn->conn);
-
-	if (send_status < 0) {
-		LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
+	if (flush_connection(on_database_connect_write_ready, conn)) {
 		on_database_connect_error(conn, false, DB_ERROR);
 		return;
 	}
-	else if (send_status) {
-		h2o_socket_notify_write(conn->sock, on_database_connect_write_ready);
-		return;
-	}
 
 	while (!PQisBusy(conn->conn)) {
 		PGresult * const result = PQgetResult(conn->conn);
@@ -241,7 +237,7 @@ 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);
+					process_queries(conn, true);
 					return;
 				default:
 					LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
@@ -271,20 +267,14 @@ static void on_database_connect_write_ready(h2o_socket_t *sock, const char *err)
 		ERROR(err);
 		on_database_connect_error(conn, false, err);
 	}
-	else {
-		const int send_status = PQflush(conn->conn);
-
-		if (send_status < 0) {
-			LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
-			on_database_connect_error(conn, false, DB_ERROR);
-		}
-		else if (send_status)
-			h2o_socket_notify_write(conn->sock, on_database_connect_write_ready);
-	}
+	else if (flush_connection(on_database_connect_write_ready, conn))
+		on_database_connect_error(conn, false, DB_ERROR);
 }
 
 static void on_database_error(db_conn_t *conn, const char *error_string)
 {
+	remove_connection(conn);
+
 	if (conn->queries.head)
 		do {
 			db_query_param_t * const param = H2O_STRUCT_FROM_MEMBER(db_query_param_t,
@@ -315,17 +305,12 @@ static void on_database_read_ready(h2o_socket_t *sock, const char *err)
 		return;
 	}
 
-	const int send_status = PQflush(conn->conn);
-
-	if (send_status < 0) {
-		LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
+	if (flush_connection(on_database_write_ready, conn)) {
 		on_database_error(conn, DB_ERROR);
 		return;
 	}
-	else if (send_status) {
-		h2o_socket_notify_write(conn->sock, on_database_write_ready);
-		return;
-	}
+
+	const bool removed = !conn->query_num;
 
 	while (!PQisBusy(conn->conn)) {
 		PGresult * const result = PQgetResult(conn->conn);
@@ -385,7 +370,7 @@ 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);
+	process_queries(conn, removed);
 }
 
 static void on_database_timeout(h2o_timer_t *timer)
@@ -414,18 +399,26 @@ static void on_database_write_ready(h2o_socket_t *sock, const char *err)
 		ERROR(err);
 		on_database_error(conn, err);
 	}
-	else {
-		const int send_status = PQflush(conn->conn);
+	else if (flush_connection(on_database_write_ready, conn))
+		on_database_error(conn, DB_ERROR);
+}
 
-		if (send_status < 0) {
-			LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
-			on_database_error(conn, DB_ERROR);
-		}
-		else if (send_status)
-			h2o_socket_notify_write(conn->sock, on_database_write_ready);
-		else
-			process_queries(conn);
+static void on_process_queries(void *arg)
+{
+	db_conn_pool_t * const pool = arg;
+
+	while (pool->queries.head && pool->conn) {
+		db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn);
+
+		pool->conn = conn->l.next;
+		assert(conn->query_num);
+		process_queries(conn, true);
 	}
+
+	if (pool->queries.head && pool->conn_num)
+		start_database_connect(pool, NULL);
+
+	pool->process_queries = false;
 }
 
 static void poll_database_connection(h2o_socket_t *sock, const char *err)
@@ -543,11 +536,11 @@ static void prepare_statements(db_conn_t *conn)
 	}
 	else {
 		h2o_socket_read_start(conn->sock, on_database_read_ready);
-		process_queries(conn);
+		process_queries(conn, true);
 	}
 }
 
-static void process_queries(db_conn_t *conn)
+static void process_queries(db_conn_t *conn, bool removed)
 {
 	const bool flush = conn->query_num && conn->pool->queries.head;
 
@@ -563,33 +556,34 @@ static void process_queries(db_conn_t *conn)
 
 		conn->pool->queries.head = param->l.next;
 
-		if (do_execute_query(conn, param, false)) {
+		if (do_execute_query(conn, param)) {
 			param->on_error(param, DB_ERROR);
-
-			if (PQstatus(conn->conn) != CONNECTION_OK) {
-				on_database_error(conn, DB_ERROR);
-				return;
-			}
-		}
-	}
-
-	if (flush) {
-		const int send_status = PQflush(conn->conn);
-
-		if (send_status < 0) {
-			LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn));
 			on_database_error(conn, DB_ERROR);
 			return;
 		}
-		else if (send_status)
-			h2o_socket_notify_write(conn->sock, on_database_write_ready);
 	}
 
-	if (!conn->queries.head && !(conn->flags & (EXPECT_SYNC | IDLE | IGNORE_RESULT))) {
+	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;
-		conn->flags |= IDLE;
 	}
+	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;
+
+	for (; iter && iter != &conn->l; iter = iter->next)
+		prev = &iter->next;
+
+	if (iter)
+		*prev = iter->next;
 }
 
 static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn)
@@ -666,34 +660,37 @@ int execute_database_query(db_conn_pool_t *pool, db_query_param_t *param)
 {
 	int ret = 1;
 
-	if (pool->conn) {
-		db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn);
+	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;
+			}
 
-		assert(!conn->queries.head);
-		assert(conn->flags & IDLE);
-		assert(!(conn->flags & (EXPECT_SYNC | IGNORE_RESULT)));
-		pool->conn = conn->l.next;
-		ret = do_execute_query(conn, param, true);
+			ret = 0;
+		}
+		else {
+			if (pool->conn_num)
+				start_database_connect(pool, NULL);
 
-		if (ret) {
-			if (PQstatus(conn->conn) == CONNECTION_OK) {
-				conn->l.next = pool->conn;
-				pool->conn = &conn->l;
-			}
-			else
-				start_database_connect(conn->pool, conn);
+			if (pool->conn_num < pool->config->max_db_conn_num && pool->query_num)
+				ret = 0;
 		}
-	}
-	else if (pool->query_num) {
-		if (pool->conn_num)
-			start_database_connect(pool, NULL);
 
-		if (pool->conn_num < pool->config->max_db_conn_num && pool->query_num) {
+		if (!ret) {
 			param->l.next = NULL;
 			*pool->queries.tail = &param->l;
 			pool->queries.tail = &param->l.next;
 			pool->query_num--;
-			ret = 0;
 		}
 	}
 
@@ -713,7 +710,6 @@ void free_database_connection_pool(db_conn_pool_t *pool)
 
 			assert(!conn->queries.head);
 			assert(conn->query_num == pool->config->max_pipeline_query_num);
-			assert(conn->flags & IDLE);
 			assert(!(conn->flags & (EXPECT_SYNC | IGNORE_RESULT | RESET)));
 			assert(!h2o_timer_is_linked(&conn->timer));
 			h2o_socket_read_stop(conn->sock);
@@ -731,11 +727,13 @@ void initialize_database_connection_pool(const char *conninfo,
                                          const struct config_t *config,
                                          const list_t *prepared_statements,
                                          h2o_loop_t *loop,
+                                         h2o_linklist_t *local_messages,
                                          db_conn_pool_t *pool)
 {
 	memset(pool, 0, sizeof(*pool));
 	pool->config = config;
 	pool->conninfo = conninfo ? conninfo : "";
+	pool->local_messages = local_messages;
 	pool->loop = loop;
 	pool->prepared_statements = prepared_statements;
 	pool->queries.tail = &pool->queries.head;

+ 4 - 0
frameworks/C/h2o/src/database.h

@@ -22,6 +22,7 @@
 #define DATABASE_H_
 
 #include <h2o.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <postgresql/libpq-fe.h>
 
@@ -61,6 +62,7 @@ typedef struct {
 	const struct config_t *config;
 	list_t *conn;
 	const char *conninfo;
+	h2o_linklist_t *local_messages;
 	h2o_loop_t *loop;
 	const list_t *prepared_statements;
 	// We use a FIFO queue instead of a simpler stack, otherwise the earlier queries may wait
@@ -68,6 +70,7 @@ typedef struct {
 	queue_t queries;
 	size_t conn_num;
 	size_t query_num;
+	bool process_queries;
 } db_conn_pool_t;
 
 void add_prepared_statement(const char *name, const char *query, list_t **prepared_statements);
@@ -77,6 +80,7 @@ void initialize_database_connection_pool(const char *conninfo,
                                          const struct config_t *config,
                                          const list_t *prepared_statements,
                                          h2o_loop_t *loop,
+                                         h2o_linklist_t *local_messages,
                                          db_conn_pool_t *pool);
 void remove_prepared_statements(list_t *prepared_statements);
 

+ 26 - 3
frameworks/C/h2o/src/event_loop.c

@@ -198,6 +198,13 @@ static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_
 
 				global_thread_data->ctx->shutdown = true;
 				break;
+			case TASK:
+			{
+				task_message_t * const task = H2O_STRUCT_FROM_MEMBER(task_message_t, super, msg);
+
+				task->task(task->arg);
+				break;
+			}
 			default:
 				break;
 		}
@@ -232,13 +239,15 @@ static void shutdown_server(h2o_socket_t *listener, const char *err)
 			ctx->event_loop.h2o_socket = NULL;
 		}
 
+		global_thread_data_t * const global_thread_data =
+			ctx->global_thread_data->global_data->global_thread_data;
+
 		for (size_t i = ctx->global_thread_data->config->thread_num - 1; i > 0; i--) {
 			message_t * const msg = h2o_mem_alloc(sizeof(*msg));
 
 			memset(msg, 0, sizeof(*msg));
 			msg->type = SHUTDOWN;
-			h2o_multithread_send_message(&ctx->global_thread_data[i].h2o_receiver,
-			                             &msg->super);
+			send_message(msg, &global_thread_data[i].h2o_receiver);
 		}
 	}
 }
@@ -268,8 +277,11 @@ static void start_accept_polling(const config_t *config,
 
 void event_loop(struct thread_context_t *ctx)
 {
-	while (!ctx->shutdown || ctx->event_loop.conn_num)
+	while (!ctx->shutdown || ctx->event_loop.conn_num) {
 		h2o_evloop_run(ctx->event_loop.h2o_ctx.loop, INT32_MAX);
+		process_messages(&ctx->global_thread_data->h2o_receiver,
+		                 &ctx->event_loop.local_messages);
+	}
 }
 
 void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver)
@@ -300,6 +312,7 @@ void initialize_event_loop(bool is_main_thread,
 	h2o_context_init(&loop->h2o_ctx, h2o_evloop_create(), &global_data->h2o_config);
 	loop->h2o_accept_ctx.ctx = &loop->h2o_ctx;
 	loop->h2o_accept_ctx.hosts = global_data->h2o_config.hosts;
+	h2o_linklist_init_anchor(&loop->local_messages);
 
 	if (global_data->ssl_ctx) {
 		loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx;
@@ -322,3 +335,13 @@ void initialize_event_loop(bool is_main_thread,
 		h2o_socket_read_start(global_data->signals, shutdown_server);
 	}
 }
+
+void send_local_message(message_t *msg, h2o_linklist_t *local_messages)
+{
+	h2o_linklist_insert(local_messages, &msg->super.link);
+}
+
+void send_message(message_t *msg, h2o_multithread_receiver_t *h2o_receiver)
+{
+	h2o_multithread_send_message(h2o_receiver, &msg->super);
+}

+ 11 - 1
frameworks/C/h2o/src/event_loop.h

@@ -28,7 +28,8 @@
 #include "global_data.h"
 
 typedef enum {
-	SHUTDOWN
+	SHUTDOWN,
+	TASK
 } message_type_t;
 
 struct thread_context_t;
@@ -39,6 +40,7 @@ typedef struct {
 	size_t conn_num;
 	h2o_accept_ctx_t h2o_accept_ctx;
 	h2o_context_t h2o_ctx;
+	h2o_linklist_t local_messages;
 } event_loop_t;
 
 typedef struct {
@@ -46,11 +48,19 @@ typedef struct {
 	h2o_multithread_message_t super;
 } message_t;
 
+typedef struct {
+	message_t super;
+	void *arg;
+	void (*task)(void *);
+} task_message_t;
+
 void event_loop(struct thread_context_t *ctx);
 void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver);
 void initialize_event_loop(bool is_main_thread,
                            global_data_t *global_data,
                            h2o_multithread_receiver_t *h2o_receiver,
                            event_loop_t *loop);
+void send_local_message(message_t *msg, h2o_linklist_t *local_messages);
+void send_message(message_t *msg, h2o_multithread_receiver_t *h2o_receiver);
 
 #endif // EVENT_LOOP_H_

+ 0 - 5
frameworks/C/h2o/src/global_data.h

@@ -54,7 +54,6 @@ typedef struct config_t {
 typedef struct {
 	h2o_logger_t *file_logger;
 	struct global_thread_data_t *global_thread_data;
-	list_t *postinitialization_tasks;
 	h2o_socket_t *signals;
 	SSL_CTX *ssl_ctx;
 	size_t memory_alignment;
@@ -64,8 +63,4 @@ typedef struct {
 	request_handler_data_t request_handler_data;
 } global_data_t;
 
-void add_postinitialization_task(void (*task)(struct thread_context_t *, void *),
-                                 void *arg,
-                                 list_t **postinitialization_tasks);
-
 #endif // GLOBAL_DATA_H_

+ 1 - 0
frameworks/C/h2o/src/handlers/world.c

@@ -857,6 +857,7 @@ void initialize_world_handler_thread_data(thread_context_t *ctx,
 	                                    ctx->global_thread_data->config,
 	                                    data->prepared_statements,
 	                                    ctx->event_loop.h2o_ctx.loop,
+	                                    &ctx->event_loop.local_messages,
 	                                    &thread_data->hello_world_db);
 }
 

+ 6 - 36
frameworks/C/h2o/src/main.c

@@ -21,6 +21,7 @@
 #include <h2o.h>
 #include <pthread.h>
 #include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -41,6 +42,8 @@
 #include "tls.h"
 #include "utility.h"
 
+#define HOST_NAME "default"
+#define SERVER_NAME "h2o"
 #define USAGE_MESSAGE \
 	"Usage:\n%s " \
 	"[-a <max connections accepted simultaneously>] " \
@@ -60,16 +63,9 @@
 	"[-s <HTTPS port>] " \
 	"[-t <thread number>]\n"
 
-typedef struct {
-	list_t l;
-	void *arg;
-	void (*task)(thread_context_t *, void *);
-} task_t;
-
 static void free_global_data(global_data_t *global_data);
 static int initialize_global_data(const config_t *config, global_data_t *global_data);
 static int parse_options(int argc, char *argv[], config_t *config);
-static void run_postinitialization_tasks(list_t **tasks, thread_context_t *ctx);
 static void set_default_options(config_t *config);
 static void setup_process(void);
 
@@ -106,11 +102,12 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
 	CHECK_ERRNO(sigaddset, &signals, SIGTERM);
 	CHECK_ERRNO_RETURN(global_data->signal_fd, signalfd, -1, &signals, SFD_NONBLOCK | SFD_CLOEXEC);
 	h2o_config_init(&global_data->h2o_config);
+	global_data->h2o_config.server_name = h2o_iovec_init(H2O_STRLIT(SERVER_NAME));
 
 	if (config->cert && config->key)
 		initialize_openssl(config, global_data);
 
-	const h2o_iovec_t host = h2o_iovec_init(H2O_STRLIT("default"));
+	const h2o_iovec_t host = h2o_iovec_init(H2O_STRLIT(HOST_NAME));
 	h2o_hostconf_t * const hostconf = h2o_config_register_host(&global_data->h2o_config,
 	                                                           host,
 	                                                           config->port);
@@ -126,7 +123,6 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
 	initialize_request_handlers(config,
 	                            hostconf,
 	                            log_handle,
-	                            &global_data->postinitialization_tasks,
 	                            &global_data->request_handler_data);
 
 	// Must be registered after the rest of the request handlers.
@@ -250,18 +246,6 @@ static int parse_options(int argc, char *argv[], config_t *config)
 	return 0;
 }
 
-static void run_postinitialization_tasks(list_t **tasks, thread_context_t *ctx)
-{
-	if (*tasks)
-		do {
-			task_t * const t = H2O_STRUCT_FROM_MEMBER(task_t, l, *tasks);
-
-			*tasks = (*tasks)->next;
-			t->task(ctx, t->arg);
-			free(t);
-		} while (*tasks);
-}
-
 static void set_default_options(config_t *config)
 {
 	if (!config->db_timeout)
@@ -277,7 +261,7 @@ static void set_default_options(config_t *config)
 		config->max_db_conn_num = 1;
 
 	if (!config->max_pipeline_query_num)
-		config->max_pipeline_query_num = 16;
+		config->max_pipeline_query_num = SIZE_MAX;
 
 	if (!config->max_query_num)
 		config->max_query_num = 10000;
@@ -310,19 +294,6 @@ static void setup_process(void)
 	CHECK_ERRNO(setrlimit, RLIMIT_NOFILE, &rlim);
 }
 
-void add_postinitialization_task(void (*task)(struct thread_context_t *, void *),
-                                 void *arg,
-                                 list_t **postinitialization_tasks)
-{
-	task_t * const t = h2o_mem_alloc(sizeof(*t));
-
-	memset(t, 0, sizeof(*t));
-	t->l.next = *postinitialization_tasks;
-	t->arg = arg;
-	t->task = task;
-	*postinitialization_tasks = &t->l;
-}
-
 int main(int argc, char *argv[])
 {
 	config_t config;
@@ -337,7 +308,6 @@ int main(int argc, char *argv[])
 			setup_process();
 			start_threads(global_data.global_thread_data);
 			initialize_thread_context(global_data.global_thread_data, true, &ctx);
-			run_postinitialization_tasks(&global_data.postinitialization_tasks, &ctx);
 			event_loop(&ctx);
 			// Even though this is global data, we need to close
 			// it before the associated event loop is cleaned up.

+ 0 - 2
frameworks/C/h2o/src/request_handler.c

@@ -106,10 +106,8 @@ void initialize_request_handler_thread_data(thread_context_t *ctx)
 void initialize_request_handlers(const config_t *config,
                                  h2o_hostconf_t *hostconf,
                                  h2o_access_log_filehandle_t *log_handle,
-                                 list_t **postinitialization_tasks,
                                  request_handler_data_t *data)
 {
-	IGNORE_FUNCTION_PARAMETER(postinitialization_tasks);
 	initialize_fortunes_handler(config, hostconf, log_handle, data);
 	initialize_json_serializer_handler(hostconf, log_handle);
 	initialize_plaintext_handler(hostconf, log_handle);

+ 0 - 1
frameworks/C/h2o/src/request_handler.h

@@ -56,7 +56,6 @@ void initialize_request_handler_thread_data(thread_context_t *ctx);
 void initialize_request_handlers(const config_t *config,
                                  h2o_hostconf_t *hostconf,
                                  h2o_access_log_filehandle_t *log_handle,
-                                 list_t **postinitialization_tasks,
                                  request_handler_data_t *data);
 void register_request_handler(const char *path,
                               int (*handler)(struct st_h2o_handler_t *, h2o_req_t *),

+ 4 - 5
frameworks/C/h2o/src/thread.c

@@ -170,11 +170,10 @@ void start_threads(global_thread_data_t *global_thread_data)
 			CHECK_ERROR(pthread_attr_setaffinity_np, &attr, cpusetsize, cpuset);
 		}
 
-		CHECK_ERROR(pthread_create,
-		            &global_thread_data[i].thread,
-		            &attr,
-		            run_thread,
-		            global_thread_data + i);
+		h2o_multithread_create_thread(&global_thread_data[i].thread,
+		                              &attr,
+		                              run_thread,
+		                              global_thread_data + i);
 	}
 
 	pthread_attr_destroy(&attr);

+ 30 - 10
frameworks/CSharp/aspnetcore/Benchmarks.sln

@@ -3,24 +3,44 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 17
 VisualStudioVersion = 17.0.31717.71
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformBenchmarks", "PlatformBenchmarks\PlatformBenchmarks.csproj", "{047A5FF4-56BB-4BEF-9DCF-9B6051365423}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Minimal", "src\Minimal\Minimal.csproj", "{6726997E-E741-4882-9307-066E7DC305AB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{C65B0C4A-B242-4A03-AC80-4B1DC6C1DF57}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc", "src\Mvc\Mvc.csproj", "{03750EC4-B6AF-4F73-8674-5C37C7B61667}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Platform", "src\Platform\Platform.csproj", "{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug_Database|Any CPU = Debug_Database|Any CPU
 		Debug|Any CPU = Debug|Any CPU
+		Release_Database|Any CPU = Release_Database|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{047A5FF4-56BB-4BEF-9DCF-9B6051365423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{047A5FF4-56BB-4BEF-9DCF-9B6051365423}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{047A5FF4-56BB-4BEF-9DCF-9B6051365423}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{047A5FF4-56BB-4BEF-9DCF-9B6051365423}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C65B0C4A-B242-4A03-AC80-4B1DC6C1DF57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C65B0C4A-B242-4A03-AC80-4B1DC6C1DF57}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C65B0C4A-B242-4A03-AC80-4B1DC6C1DF57}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C65B0C4A-B242-4A03-AC80-4B1DC6C1DF57}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Debug_Database|Any CPU.ActiveCfg = Debug|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Debug_Database|Any CPU.Build.0 = Debug|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Release_Database|Any CPU.ActiveCfg = Release|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Release_Database|Any CPU.Build.0 = Release|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6726997E-E741-4882-9307-066E7DC305AB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Debug_Database|Any CPU.ActiveCfg = Debug|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Debug_Database|Any CPU.Build.0 = Debug|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Release_Database|Any CPU.ActiveCfg = Release|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Release_Database|Any CPU.Build.0 = Release|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{03750EC4-B6AF-4F73-8674-5C37C7B61667}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Debug_Database|Any CPU.ActiveCfg = Debug_Database|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Debug_Database|Any CPU.Build.0 = Debug_Database|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Release_Database|Any CPU.ActiveCfg = Release_Database|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Release_Database|Any CPU.Build.0 = Release_Database|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1D73EC03-15CC-4D7C-B919-09DEA12D6EEC}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 23
frameworks/CSharp/aspnetcore/Benchmarks/Benchmarks.csproj

@@ -1,23 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-  <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
-    <OutputType>Exe</OutputType>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <TieredPGO>true</TieredPGO>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <None Update="wwwroot/**" CopyToOutputDirectory="PreserveNewest" />
-    <None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
-    <None Include="appsettings.postgresql.json" />
-    <None Include="appsettings.mysql.json" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
-
-    <PackageReference Include="Dapper" Version="2.0.123" />
-    <PackageReference Include="MySqlConnector" Version="2.2.0" />
-    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
-  </ItemGroup>
-</Project>

+ 0 - 22
frameworks/CSharp/aspnetcore/Benchmarks/Benchmarks.sln

@@ -1,22 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26507.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Benchmarks.csproj", "{8D5521DB-5F71-4F26-9E60-92A158E1F50E}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Release|Any CPU = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{8D5521DB-5F71-4F26-9E60-92A158E1F50E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{8D5521DB-5F71-4F26-9E60-92A158E1F50E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{8D5521DB-5F71-4F26-9E60-92A158E1F50E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{8D5521DB-5F71-4F26-9E60-92A158E1F50E}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal

+ 0 - 11
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/AppSettings.cs

@@ -1,11 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Benchmarks.Configuration;
-
-public class AppSettings
-{
-    public string ConnectionString { get; set; }
-
-    public DatabaseServer Database { get; set; } = DatabaseServer.None;
-}

+ 0 - 14
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleArgs.cs

@@ -1,14 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-namespace Benchmarks.Configuration;
-
-public class ConsoleArgs
-{
-    public ConsoleArgs(string[] args)
-    {
-        Args = args;
-    }
-
-    public string[] Args { get; }
-}

+ 0 - 79
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleHostScenariosConfiguration.cs

@@ -1,79 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Benchmarks.Configuration;
-
-public class ConsoleHostScenariosConfiguration : IScenariosConfiguration
-{
-    private readonly string[] _args;
-
-    public ConsoleHostScenariosConfiguration(ConsoleArgs args)
-    {
-        _args = args.Args;
-    }
-
-    public void ConfigureScenarios(Scenarios scenarios)
-    {
-        var scenarioConfig = new ConfigurationBuilder()
-            .AddJsonFile("scenarios.json", optional: true)
-            .AddCommandLine(_args)
-            .Build();
-
-        var enabledCount = 0;
-        var configuredScenarios = scenarioConfig["scenarios"];
-        if (!string.IsNullOrWhiteSpace(configuredScenarios))
-        {
-            Console.WriteLine("Scenario configuration found in scenarios.json and/or command line args");
-            var choices = configuredScenarios.Split(',');
-            foreach (var choice in choices)
-            {
-                enabledCount += scenarios.Enable(choice);
-            }
-        }
-        else
-        {
-            Console.WriteLine("Which scenarios would you like to enable?:");
-            Console.WriteLine();
-            foreach (var scenario in Scenarios.GetNames())
-            {
-                Console.WriteLine("  " + scenario);
-            }
-            Console.WriteLine();
-            Console.WriteLine("Type full or partial scenario names separated by commas and hit [Enter]");
-            Console.Write("> ");
-
-            var choices = Console.ReadLine().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-
-            if (choices.Length > 0)
-            {
-                foreach (var choice in choices)
-                {
-                    enabledCount += scenarios.Enable(choice);
-                }
-            }
-        }
-
-        if (enabledCount == 0)
-        {
-            Console.WriteLine();
-            Console.WriteLine("No matching scenarios found, enabling defaults");
-            scenarios.EnableDefault();
-        }
-
-        PrintEnabledScenarios(scenarios.GetEnabled());
-    }
-
-    private static void PrintEnabledScenarios(IEnumerable<EnabledScenario> scenarios)
-    {
-        Console.WriteLine();
-        Console.WriteLine("The following scenarios were enabled:");
-
-        var maxNameLength = scenarios.Max(s => s.Name.Length);
-
-        foreach (var scenario in scenarios)
-        {
-            Console.WriteLine($"  {scenario.Name.PadRight(maxNameLength)} -> {string.Join($"{Environment.NewLine}{"".PadLeft(maxNameLength + 6)}", scenario.Paths)}");
-        }
-        Console.WriteLine();
-    }
-}

+ 0 - 17
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/EnabledScenario.cs

@@ -1,17 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-namespace Benchmarks.Configuration;
-
-public class EnabledScenario
-{
-    public EnabledScenario(string name, IEnumerable<string> paths)
-    {
-        Name = name;
-        Paths = paths;
-    }
-
-    public string Name { get; }
-
-    public IEnumerable<string> Paths { get; }
-}

+ 0 - 9
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/IScenariosConfiguration.cs

@@ -1,9 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Benchmarks.Configuration;
-
-public interface IScenariosConfiguration
-{
-    void ConfigureScenarios(Scenarios scenarios);
-}

+ 0 - 163
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/Scenarios.cs

@@ -1,163 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Linq.Expressions;
-using System.Reflection;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-
-namespace Benchmarks.Configuration;
-
-public class Scenarios
-{
-    public Scenarios(IScenariosConfiguration scenariosConfiguration)
-    {
-        scenariosConfiguration.ConfigureScenarios(this);
-    }
-
-    [ScenarioPath("/plaintext")]
-    public bool Plaintext { get; set; }
-
-    [ScenarioPath("/json")]
-    public bool Json { get; set; }
-
-    [ScenarioPath("/128B.txt", "/512B.txt", "/1KB.txt", "/4KB.txt", "/16KB.txt", "/512KB.txt", "/1MB.txt", "/5MB.txt")]
-    public bool StaticFiles { get; set; }
-
-    [ScenarioPath("/db/raw")]
-    public bool DbSingleQueryRaw { get; set; }
-
-    [ScenarioPath("/db/ef")]
-    public bool DbSingleQueryEf { get; set; }
-
-    [ScenarioPath("/db/dapper")]
-    public bool DbSingleQueryDapper { get; set; }
-
-    [ScenarioPath("/queries/raw")]
-    public bool DbMultiQueryRaw { get; set; }
-
-    [ScenarioPath("/queries/ef")]
-    public bool DbMultiQueryEf { get; set; }
-
-    [ScenarioPath("/queries/dapper")]
-    public bool DbMultiQueryDapper { get; set; }
-
-    [ScenarioPath("/updates/raw")]
-    public bool DbMultiUpdateRaw { get; set; }
-
-    [ScenarioPath("/updates/ef")]
-    public bool DbMultiUpdateEf { get; set; }
-
-    [ScenarioPath("/updates/dapper")]
-    public bool DbMultiUpdateDapper { get; set; }
-
-    [ScenarioPath("/fortunes/raw")]
-    public bool DbFortunesRaw { get; set; }
-
-    [ScenarioPath("/fortunes/ef")]
-    public bool DbFortunesEf { get; set; }
-
-    [ScenarioPath("/fortunes/dapper")]
-    public bool DbFortunesDapper { get; set; }
-
-    [ScenarioPath("/mvc/plaintext")]
-    public bool MvcPlaintext { get; set; }
-
-    [ScenarioPath("/mvc/json")]
-    public bool MvcJson { get; set; }
-
-    [ScenarioPath("/mvc/view")]
-    public bool MvcViews { get; set; }
-
-    [ScenarioPath("/mvc/db/raw")]
-    public bool MvcDbSingleQueryRaw { get; set; }
-
-    [ScenarioPath("/mvc/db/dapper")]
-    public bool MvcDbSingleQueryDapper { get; set; }
-
-    [ScenarioPath("/mvc/db/ef")]
-    public bool MvcDbSingleQueryEf { get; set; }
-
-    [ScenarioPath("/mvc/queries/raw")]
-    public bool MvcDbMultiQueryRaw { get; set; }
-
-    [ScenarioPath("/mvc/queries/dapper")]
-    public bool MvcDbMultiQueryDapper { get; set; }
-
-    [ScenarioPath("/mvc/queries/ef")]
-    public bool MvcDbMultiQueryEf { get; set; }
-
-    [ScenarioPath("/mvc/updates/raw")]
-    public bool MvcDbMultiUpdateRaw { get; set; }
-
-    [ScenarioPath("/mvc/updates/dapper")]
-    public bool MvcDbMultiUpdateDapper { get; set; }
-
-    [ScenarioPath("/mvc/updates/ef")]
-    public bool MvcDbMultiUpdateEf { get; set; }
-
-    [ScenarioPath("/mvc/fortunes/raw")]
-    public bool MvcDbFortunesRaw { get; set; }
-
-    [ScenarioPath("/mvc/fortunes/ef")]
-    public bool MvcDbFortunesEf { get; set; }
-
-    [ScenarioPath("/mvc/fortunes/dapper")]
-    public bool MvcDbFortunesDapper { get; set; }
-
-    public bool Any(string partialName) =>
-        typeof(Scenarios).GetTypeInfo().DeclaredProperties
-            .Where(p => p.Name.IndexOf(partialName, StringComparison.Ordinal) >= 0 && (bool)p.GetValue(this))
-            .Any();
-
-    public IEnumerable<EnabledScenario> GetEnabled() =>
-        typeof(Scenarios).GetTypeInfo().DeclaredProperties
-            .Where(p => p.GetValue(this) is bool && (bool)p.GetValue(this))
-            .Select(p => new EnabledScenario(p.Name, p.GetCustomAttribute<ScenarioPathAttribute>()?.Paths));
-
-    public static IEnumerable<string> GetNames() =>
-        typeof(Scenarios).GetTypeInfo().DeclaredProperties
-            .Select(p => p.Name);
-
-    public static string[] GetPaths(Expression<Func<Scenarios, bool>> scenarioExpression) =>
-        scenarioExpression.GetPropertyAccess().GetCustomAttribute<ScenarioPathAttribute>().Paths;
-
-    public static string GetPath(Expression<Func<Scenarios, bool>> scenarioExpression) =>
-        GetPaths(scenarioExpression)[0];
-
-    public int Enable(string partialName)
-    {
-        if (string.Equals(partialName, "[default]", StringComparison.OrdinalIgnoreCase))
-        {
-            EnableDefault();
-            return 2;
-        }
-
-        var props = typeof(Scenarios).GetTypeInfo().DeclaredProperties
-            .Where(p => string.Equals(partialName, "[all]", StringComparison.OrdinalIgnoreCase) || p.Name.StartsWith(partialName, StringComparison.OrdinalIgnoreCase))
-            .ToList();
-
-        foreach (var p in props)
-        {
-            p.SetValue(this, true);
-        }
-
-        return props.Count;
-    }
-
-    public void EnableDefault()
-    {
-        Plaintext = true;
-        Json = true;
-    }
-}
-
-[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
-public sealed class ScenarioPathAttribute : Attribute
-{
-    public ScenarioPathAttribute(params string[] paths)
-    {
-        Paths = paths;
-    }
-
-    public string[] Paths { get; }
-}

+ 0 - 32
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/FortunesController.cs

@@ -1,32 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Benchmarks.Data;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Benchmarks.Controllers;
-
-[Route("mvc/fortunes")]
-public class FortunesController : Controller
-{
-    [HttpGet("raw")]
-    public async Task<IActionResult> Raw()
-    {
-        var db = HttpContext.RequestServices.GetRequiredService<RawDb>();
-        return View("Fortunes", await db.LoadFortunesRows());
-    }
-
-    [HttpGet("dapper")]
-    public async Task<IActionResult> Dapper()
-    {
-        var db = HttpContext.RequestServices.GetRequiredService<DapperDb>();
-        return View("Fortunes", await db.LoadFortunesRows());
-    }
-
-    [HttpGet("ef")]
-    public async Task<IActionResult> Ef()
-    {
-        var db = HttpContext.RequestServices.GetRequiredService<EfDb>();
-        return View("Fortunes", await db.LoadFortunesRows());
-    }
-}

+ 0 - 45
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/HomeController.cs

@@ -1,45 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-using System.Text;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Benchmarks.Controllers;
-
-[Route("mvc")]
-public class HomeController : Controller
-{
-    [HttpGet("plaintext")]
-    public IActionResult Plaintext()
-    {
-        return new PlainTextActionResult();
-    }
-
-    [HttpGet("json")]
-    [Produces("application/json")]
-    public object Json()
-    {
-        return new { message = "Hello, World!" };
-    }
-
-    [HttpGet("view")]
-    public ViewResult Index()
-    {
-        return View();
-    }
-
-    private class PlainTextActionResult : IActionResult
-    {
-        private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
-
-        public Task ExecuteResultAsync(ActionContext context)
-        {
-            var response = context.HttpContext.Response;
-            response.StatusCode = StatusCodes.Status200OK;
-            response.ContentType = "text/plain";
-            var payloadLength = _helloWorldPayload.Length;
-            response.ContentLength = payloadLength;
-            return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength);
-        }
-    }
-}

+ 0 - 39
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/MultipleQueriesController.cs

@@ -1,39 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Benchmarks.Data;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Benchmarks.Controllers;
-
-[Route("mvc/queries")]
-public class MultipleQueriesController : Controller
-{
-    [HttpGet("raw")]
-    [Produces("application/json")]
-    public Task<World[]> Raw(int queries = 1)
-    {
-        return ExecuteQuery<RawDb>(queries);
-    }
-
-    [HttpGet("dapper")]
-    [Produces("application/json")]
-    public Task<World[]> Dapper(int queries = 1)
-    {
-        return ExecuteQuery<DapperDb>(queries);
-    }
-
-    [HttpGet("ef")]
-    [Produces("application/json")]
-    public Task<World[]> Ef(int queries = 1)
-    {
-        return ExecuteQuery<EfDb>(queries);
-    }
-
-    private Task<World[]> ExecuteQuery<T>(int queries) where T : IDb
-    {
-        queries = queries < 1 ? 1 : queries > 500 ? 500 : queries;
-        var db = HttpContext.RequestServices.GetRequiredService<T>();
-        return db.LoadMultipleQueriesRows(queries);
-    }
-}

+ 0 - 39
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/MultipleUpdatesController.cs

@@ -1,39 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Benchmarks.Data;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Benchmarks.Controllers;
-
-[Route("mvc/updates")]
-public class MultipleUpdatesController : Controller
-{
-    [HttpGet("raw")]
-    [Produces("application/json")]
-    public Task<World[]> Raw(int queries = 1)
-    {
-        return ExecuteQuery<RawDb>(queries);
-    }
-
-    [HttpGet("dapper")]
-    [Produces("application/json")]
-    public Task<World[]> Dapper(int queries = 1)
-    {
-        return ExecuteQuery<DapperDb>(queries);
-    }
-
-    [HttpGet("ef")]
-    [Produces("application/json")]
-    public Task<World[]> Ef(int queries = 1)
-    {
-        return ExecuteQuery<EfDb>(queries);
-    }
-
-    private Task<World[]> ExecuteQuery<T>(int queries) where T : IDb
-    {
-        queries = queries < 1 ? 1 : queries > 500 ? 500 : queries;
-        var db = HttpContext.RequestServices.GetRequiredService<T>();
-        return db.LoadMultipleUpdatesRows(queries);
-    }
-}

+ 0 - 38
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/SingleQueryController.cs

@@ -1,38 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Benchmarks.Data;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Benchmarks.Controllers;
-
-[Route("mvc/db")]
-public class SingleQueryController : Controller
-{
-    [HttpGet("raw")]
-    [Produces("application/json")]
-    public Task<World> Raw()
-    {
-        return ExecuteQuery<RawDb>();
-    }
-
-    [HttpGet("dapper")]
-    [Produces("application/json")]
-    public Task<World> Dapper()
-    {
-        return ExecuteQuery<DapperDb>();
-    }
-
-    [HttpGet("ef")]
-    [Produces("application/json")]
-    public Task<World> Ef()
-    {
-        return ExecuteQuery<EfDb>();
-    }
-
-    private Task<World> ExecuteQuery<T>() where T : IDb
-    {
-        var db = HttpContext.RequestServices.GetRequiredService<T>();
-        return db.LoadSingleQueryRow();
-    }
-}

+ 0 - 40
frameworks/CSharp/aspnetcore/Benchmarks/Data/BatchUpdateString.cs

@@ -1,40 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-using Benchmarks.Configuration;
-
-namespace Benchmarks.Data;
-
-internal class BatchUpdateString
-{
-    private const int MaxBatch = 500;
-
-    private static readonly string[] _queries = new string[MaxBatch + 1];
-
-    public static DatabaseServer DatabaseServer;
-
-    public static string Query(int batchSize)
-    {
-        if (_queries[batchSize] != null)
-        {
-            return _queries[batchSize];
-        }
-
-        var lastIndex = batchSize - 1;
-
-        var sb = StringBuilderCache.Acquire();
-
-        if (DatabaseServer == DatabaseServer.PostgreSql)
-        {
-            sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ");
-            Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@Id_{i}, @Random_{i}), "));
-            sb.Append($"(@Id_{lastIndex}, @Random_{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id");
-        }
-        else
-        {
-            Enumerable.Range(0, batchSize).ToList().ForEach(i => sb.Append($"UPDATE world SET randomnumber = @Random_{i} WHERE id = @Id_{i};"));
-        }
-
-        return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb);
-    }
-}

+ 0 - 107
frameworks/CSharp/aspnetcore/Benchmarks/Data/DapperDb.cs

@@ -1,107 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Data.Common;
-using System.Dynamic;
-using Benchmarks.Configuration;
-using Dapper;
-using Microsoft.Extensions.Options;
-
-namespace Benchmarks.Data;
-
-public class DapperDb : IDb
-{
-    private static readonly Comparison<World> WorldSortComparison = (a, b) => a.Id.CompareTo(b.Id);
-
-    private readonly IRandom _random;
-    private readonly DbProviderFactory _dbProviderFactory;
-    private readonly string _connectionString;
-
-    public DapperDb(IRandom random, DbProviderFactory dbProviderFactory, IOptions<AppSettings> appSettings)
-    {
-        _random = random;
-        _dbProviderFactory = dbProviderFactory;
-        _connectionString = appSettings.Value.ConnectionString;
-    }
-
-    public async Task<World> LoadSingleQueryRow()
-    {
-        using var db = _dbProviderFactory.CreateConnection();
-        db.ConnectionString = _connectionString;
-
-        // Note: Don't need to open connection if only doing one thing; let dapper do it
-        return await ReadSingleRow(db);
-    }
-
-    Task<World> ReadSingleRow(DbConnection db)
-    {
-        return db.QueryFirstOrDefaultAsync<World>(
-                "SELECT id, randomnumber FROM world WHERE id = @Id",
-                new { Id = _random.Next(1, 10001) });
-    }
-
-    public async Task<World[]> LoadMultipleQueriesRows(int count)
-    {
-        var results = new World[count];
-        using (var db = _dbProviderFactory.CreateConnection())
-        {
-            db.ConnectionString = _connectionString;
-            await db.OpenAsync();
-
-            for (int i = 0; i < count; i++)
-            {
-                results[i] = await ReadSingleRow(db);
-            }
-        }
-
-        return results;
-    }
-
-    public async Task<World[]> LoadMultipleUpdatesRows(int count)
-    {
-        IDictionary<string, object> parameters = new ExpandoObject();
-
-        using (var db = _dbProviderFactory.CreateConnection())
-        {
-            db.ConnectionString = _connectionString;
-            await db.OpenAsync();
-
-            var results = new World[count];
-            for (int i = 0; i < count; i++)
-            {
-                results[i] = await ReadSingleRow(db);
-            }
-
-            for (int i = 0; i < count; i++)
-            {
-                var randomNumber = _random.Next(1, 10001);
-                parameters[$"@Random_{i}"] = randomNumber;
-                parameters[$"@Id_{i}"] = results[i].Id;
-
-                results[i].RandomNumber = randomNumber;
-            }
-
-            await db.ExecuteAsync(BatchUpdateString.Query(count), parameters);
-            return results;
-        }
-
-    }
-
-    public async Task<List<Fortune>> LoadFortunesRows()
-    {
-        List<Fortune> result;
-
-        using (var db = _dbProviderFactory.CreateConnection())
-        {
-            db.ConnectionString = _connectionString;
-
-            // Note: don't need to open connection if only doing one thing; let dapper do it
-            result = (await db.QueryAsync<Fortune>("SELECT id, message FROM fortune")).AsList();
-        }
-
-        result.Add(new Fortune { Message = "Additional fortune added at request time." });
-        result.Sort();
-
-        return result;
-    }
-}

+ 0 - 30
frameworks/CSharp/aspnetcore/Benchmarks/Data/Fortune.cs

@@ -1,30 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace Benchmarks.Data;
-
-[Table("fortune")]
-public class Fortune : IComparable<Fortune>, IComparable
-{
-    [Column("id")]
-    public int Id { get; set; }
-
-    [Column("message")]
-    [StringLength(2048)]
-    [Required]
-    public string Message { get; set; }
-
-    public int CompareTo(object obj)
-    {
-        return CompareTo((Fortune)obj);
-    }
-
-    public int CompareTo(Fortune other)
-    {
-        // Performance critical, using culture insensitive comparison
-        return String.CompareOrdinal(Message, other.Message);
-    }
-}

+ 0 - 15
frameworks/CSharp/aspnetcore/Benchmarks/Data/IDb.cs

@@ -1,15 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-namespace Benchmarks.Data;
-
-public interface IDb
-{
-    Task<World> LoadSingleQueryRow();
-
-    Task<World[]> LoadMultipleQueriesRows(int count);
-
-    Task<World[]> LoadMultipleUpdatesRows(int count);
-
-    Task<List<Fortune>> LoadFortunesRows();
-}

+ 0 - 29
frameworks/CSharp/aspnetcore/Benchmarks/Data/Random.cs

@@ -1,29 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-using System.Runtime.CompilerServices;
-
-namespace Benchmarks.Data;
-
-public class DefaultRandom : IRandom
-{
-    private static int nextSeed = 0;
-
-    // Random isn't thread safe
-    [ThreadStatic]
-    private static Random _random;
-
-    private static Random Random => _random ?? CreateRandom();
-
-    [MethodImpl(MethodImplOptions.NoInlining)]
-    private static Random CreateRandom()
-    {
-        _random = new Random(Interlocked.Increment(ref nextSeed));
-        return _random;
-    }
-
-    public int Next(int minValue, int maxValue)
-    {
-        return Random.Next(minValue, maxValue);
-    }
-}

+ 0 - 153
frameworks/CSharp/aspnetcore/Benchmarks/Data/RawDb.cs

@@ -1,153 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Data;
-using System.Data.Common;
-using Benchmarks.Configuration;
-using Microsoft.Extensions.Options;
-
-namespace Benchmarks.Data;
-
-public class RawDb : IDb
-{
-    private static readonly Comparison<World> WorldSortComparison = (a, b) => a.Id.CompareTo(b.Id);
-
-    private readonly IRandom _random;
-    private readonly DbProviderFactory _dbProviderFactory;
-    private readonly string _connectionString;
-
-    public RawDb(IRandom random, DbProviderFactory dbProviderFactory, IOptions<AppSettings> appSettings)
-    {
-        _random = random;
-        _dbProviderFactory = dbProviderFactory;
-        _connectionString = appSettings.Value.ConnectionString;
-    }
-
-    public async Task<World> LoadSingleQueryRow()
-    {
-        using var db = _dbProviderFactory.CreateConnection();
-        db.ConnectionString = _connectionString;
-        await db.OpenAsync();
-
-        using var cmd = CreateReadCommand(db);
-        return await ReadSingleRow(db, cmd);
-    }
-
-    async Task<World> ReadSingleRow(DbConnection connection, DbCommand cmd)
-    {
-        using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow))
-        {
-            await rdr.ReadAsync();
-
-            return new World
-            {
-                Id = rdr.GetInt32(0),
-                RandomNumber = rdr.GetInt32(1)
-            };
-        }
-    }
-
-    DbCommand CreateReadCommand(DbConnection connection)
-    {
-        var cmd = connection.CreateCommand();
-        cmd.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id";
-        var id = cmd.CreateParameter();
-        id.ParameterName = "@Id";
-        id.DbType = DbType.Int32;
-        id.Value = _random.Next(1, 10001);
-        cmd.Parameters.Add(id);
-
-        (cmd as MySqlConnector.MySqlCommand)?.Prepare();
-
-        return cmd;
-    }
-
-    public async Task<World[]> LoadMultipleQueriesRows(int count)
-    {
-        var result = new World[count];
-
-        using (var db = _dbProviderFactory.CreateConnection())
-        {
-            db.ConnectionString = _connectionString;
-            await db.OpenAsync();
-            using var cmd = CreateReadCommand(db);
-            for (int i = 0; i < count; i++)
-            {
-                result[i] = await ReadSingleRow(db, cmd);
-                cmd.Parameters["@Id"].Value = _random.Next(1, 10001);
-            }
-        }
-
-        return result;
-    }
-
-    public async Task<World[]> LoadMultipleUpdatesRows(int count)
-    {
-        using var db = _dbProviderFactory.CreateConnection();
-        db.ConnectionString = _connectionString;
-        await db.OpenAsync();
-
-        using var updateCmd = db.CreateCommand();
-        using var queryCmd = CreateReadCommand(db);
-        var results = new World[count];
-        for (int i = 0; i < count; i++)
-        {
-            results[i] = await ReadSingleRow(db, queryCmd);
-            queryCmd.Parameters["@Id"].Value = _random.Next(1, 10001);
-        }
-
-        updateCmd.CommandText = BatchUpdateString.Query(count);
-
-        for (int i = 0; i < count; i++)
-        {
-            var id = updateCmd.CreateParameter();
-            id.ParameterName = $"@Id_{i}";
-            id.DbType = DbType.Int32;
-            updateCmd.Parameters.Add(id);
-
-            var random = updateCmd.CreateParameter();
-            random.ParameterName = $"@Random_{i}";
-            random.DbType = DbType.Int32;
-            updateCmd.Parameters.Add(random);
-
-            var randomNumber = _random.Next(1, 10001);
-            id.Value = results[i].Id;
-            random.Value = randomNumber;
-            results[i].RandomNumber = randomNumber;
-        }
-
-        await updateCmd.ExecuteNonQueryAsync();
-        return results;
-    }
-
-    public async Task<List<Fortune>> LoadFortunesRows()
-    {
-        var result = new List<Fortune>();
-
-        using (var db = _dbProviderFactory.CreateConnection())
-        using (var cmd = db.CreateCommand())
-        {
-            cmd.CommandText = "SELECT id, message FROM fortune";
-
-            db.ConnectionString = _connectionString;
-            await db.OpenAsync();
-
-            (cmd as MySqlConnector.MySqlCommand)?.Prepare();
-
-            using var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
-            while (await rdr.ReadAsync())
-            {
-                result.Add(new Fortune
-                {
-                    Id = rdr.GetInt32(0),
-                    Message = rdr.GetString(1)
-                });
-            }
-        }
-
-        result.Add(new Fortune { Message = "Additional fortune added at request time." });
-        result.Sort();
-
-        return result;
-    }
-}

+ 0 - 57
frameworks/CSharp/aspnetcore/Benchmarks/Data/StringBuilderCache.cs

@@ -1,57 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
-
-using System.Text;
-
-namespace Benchmarks.Data;
-
-internal static class StringBuilderCache
-{
-    private const int DefaultCapacity = 1386;
-    private const int MaxBuilderSize = DefaultCapacity * 3;
-
-    [ThreadStatic]
-    private static StringBuilder t_cachedInstance;
-
-    /// <summary>Get a StringBuilder for the specified capacity.</summary>
-    /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
-    public static StringBuilder Acquire(int capacity = DefaultCapacity)
-    {
-        if (capacity <= MaxBuilderSize)
-        {
-            StringBuilder sb = t_cachedInstance;
-            if (capacity < DefaultCapacity)
-            {
-                capacity = DefaultCapacity;
-            }
-
-            if (sb != null)
-            {
-                // Avoid stringbuilder block fragmentation by getting a new StringBuilder
-                // when the requested size is larger than the current capacity
-                if (capacity <= sb.Capacity)
-                {
-                    t_cachedInstance = null;
-                    sb.Clear();
-                    return sb;
-                }
-            }
-        }
-        return new StringBuilder(capacity);
-    }
-
-    public static void Release(StringBuilder sb)
-    {
-        if (sb.Capacity <= MaxBuilderSize)
-        {
-            t_cachedInstance = sb;
-        }
-    }
-
-    public static string GetStringAndRelease(StringBuilder sb)
-    {
-        string result = sb.ToString();
-        Release(sb);
-        return result;
-    }
-}

+ 0 - 45
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesDapperMiddleware.cs

@@ -1,45 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Encodings.Web;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class FortunesDapperMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbFortunesDapper));
-
-    private readonly RequestDelegate _next;
-    private readonly HtmlEncoder _htmlEncoder;
-
-    public FortunesDapperMiddleware(RequestDelegate next, HtmlEncoder htmlEncoder)
-    {
-        _next = next;
-        _htmlEncoder = htmlEncoder;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var db = httpContext.RequestServices.GetService<DapperDb>();
-            var rows = await db.LoadFortunesRows();
-
-            await MiddlewareHelpers.RenderFortunesHtml(rows, httpContext, _htmlEncoder);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class FortunesDapperMiddlewareExtensions
-{
-    public static IApplicationBuilder UseFortunesDapper(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<FortunesDapperMiddleware>();
-    }
-}

+ 0 - 45
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesEfMiddleware.cs

@@ -1,45 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Encodings.Web;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class FortunesEfMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbFortunesEf));
-
-    private readonly RequestDelegate _next;
-    private readonly HtmlEncoder _htmlEncoder;
-
-    public FortunesEfMiddleware(RequestDelegate next, HtmlEncoder htmlEncoder)
-    {
-        _next = next;
-        _htmlEncoder = htmlEncoder;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var db = httpContext.RequestServices.GetService<EfDb>();
-            var rows = await db.LoadFortunesRows();
-
-            await MiddlewareHelpers.RenderFortunesHtml(rows, httpContext, _htmlEncoder);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class FortunesEfMiddlewareExtensions
-{
-    public static IApplicationBuilder UseFortunesEf(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<FortunesEfMiddleware>();
-    }
-}

+ 0 - 45
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesRawMiddleware.cs

@@ -1,45 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Encodings.Web;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class FortunesRawMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbFortunesRaw));
-
-    private readonly RequestDelegate _next;
-    private readonly HtmlEncoder _htmlEncoder;
-
-    public FortunesRawMiddleware(RequestDelegate next, HtmlEncoder htmlEncoder)
-    {
-        _next = next;
-        _htmlEncoder = htmlEncoder;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var db = httpContext.RequestServices.GetService<RawDb>();
-            var rows = await db.LoadFortunesRows();
-
-            await MiddlewareHelpers.RenderFortunesHtml(rows, httpContext, _htmlEncoder);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class FortunesRawMiddlewareExtensions
-{
-    public static IApplicationBuilder UseFortunesRaw(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<FortunesRawMiddleware>();
-    }
-}

+ 0 - 47
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/JsonMiddleware.cs

@@ -1,47 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-
-namespace Benchmarks.Middleware;
-
-public class JsonMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.Json));
-    private const int _bufferSize = 27;
-
-    private readonly RequestDelegate _next;
-
-    public JsonMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            httpContext.Response.StatusCode = 200;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = _bufferSize;
-
-            return JsonSerializer.SerializeAsync<JsonMessage>(httpContext.Response.Body, new JsonMessage { message = "Hello, World!" });
-        }
-
-        return _next(httpContext);
-    }
-}
-
-public static class JsonMiddlewareExtensions
-{
-    public static IApplicationBuilder UseJson(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<JsonMiddleware>();
-    }
-}
-
-public struct JsonMessage
-{
-    public string message { get; set; }
-}

+ 0 - 52
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MiddlewareHelpers.cs

@@ -1,52 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved. 
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Globalization;
-using System.Text;
-using System.Text.Encodings.Web;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public static class MiddlewareHelpers
-{
-    public static int GetMultipleQueriesQueryCount(HttpContext httpContext)
-    {
-        var queries = 1;
-        var queriesRaw = httpContext.Request.Query["queries"];
-
-        if (queriesRaw.Count == 1)
-        {
-            int.TryParse(queriesRaw, out queries);
-        }
-
-        return queries > 500
-            ? 500
-            : queries > 0
-                ? queries
-                : 1;
-    }
-
-    public static Task RenderFortunesHtml(IEnumerable<Fortune> model, HttpContext httpContext, HtmlEncoder htmlEncoder)
-    {
-        httpContext.Response.StatusCode = StatusCodes.Status200OK;
-        httpContext.Response.ContentType = "text/html; charset=UTF-8";
-
-        var sb = StringBuilderCache.Acquire();
-        sb.Append("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>");
-        foreach (var item in model)
-        {
-            sb.Append("<tr><td>");
-            sb.Append(item.Id.ToString(CultureInfo.InvariantCulture));
-            sb.Append("</td><td>");
-            sb.Append(htmlEncoder.Encode(item.Message));
-            sb.Append("</td></tr>");
-        }
-
-        sb.Append("</table></body></html>");
-        var response = StringBuilderCache.GetStringAndRelease(sb);
-        // fortunes includes multibyte characters so response.Length is incorrect
-        httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(response);
-        return httpContext.Response.WriteAsync(response);
-    }
-}

+ 0 - 52
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesDapperMiddleware.cs

@@ -1,52 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class MultipleQueriesDapperMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbMultiQueryDapper));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public MultipleQueriesDapperMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
-
-            var db = httpContext.RequestServices.GetService<DapperDb>();
-            var rows = await db.LoadMultipleQueriesRows(count);
-
-            var result = JsonSerializer.Serialize(rows, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class MultipleQueriesDapperMiddlewareExtensions
-{
-    public static IApplicationBuilder UseMultipleQueriesDapper(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<MultipleQueriesDapperMiddleware>();
-    }
-}

+ 0 - 52
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesEfMiddleware.cs

@@ -1,52 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class MultipleQueriesEfMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbMultiQueryEf));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public MultipleQueriesEfMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
-
-            var db = httpContext.RequestServices.GetService<EfDb>();
-            var rows = await db.LoadMultipleQueriesRows(count);
-
-            var result = JsonSerializer.Serialize(rows, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class MultipleQueriesEfMiddlewareExtensions
-{
-    public static IApplicationBuilder UseMultipleQueriesEf(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<MultipleQueriesEfMiddleware>();
-    }
-}

+ 0 - 52
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesRawMiddleware.cs

@@ -1,52 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class MultipleQueriesRawMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbMultiQueryRaw));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public MultipleQueriesRawMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
-
-            var db = httpContext.RequestServices.GetService<RawDb>();
-            var rows = await db.LoadMultipleQueriesRows(count);
-
-            var result = JsonSerializer.Serialize(rows, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class MultipleQueriesRawMiddlewareExtensions
-{
-    public static IApplicationBuilder UseMultipleQueriesRaw(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<MultipleQueriesRawMiddleware>();
-    }
-}

+ 0 - 51
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleUpdatesDapperMiddleware.cs

@@ -1,51 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class MultipleUpdatesDapperMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbMultiUpdateDapper));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-    private readonly RequestDelegate _next;
-
-    public MultipleUpdatesDapperMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
-
-            var db = httpContext.RequestServices.GetService<DapperDb>();
-            var rows = await db.LoadMultipleUpdatesRows(count);
-
-            var result = JsonSerializer.Serialize(rows, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class MultipleUpdatesDapperMiddlewareExtensions
-{
-    public static IApplicationBuilder UseMultipleUpdatesDapper(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<MultipleUpdatesDapperMiddleware>();
-    }
-}

+ 0 - 51
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleUpdatesEfMiddleware.cs

@@ -1,51 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class MultipleUpdatesEfMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbMultiUpdateEf));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-    private readonly RequestDelegate _next;
-
-    public MultipleUpdatesEfMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
-
-            var db = httpContext.RequestServices.GetService<EfDb>();
-            var rows = await db.LoadMultipleUpdatesRows(count);
-
-            var result = JsonSerializer.Serialize(rows, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class MultipleUpdatesEfMiddlewareExtensions
-{
-    public static IApplicationBuilder UseMultipleUpdatesEf(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<MultipleUpdatesEfMiddleware>();
-    }
-}

+ 0 - 52
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleUpdatesRawMiddleware.cs

@@ -1,52 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class MultipleUpdatesRawMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbMultiUpdateRaw));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public MultipleUpdatesRawMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
-
-            var db = httpContext.RequestServices.GetService<RawDb>();
-            var rows = await db.LoadMultipleUpdatesRows(count);
-
-            var result = JsonSerializer.Serialize(rows, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class MultipleUpdatesRawMiddlewareExtensions
-{
-    public static IApplicationBuilder UseMultipleUpdatesRaw(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<MultipleUpdatesRawMiddleware>();
-    }
-}

+ 0 - 47
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/PlaintextMiddleware.cs

@@ -1,47 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text;
-using Benchmarks.Configuration;
-
-namespace Benchmarks.Middleware;
-
-public class PlaintextMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.Plaintext));
-    private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
-
-    private readonly RequestDelegate _next;
-
-    public PlaintextMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            return WriteResponse(httpContext.Response);
-        }
-
-        return _next(httpContext);
-    }
-
-    public static Task WriteResponse(HttpResponse response)
-    {
-        var payloadLength = _helloWorldPayload.Length;
-        response.StatusCode = 200;
-        response.ContentType = "text/plain";
-        response.ContentLength = payloadLength;
-        return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength);
-    }
-}
-
-public static class PlaintextMiddlewareExtensions
-{
-    public static IApplicationBuilder UsePlainText(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<PlaintextMiddleware>();
-    }
-}

+ 0 - 50
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryDapperMiddleware.cs

@@ -1,50 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class SingleQueryDapperMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbSingleQueryDapper));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public SingleQueryDapperMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var db = httpContext.RequestServices.GetService<DapperDb>();
-            var row = await db.LoadSingleQueryRow();
-
-            var result = JsonSerializer.Serialize(row, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class SingleQueryDapperMiddlewareExtensions
-{
-    public static IApplicationBuilder UseSingleQueryDapper(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<SingleQueryDapperMiddleware>();
-    }
-}

+ 0 - 49
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryEfMiddleware.cs

@@ -1,49 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class SingleQueryEfMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbSingleQueryEf));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public SingleQueryEfMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var db = httpContext.RequestServices.GetService<EfDb>();
-            var row = await db.LoadSingleQueryRow();
-            var result = JsonSerializer.Serialize(row, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class SingleQueryEfMiddlewareExtensions
-{
-    public static IApplicationBuilder UseSingleQueryEf(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<SingleQueryEfMiddleware>();
-    }
-}

+ 0 - 50
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryRawMiddleware.cs

@@ -1,50 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-
-namespace Benchmarks.Middleware;
-
-public class SingleQueryRawMiddleware
-{
-    private static readonly PathString _path = new(Scenarios.GetPath(s => s.DbSingleQueryRaw));
-    private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
-    private readonly RequestDelegate _next;
-
-    public SingleQueryRawMiddleware(RequestDelegate next)
-    {
-        _next = next;
-    }
-
-    public async Task Invoke(HttpContext httpContext)
-    {
-        if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
-        {
-            var db = httpContext.RequestServices.GetService<RawDb>();
-            var row = await db.LoadSingleQueryRow();
-
-            var result = JsonSerializer.Serialize(row, _serializerOptions);
-
-            httpContext.Response.StatusCode = StatusCodes.Status200OK;
-            httpContext.Response.ContentType = "application/json";
-            httpContext.Response.ContentLength = result.Length;
-
-            await httpContext.Response.WriteAsync(result);
-
-            return;
-        }
-
-        await _next(httpContext);
-    }
-}
-
-public static class SingleQueryRawMiddlewareExtensions
-{
-    public static IApplicationBuilder UseSingleQueryRaw(this IApplicationBuilder builder)
-    {
-        return builder.UseMiddleware<SingleQueryRawMiddleware>();
-    }
-}

+ 0 - 31
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.Designer.cs

@@ -1,31 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Benchmarks.Data;
-
-namespace Benchmarks.Migrations
-{
-    [DbContext(typeof(ApplicationDbContext))]
-    [Migration("20151113004227_Initial")]
-    partial class Initial
-    {
-        protected override void BuildTargetModel(ModelBuilder modelBuilder)
-        {
-            modelBuilder
-                .HasAnnotation("ProductVersion", "7.0.0-rc2-16329")
-                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
-
-            modelBuilder.Entity("AspNet5.Data.World", b =>
-                {
-                    b.Property<int>("Id")
-                        .ValueGeneratedOnAdd();
-
-                    b.Property<int>("RandomNumber");
-
-                    b.HasKey("Id");
-                });
-        }
-    }
-}

+ 0 - 32
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.cs

@@ -1,32 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Metadata;
-using System.Text;
-
-namespace Benchmarks.Migrations
-{
-    public partial class Initial : Migration
-    {
-        protected override void Up(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.CreateTable(
-                name: "World",
-                columns: table => new
-                {
-                    Id = table.Column<int>(nullable: false)
-                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
-                    RandomNumber = table.Column<int>(nullable: false)
-                },
-                constraints: table =>
-                {
-                    table.PrimaryKey("PK_World", x => x.Id);
-                });
-        }
-
-        protected override void Down(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.DropTable("World");
-        }
-    }
-}

+ 0 - 42
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.Designer.cs

@@ -1,42 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Benchmarks.Data;
-
-namespace Benchmarks.Migrations
-{
-    [DbContext(typeof(ApplicationDbContext))]
-    [Migration("20151124205054_Fortune")]
-    partial class Fortune
-    {
-        protected override void BuildTargetModel(ModelBuilder modelBuilder)
-        {
-            modelBuilder
-                .HasAnnotation("ProductVersion", "7.0.0-rc2-16413")
-                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
-
-            modelBuilder.Entity("Benchmarks.Data.Fortune", b =>
-                {
-                    b.Property<int>("Id")
-                        .ValueGeneratedOnAdd();
-
-                    b.Property<string>("Message")
-                        .HasAnnotation("MaxLength", 2048);
-
-                    b.HasKey("Id");
-                });
-
-            modelBuilder.Entity("Benchmarks.Data.World", b =>
-                {
-                    b.Property<int>("Id")
-                        .ValueGeneratedOnAdd();
-
-                    b.Property<int>("RandomNumber");
-
-                    b.HasKey("Id");
-                });
-        }
-    }
-}

+ 0 - 32
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.cs

@@ -1,32 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Metadata;
-
-namespace Benchmarks.Migrations
-{
-    public partial class Fortune : Migration
-    {
-        protected override void Up(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.CreateTable(
-                name: "Fortune",
-                columns: table => new
-                {
-                    Id = table.Column<int>(nullable: false)
-                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
-                    Message = table.Column<string>(nullable: true)
-                },
-                constraints: table =>
-                {
-                    table.PrimaryKey("PK_Fortune", x => x.Id);
-                });
-        }
-
-        protected override void Down(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.DropTable(
-                name: "Fortune");
-        }
-    }
-}

+ 0 - 41
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/ApplicationDbContextModelSnapshot.cs

@@ -1,41 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Benchmarks.Data;
-
-namespace Benchmarks.Migrations
-{
-    [DbContext(typeof(ApplicationDbContext))]
-    partial class ApplicationDbContextModelSnapshot : ModelSnapshot
-    {
-        protected override void BuildModel(ModelBuilder modelBuilder)
-        {
-            modelBuilder
-                .HasAnnotation("ProductVersion", "7.0.0-rc2-16413")
-                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
-
-            modelBuilder.Entity("Benchmarks.Data.Fortune", b =>
-                {
-                    b.Property<int>("Id")
-                        .ValueGeneratedOnAdd();
-
-                    b.Property<string>("Message")
-                        .HasAnnotation("MaxLength", 2048);
-
-                    b.HasKey("Id");
-                });
-
-            modelBuilder.Entity("Benchmarks.Data.World", b =>
-                {
-                    b.Property<int>("Id")
-                        .ValueGeneratedOnAdd();
-
-                    b.Property<int>("RandomNumber");
-
-                    b.HasKey("Id");
-                });
-        }
-    }
-}

+ 0 - 68
frameworks/CSharp/aspnetcore/Benchmarks/Program.cs

@@ -1,68 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Reflection;
-using System.Runtime;
-using Benchmarks.Configuration;
-
-namespace Benchmarks;
-
-public class Program
-{
-    public static string[] Args;
-
-    public static void Main(string[] args)
-    {
-        Args = args;
-
-        Console.WriteLine();
-        Console.WriteLine("ASP.NET Core Benchmarks");
-        Console.WriteLine("-----------------------");
-
-        Console.WriteLine($"Current directory: {Directory.GetCurrentDirectory()}");
-        Console.WriteLine($"WebHostBuilder loading from: {typeof(WebHostBuilder).GetTypeInfo().Assembly.Location}");
-
-        var config = new ConfigurationBuilder()
-            .AddJsonFile("hosting.json", optional: true)
-            .AddEnvironmentVariables(prefix: "ASPNETCORE_")
-            .AddCommandLine(args)
-            .Build();
-
-        var webHostBuilder = new WebHostBuilder()
-            .UseContentRoot(Directory.GetCurrentDirectory())
-            .UseConfiguration(config)
-            .UseStartup<Startup>()
-            .ConfigureServices(services => services
-                .AddSingleton(new ConsoleArgs(args))
-                .AddSingleton<IScenariosConfiguration, ConsoleHostScenariosConfiguration>()
-                .AddSingleton<Scenarios>()
-            )
-            .UseDefaultServiceProvider(
-                (context, options) => options.ValidateScopes = context.HostingEnvironment.IsDevelopment())
-            .UseKestrel();
-
-        var threadCount = GetThreadCount(config);
-
-        webHostBuilder.UseSockets(x =>
-        {
-            if (threadCount > 0)
-            {
-                x.IOQueueCount = threadCount;
-            }
-
-            Console.WriteLine($"Using Sockets with {x.IOQueueCount} threads");
-        });
-
-        var webHost = webHostBuilder.Build();
-
-        Console.WriteLine($"Server GC is currently {(GCSettings.IsServerGC ? "ENABLED" : "DISABLED")}");
-
-        webHost.Run();
-    }
-
-    private static int GetThreadCount(IConfigurationRoot config)
-    {
-        var threadCountValue = config["threadCount"];
-        return threadCountValue == null ? -1 : int.Parse(threadCountValue);
-    }
-}

+ 0 - 208
frameworks/CSharp/aspnetcore/Benchmarks/Startup.cs

@@ -1,208 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Benchmarks.Configuration;
-using Benchmarks.Data;
-using Benchmarks.Middleware;
-using Microsoft.EntityFrameworkCore;
-using MySqlConnector;
-using Npgsql;
-using System.Data.Common;
-using System.Text.Encodings.Web;
-using System.Text.Unicode;
-using Microsoft.EntityFrameworkCore.Storage;
-
-namespace Benchmarks;
-
-public class Startup
-{
-    public Startup(IWebHostEnvironment hostingEnv, Scenarios scenarios)
-    {
-        // Set up configuration sources.
-        var builder = new ConfigurationBuilder()
-            .SetBasePath(hostingEnv.ContentRootPath)
-            .AddJsonFile("appsettings.json")
-            .AddJsonFile($"appsettings.{hostingEnv.EnvironmentName}.json", optional: true)
-            .AddEnvironmentVariables()
-            .AddCommandLine(Program.Args)
-            ;
-
-        Configuration = builder.Build();
-
-        Scenarios = scenarios;
-    }
-
-    public IConfigurationRoot Configuration { get; set; }
-
-    public Scenarios Scenarios { get; }
-
-    public void ConfigureServices(IServiceCollection services)
-    {
-        services.Configure<AppSettings>(Configuration);
-
-        // We re-register the Scenarios as an instance singleton here to avoid it being created again due to the
-        // registration done in Program.Main
-        services.AddSingleton(Scenarios);
-
-        // Common DB services
-        services.AddSingleton<IRandom, DefaultRandom>();
-        services.AddEntityFrameworkSqlServer();
-
-        var appSettings = Configuration.Get<AppSettings>();
-        BatchUpdateString.DatabaseServer = appSettings.Database;
-
-        Console.WriteLine($"Database: {appSettings.Database}");
-
-        if (appSettings.Database == DatabaseServer.PostgreSql)
-        {
-            if (Scenarios.Any("Ef"))
-            {
-                services.AddDbContextPool<ApplicationDbContext>(options => options
-                    .UseNpgsql(appSettings.ConnectionString,
-                        o => o.ExecutionStrategy(d => new NonRetryingExecutionStrategy(d)))
-                    .EnableThreadSafetyChecks(false));
-            }
-
-            if (Scenarios.Any("Raw") || Scenarios.Any("Dapper"))
-            {
-                services.AddSingleton<DbProviderFactory>(NpgsqlFactory.Instance);
-            }
-        }
-        else if (appSettings.Database == DatabaseServer.MySql)
-        {
-            if (Scenarios.Any("Raw") || Scenarios.Any("Dapper"))
-            {
-                services.AddSingleton<DbProviderFactory>(MySqlConnectorFactory.Instance);
-            }
-        }
-
-        if (Scenarios.Any("Ef"))
-        {
-            services.AddScoped<EfDb>();
-        }
-
-        if (Scenarios.Any("Raw"))
-        {
-            services.AddScoped<RawDb>();
-        }
-
-        if (Scenarios.Any("Dapper"))
-        {
-            services.AddScoped<DapperDb>();
-        }
-
-        if (Scenarios.Any("Fortunes"))
-        {
-            var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana);
-            settings.AllowCharacter('\u2014');  // allow EM DASH through
-            services.AddWebEncoders((options) =>
-            {
-                options.TextEncoderSettings = settings;
-            });
-        }
-
-        if (Scenarios.Any("Mvc"))
-        {
-            var mvcBuilder = services.AddMvcCore();
-
-            if (Scenarios.MvcViews || Scenarios.Any("MvcDbFortunes"))
-            {
-                mvcBuilder
-                    .AddViews()
-                    .AddRazorViewEngine();
-            }
-        }
-    }
-
-    public void Configure(IApplicationBuilder app)
-    {
-        if (Scenarios.Plaintext)
-        {
-            app.UsePlainText();
-        }
-
-        if (Scenarios.Json)
-        {
-            app.UseJson();
-        }
-
-        // Fortunes endpoints
-        if (Scenarios.DbFortunesRaw)
-        {
-            app.UseFortunesRaw();
-        }
-
-        if (Scenarios.DbFortunesDapper)
-        {
-            app.UseFortunesDapper();
-        }
-
-        if (Scenarios.DbFortunesEf)
-        {
-            app.UseFortunesEf();
-        }
-
-        // Single query endpoints
-        if (Scenarios.DbSingleQueryRaw)
-        {
-            app.UseSingleQueryRaw();
-        }
-
-        if (Scenarios.DbSingleQueryDapper)
-        {
-            app.UseSingleQueryDapper();
-        }
-
-        if (Scenarios.DbSingleQueryEf)
-        {
-            app.UseSingleQueryEf();
-        }
-
-        // Multiple query endpoints
-        if (Scenarios.DbMultiQueryRaw)
-        {
-            app.UseMultipleQueriesRaw();
-        }
-
-        if (Scenarios.DbMultiQueryDapper)
-        {
-            app.UseMultipleQueriesDapper();
-        }
-
-        if (Scenarios.DbMultiQueryEf)
-        {
-            app.UseMultipleQueriesEf();
-        }
-
-        // Multiple update endpoints
-        if (Scenarios.DbMultiUpdateRaw)
-        {
-            app.UseMultipleUpdatesRaw();
-        }
-
-        if (Scenarios.DbMultiUpdateDapper)
-        {
-            app.UseMultipleUpdatesDapper();
-        }
-
-        if (Scenarios.DbMultiUpdateEf)
-        {
-            app.UseMultipleUpdatesEf();
-        }
-
-        if (Scenarios.Any("Mvc"))
-        {
-            app.UseRouting();
-
-            app.UseEndpoints(endpoints =>
-            {
-                endpoints.MapControllers();
-            });
-        }
-
-        if (Scenarios.StaticFiles)
-        {
-            app.UseStaticFiles();
-        }
-    }
-}

+ 0 - 5
frameworks/CSharp/aspnetcore/Benchmarks/Views/Home/Index.cshtml

@@ -1,5 +0,0 @@
-@{
-    var message = "Hello, World!";
-}
-
-@message

+ 0 - 3
frameworks/CSharp/aspnetcore/Benchmarks/appsettings.json

@@ -1,3 +0,0 @@
-{
-  "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnetcore-Benchmarks;Trusted_Connection=True;MultipleActiveResultSets=true"
-}

+ 0 - 4
frameworks/CSharp/aspnetcore/Benchmarks/appsettings.postgresql.updates.json

@@ -1,4 +0,0 @@
-{
-  "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000",
-  "Database": "postgresql"
-}

BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/1KB.txt


+ 0 - 67
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs

@@ -1,67 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-#if DATABASE
-
-using System.IO.Pipelines;
-using System.Runtime.CompilerServices;
-using RazorSlices;
-
-namespace PlatformBenchmarks
-{
-    public partial class BenchmarkApplication
-    {
-        private async Task Fortunes(PipeWriter pipeWriter)
-        {
-            await OutputFortunes(pipeWriter, await Db.LoadFortunesRows(), FortunesTemplateFactory);
-        }
-
-        private ValueTask OutputFortunes<TModel>(PipeWriter pipeWriter, TModel model, SliceFactory<TModel> templateFactory)
-        {
-            // Render headers
-            var preamble = """
-                HTTP/1.1 200 OK
-                Server: K
-                Content-Type: text/html; charset=utf-8
-                Transfer-Encoding: chunked
-                """u8;
-            var headersLength = preamble.Length + DateHeader.HeaderBytes.Length;
-            var headersSpan = pipeWriter.GetSpan(headersLength);
-            preamble.CopyTo(headersSpan);
-            DateHeader.HeaderBytes.CopyTo(headersSpan[preamble.Length..]);
-            pipeWriter.Advance(headersLength);
-
-            // Render body
-            var template = templateFactory(model);
-            // Kestrel PipeWriter span size is 4K, headers above already written to first span & template output is ~1350 bytes,
-            // so 2K chunk size should result in only a single span and chunk being used.
-            var chunkedWriter = GetChunkedWriter(pipeWriter, chunkSizeHint: 2048);
-            var renderTask = template.RenderAsync(chunkedWriter, null, HtmlEncoder);
-
-            if (renderTask.IsCompletedSuccessfully)
-            {
-                renderTask.GetAwaiter().GetResult();
-                EndTemplateRendering(chunkedWriter, template);
-                return ValueTask.CompletedTask;
-            }
-
-            return AwaitTemplateRenderTask(renderTask, chunkedWriter, template);
-        }
-
-        private static async ValueTask AwaitTemplateRenderTask(ValueTask renderTask, ChunkedBufferWriter<WriterAdapter> chunkedWriter, RazorSlice template)
-        {
-            await renderTask;
-            EndTemplateRendering(chunkedWriter, template);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static void EndTemplateRendering(ChunkedBufferWriter<WriterAdapter> chunkedWriter, RazorSlice template)
-        {
-            chunkedWriter.End();
-            ReturnChunkedWriter(chunkedWriter);
-            template.Dispose();
-        }
-    }
-}
-
-#endif

+ 0 - 46
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs

@@ -1,46 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-#if DATABASE
-
-using System.IO.Pipelines;
-using System.Text.Json;
-using System.Text.Json.Serialization.Metadata;
-using System.Threading.Tasks;
-
-namespace PlatformBenchmarks
-{
-    public partial class BenchmarkApplication
-    {
-        private static async Task MultipleQueries(PipeWriter pipeWriter, int count)
-        {
-            OutputMultipleQueries(pipeWriter, await Db.LoadMultipleQueriesRows(count), SerializerContext.WorldArray);
-        }
-
-        private static void OutputMultipleQueries<TWorld>(PipeWriter pipeWriter, TWorld[] rows, JsonTypeInfo<TWorld[]> jsonTypeInfo)
-        {
-            var writer = GetWriter(pipeWriter, sizeHint: 160 * rows.Length); // in reality it's 152 for one
-
-            writer.Write(_dbPreamble);
-
-            var lengthWriter = writer;
-            writer.Write(_contentLengthGap);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            writer.Commit();
-
-            var utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
-            utf8JsonWriter.Reset(pipeWriter);
-
-            // Body
-            JsonSerializer.Serialize(utf8JsonWriter, rows, jsonTypeInfo);
-
-            // Content-Length
-            lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
-        }
-    }
-}
-
-#endif

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