Browse Source

Update TreeFrog Framework to version 1.31 (#6349)

* Updated TreeFrog Framework to version 1.31.0.

* Added caching tests.

* modified to use redis server for cache.

* Updated TreeFrog Framework to version 1.31.1.

* bugfixes of cached_pqueries().

* bugfixes of cached_pqueries().

* modified config.toml

Co-authored-by: AOYAMA Kazuharu <>
TreeFrog Framework 4 years ago
parent
commit
3e9e01b2c0

+ 29 - 2
frameworks/C++/treefrog/benchmark_config.json

@@ -8,6 +8,7 @@
       "fortune_url": "/fortune/index",
       "update_url": "/world/updates/",
       "plaintext_url": "/world/plain",
+      "cached_query_url": "/world/cached_queries/",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Fullstack",
@@ -24,16 +25,41 @@
       "versus": ""
     },
     "postgres": {
+      "json_url": "/json/json",
+      "db_url": "/world/prandom",
+      "query_url": "/world/pqueries/",
+      "fortune_url": "/fortune/index",
+      "update_url": "/world/pupdates/",
+      "plaintext_url": "/world/plain",
+      "cached_query_url": "/world/cached_pqueries/",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "treefrog",
+      "language": "C++",
+      "flavor": "None",
+      "orm": "Micro",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "treefrog-postgres",
+      "notes": "",
+      "versus": ""
+    },
+    "epoll": {
       "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",
       "classification": "Fullstack",
-      "database": "Postgres",
+      "database": "MySQL",
       "framework": "treefrog",
       "language": "C++",
       "flavor": "None",
@@ -42,7 +68,7 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "treefrog-postgres",
+      "display_name": "treefrog-epoll",
       "notes": "",
       "versus": ""
     },
@@ -53,6 +79,7 @@
       "fortune_url": "/fortune/mindex",
       "update_url": "/world/mupdates/",
       "plaintext_url": "/world/plain",
+      "cached_query_url": "/world/cached_mqueries/",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Fullstack",

+ 22 - 1
frameworks/C++/treefrog/config.toml

@@ -8,6 +8,7 @@ urls.db = "/world/random"
 urls.query = "/world/queries/"
 urls.update = "/world/updates/"
 urls.fortune = "/fortune/index"
+urls.cached_query = "/world/cached_queries/"
 approach = "Realistic"
 classification = "Fullstack"
 database = "MySQL"
@@ -25,6 +26,7 @@ urls.db = "/world/mrandom"
 urls.query = "/world/mqueries/"
 urls.update = "/world/mupdates/"
 urls.fortune = "/fortune/mindex"
+urls.cached_query = "/world/cached_mqueries/"
 approach = "Realistic"
 classification = "Fullstack"
 database = "MongoDB"
@@ -38,13 +40,32 @@ versus = "treefrog"
 [postgres]
 urls.plaintext = "/world/plain"
 urls.json = "/json/json"
+urls.db = "/world/prandom"
+urls.query = "/world/pqueries/"
+urls.update = "/world/pupdates/"
+urls.fortune = "/fortune/index"
+urls.cached_query = "/world/cached_pqueries/"
+approach = "Realistic"
+classification = "Fullstack"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Micro"
+platform = "None"
+webserver = "None"
+versus = ""
+
+[epoll]
+urls.plaintext = "/world/plain"
+urls.json = "/json/json"
 urls.db = "/world/random"
 urls.query = "/world/queries/"
 urls.update = "/world/updates/"
 urls.fortune = "/fortune/index"
+urls.cached_query = "/world/cached_queries/"
 approach = "Realistic"
 classification = "Fullstack"
-database = "Postgres"
+database = "MySQL"
 database_os = "Linux"
 os = "Linux"
 orm = "Micro"

+ 4 - 4
frameworks/C++/treefrog/config/application.ini

@@ -242,16 +242,16 @@ ActionMailer.smtp.DelayedDelivery=false
 
 # Specify the settings file to enable the cache module.
 # Comment out the following line.
-#Cache.SettingsFile=cache.ini
+Cache.SettingsFile=cache.ini
 
 # Specify the cache backend, such as 'sqlite', 'mongodb'
 # or 'redis'.
-Cache.Backend=sqlite
+Cache.Backend=redis
 
 # Probability of starting garbage collection (GC) for cache.
 # If 100 is specified, GC will be started at a rate of once per 100
 # sets. If 0 is specified, the GC never starts.
-Cache.GcProbability=100
+Cache.GcProbability=10000
 
 # If true, enable LZ4 compression when storing data.
-Cache.EnableCompression=true
+Cache.EnableCompression=no

+ 30 - 0
frameworks/C++/treefrog/config/cache.ini

@@ -0,0 +1,30 @@
+#
+# Cache settings
+#
+
+[sqlite]
+DatabaseName=tmp/cachedb
+HostName=
+Port=
+UserName=
+Password=
+ConnectOptions=
+PostOpenStatements=PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000; PRAGMA synchronous=NORMAL; VACUUM;
+
+[redis]
+DatabaseName=
+HostName=localhost
+Port=
+UserName=
+Password=
+ConnectOptions=
+PostOpenStatements=SELECT 1;
+
+[mongodb]
+DatabaseName=mdb
+HostName=localhost
+Port=
+UserName=
+Password=
+ConnectOptions=
+PostOpenStatements=

+ 2 - 2
frameworks/C++/treefrog/controllers/fortunecontroller.cpp

@@ -20,7 +20,7 @@ void FortuneController::index()
     fortune.setMessage(QStringLiteral("Additional fortune added at request time."));
     fortuneList << fortune;
     // Sort
-    qSort(fortuneList.begin(), fortuneList.end(), caseSensitiveLessThan);
+    std::sort(fortuneList.begin(), fortuneList.end(), caseSensitiveLessThan);
     texport(fortuneList);
     render();
 }
@@ -32,7 +32,7 @@ void FortuneController::mindex()
     fortune.setMessage(QStringLiteral("Additional fortune added at request time."));
     fortuneList << fortune;
     // Sort
-    qSort(fortuneList.begin(), fortuneList.end(), caseSensitiveMngFortuneLessThan);
+    std::sort(fortuneList.begin(), fortuneList.end(), caseSensitiveMngFortuneLessThan);
     texport(fortuneList);
     render("mindex");
 }

+ 146 - 5
frameworks/C++/treefrog/controllers/worldcontroller.cpp

@@ -1,6 +1,8 @@
 #include "worldcontroller.h"
 #include "world.h"
+#include "pworld.h"
 #include "mngworld.h"
+#include <TCache>
 
 
 void WorldController::index()
@@ -31,7 +33,7 @@ void WorldController::queries()
 void WorldController::queries(const QString &num)
 {
     QVariantList worlds;
-    int d = qMin(qMax(num.toInt(), 1), 500);
+    int d = std::min(std::max(num.toInt(), 1), 500);
 
     for (int i = 0; i < d; ++i) {
         int id = Tf::random(1, 10000);
@@ -40,6 +42,37 @@ void WorldController::queries(const QString &num)
     renderJson(worlds);
 }
 
+void WorldController::cached_queries()
+{
+    cached_queries("1");
+}
+
+void WorldController::cached_queries(const QString &num)
+{
+    constexpr int SECONDS = 60 * 10;  // cache time
+    QVariantList worlds;
+    QVariantMap world;
+    int d = std::min(std::max(num.toInt(), 1), 500);
+
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(1, 10000);
+        auto key = QByteArray::number(id);
+        auto randomNumber = Tf::cache()->get(key);  // Gets from cache
+
+        if (randomNumber.isEmpty()) {
+            auto w = World::get(id);
+            worlds << w.toVariantMap();
+            // Cache the value
+            Tf::cache()->set(key, QByteArray::number(w.randomNumber()), SECONDS);
+        } else {
+            world.insert("id", id);
+            world.insert("randomNumber", randomNumber.toInt());
+            worlds << world;
+        }
+    }
+    renderJson(worlds);
+}
+
 void WorldController::random()
 {
     int id = Tf::random(1, 10000);
@@ -129,7 +162,7 @@ void WorldController::updates()
 void WorldController::updates(const QString &num)
 {
     QVariantList worlds;
-    int d = qMin(qMax(num.toInt(), 1), 500);
+    int d = std::min(std::max(num.toInt(), 1), 500);
     World world;
 
     for (int i = 0; i < d; ++i) {
@@ -153,10 +186,87 @@ void WorldController::remove(const QString &pk)
     redirect(urla("index"));
 }
 
+/*
+ * PostgreSQL
+ */
+void WorldController::prandom()
+{
+    int id = Tf::random(1, 10000);
+    PWorld world = PWorld::get(id);
+    renderJson(world.toVariantMap());
+}
+
+void WorldController::pqueries()
+{
+    pqueries("1");
+}
+
+void WorldController::pqueries(const QString &num)
+{
+    QVariantList worlds;
+    int d = std::min(std::max(num.toInt(), 1), 500);
+
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(1, 10000);
+        worlds << PWorld::get(id).toVariantMap();
+    }
+    renderJson(worlds);
+}
+
+void WorldController::cached_pqueries()
+{
+    cached_pqueries("1");
+}
+
+void WorldController::cached_pqueries(const QString &num)
+{
+    constexpr int SECONDS = 60 * 10;  // cache time
+    QVariantList worlds;
+    QVariantMap world;
+    int d = std::min(std::max(num.toInt(), 1), 500);
+
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(1, 10000);
+        auto key = QByteArray::number(id);
+        auto randomNumber = Tf::cache()->get(key);  // Gets from cache
+
+        if (randomNumber.isEmpty()) {
+            auto w = PWorld::get(id);
+            worlds << w.toVariantMap();
+            // Cache the value
+            Tf::cache()->set(key, QByteArray::number(w.randomNumber()), SECONDS);
+        } else {
+            world.insert("id", id);
+            world.insert("randomnumber", randomNumber.toInt());
+            worlds << world;
+        }
+    }
+    renderJson(worlds);
+}
+
+void WorldController::pupdates(const QString &num)
+{
+    QVariantList worlds;
+    int d = std::min(std::max(num.toInt(), 1), 500);
+    PWorld world;
+
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(1, 10000);
+        world = PWorld::get(id);
+        world.setRandomNumber( Tf::random(1, 10000) );
+        world.update();
+        worlds << world.toVariantMap();
+    }
+    renderJson(worlds);
+}
 
+void WorldController::pupdates()
+{
+    pupdates("1");
+}
 
 /*
-  MongoDB
+ * MongoDB
  */
 void WorldController::mqueries()
 {
@@ -166,7 +276,7 @@ void WorldController::mqueries()
 void WorldController::mqueries(const QString &num)
 {
     QVariantList worlds;
-    int d = qMin(qMax(num.toInt(), 1), 500);
+    int d = std::min(std::max(num.toInt(), 1), 500);
 
     for (int i = 0; i < d; ++i) {
         QString id = QString::number(Tf::random(1, 10000));
@@ -175,6 +285,37 @@ void WorldController::mqueries(const QString &num)
     renderJson(worlds);
 }
 
+void WorldController::cached_mqueries()
+{
+    cached_mqueries("1");
+}
+
+void WorldController::cached_mqueries(const QString &num)
+{
+    constexpr int SECONDS = 60 * 10;  // cache time
+    QVariantList worlds;
+    QVariantMap world;
+    int d = std::min(std::max(num.toInt(), 1), 500);
+
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(1, 10000);
+        QByteArray key = QByteArray::number(id);
+        auto randomNumber = Tf::cache()->get(key);  // Gets from cache
+
+        if (randomNumber.isEmpty()) {
+            auto w = MngWorld::get(key);
+            worlds << w.toVariantMap();
+            // Cache the value
+            Tf::cache()->set(key, QByteArray::number(w.randomNumber()), SECONDS);
+        } else {
+            world.insert("id", id);
+            world.insert("randomNumber", randomNumber.toInt());
+            worlds << world;
+        }
+    }
+    renderJson(worlds);
+}
+
 void WorldController::mrandom()
 {
     QString id = QString::number(Tf::random(1, 10000));
@@ -190,7 +331,7 @@ void WorldController::mupdates()
 void WorldController::mupdates(const QString &num)
 {
     QVariantList worlds;
-    int d = qMin(qMax(num.toInt(), 1), 500);
+    int d = std::min(std::max(num.toInt(), 1), 500);
     MngWorld world;
 
     for (int i = 0; i < d; ++i) {

+ 13 - 0
frameworks/C++/treefrog/controllers/worldcontroller.h

@@ -18,6 +18,8 @@ public slots:
     void show(const QString &pk);
     void queries();
     void queries(const QString &num);
+    void cached_queries();
+    void cached_queries(const QString &num);
     void random();
     void entry();
     void create();
@@ -27,9 +29,20 @@ public slots:
     void updates();
     void remove(const QString &pk);
 
+    // PostgreSQL
+    void prandom();
+    void pqueries();
+    void pqueries(const QString &num);
+    void cached_pqueries();
+    void cached_pqueries(const QString &num);
+    void pupdates(const QString &num);
+    void pupdates();
+
     // MongoDB
     void mqueries();
     void mqueries(const QString &num);
+    void cached_mqueries();
+    void cached_mqueries(const QString &num);
     void mrandom();
     void mupdates(const QString &num);
     void mupdates();

+ 1 - 1
frameworks/C++/treefrog/models/fortune.cpp

@@ -78,7 +78,7 @@ int Fortune::count()
 QList<Fortune> Fortune::getAll()
 {
     TSqlQueryORMapper<FortuneObject> mapper;
-    mapper.prepare(QStringLiteral("SELECT * from Fortune"));
+    mapper.prepare(QStringLiteral("SELECT * from fortune"));
 
     QList<Fortune> fortunes;
     if (mapper.exec()) {

+ 3 - 0
frameworks/C++/treefrog/models/models.pro

@@ -17,6 +17,9 @@ SOURCES += fortune.cpp
 HEADERS += sqlobjects/worldobject.h
 HEADERS += world.h
 SOURCES += world.cpp
+HEADERS += sqlobjects/pworldobject.h
+HEADERS += pworld.h
+SOURCES += pworld.cpp
 HEADERS += mongoobjects/mngworldobject.h
 HEADERS += mngworld.h
 SOURCES += mngworld.cpp

+ 106 - 0
frameworks/C++/treefrog/models/pworld.cpp

@@ -0,0 +1,106 @@
+#include <TreeFrogModel>
+#include "pworld.h"
+#include "pworldobject.h"
+
+//
+// World class for PostgreSQL
+//
+
+PWorld::PWorld()
+    : TAbstractModel(), d(new PWorldObject)
+{
+    d->id = 0;
+    d->randomnumber = 0;
+}
+
+PWorld::PWorld(const PWorld &other)
+    : TAbstractModel(), d(other.d)
+{ }
+
+PWorld::PWorld(const PWorldObject &object)
+    : TAbstractModel(), d(new PWorldObject(object))
+{ }
+
+PWorld::~PWorld()
+{
+    // If the reference count becomes 0,
+    // the shared data object 'PWorldObject' is deleted.
+}
+
+uint PWorld::id() const
+{
+    return d->id;
+}
+
+int PWorld::randomNumber() const
+{
+    return d->randomnumber;
+}
+
+void PWorld::setRandomNumber(int randomNumber)
+{
+    d->randomnumber = randomNumber;
+}
+
+PWorld &PWorld::operator=(const PWorld &other)
+{
+    d = other.d;  // increments the reference count of the data
+    return *this;
+}
+
+bool PWorld::update()
+{
+    TSqlQueryORMapper<PWorldObject> mapper;
+    mapper.prepare(QStringLiteral("UPDATE world SET randomnumber=? WHERE id=?"));
+    mapper.addBind(randomNumber()).addBind(id());
+    return mapper.exec();
+}
+
+PWorld PWorld::create(int randomNumber)
+{
+    PWorldObject obj;
+    obj.randomnumber = randomNumber;
+    if (!obj.create()) {
+        return PWorld();
+    }
+    return PWorld(obj);
+}
+
+PWorld PWorld::create(const QVariantMap &values)
+{
+    PWorld model;
+    model.setProperties(values);
+    if (!model.d->create()) {
+        model.d->clear();
+    }
+    return model;
+}
+
+PWorld PWorld::get(uint id)
+{
+    TSqlQueryORMapper<PWorldObject> mapper;
+    mapper.prepare(QStringLiteral("SELECT * from world WHERE id=?"));
+    mapper.addBind(id);
+    return PWorld(mapper.execFirst());
+}
+
+int PWorld::count()
+{
+    TSqlORMapper<PWorldObject> mapper;
+    return mapper.findCount();
+}
+
+QList<PWorld> PWorld::getAll()
+{
+    return tfGetModelListByCriteria<PWorld, PWorldObject>(TCriteria());
+}
+
+TModelObject *PWorld::modelData()
+{
+    return d.data();
+}
+
+const TModelObject *PWorld::modelData() const
+{
+    return d.data();
+}

+ 49 - 0
frameworks/C++/treefrog/models/pworld.h

@@ -0,0 +1,49 @@
+#ifndef PWORLD_H
+#define PWORLD_H
+
+#include <QStringList>
+#include <QDateTime>
+#include <QVariant>
+#include <QSharedDataPointer>
+#include <TGlobal>
+#include <TAbstractModel>
+
+class TModelObject;
+class PWorldObject;
+
+
+class T_MODEL_EXPORT PWorld : public TAbstractModel
+{
+public:
+    PWorld();
+    PWorld(const PWorld &other);
+    PWorld(const PWorldObject &object);
+    ~PWorld();
+
+    uint id() const;
+    int randomNumber() const;
+    void setRandomNumber(int randomNumber);
+    PWorld &operator=(const PWorld &other);
+
+    bool create() { return TAbstractModel::create(); }
+    bool update();
+    bool save()   { return TAbstractModel::save(); }
+    bool remove() { return TAbstractModel::remove(); }
+
+    static PWorld create(int randomNumber);
+    static PWorld create(const QVariantMap &values);
+    static PWorld get(uint id);
+    static int count();
+    static QList<PWorld> getAll();
+
+private:
+    QSharedDataPointer<PWorldObject> d;
+
+    TModelObject *modelData();
+    const TModelObject *modelData() const;
+};
+
+Q_DECLARE_METATYPE(PWorld)
+Q_DECLARE_METATYPE(QList<PWorld>)
+
+#endif // PWORLD_H

+ 31 - 0
frameworks/C++/treefrog/models/sqlobjects/pworldobject.h

@@ -0,0 +1,31 @@
+#ifndef PWORLDOBJECT_H
+#define PWORLDOBJECT_H
+
+#include <TSqlObject>
+#include <QSharedData>
+
+
+class T_MODEL_EXPORT PWorldObject : public TSqlObject, public QSharedData
+{
+public:
+    uint id {0};
+    int randomnumber {0};
+
+    enum PropertyIndex {
+        Id = 0,
+        Randomnumber,
+    };
+
+    int primaryKeyIndex() const override { return Id; }
+    int autoValueIndex() const override { return Id; }
+    QString tableName() const override { return QStringLiteral("world"); }
+
+private:    /*** Don't modify below this line ***/
+    Q_OBJECT
+    Q_PROPERTY(uint id READ getid WRITE setid)
+    T_DEFINE_PROPERTY(uint, id)
+    Q_PROPERTY(int randomnumber READ getrandomnumber WRITE setrandomnumber)
+    T_DEFINE_PROPERTY(int, randomnumber)
+};
+
+#endif // PWORLDOBJECT_H

+ 2 - 2
frameworks/C++/treefrog/models/world.cpp

@@ -47,7 +47,7 @@ World &World::operator=(const World &other)
 bool World::update()
 {
     TSqlQueryORMapper<WorldObject> mapper;
-    mapper.prepare(QStringLiteral("UPDATE World SET randomNumber=? WHERE id=?"));
+    mapper.prepare(QStringLiteral("UPDATE world SET randomNumber=? WHERE id=?"));
     mapper.addBind(randomNumber()).addBind(id());
     return mapper.exec();
 }
@@ -75,7 +75,7 @@ World World::create(const QVariantMap &values)
 World World::get(uint id)
 {
     TSqlQueryORMapper<WorldObject> mapper;
-    mapper.prepare(QStringLiteral("SELECT * from World WHERE id=?"));
+    mapper.prepare(QStringLiteral("SELECT * from world WHERE id=?"));
     mapper.addBind(id);
     return World(mapper.execFirst());
 }

+ 6 - 4
frameworks/C++/treefrog/treefrog-epoll.dockerfile

@@ -1,14 +1,15 @@
-FROM buildpack-deps:bionic
+FROM buildpack-deps:focal
 
 ENV DEBIAN_FRONTEND noninteractive
 ENV DEBCONF_NOWARNINGS yes
-ENV TFVER=1.30.0
+ENV TFVER=1.31.1
 
 RUN apt-get update -yqq && apt-get upgrade -yq && apt-get install -yqq --no-install-recommends \
     software-properties-common unzip wget make cmake gcc clang libjemalloc-dev qt5-qmake qt5-default qtbase5-dev \
     qtbase5-dev-tools libqt5sql5 libqt5sql5-mysql libqt5sql5-psql libqt5qml5 libqt5xml5 \
     qtdeclarative5-dev libqt5quick5 libqt5quickparticles5 libqt5gui5 libqt5printsupport5 \
-    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev
+    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev \
+    redis-server
 
 WORKDIR /usr/src
 RUN wget -q https://github.com/treefrogframework/treefrog-framework/archive/v${TFVER}.tar.gz
@@ -36,4 +37,5 @@ RUN sed -i 's|MultiProcessingModule=.*|MultiProcessingModule=epoll|g' config/app
 EXPOSE 8080
 
 # 3. Start TreeFrog
-CMD treefrog /workspace
+CMD service redis-server start && \
+    treefrog /workspace

+ 6 - 4
frameworks/C++/treefrog/treefrog-mongodb.dockerfile

@@ -1,14 +1,15 @@
-FROM buildpack-deps:bionic
+FROM buildpack-deps:focal
 
 ENV DEBIAN_FRONTEND noninteractive
 ENV DEBCONF_NOWARNINGS yes
-ENV TFVER=1.30.0
+ENV TFVER=1.31.1
 
 RUN apt-get update -yqq && apt-get upgrade -yq && apt-get install -yqq --no-install-recommends \
     software-properties-common unzip wget make cmake gcc clang libjemalloc-dev qt5-qmake qt5-default qtbase5-dev \
     qtbase5-dev-tools libqt5sql5 libqt5sql5-mysql libqt5sql5-psql libqt5qml5 libqt5xml5 \
     qtdeclarative5-dev libqt5quick5 libqt5quickparticles5 libqt5gui5 libqt5printsupport5 \
-    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev
+    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev \
+    redis-server
 
 WORKDIR /usr/src
 RUN wget -q https://github.com/treefrogframework/treefrog-framework/archive/v${TFVER}.tar.gz
@@ -36,4 +37,5 @@ RUN sed -i 's|MultiProcessingModule=.*|MultiProcessingModule=thread|g' config/ap
 EXPOSE 8080
 
 # 3. Start TreeFrog
-CMD treefrog /workspace
+CMD service redis-server start && \
+    treefrog /workspace

+ 6 - 4
frameworks/C++/treefrog/treefrog-postgres.dockerfile

@@ -1,14 +1,15 @@
-FROM buildpack-deps:bionic
+FROM buildpack-deps:focal
 
 ENV DEBIAN_FRONTEND noninteractive
 ENV DEBCONF_NOWARNINGS yes
-ENV TFVER=1.30.0
+ENV TFVER=1.31.1
 
 RUN apt-get update -yqq && apt-get upgrade -yq && apt-get install -yqq --no-install-recommends \
     software-properties-common unzip wget make cmake gcc clang libjemalloc-dev qt5-qmake qt5-default qtbase5-dev \
     qtbase5-dev-tools libqt5sql5 libqt5sql5-mysql libqt5sql5-psql libqt5qml5 libqt5xml5 \
     qtdeclarative5-dev libqt5quick5 libqt5quickparticles5 libqt5gui5 libqt5printsupport5 \
-    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev
+    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev \
+    redis-server
 
 WORKDIR /usr/src
 RUN wget -q https://github.com/treefrogframework/treefrog-framework/archive/v${TFVER}.tar.gz
@@ -36,4 +37,5 @@ RUN sed -i 's|MultiProcessingModule=.*|MultiProcessingModule=thread|g' config/ap
 EXPOSE 8080
 
 # 3. Start TreeFrog
-CMD treefrog /workspace
+CMD service redis-server start && \
+    treefrog /workspace

+ 6 - 4
frameworks/C++/treefrog/treefrog.dockerfile

@@ -1,14 +1,15 @@
-FROM buildpack-deps:bionic
+FROM buildpack-deps:focal
 
 ENV DEBIAN_FRONTEND noninteractive
 ENV DEBCONF_NOWARNINGS yes
-ENV TFVER=1.30.0
+ENV TFVER=1.31.1
 
 RUN apt-get update -yqq && apt-get upgrade -yq && apt-get install -yqq --no-install-recommends \
     software-properties-common unzip wget make cmake gcc clang libjemalloc-dev qt5-qmake qt5-default qtbase5-dev \
     qtbase5-dev-tools libqt5sql5 libqt5sql5-mysql libqt5sql5-psql libqt5qml5 libqt5xml5 \
     qtdeclarative5-dev libqt5quick5 libqt5quickparticles5 libqt5gui5 libqt5printsupport5 \
-    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev
+    libqt5widgets5 libqt5opengl5-dev libqt5quicktest5 libqt5sql5-sqlite libsqlite3-dev libmongoc-dev libbson-dev \
+    redis-server
 
 WORKDIR /usr/src
 RUN wget -q https://github.com/treefrogframework/treefrog-framework/archive/v${TFVER}.tar.gz
@@ -36,4 +37,5 @@ RUN sed -i 's|MultiProcessingModule=.*|MultiProcessingModule=thread|g' config/ap
 EXPOSE 8080
 
 # 3. Start TreeFrog
-CMD treefrog /workspace
+CMD service redis-server start && \
+    treefrog /workspace