Browse Source

Cutelyst changes - adding fortunes tests rendered by Grantlee template engine (#3756)

* cutelyst: Simplify code due new v2 APIs

* cutelyst: Revert using half of processors

* cutelyst: prettify code

* cutelyst: Add fortunes test rendered by Grantlee

* cutelyst: Add missing docker files

* cutelyst: Fix generating HTML for fortunes
Daniel Nicoletti 7 years ago
parent
commit
720d943972

+ 34 - 0
frameworks/C++/cutelyst/benchmark_config.json

@@ -97,6 +97,23 @@
                 "notes": "",
                 "versus": ""
             },
+            "thread-pg-grantlee": {
+                "fortune_url": "/fortunes_grantlee_postgres",
+                "port": 8080,
+                "approach": "Realistic",
+                "classification": "Fullstack",
+                "database": "Postgres",
+                "framework": "cutelyst",
+                "language": "C++",
+                "orm": "Raw",
+                "platform": "Qt",
+                "webserver": "None",
+                "os": "Linux",
+                "database_os": "Linux",
+                "display_name": "cutelyst-thr-pg-grantlee",
+                "notes": "",
+                "versus": ""
+            },
             "thread-my": {
                 "db_url": "/db_mysql",
                 "query_url": "/query_mysql?queries=",
@@ -117,6 +134,23 @@
                 "notes": "",
                 "versus": ""
             },
+            "thread-my-grantlee": {
+                "fortune_url": "/fortunes_grantlee_mysql",
+                "port": 8080,
+                "approach": "Realistic",
+                "classification": "Fullstack",
+                "database": "MySQL",
+                "framework": "cutelyst",
+                "language": "C++",
+                "orm": "Raw",
+                "platform": "Qt",
+                "webserver": "None",
+                "os": "Linux",
+                "database_os": "Linux",
+                "display_name": "cutelyst-thr-my-grantlee",
+                "notes": "",
+                "versus": ""
+            },
             "pf-nodelay": {
                 "json_url": "/json",
                 "plaintext_url": "/plaintext",

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

@@ -18,7 +18,7 @@ apt update -qq && \
     libzmq3-dev \
     libpcre3-dev \
     zlib1g-dev \
-    nginx 
+    nginx
 
 wget -q https://github.com/cutelyst/cutelyst/archive/v$CUTELYST_VER.tar.gz -O cutelyst-$CUTELYST_VER.tar.gz && \
     tar zxf cutelyst-$CUTELYST_VER.tar.gz && \

+ 1 - 0
frameworks/C++/cutelyst/config/config.ini

@@ -3,6 +3,7 @@ master = true
 ; Increase listen queue used for nginx connecting to uWSGI. This matches
 ; net.ipv4.tcp_max_syn_backlog and net.core.somaxconn.
 ; for performance
+listen = 65535
 disable-logging
 ; use UNIX sockets instead of TCP loopback for performance
 http-socket = :8080

+ 40 - 0
frameworks/C++/cutelyst/cutelyst-thread-my-grantlee.dockerfile

@@ -0,0 +1,40 @@
+FROM ubuntu:18.04
+
+RUN apt update -qq && \
+    apt install -yqq locales wget build-essential
+
+RUN locale-gen en_US.UTF-8
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+ENV DEBIAN_FRONTEND noninteractive
+
+ENV TROOT /cutelyst-benchmark-app
+ENV CUTELYST_APP ${TROOT}/build/libcutelyst_benchmarks.so
+
+COPY src ${TROOT}/
+
+COPY build.sh .
+RUN ./build.sh
+
+COPY config/config.ini /cutelyst.ini
+COPY config/config_socket.ini /cutelyst_socket.ini
+COPY nginx.conf /nginx.conf
+
+RUN sed -i "s|DatabaseHostName=.*|DatabaseHostName=tfb-database|g" /cutelyst.ini
+RUN sed -i "s|DatabaseHostName=.*|DatabaseHostName=tfb-database|g" /cutelyst_socket.ini
+
+ENV C_PROCESSES 1
+ENV CPU_AFFINITY 1
+ENV DRIVER QMYSQL
+
+RUN sed -i "s|Driver=.*|Driver=${DRIVER}|g" /cutelyst.ini
+
+CMD cutelyst-wsgi2 \
+    --ini /cutelyst.ini:uwsgi \
+    --application ${CUTELYST_APP} \
+    --processes=${C_PROCESSES} \
+    --threads=$(nproc) \
+    --cpu-affinity=${CPU_AFFINITY} \
+    --socket-timeout 0 \
+    --reuse-port

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

@@ -31,7 +31,7 @@ CMD cutelyst-wsgi2 \
     --ini /cutelyst.ini:uwsgi \
     --application ${CUTELYST_APP} \
     --processes=${C_PROCESSES} \
-    --threads=$(( (`nproc` + 1) / 2 )) \
+    --threads=$(nproc) \
     --cpu-affinity=${CPU_AFFINITY} \
     --socket-timeout 0 \
     --reuse-port \

+ 40 - 0
frameworks/C++/cutelyst/cutelyst-thread-pg-grantlee.dockerfile

@@ -0,0 +1,40 @@
+FROM ubuntu:18.04
+
+RUN apt update -qq && \
+    apt install -yqq locales wget build-essential
+
+RUN locale-gen en_US.UTF-8
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+ENV DEBIAN_FRONTEND noninteractive
+
+ENV TROOT /cutelyst-benchmark-app
+ENV CUTELYST_APP ${TROOT}/build/libcutelyst_benchmarks.so
+
+COPY src ${TROOT}/
+
+COPY build.sh .
+RUN ./build.sh
+
+COPY config/config.ini /cutelyst.ini
+COPY config/config_socket.ini /cutelyst_socket.ini
+COPY nginx.conf /nginx.conf
+
+RUN sed -i "s|DatabaseHostName=.*|DatabaseHostName=tfb-database|g" /cutelyst.ini
+RUN sed -i "s|DatabaseHostName=.*|DatabaseHostName=tfb-database|g" /cutelyst_socket.ini
+
+ENV C_PROCESSES 1
+ENV CPU_AFFINITY 1
+ENV DRIVER QPSQL
+
+RUN sed -i "s|Driver=.*|Driver=${DRIVER}|g" /cutelyst.ini
+
+CMD cutelyst-wsgi2 \
+    --ini /cutelyst.ini:uwsgi \
+    --application ${CUTELYST_APP} \
+    --processes=${C_PROCESSES} \
+    --threads=$(nproc) \
+    --cpu-affinity=${CPU_AFFINITY} \
+    --socket-timeout 0 \
+    --reuse-port

+ 1 - 0
frameworks/C++/cutelyst/src/CMakeLists.txt

@@ -38,6 +38,7 @@ add_library(cutelyst_benchmarks SHARED ${cutelyst_benchmarks_SRCS})
 target_link_libraries(cutelyst_benchmarks
     Cutelyst::Core
     Cutelyst::Utils::Sql
+    Cutelyst::View::Grantlee
     Qt5::Core
     Qt5::Network
     Qt5::Sql

+ 6 - 0
frameworks/C++/cutelyst/src/cutelyst-benchmarks.cpp

@@ -1,6 +1,7 @@
 #include "cutelyst-benchmarks.h"
 
 #include <Cutelyst/Plugins/Utils/Sql>
+#include <Cutelyst/Plugins/View/Grantlee/grantleeview.h>
 
 #include <QtSql/QSqlDatabase>
 #include <QtSql/QSqlError>
@@ -8,6 +9,7 @@
 #include <QThread>
 #include <QDebug>
 #include <QMutexLocker>
+#include <QDir>
 
 #include "root.h"
 #include "jsontest.h"
@@ -37,6 +39,10 @@ bool cutelyst_benchmarks::init()
         new Root(this);
     }
 
+    auto view = new GrantleeView(this);
+    view->setIncludePaths({ QString::fromLatin1(qgetenv("TROOT")), QDir::currentPath() });
+    view->preloadTemplates();
+
     new JsonTest(this);
     new SingleDatabaseQueryTest(this);
     new MultipleDatabaseQueriesTest(this);

+ 3 - 4
frameworks/C++/cutelyst/src/databaseupdatestest.cpp

@@ -70,10 +70,9 @@ void DatabaseUpdatesTest::processQuery(Context *c, QSqlQuery &query, QSqlQuery &
 
     updateQuery.bindValue(QStringLiteral(":id"), ids);
     updateQuery.bindValue(QStringLiteral(":randomNumber"), randomNumbers);
-    if (Q_UNLIKELY(!updateQuery.execBatch())) {
+    if (Q_LIKELY(updateQuery.execBatch())) {
+        c->response()->setJsonArrayBody(array);
+    } else {
         c->res()->setStatus(Response::InternalServerError);
-        return;
     }
-
-    c->response()->setJsonBody(QJsonDocument(array));
 }

+ 1 - 0
frameworks/C++/cutelyst/src/fortunes.html

@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{% for fortune in fortunes %}<tr><td>{{fortune.id}}</td><td>{{fortune.message}}</td></tr>{% endfor %}</table></body></html>

+ 45 - 0
frameworks/C++/cutelyst/src/fortunetest.cpp

@@ -1,6 +1,7 @@
 #include "fortunetest.h"
 
 #include <Cutelyst/Plugins/Utils/Sql>
+#include <Cutelyst/View>
 
 #include <QSqlQuery>
 
@@ -27,6 +28,50 @@ void FortuneTest::fortunes_raw_mysql(Context *c)
     renderRaw(c, fortunes);
 }
 
+void FortuneTest::fortunes_grantlee_postgres(Context *c)
+{
+    QSqlQuery query = CPreparedSqlQueryThreadForDB(
+                QLatin1String("SELECT id, message FROM fortune"),
+                QStringLiteral("postgres"));
+    if (query.exec()) {
+        QVariantList fortunes = Sql::queryToMapList(query);
+        fortunes.append(QVariantMap{
+                            {QStringLiteral("id"), 0},
+                            {QStringLiteral("message"), QStringLiteral("Additional fortune added at request time.")},
+                        });
+        std::sort(fortunes.begin(), fortunes.end(), [] (const QVariant &a1, const QVariant &a2) {
+            return a1.toMap()[QStringLiteral("message")].toString() < a2.toMap()[QStringLiteral("message")].toString();
+        });
+        c->setStash(QStringLiteral("template"), QStringLiteral("fortunes.html"));
+        c->setStash(QStringLiteral("fortunes"), fortunes);
+        static thread_local View *view = c->view();
+        view->execute(c);
+        c->response()->setContentType(QStringLiteral("text/html; charset=UTF-8"));
+    }
+}
+
+void FortuneTest::fortunes_grantlee_mysql(Context *c)
+{
+    QSqlQuery query = CPreparedSqlQueryThreadForDB(
+                QLatin1String("SELECT id, message FROM fortune"),
+                QStringLiteral("mysql"));
+    if (query.exec()) {
+        QVariantList fortunes = Sql::queryToMapList(query);
+        fortunes.append(QVariantMap{
+                            {QStringLiteral("id"), 0},
+                            {QStringLiteral("message"), QStringLiteral("Additional fortune added at request time.")},
+                        });
+        std::sort(fortunes.begin(), fortunes.end(), [] (const QVariant &a1, const QVariant &a2) {
+            return a1.toMap()[QStringLiteral("message")].toString() < a2.toMap()[QStringLiteral("message")].toString();
+        });
+        c->setStash(QStringLiteral("template"), QStringLiteral("fortunes.html"));
+        c->setStash(QStringLiteral("fortunes"), fortunes);
+        static thread_local View *view = c->view();
+        view->execute(c);
+        c->response()->setContentType(QStringLiteral("text/html; charset=UTF-8"));
+    }
+}
+
 FortuneList FortuneTest::processQuery(Context *c, QSqlQuery &query)
 {
     FortuneList fortunes;

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

@@ -22,6 +22,12 @@ public:
     C_ATTR(fortunes_raw_mysql, :Local :AutoArgs)
     void fortunes_raw_mysql(Context *c);
 
+    C_ATTR(fortunes_grantlee_postgres, :Local :AutoArgs)
+    void fortunes_grantlee_postgres(Context *c);
+
+    C_ATTR(fortunes_grantlee_mysql, :Local :AutoArgs)
+    void fortunes_grantlee_mysql(Context *c);
+
 private:
     inline FortuneList processQuery(Context *c, QSqlQuery &query);
     inline void renderRaw(Context *c, const FortuneList &fortunes);

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

@@ -10,7 +10,5 @@ JsonTest::JsonTest(QObject *parent) : Controller(parent)
 
 void JsonTest::json(Context *c)
 {
-    c->response()->setJsonBody(QJsonDocument({
-                                                 {QStringLiteral("message"), QStringLiteral("Hello, World!")}
-                                             }));
+    c->response()->setJsonObjectBody({ {QStringLiteral("message"), QStringLiteral("Hello, World!")} });
 }

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

@@ -33,7 +33,7 @@ void MultipleDatabaseQueriesTest::processQuery(Context *c, QSqlQuery &query)
 {
     QJsonArray array;
 
-    int queries = c->request()->queryParam(QStringLiteral("queries"), QStringLiteral("1")).toInt();
+    int queries = c->request()->queryParam(QStringLiteral("queries")).toInt();
     if (queries < 1) {
         queries = 1;
     } else if (queries > 500) {
@@ -41,19 +41,19 @@ void MultipleDatabaseQueriesTest::processQuery(Context *c, QSqlQuery &query)
     }
 
     for (int i = 0; i < queries; ++i) {
-        int id = (qrand() % 10000) + 1;
+        const int id = (qrand() % 10000) + 1;
 
         query.bindValue(QStringLiteral(":id"), id);
-        if (Q_UNLIKELY(!query.exec() || !query.next())) {
+        if (Q_LIKELY(query.exec() && query.next())) {
+            array.append(QJsonObject{
+                             {QStringLiteral("id"), query.value(0).toInt()},
+                             {QStringLiteral("randomNumber"), query.value(1).toInt()}
+                         });
+        } else {
             c->res()->setStatus(Response::InternalServerError);
             return;
         }
-
-        array.append(QJsonObject{
-                         {QStringLiteral("id"), query.value(0).toInt()},
-                         {QStringLiteral("randomNumber"), query.value(1).toInt()}
-                     });
     }
 
-    c->response()->setJsonBody(QJsonDocument(array));
+    c->response()->setJsonArrayBody(array);
 }

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

@@ -38,8 +38,8 @@ void SingleDatabaseQueryTest::processQuery(Context *c, QSqlQuery &query)
         return;
     }
 
-    c->response()->setJsonBody(QJsonDocument({
-                                                 {QStringLiteral("id"), query.value(0).toInt()},
-                                                 {QStringLiteral("randomNumber"), query.value(1).toInt()}
-                                             }));
+    c->response()->setJsonObjectBody({
+                                         {QStringLiteral("id"), query.value(0).toInt()},
+                                         {QStringLiteral("randomNumber"), query.value(1).toInt()}
+                                     });
 }