Browse Source

Upgrade to Cutelyst 3.7, ASql 0.74 and Qt6 (#7700)

Daniel Nicoletti 2 years ago
parent
commit
e743e8a197
33 changed files with 289 additions and 205 deletions
  1. 27 25
      frameworks/C++/cutelyst/benchmark_config.json
  2. 13 13
      frameworks/C++/cutelyst/build.sh
  3. 1 1
      frameworks/C++/cutelyst/cutelyst-nginx-my.dockerfile
  4. 1 1
      frameworks/C++/cutelyst/cutelyst-nginx-pg.dockerfile
  5. 1 1
      frameworks/C++/cutelyst/cutelyst-nginx.dockerfile
  6. 1 1
      frameworks/C++/cutelyst/cutelyst-pf-apg-batch.dockerfile
  7. 1 1
      frameworks/C++/cutelyst/cutelyst-pf-apg.dockerfile
  8. 1 1
      frameworks/C++/cutelyst/cutelyst-pf-my.dockerfile
  9. 1 1
      frameworks/C++/cutelyst/cutelyst-pf-pg.dockerfile
  10. 1 1
      frameworks/C++/cutelyst/cutelyst-t-apg-cutelee.dockerfile
  11. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-apg-batch.dockerfile
  12. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-apg.dockerfile
  13. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-my-cutelee.dockerfile
  14. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-my.dockerfile
  15. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-pg-cutelee.dockerfile
  16. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-pg.dockerfile
  17. 1 1
      frameworks/C++/cutelyst/cutelyst-thread-pico.dockerfile
  18. 1 1
      frameworks/C++/cutelyst/cutelyst-thread.dockerfile
  19. 1 1
      frameworks/C++/cutelyst/cutelyst.dockerfile
  20. 16 14
      frameworks/C++/cutelyst/src/CMakeLists.txt
  21. 70 0
      frameworks/C++/cutelyst/src/cachedqueries.cpp
  22. 19 0
      frameworks/C++/cutelyst/src/cachedqueries.h
  23. 16 7
      frameworks/C++/cutelyst/src/cutelyst-benchmarks.cpp
  24. 39 38
      frameworks/C++/cutelyst/src/databaseupdatestest.cpp
  25. 4 4
      frameworks/C++/cutelyst/src/databaseupdatestest.h
  26. 6 4
      frameworks/C++/cutelyst/src/fortunetest.cpp
  27. 6 6
      frameworks/C++/cutelyst/src/fortunetest.h
  28. 7 5
      frameworks/C++/cutelyst/src/multipledatabasequeriestest.cpp
  29. 3 3
      frameworks/C++/cutelyst/src/multipledatabasequeriestest.h
  30. 0 37
      frameworks/C++/cutelyst/src/root.cpp
  31. 0 22
      frameworks/C++/cutelyst/src/root.h
  32. 39 6
      frameworks/C++/cutelyst/src/singledatabasequerytest.cpp
  33. 7 4
      frameworks/C++/cutelyst/src/singledatabasequerytest.h

+ 27 - 25
frameworks/C++/cutelyst/benchmark_config.json

@@ -20,10 +20,11 @@
                 "versus": ""
             },
             "pf-apg": {
-                "db_url": "/dbp",
-                "query_url": "/queriesp?queries=",
+                "db_url": "/pg",
+                "query_url": "/querAPG?queries=",
                 "update_url": "/updatep?queries=",
-                "fortune_url": "/fortunes_raw_p",
+                "fortune_url": "/f_RW_APG",
+                "cached_query_url": "/cached_queries?count=",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -57,10 +58,10 @@
                 "versus": ""
             },
             "pf-pg": {
-                "db_url": "/db_postgres",
-                "query_url": "/query_postgres?queries=",
-                "update_url": "/updates_postgres?queries=",
-                "fortune_url": "/fortunes_raw_postgres",
+                "db_url": "/PG",
+                "query_url": "/queryPG?queries=",
+                "update_url": "/ups_QPG?queries=",
+                "fortune_url": "/f_RW_QPG",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -77,10 +78,10 @@
                 "versus": ""
             },
             "pf-my": {
-                "db_url": "/db_mysql",
-                "query_url": "/query_mysql?queries=",
-                "update_url": "/updates_mysql?queries=",
-                "fortune_url": "/fortunes_raw_mysql",
+                "db_url": "/MY",
+                "query_url": "/queryMY?queries=",
+                "update_url": "/ups_QMY?queries=",
+                "fortune_url": "/f_RW_QMY",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -132,10 +133,11 @@
                 "versus": ""
             },
             "thread-apg": {
-                "db_url": "/dbp",
-                "query_url": "/queriesp?queries=",
+                "db_url": "/pg",
+                "query_url": "/querAPG?queries=",
                 "update_url": "/updatep?queries=",
-                "fortune_url": "/fortunes_raw_p",
+                "fortune_url": "/f_RW_APG",
+                "cached_query_url": "/cached_queries?count=",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -169,10 +171,10 @@
                 "versus": ""
             },
             "thread-pg": {
-                "db_url": "/db_postgres",
-                "query_url": "/query_postgres?queries=",
-                "update_url": "/updates_postgres?queries=",
-                "fortune_url": "/fortunes_raw_postgres",
+                "db_url": "/PG",
+                "query_url": "/queryPG?queries=",
+                "update_url": "/ups_QPG?queries=",
+                "fortune_url": "/f_RW_QPG",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -189,7 +191,7 @@
                 "versus": ""
             },
             "thread-pg-cutelee": {
-                "fortune_url": "/fortunes_cutelee_postgres",
+                "fortune_url": "/f_CL_QPG",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -206,7 +208,7 @@
                 "versus": ""
             },
             "t-apg-cutelee": {
-                "fortune_url": "/fortunes_c_p",
+                "fortune_url": "/f_CL_APG",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -223,10 +225,10 @@
                 "versus": ""
             },
             "thread-my": {
-                "db_url": "/db_mysql",
-                "query_url": "/query_mysql?queries=",
-                "update_url": "/updates_mysql?queries=",
-                "fortune_url": "/fortunes_raw_mysql",
+                "db_url": "/MY",
+                "query_url": "/queryMY?queries=",
+                "update_url": "/ups_QMY?queries=",
+                "fortune_url": "/f_RW_QMY",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",
@@ -243,7 +245,7 @@
                 "versus": ""
             },
             "thread-my-cutelee": {
-                "fortune_url": "/fortunes_cutelee_mysql",
+                "fortune_url": "/f_CL_QMY",
                 "port": 8080,
                 "approach": "Realistic",
                 "classification": "Fullstack",

+ 13 - 13
frameworks/C++/cutelyst/build.sh

@@ -1,28 +1,28 @@
 #!/bin/bash
 
-export ASQL_VER=0.46.0
-export CUTELEE_VER=6.0.0
-export CUTELYST_VER=3.1.0
+export ASQL_VER=0.74.0
+export CUTELEE_VER=6.1.0
+export CUTELYST_VER=3.7.0
 
 apt update -qq && \
     apt install -yqq --no-install-recommends \
     cmake \
     git \
     pkg-config \
-    qtbase5-dev \
-    libqt5sql5-mysql \
-    libqt5sql5-psql \
-    qtdeclarative5-dev \
+    qt6-base-dev \
+    libqt6sql6-mysql \
+    libqt6sql6-psql \
+    libegl1-mesa-dev \
     postgresql-server-dev-all
 
-wget -q https://github.com/cutelyst/cutelee/releases/download/v${CUTELEE_VER}/cutelee_${CUTELEE_VER}_amd64.deb && \
-    apt install -yqq ./cutelee_${CUTELEE_VER}_amd64.deb
+wget -q https://github.com/cutelyst/cutelee/releases/download/v${CUTELEE_VER}/cutelee6-qt6_${CUTELEE_VER}_amd64.deb && \
+    apt install -yqq ./cutelee6-qt6_${CUTELEE_VER}_amd64.deb
 
-wget -q https://github.com/cutelyst/asql/releases/download/v${ASQL_VER}/libasql_${ASQL_VER}_amd64.deb && \
-    apt install -yqq ./libasql_${ASQL_VER}_amd64.deb
+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}/cutelyst_${CUTELYST_VER}_amd64.deb && \
-    apt install -yqq ./cutelyst_${CUTELYST_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
 
 cd ${TROOT} && \
     mkdir -p build && \

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-nginx-my.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-nginx-pg.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-nginx.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-pf-apg-batch.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-pf-apg.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-pf-my.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-pf-pg.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-t-apg-cutelee.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-apg-batch.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-apg.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-my-cutelee.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-my.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-pg-cutelee.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-pg.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread-pico.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 1 - 1
frameworks/C++/cutelyst/cutelyst-thread.dockerfile

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

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

@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:22.04
 
 RUN apt-get update -qq && \
     apt-get install -yqq locales wget build-essential

+ 16 - 14
frameworks/C++/cutelyst/src/CMakeLists.txt

@@ -13,10 +13,10 @@ FetchContent_Declare(
 )
 FetchContent_MakeAvailable(mimalloc)
 
-find_package(Qt5 5.6.0 REQUIRED COMPONENTS Core Network Sql)
-find_package(ASqlQt5 0.43.0 REQUIRED)
-find_package(Cutelyst3Qt5 3.1 REQUIRED)
-find_package(Cutelee6Qt5 6.0.0 REQUIRED)
+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(Cutelee6Qt6 6.1.0 REQUIRED)
 find_package(PostgreSQL REQUIRED)
 
 # Auto generate moc files
@@ -44,10 +44,10 @@ set(cutelyst_benchmarks_SRCS
     multipledatabasequeriestest.h
     plaintexttest.cpp
     plaintexttest.h
-    root.cpp
-    root.h
     singledatabasequerytest.cpp
     singledatabasequerytest.h
+    cachedqueries.h
+    cachedqueries.cpp
     ${TEMPLATES_SRC}
 )
 
@@ -60,10 +60,11 @@ target_link_libraries(cutelyst_benchmarks
     Cutelyst::Core
     Cutelyst::Utils::Sql
     Cutelyst::View::Cutelee
-    Qt5::Core
-    Qt5::Network
-    Qt5::Sql
-    ASqlQt5::Core
+    Qt::Core
+    Qt::Network
+    Qt::Sql
+    ASql::Core
+    ASql::Pg
 )
 
 add_executable(cutelyst-benchmarks ${cutelyst_benchmarks_SRCS} main.cpp)
@@ -73,10 +74,11 @@ target_link_libraries(cutelyst-benchmarks
     Cutelyst::Server
     Cutelyst::Utils::Sql
     Cutelyst::View::Cutelee
-    Qt5::Core
-    Qt5::Network
-    Qt5::Sql
-    ASqlQt5::Core
+    Qt::Core
+    Qt::Network
+    Qt::Sql
+    ASql::Core
+    ASql::Pg
     mimalloc
 )
 if (mimalloc_FOUND)

+ 70 - 0
frameworks/C++/cutelyst/src/cachedqueries.cpp

@@ -0,0 +1,70 @@
+#include "cachedqueries.h"
+
+#include <apool.h>
+#include <aresult.h>
+#include <apreparedquery.h>
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+#include <QCache>
+
+using namespace ASql;
+
+CachedQueries::CachedQueries(QObject *parent)
+    : Controller{parent}
+{
+
+}
+
+void CachedQueries::cached_queries(Context *c)
+{
+    int queries = c->request()->queryParam(QStringLiteral("count")).toInt();
+    if (queries < 1) {
+        queries = 1;
+    } else if (queries > 500) {
+        queries = 500;
+    }
+
+    static thread_local QCache<int, QJsonObject> cache(1024);
+
+    auto array = std::shared_ptr<QJsonArray>(new QJsonArray);
+
+    ASync async(c);
+    static thread_local auto db = APool::database();
+    for (int i = 0; i < queries; ++i) {
+        const int id = (rand() % 10000) + 1;
+
+        QJsonObject *obj = cache[id];
+        if (obj) {
+            array->append(*obj);
+            continue;
+        }
+
+        db.exec(APreparedQueryLiteral(u8"SELECT id, randomNumber FROM world WHERE id=$1"),
+                               {id}, c, [c, async, i, queries, array] (AResult &result) {
+            if (Q_LIKELY(!result.error() && result.size())) {
+                auto it = result.begin();
+                int id = it[0].toInt();
+                auto obj = new QJsonObject({
+                                               {QStringLiteral("id"), id},
+                                               {QStringLiteral("randomNumber"), it[1].toInt()}
+                                           });
+                array->append(*obj);
+                cache.insert(id, obj, 1);
+
+                if (array->size() == queries) {
+                    c->response()->setJsonArrayBody(*array);
+                }
+                return;
+            }
+
+            c->res()->setStatus(Response::InternalServerError);
+        });
+    }
+
+    if (array->size() == queries) {
+        c->response()->setJsonArrayBody(*array);
+    }
+}

+ 19 - 0
frameworks/C++/cutelyst/src/cachedqueries.h

@@ -0,0 +1,19 @@
+#ifndef CACHEDQUERIES_H
+#define CACHEDQUERIES_H
+
+#include <Cutelyst/Controller>
+
+using namespace Cutelyst;
+
+class CachedQueries : public Controller
+{
+    Q_OBJECT
+    C_NAMESPACE("")
+public:
+    explicit CachedQueries(QObject *parent = nullptr);
+
+    C_ATTR(cached_queries, :Local :AutoArgs)
+    void cached_queries(Context *c);
+};
+
+#endif // CACHEDQUERIES_H

+ 16 - 7
frameworks/C++/cutelyst/src/cutelyst-benchmarks.cpp

@@ -13,6 +13,7 @@
 #include <QDir>
 
 #include <apool.h>
+#include <apg.h>
 
 #include "jsontest.h"
 #include "singledatabasequerytest.h"
@@ -20,14 +21,17 @@
 #include "databaseupdatestest.h"
 #include "fortunetest.h"
 #include "plaintexttest.h"
+#include "cachedqueries.h"
 
 using namespace Cutelyst;
+using namespace ASql;
 
 static QMutex mutex;
 
 cutelyst_benchmarks::cutelyst_benchmarks(QObject *parent) : Application(parent)
 {
-    qsrand(QDateTime::currentMSecsSinceEpoch());
+    static std::once_flag once;
+    std::call_once(once, []() { srand(time(NULL)); });
 }
 
 cutelyst_benchmarks::~cutelyst_benchmarks()
@@ -56,6 +60,7 @@ bool cutelyst_benchmarks::init()
     new DatabaseUpdatesTest(this);
     new FortuneTest(this);
     new PlaintextTest(this);
+    new CachedQueries(this);
 
     if (defaultHeaders().server().isEmpty()) {
         defaultHeaders().setServer(QStringLiteral("Cutelyst"));
@@ -71,7 +76,7 @@ bool cutelyst_benchmarks::postFork()
 
     QSqlDatabase db;
     const auto driver = config(QStringLiteral("Driver")).toString();
-    if (driver == QLatin1String("QPSQL")) {
+    if (driver == u"QPSQL") {
         db = QSqlDatabase::addDatabase(driver, Sql::databaseNameThread(QStringLiteral("postgres")));
         db.setDatabaseName(QStringLiteral("hello_world"));
         db.setUserName(QStringLiteral("benchmarkdbuser"));
@@ -81,7 +86,7 @@ bool cutelyst_benchmarks::postFork()
             qDebug() << "Error opening PostgreSQL db:" << db << db.connectionName() << db.lastError().databaseText();
             return false;
         }
-    } else if (driver == QLatin1String("QMYSQL")) {
+    } else if (driver == u"QMYSQL") {
         db = QSqlDatabase::addDatabase(driver, Sql::databaseNameThread(QStringLiteral("mysql")));
         db.setDatabaseName(QStringLiteral("hello_world"));
         db.setUserName(QStringLiteral("benchmarkdbuser"));
@@ -91,13 +96,17 @@ bool cutelyst_benchmarks::postFork()
             qDebug() << "Error opening MySQL db:" << db << db.connectionName() << db.lastError().databaseText();
             return false;
         }
-    } else if (driver == QLatin1String("postgres")) {
+    } else if (driver == u"postgres") {
         QUrl uri(QStringLiteral("postgresql://benchmarkdbuser:benchmarkdbpass@server/hello_world"));
         uri.setHost(config(QStringLiteral("DatabaseHostName")).toString());
         qDebug() << "ASql URI:" << uri.toString();
 
-        APool::addDatabase(uri.toString());
-        APool::setDatabaseMaxIdleConnections(128);
+        APool::create(ASql::APg::factory(uri.toString()));
+        APool::setMaxIdleConnections(128);
+        APool::setSetupCallback([](ADatabase &db) {
+            // Enable Pipeline mode
+            db.enterPipelineMode(500);
+        });
     }
 
     qDebug() << "Connections" << QCoreApplication::applicationPid() << QThread::currentThread() << QSqlDatabase::connectionNames();
@@ -110,4 +119,4 @@ bool cutelyst_benchmarks::postFork()
     return true;
 }
 
-#include "moc_cutelyst-benchmarks.cpp"
+//#include "moc_cutelyst-benchmarks.cpp"

+ 39 - 38
frameworks/C++/cutelyst/src/databaseupdatestest.cpp

@@ -16,6 +16,8 @@
 
 #include "picojson.h"
 
+using namespace ASql;
+
 DatabaseUpdatesTest::DatabaseUpdatesTest(QObject *parent) : Controller(parent)
 {
 
@@ -34,29 +36,29 @@ void DatabaseUpdatesTest::updatep(Context *c)
     ASync async(c);
     static thread_local auto db = APool::database();
     for (int i = 0; i < queries; ++i) {
-        int id = (qrand() % 10000) + 1;
+        int id = (rand() % 10000) + 1;
 
-        int randomNumber = (qrand() % 10000) + 1;
+        int randomNumber = (rand() % 10000) + 1;
 
         array.emplace_back(picojson::object({
                             {"id", picojson::value(double(id))},
                             {"randomNumber", picojson::value(double(randomNumber))}
                         }));
 
-        db.exec(APreparedQueryLiteral(u"SELECT randomNumber, id FROM world WHERE id=$1"),
-                               {id}, [c, async] (AResult &result) {
+        db.exec(APreparedQueryLiteral(u8"SELECT randomNumber, id FROM world WHERE id=$1"),
+                               {id}, c, [c, async] (AResult &result) {
             if (Q_UNLIKELY(result.error() || !result.size())) {
                 c->res()->setStatus(Response::InternalServerError);
                 return;
             }
-        }, c);
-        db.exec(APreparedQueryLiteral(u"UPDATE world SET randomNumber=$1 WHERE id=$2"),
-                               {randomNumber, id}, [c, async] (AResult &result) {
+        });
+        db.exec(APreparedQueryLiteral(u8"UPDATE world SET randomNumber=$1 WHERE id=$2"),
+                               {randomNumber, id}, c, [c, async] (AResult &result) {
             if (Q_UNLIKELY(result.error())) {
                 c->res()->setStatus(Response::InternalServerError);
                 return;
             }
-        }, c);
+        });
     }
 
     c->response()->setJsonBody(QByteArray::fromStdString(picojson::value(array).serialize()));
@@ -78,9 +80,9 @@ void DatabaseUpdatesTest::updateb(Context *c)
     ASync async(c);
     static thread_local auto db = APool::database();
     for (int i = 0; i < queries; ++i) {
-        int id = (qrand() % 10000) + 1;
+        int id = (rand() % 10000) + 1;
 
-        int randomNumber = (qrand() % 10000) + 1;
+        int randomNumber = (rand() % 10000) + 1;
 
         argsIds.append(id);
         args.append(id);
@@ -91,23 +93,23 @@ void DatabaseUpdatesTest::updateb(Context *c)
                             {"randomNumber", picojson::value(double(randomNumber))}
                         }));
 
-        db.exec(APreparedQueryLiteral(u"SELECT randomNumber, id FROM world WHERE id=$1"),
-                               {id}, [c, async] (AResult &result) {
+        db.exec(APreparedQueryLiteral(u8"SELECT randomNumber, id FROM world WHERE id=$1"),
+                               {id}, c, [c, async] (AResult &result) {
             if (Q_UNLIKELY(result.error() || !result.size())) {
                 c->res()->setStatus(Response::InternalServerError);
                 return;
             }
-        }, c);
+        });
     }
     args.append(argsIds);
 
     const APreparedQuery pq = getSql(queries);
-    db.exec(pq, args, [c, async] (AResult &result) {
+    db.exec(pq, args, c, [c, async] (AResult &result) {
         if (Q_UNLIKELY(result.error())) {
             c->res()->setStatus(Response::InternalServerError);
             return;
         }
-    }, c);
+    });
 
     c->response()->setJsonBody(QByteArray::fromStdString(picojson::value(array).serialize()));
 }
@@ -149,7 +151,7 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
     ids.reserve(queries);
     randomNumbers.reserve(queries);
     for (int i = 0; i < queries; ++i) {
-        int id = (qrand() % 10000) + 1;
+        int id = (rand() % 10000) + 1;
 
         query.bindValue(QStringLiteral(":id"), id);
         if (Q_UNLIKELY(!query.exec() || !query.next())) {
@@ -157,7 +159,7 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
             return;
         }
 
-        int randomNumber = (qrand() % 10000) + 1;
+        int randomNumber = (rand() % 10000) + 1;
         ids.append(id);
         randomNumbers.append(randomNumber);
 
@@ -179,29 +181,28 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
 APreparedQuery DatabaseUpdatesTest::getSql(int count)
 {
     auto iter = m_sqlMap.find(count);
-    if (iter != m_sqlMap.end())
-    {
-        return iter.value();
-    }
-    QString sql = QStringLiteral("UPDATE WORLD SET randomnumber=CASE id ");
-    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));
-        placeholdersCounter += 2;
-    }
-    sql.append(QStringLiteral("ELSE randomnumber END WHERE id IN ("));
+    if (Q_UNLIKELY(iter == m_sqlMap.end())) {
+        QString sql = QStringLiteral("UPDATE WORLD SET randomnumber=CASE id ");
+        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));
+            placeholdersCounter += 2;
+        }
+        sql.append(QStringLiteral("ELSE randomnumber END WHERE id IN ("));
 
-    for (int i = 0; i < count; i++) {
-        sql.append(QLatin1Char('$') + QString::number(placeholdersCounter) + QLatin1Char(','));
-        ++placeholdersCounter;
-    }
+        for (int i = 0; i < count; i++) {
+            sql.append(QLatin1Char('$') + QString::number(placeholdersCounter) + QLatin1Char(','));
+            ++placeholdersCounter;
+        }
+
+        if (count) {
+            sql.remove(sql.size() - 1, 1);
+        }
+        sql.append(QLatin1Char(')'));
 
-    if (count) {
-        sql.remove(sql.size() - 1, 1);
+        iter = m_sqlMap.insert(count, APreparedQuery(sql));
     }
-    sql.append(QLatin1Char(')'));
-    m_sqlMap.insert(count, sql);
 
-    return sql;
+    return iter.value();
 }

+ 4 - 4
frameworks/C++/cutelyst/src/databaseupdatestest.h

@@ -20,17 +20,17 @@ public:
     C_ATTR(updateb, :Local :AutoArgs)
     void updateb(Context *c);
 
-    C_ATTR(updates_postgres, :Local :AutoArgs)
+    C_ATTR(updates_postgres, :Path('ups_QPG') :AutoArgs)
     void updates_postgres(Context *c);
 
-    C_ATTR(updates_mysql, :Local :AutoArgs)
+    C_ATTR(updates_mysql, :Path('ups_QMY') :AutoArgs)
     void updates_mysql(Context *c);
 
 private:
     inline void processQuery(Context *c, QSqlQuery &query, QSqlQuery &updateQuery);
-    inline APreparedQuery getSql(int count);
+    inline ASql::APreparedQuery getSql(int count);
 
-    QMap<int, APreparedQuery> m_sqlMap;
+    QMap<int, ASql::APreparedQuery> m_sqlMap;
 };
 
 #endif // DATABASEUPDATESTEST_H

+ 6 - 4
frameworks/C++/cutelyst/src/fortunetest.cpp

@@ -9,6 +9,8 @@
 
 #include <QSqlQuery>
 
+using namespace ASql;
+
 FortuneTest::FortuneTest(QObject *parent) : Controller(parent)
 {
 
@@ -18,7 +20,7 @@ void FortuneTest::fortunes_raw_p(Context *c)
 {
     ASync async(c);
     static thread_local auto db = APool::database();
-    db.exec(APreparedQueryLiteral(u"SELECT id, message FROM fortune"), [c, async, this] (AResult &result) {
+    db.exec(APreparedQueryLiteral(u8"SELECT id, message FROM fortune"), c, [c, async, this] (AResult &result) {
         if (Q_UNLIKELY(result.error() && !result.size())) {
             c->res()->setStatus(Response::InternalServerError);
             return;
@@ -38,7 +40,7 @@ void FortuneTest::fortunes_raw_p(Context *c)
         });
 
         renderRaw(c, fortunes);
-    }, c);
+    });
 }
 
 void FortuneTest::fortunes_raw_postgres(Context *c)
@@ -63,7 +65,7 @@ void FortuneTest::fortunes_c_p(Context *c)
 {
     ASync async(c);
     static thread_local auto db = APool::database();
-    db.exec(APreparedQueryLiteral(u"SELECT id, message FROM fortune"), [c, async] (AResult &result) {
+    db.exec(APreparedQueryLiteral(u8"SELECT id, message FROM fortune"), c, [c, async] (AResult &result) {
         if (Q_UNLIKELY(result.error() && !result.size())) {
             c->res()->setStatus(Response::InternalServerError);
             return;
@@ -91,7 +93,7 @@ void FortuneTest::fortunes_c_p(Context *c)
         static thread_local View *view = c->view();
         view->execute(c);
         c->response()->setContentType(QStringLiteral("text/html; charset=UTF-8"));
-    }, c);
+    });
 }
 
 void FortuneTest::fortunes_cutelee_postgres(Context *c)

+ 6 - 6
frameworks/C++/cutelyst/src/fortunetest.h

@@ -19,22 +19,22 @@ class FortuneTest : public Controller
 public:
     explicit FortuneTest(QObject *parent = 0);
 
-    C_ATTR(fortunes_raw_p, :Local :AutoArgs)
+    C_ATTR(fortunes_raw_p, :Path('f_RW_APG') :AutoArgs)
     void fortunes_raw_p(Context *c);
 
-    C_ATTR(fortunes_raw_postgres, :Local :AutoArgs)
+    C_ATTR(fortunes_raw_postgres, :Path('f_RW_QPG') :AutoArgs)
     void fortunes_raw_postgres(Context *c);
 
-    C_ATTR(fortunes_raw_mysql, :Local :AutoArgs)
+    C_ATTR(fortunes_raw_mysql, :Path('f_RW_QMY') :AutoArgs)
     void fortunes_raw_mysql(Context *c);
 
-    C_ATTR(fortunes_c_p, :Local :AutoArgs)
+    C_ATTR(fortunes_c_p, :Path('f_CL_APG') :AutoArgs)
     void fortunes_c_p(Context *c);
 
-    C_ATTR(fortunes_cutelee_postgres, :Local :AutoArgs)
+    C_ATTR(fortunes_cutelee_postgres, :Path('f_CL_QPG') :AutoArgs)
     void fortunes_cutelee_postgres(Context *c);
 
-    C_ATTR(fortunes_cutelee_mysql, :Local :AutoArgs)
+    C_ATTR(fortunes_cutelee_mysql, :Path('f_CL_QMY') :AutoArgs)
     void fortunes_cutelee_mysql(Context *c);
 
 private:

+ 7 - 5
frameworks/C++/cutelyst/src/multipledatabasequeriestest.cpp

@@ -12,6 +12,8 @@
 #include <QJsonObject>
 #include <QJsonArray>
 
+using namespace ASql;
+
 MultipleDatabaseQueriesTest::MultipleDatabaseQueriesTest(QObject *parent) : Controller(parent)
 {
 
@@ -30,10 +32,10 @@ void MultipleDatabaseQueriesTest::queriesp(Context *c)
     ASync async(c);
     static thread_local auto db = APool::database();
     for (int i = 0; i < queries; ++i) {
-        const int id = (qrand() % 10000) + 1;
+        const int id = (rand() % 10000) + 1;
 
-        db.exec(APreparedQueryLiteral(u"SELECT id, randomNumber FROM world WHERE id=$1"),
-                               {id}, [c, async, i, queries, array] (AResult &result) {
+        db.exec(APreparedQueryLiteral(u8"SELECT id, randomNumber FROM world WHERE id=$1"),
+                               {id}, c, [c, async, i, queries, array] (AResult &result) {
             if (Q_LIKELY(!result.error() && result.size())) {
                 auto it = result.begin();
                 array->append(QJsonObject{
@@ -48,7 +50,7 @@ void MultipleDatabaseQueriesTest::queriesp(Context *c)
             }
 
             c->res()->setStatus(Response::InternalServerError);
-        }, c);
+        });
     }
 }
 
@@ -80,7 +82,7 @@ void MultipleDatabaseQueriesTest::processQuery(Context *c, QSqlQuery &query)
     }
 
     for (int i = 0; i < queries; ++i) {
-        const int id = (qrand() % 10000) + 1;
+        const int id = (rand() % 10000) + 1;
 
         query.bindValue(QStringLiteral(":id"), id);
         if (Q_LIKELY(query.exec() && query.next())) {

+ 3 - 3
frameworks/C++/cutelyst/src/multipledatabasequeriestest.h

@@ -13,13 +13,13 @@ class MultipleDatabaseQueriesTest : public Controller
 public:
     explicit MultipleDatabaseQueriesTest(QObject *parent = 0);
 
-    C_ATTR(queriesp, :Local :AutoArgs)
+    C_ATTR(queriesp, :Path('querAPG') :AutoArgs)
     void queriesp(Context *c);
 
-    C_ATTR(query_postgres, :Local :AutoArgs)
+    C_ATTR(query_postgres, :Path('queryPG') :AutoArgs)
     void query_postgres(Context *c);
 
-    C_ATTR(query_mysql, :Local :AutoArgs)
+    C_ATTR(query_mysql, :Path('queryMY') :AutoArgs)
     void query_mysql(Context *c);
 
 private:

+ 0 - 37
frameworks/C++/cutelyst/src/root.cpp

@@ -1,37 +0,0 @@
-#include "root.h"
-
-#include <QElapsedTimer>
-
-using namespace Cutelyst;
-
-Root::Root(QObject *parent) : Controller(parent)
-{
-}
-
-Root::~Root()
-{
-}
-
-QElapsedTimer timerSetup(Context *c)
-{
-    QElapsedTimer timer;
-    timer.start();
-    return timer;
-}
-
-QString setupHeader(Context *c)
-{
-    return c->response()->headers().setDateWithDateTime(QDateTime::currentDateTimeUtc());
-}
-
-void Root::End(Context *c)
-{
-    static thread_local QString lastDate = setupHeader(c);
-    static thread_local QElapsedTimer timer = timerSetup(c);
-    if (timer.hasExpired(1000)) {
-        lastDate = setupHeader(c);
-        timer.restart();
-    } else {
-        c->response()->setHeader(QStringLiteral("date"), lastDate);
-    }
-}

+ 0 - 22
frameworks/C++/cutelyst/src/root.h

@@ -1,22 +0,0 @@
-#ifndef ROOT_H
-#define ROOT_H
-
-#include <Cutelyst/Controller>
-
-using namespace Cutelyst;
-
-class Root : public Controller
-{
-    Q_OBJECT
-    C_NAMESPACE("")
-public:
-    explicit Root(QObject *parent = 0);
-    ~Root();
-
-private:
-    C_ATTR(End, :AutoArgs)
-    void End(Context *c);
-};
-
-#endif //ROOT_H
-

+ 39 - 6
frameworks/C++/cutelyst/src/singledatabasequerytest.cpp

@@ -10,22 +10,55 @@
 
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QTimer>
 
 #include "picojson.h"
 
+using namespace ASql;
+
 SingleDatabaseQueryTest::SingleDatabaseQueryTest(QObject *parent) : Controller(parent)
 {
 
 }
 
-void SingleDatabaseQueryTest::dbp(Context *c)
+void SingleDatabaseQueryTest::db_asql_pg(Context *c)
 {
-    const int id = (qrand() % 10000) + 1;
+    const int id = (rand() % 10000) + 1;
 
     ASync async(c);
     static thread_local auto db = APool::database();
-    db.exec(APreparedQueryLiteral(u"SELECT id, randomNumber FROM world WHERE id=$1"),
-                           {id}, [c, async] (AResult &result) {
+
+    db.exec(APreparedQueryLiteral(u8"SELECT id, randomNumber FROM world WHERE id=$1"),
+                           {id}, c, [c, async] (AResult &result) {
+        if (Q_LIKELY(!result.error() && result.size())) {
+            auto it = result.begin();
+            c->response()->setJsonBody(QByteArray::fromStdString(
+                            picojson::value(picojson::object({
+                                                {"id", picojson::value(double(it[0].toInt()))},
+                                                {"randomNumber", picojson::value(double(it[1].toInt()))}
+                                            })).serialize()));
+            return;
+        }
+
+        c->res()->setStatus(Response::InternalServerError);
+    });
+}
+
+ADatabase getPipelineEnabledDatabase()
+{
+    auto db = APool::database();
+    db.enterPipelineMode(300);
+    return db;
+}
+
+void SingleDatabaseQueryTest::db_asql_pipeline_pg(Context *c)
+{
+    const int id = (rand() % 10000) + 1;
+
+    ASync async(c);
+    static thread_local auto db = getPipelineEnabledDatabase();
+    db.exec(APreparedQueryLiteral(u8"SELECT id, randomNumber FROM world WHERE id=$1"),
+                           {id}, c, [c, async] (AResult &result) {
         if (Q_LIKELY(!result.error() && result.size())) {
             auto it = result.begin();
             c->response()->setJsonBody(QByteArray::fromStdString(
@@ -37,7 +70,7 @@ void SingleDatabaseQueryTest::dbp(Context *c)
         }
 
         c->res()->setStatus(Response::InternalServerError);
-    }, c);
+    });
 }
 
 void SingleDatabaseQueryTest::db_postgres(Context *c)
@@ -58,7 +91,7 @@ void SingleDatabaseQueryTest::db_mysql(Context *c)
 
 void SingleDatabaseQueryTest::processQuery(Context *c, QSqlQuery &query)
 {
-    int id = (qrand() % 10000) + 1;
+    int id = (rand() % 10000) + 1;
 
     query.bindValue(QStringLiteral(":id"), id);
     if (Q_UNLIKELY(!query.exec() || !query.next())) {

+ 7 - 4
frameworks/C++/cutelyst/src/singledatabasequerytest.h

@@ -13,13 +13,16 @@ class SingleDatabaseQueryTest : public Controller
 public:
     explicit SingleDatabaseQueryTest(QObject *parent = 0);
 
-    C_ATTR(dbp, :Local :AutoArgs)
-    void dbp(Context *c);
+    C_ATTR(db_asql_pg, :Path('pg') :AutoArgs)
+    void db_asql_pg(Context *c);
 
-    C_ATTR(db_postgres, :Local :AutoArgs)
+    C_ATTR(db_asql_pipeline_pg, :Path('Pg') :AutoArgs)
+    void db_asql_pipeline_pg(Context *c);
+
+    C_ATTR(db_postgres, :Path('PG') :AutoArgs)
     void db_postgres(Context *c);
 
-    C_ATTR(db_mysql, :Local :AutoArgs)
+    C_ATTR(db_mysql, :Path('MY') :AutoArgs)
     void db_mysql(Context *c);
 
 private: