Browse Source

Add database tests for the Drogon framework (#4495)

An Tao 6 years ago
parent
commit
0c35e62785
31 changed files with 1343 additions and 52 deletions
  1. 22 3
      frameworks/C++/drogon/README.md
  2. 24 1
      frameworks/C++/drogon/benchmark_config.json
  3. 45 0
      frameworks/C++/drogon/drogon-raw.dockerfile
  4. 2 4
      frameworks/C++/drogon/drogon.dockerfile
  5. 26 0
      frameworks/C++/drogon/drogon_benchmark/CMakeLists.txt
  6. 114 0
      frameworks/C++/drogon/drogon_benchmark/cmake_modules/FindMySQL.cmake
  7. 37 0
      frameworks/C++/drogon/drogon_benchmark/cmake_modules/FindSQLite3.cmake
  8. 135 0
      frameworks/C++/drogon/drogon_benchmark/config-raw.json
  9. 47 29
      frameworks/C++/drogon/drogon_benchmark/config.json
  10. 33 0
      frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrl.cc
  11. 12 0
      frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrl.h
  12. 36 0
      frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrlRaw.cc
  13. 12 0
      frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrlRaw.h
  14. 34 0
      frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrl.cc
  15. 11 0
      frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrl.h
  16. 33 0
      frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.cc
  17. 11 0
      frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.h
  18. 1 1
      frameworks/C++/drogon/drogon_benchmark/controllers/JsonCtrl.h
  19. 1 1
      frameworks/C++/drogon/drogon_benchmark/controllers/PlaintextCtrl.h
  20. 50 0
      frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrl.cc
  21. 12 0
      frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrl.h
  22. 50 0
      frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrlRaw.cc
  23. 12 0
      frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrlRaw.h
  24. 10 8
      frameworks/C++/drogon/drogon_benchmark/main.cc
  25. 175 0
      frameworks/C++/drogon/drogon_benchmark/models/Fortune.cc
  26. 95 0
      frameworks/C++/drogon/drogon_benchmark/models/Fortune.h
  27. 170 0
      frameworks/C++/drogon/drogon_benchmark/models/World.cc
  28. 94 0
      frameworks/C++/drogon/drogon_benchmark/models/World.h
  29. 5 5
      frameworks/C++/drogon/drogon_benchmark/models/model.json
  30. 19 0
      frameworks/C++/drogon/drogon_benchmark/views/fortune.csp
  31. 15 0
      frameworks/C++/drogon/drogon_benchmark/views/fortune_raw.csp

+ 22 - 3
frameworks/C++/drogon/README.md

@@ -4,8 +4,14 @@ This is the [Drogon](https://github.com/an-tao/drogon) portion of a [benchmarkin
 
 
 ### Test Type Implementation Source Code
 ### Test Type Implementation Source Code
 
 
-* [JSON](drogon_benchmark/controllers/JsonCtl.cc)
-* [PLAINTEXT](drogon_benchmark/controllers/Plaintext.cc)
+* [JSON](drogon_benchmark/controllers/JsonCtrl.cc)
+* [PLAINTEXT](drogon_benchmark/controllers/PlaintextCtrl.cc)
+* [Single Database Query](drogon_benchmark/controllers/DbCtrl.cc)
+* [Single Database Query Without ORM](drogon_benchmark/controllers/DbCtrlRaw.cc)
+* [Fortune ORM](drogon_benchmark/controllers/FortuneCtrl.cc)
+* [Fortune Without ORM](drogon_benchmark/controllers/FortuneCtrlRaw.cc)
+* [Multiple Database Queries ORM](drogon_benchmark/controllers/QueriesCtrl.cc)
+* [Multiple Database Queries Without ORM](drogon_benchmark/controllers/QueriesCtrlRaw.cc)
 
 
 ## Test URLs
 ## Test URLs
 ### JSON
 ### JSON
@@ -14,4 +20,17 @@ http://localhost:8080/json
 
 
 ### PLAINTEXT
 ### PLAINTEXT
 
 
-http://localhost:8080/plaintext
+http://localhost:8080/plaintext
+
+
+### Single Database Query
+
+http://localhost:8080/db
+
+### Fortune
+
+http://localhost:8080/fortunes
+
+### Multiple Database Queries
+
+http://localhost:8080/queries

+ 24 - 1
frameworks/C++/drogon/benchmark_config.json

@@ -5,6 +5,9 @@
       "default": {
       "default": {
         "json_url": "/json",
         "json_url": "/json",
         "plaintext_url": "/plaintext",
         "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "fortune_url": "/fortunes",
+        "query_url": "/queries?queries=",
         "port": 8080,
         "port": 8080,
         "approach": "Realistic",
         "approach": "Realistic",
         "classification": "Fullstack",
         "classification": "Fullstack",
@@ -20,7 +23,27 @@
         "display_name": "drogon",
         "display_name": "drogon",
         "notes": "",
         "notes": "",
         "versus": "None"
         "versus": "None"
+      },
+      "raw": {
+        "db_url": "/db",
+        "fortune_url": "/fortunes",
+        "query_url": "/queries?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Fullstack",
+        "database": "Postgres",
+        "framework": "drogon",
+        "language": "C++",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "drogon",
+        "notes": "",
+        "versus": "None"
       }
       }
     }
     }
   ]
   ]
-}
+}

+ 45 - 0
frameworks/C++/drogon/drogon-raw.dockerfile

@@ -0,0 +1,45 @@
+FROM ubuntu:18.04
+
+COPY ./ ./
+
+RUN  apt update -yqq && \
+     apt-get install -yqq software-properties-common && \
+	 apt install -yqq sudo curl wget cmake locales git \
+     openssl libssl-dev \
+     libjsoncpp-dev \
+     uuid-dev \
+     zlib1g-dev \
+	 postgresql-server-dev-all && \
+     add-apt-repository ppa:ubuntu-toolchain-r/test -y && \
+	 apt update -yqq && \
+	 apt install -yqq gcc-8 g++-8
+
+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 CC=gcc-8
+ENV CXX=g++-8
+ENV AR=gcc-ar-8
+ENV RANLIB=gcc-ranlib-8
+
+ENV IROOT=/install
+ENV DROGON_ROOT=$IROOT/drogon
+ENV TEST_PATH=/drogon_benchmark/build
+WORKDIR $IROOT
+
+RUN git clone https://github.com/an-tao/drogon
+
+WORKDIR $DROGON_ROOT
+
+RUN git checkout cf29b0805007ebcd8d6591aa7945ce2ca4c1371f
+
+RUN ./build.sh
+
+WORKDIR $TEST_PATH
+
+RUN cmake ..
+RUN make
+CMD ./drogon_benchmark config-raw.json

+ 2 - 4
frameworks/C++/drogon/drogon.dockerfile

@@ -34,7 +34,7 @@ RUN git clone https://github.com/an-tao/drogon
 
 
 WORKDIR $DROGON_ROOT
 WORKDIR $DROGON_ROOT
 
 
-RUN git checkout 8829203d0458145a93efae68aa856367e5a5757d
+RUN git checkout cf29b0805007ebcd8d6591aa7945ce2ca4c1371f
 
 
 RUN ./build.sh
 RUN ./build.sh
 
 
@@ -42,7 +42,5 @@ WORKDIR $TEST_PATH
 
 
 RUN cmake ..
 RUN cmake ..
 RUN make
 RUN make
-CMD ./drogon_benchmark
-
-
+CMD ./drogon_benchmark config.json
 
 

+ 26 - 0
frameworks/C++/drogon/drogon_benchmark/CMakeLists.txt

@@ -44,6 +44,7 @@ link_libraries(${UUID_LIBRARIES})
 #OpenSSL
 #OpenSSL
 find_package (OpenSSL)
 find_package (OpenSSL)
 if(OpenSSL_FOUND)
 if(OpenSSL_FOUND)
+    include_directories(${OPENSSL_INCLUDE_DIR})
     link_libraries(${OPENSSL_LIBRARIES})
     link_libraries(${OPENSSL_LIBRARIES})
 endif()
 endif()
 
 
@@ -59,6 +60,27 @@ include_directories(${PostgreSQL_INCLUDE_DIR})
 link_libraries(${PostgreSQL_LIBRARIES})
 link_libraries(${PostgreSQL_LIBRARIES})
 endif()
 endif()
 
 
+#Find mysql, only mariadb client liberary is supported
+find_package(MySQL)
+if(MYSQL_FOUND)
+    message(STATUS "inc:" ${MYSQL_INCLUDE_DIR})
+    message(STATUS "libs:" ${MYSQL_CLIENT_LIBS})
+    message(STATUS "version:" ${MYSQL_VERSION_STRING})
+    if(MYSQL_VERSION_STRING STREQUAL "")
+        message(STATUS "The mysql in your system is not the mariadb, so we can't use it in drogon")
+    else()
+        message(STATUS "Ok! We find the mariadb!")
+        include_directories(${MYSQL_INCLUDE_DIR})
+        link_libraries(${MYSQL_CLIENT_LIBS})
+    endif()
+endif()
+
+#Find sqlite3.
+find_package (SQLite3)
+if (SQLITE3_FOUND)
+  include_directories(${SQLITE3_INCLUDE_DIRS})
+  link_libraries(${SQLITE3_LIBRARIES})
+endif()
 
 
 AUX_SOURCE_DIRECTORY(./ SRC_DIR)
 AUX_SOURCE_DIRECTORY(./ SRC_DIR)
 AUX_SOURCE_DIRECTORY(controllers CTL_SRC)
 AUX_SOURCE_DIRECTORY(controllers CTL_SRC)
@@ -82,3 +104,7 @@ endforeach()
 
 
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 add_executable(drogon_benchmark ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${MODEL_SRC})
 add_executable(drogon_benchmark ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${MODEL_SRC})
+
+add_custom_command(TARGET drogon_benchmark POST_BUILD
+                   COMMAND ${CMAKE_COMMAND} -E copy_if_different
+                   ${CMAKE_SOURCE_DIR}/*.json $<TARGET_FILE_DIR:drogon_benchmark>)

+ 114 - 0
frameworks/C++/drogon/drogon_benchmark/cmake_modules/FindMySQL.cmake

@@ -0,0 +1,114 @@
+#--------------------------------------------------------
+# Copyright (C) 1995-2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# There are special exceptions to the terms and conditions of the GPL
+# as it is applied to this software. View the full text of the exception
+# in file LICENSE.exceptions in the top-level directory of this software
+# distribution.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+#
+# The MySQL Connector/ODBC is licensed under the terms of the
+# GPL, like most MySQL Connectors. There are special exceptions
+# to the terms and conditions of the GPL as it is applied to
+# this software, see the FLOSS License Exception available on
+# mysql.com.
+
+##########################################################################
+
+
+#-------------- FIND MYSQL_INCLUDE_DIR ------------------
+FIND_PATH(MYSQL_INCLUDE_DIR mysql.h
+  /usr/include/mysql
+  /usr/local/include/mysql
+  /opt/mysql/mysql/include
+  /opt/mysql/mysql/include/mysql
+  /opt/mysql/include
+  /opt/local/include/mysql5
+  /usr/local/mysql/include
+  /usr/local/mysql/include/mysql
+  $ENV{ProgramFiles}/MySQL/*/include
+  $ENV{SystemDrive}/MySQL/*/include)
+
+#----------------- FIND MYSQL_LIB_DIR -------------------
+IF (WIN32)
+  # Set lib path suffixes
+  # dist = for mysql binary distributions
+  # build = for custom built tree
+  IF (CMAKE_BUILD_TYPE STREQUAL Debug)
+    SET(libsuffixDist debug)
+    SET(libsuffixBuild Debug)
+  ELSE (CMAKE_BUILD_TYPE STREQUAL Debug)
+    SET(libsuffixDist opt)
+    SET(libsuffixBuild Release)
+    ADD_DEFINITIONS(-DDBUG_OFF)
+  ENDIF (CMAKE_BUILD_TYPE STREQUAL Debug)
+
+  FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient
+    PATHS
+    $ENV{MYSQL_DIR}/lib/${libsuffixDist}
+    $ENV{MYSQL_DIR}/libmysql
+    $ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
+    $ENV{MYSQL_DIR}/client/${libsuffixBuild}
+    $ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
+    $ENV{ProgramFiles}/MySQL/*/lib/${libsuffixDist}
+    $ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist})
+ELSE (WIN32)
+  FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient_r mariadbclient
+    PATHS
+    /usr/lib/mysql
+    /usr/local/lib/mysql
+    /usr/local/mysql/lib
+    /usr/local/mysql/lib/mysql
+    /opt/local/mysql5/lib
+    /opt/local/lib/mysql5/mysql
+    /opt/mysql/mysql/lib/mysql
+    /opt/mysql/lib/mysql)
+ENDIF (WIN32)
+
+IF(MYSQL_LIB)
+  GET_FILENAME_COMPONENT(MYSQL_LIB_DIR ${MYSQL_LIB} PATH)
+ENDIF(MYSQL_LIB)
+
+set(MYSQL_VERSION_STRING "")
+
+EXEC_PROGRAM (grep ARGS "MARIADB_BASE_VERSION ${MYSQL_INCLUDE_DIR}/*.h|awk '{print $3}'" OUTPUT_VARIABLE MYSQL_VERSION_STRING)
+
+IF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR)
+  SET(MYSQL_FOUND TRUE)
+
+  FIND_LIBRARY(MYSQL_ZLIB zlib PATHS ${MYSQL_LIB_DIR})
+  FIND_LIBRARY(MYSQL_TAOCRYPT taocrypt PATHS ${MYSQL_LIB_DIR})
+  IF (MYSQL_LIB)
+    SET(MYSQL_CLIENT_LIBS ${MYSQL_LIB})
+  ELSE()
+    SET(MYSQL_CLIENT_LIBS mysqlclient_r)
+  ENDIF()
+  IF (MYSQL_ZLIB)
+    SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} zlib)
+  ENDIF (MYSQL_ZLIB)
+  IF (MYSQL_TAOCRYPT)
+    SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} taocrypt)
+  ENDIF (MYSQL_TAOCRYPT)
+  # Added needed mysqlclient dependencies on Windows
+  IF (WIN32)
+    SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} ws2_32)
+  ENDIF (WIN32)
+
+  MESSAGE(STATUS "MySQL Include dir: ${MYSQL_INCLUDE_DIR}  library dir: ${MYSQL_LIB_DIR}")
+  MESSAGE(STATUS "MySQL client libraries: ${MYSQL_CLIENT_LIBS}")
+ELSEIF (MySQL_FIND_REQUIRED)
+  MESSAGE(FATAL_ERROR "Cannot find MySQL. Include dir: ${MYSQL_INCLUDE_DIR}  library dir: ${MYSQL_LIB_DIR}")
+ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR)

+ 37 - 0
frameworks/C++/drogon/drogon_benchmark/cmake_modules/FindSQLite3.cmake

@@ -0,0 +1,37 @@
+# Copyright (C) 2007-2009 LuaDist.
+# Created by Peter Kapec <[email protected]>
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+#	Note:
+#		Searching headers and libraries is very simple and is NOT as powerful as scripts
+#		distributed with CMake, because LuaDist defines directories to search for.
+#		Everyone is encouraged to contact the author with improvements. Maybe this file
+#		becomes part of CMake distribution sometimes.
+
+# - Find sqlite3
+# Find the native SQLITE3 headers and libraries.
+#
+# SQLITE3_INCLUDE_DIRS	- where to find sqlite3.h, etc.
+# SQLITE3_LIBRARIES	- List of libraries when using sqlite.
+# SQLITE3_FOUND	- True if sqlite found.
+
+# Look for the header file.
+FIND_PATH(SQLITE3_INCLUDE_DIR NAMES sqlite3.h)
+
+# Look for the library.
+FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3)
+
+# Handle the QUIETLY and REQUIRED arguments and set SQLITE3_FOUND to TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SQLITE3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+IF(SQLITE3_FOUND)
+	SET(SQLITE3_LIBRARIES ${SQLITE3_LIBRARY})
+	SET(SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIR})
+ELSE(SQLITE3_FOUND)
+	SET(SQLITE3_LIBRARIES)
+	SET(SQLITE3_INCLUDE_DIRS)
+ENDIF(SQLITE3_FOUND)
+
+MARK_AS_ADVANCED(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES)

+ 135 - 0
frameworks/C++/drogon/drogon_benchmark/config-raw.json

@@ -0,0 +1,135 @@
+/* This is a JSON format configuration file
+*/
+{
+  //ssl:the global ssl files setting
+  /*
+  "ssl": {
+    "cert": "../../trantor/trantor/tests/server.pem",
+    "key": "../../trantor/trantor/tests/server.pem"
+  },*/
+  "listeners": [
+    {
+      //address:ip address,0.0.0.0 by default
+      "address": "0.0.0.0",
+      //port:port number
+      "port": 8080,
+      //https:if use https for security,false by default
+      "https": false
+    }
+  ],
+  "db_clients": [
+    {
+      //name:Name of the client,'default' by default
+      //"name":"",
+      //rdbms:server type, "postgreSQL" by default
+      "rdbms": "postgreSQL",
+      //host:server address,localhost by default
+      "host": "tfb-database",
+      //port:server port, 5432 by default
+      "port": 5432,
+      //dbname:Database name
+      "dbname": "hello_world",
+      //user:'postgres' by default
+      "user": "benchmarkdbuser",
+      //passwd:'' by default
+      "passwd": "benchmarkdbpass",
+      //connection_number:1 by default
+      "connection_number": 1
+    }
+  ],
+  "app": {
+    //threads_num:the number of IO threads,1 by default, if the value is set to 0, the number of threads
+    //will be the number of processors.
+    "threads_num": 0,
+    //enable_session:false by default
+    "enable_session": false,
+    "session_timeout": 0,
+    //document_root:Root path of HTTP document,defaut path is ./
+    "document_root": "./",
+    /* file_types:
+     * HTTP download file types,The file types supported by drogon
+     * by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
+     * "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
+     * "gif", "bmp", "ico", "icns", etc. */
+    "file_types": [
+      "gif",
+      "png",
+      "jpg",
+      "js",
+      "css",
+      "html",
+      "ico",
+      "swf",
+      "xap",
+      "apk",
+      "cur",
+      "xml"
+    ],
+    //max_connections:max connections number,100000 by default
+    "max_connections": 100000,
+    //max_connections_per_ip:max connections number per clinet,0 by default which means no limit
+    "max_connections_per_ip": 0,
+    //Load_dynamic_views: false by default, when set to true, drogon will
+    //compile and load dynamically "CSP View Files" in directories defined
+    //by "dynamic_views_path"
+    //"load_dynamic_views":true,
+    //dynamic_views_path: if the path isn't prefixed with / or ./,
+    //it will be relative path of document_root path
+    //"dynamic_views_path":["./views"],
+    //log:set log output,drogon output logs to stdout by default
+    "log": {
+      //log_path:log file path,empty by default,in which case,log will output to the stdout
+      //"log_path": "./",
+      //logfile_base_name:log file base name,empty by default which means drogon will name logfile as
+      //drogon.log ...
+      "logfile_base_name": "",
+      //log_size_limit:100000000 bytes by default,
+      //When the log file size reaches "log_size_limit", the log file will be switched.
+      "log_size_limit": 100000000,
+      //log_level:"DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
+      //The TRACE level is only valid when built in DEBUG mode.
+      "log_level": "WARN"
+    },
+    //run_as_daemon:false by default
+    "run_as_daemon": false,
+    //relaunch_on_error:false by default,if true,the program will be restart by parent after exit;
+    "relaunch_on_error": false,
+    //use_sendfile:true by default,if ture,the program will
+    //use sendfile() system-call to send static file to client;
+    "use_sendfile": true,
+    //use_gzip:true by default,use gzip to compress the response body's content;
+    "use_gzip": false,
+    //static_files_cache_time:5 (seconds) by default,the time in which static file response is cached,
+    //0 means cache forever,the negative value means no cache
+    "static_files_cache_time": 5,
+    //simple_controllers_map:Configuring mapping from path to simple controller
+    "simple_controllers_map": [
+      {
+        "path": "/db",
+        "controller": "DbCtrlRaw",
+        "http_methods": [
+          "get"
+        ]
+      },
+      {
+        "path": "/fortunes",
+        "controller": "FortuneCtrlRaw",
+        "http_methods": [
+          "get"
+        ]
+      },
+      {
+        "path": "/queries",
+        "controller": "QueriesCtrlRaw",
+        "http_methods": [
+          "get"
+        ]
+      }
+    ],
+    //idle_connection_timeout: defaults to 60 seconds, the lifetime 
+    //of the connection without read or write
+    "idle_connection_timeout": 60,
+    //enable_fast_db_client: Defaults to false
+    "enable_fast_db_client": true
+  }
+}

+ 47 - 29
frameworks/C++/drogon/drogon_benchmark/config.json

@@ -6,27 +6,17 @@
   "ssl": {
   "ssl": {
     "cert": "../../trantor/trantor/tests/server.pem",
     "cert": "../../trantor/trantor/tests/server.pem",
     "key": "../../trantor/trantor/tests/server.pem"
     "key": "../../trantor/trantor/tests/server.pem"
-  },
+  },*/
   "listeners": [
   "listeners": [
     {
     {
       //address:ip address,0.0.0.0 by default
       //address:ip address,0.0.0.0 by default
       "address": "0.0.0.0",
       "address": "0.0.0.0",
       //port:port number
       //port:port number
-      "port": 80,
+      "port": 8080,
       //https:if use https for security,false by default
       //https:if use https for security,false by default
       "https": false
       "https": false
-    },
-    {
-      "address": "0.0.0.0",
-      "port": 443,
-      "https": true,
-      //cert,key:cert file path and key file path,empty by default,
-      //if empty,use global setting
-      "cert": "",
-      "key": ""
     }
     }
-  ],*/
-  /*
+  ],
   "db_clients": [
   "db_clients": [
     {
     {
       //name:Name of the client,'default' by default
       //name:Name of the client,'default' by default
@@ -34,22 +24,22 @@
       //rdbms:server type, "postgreSQL" by default
       //rdbms:server type, "postgreSQL" by default
       "rdbms": "postgreSQL",
       "rdbms": "postgreSQL",
       //host:server address,localhost by default
       //host:server address,localhost by default
-      "host": "127.0.0.1",
+      "host": "tfb-database",
       //port:server port, 5432 by default
       //port:server port, 5432 by default
       "port": 5432,
       "port": 5432,
       //dbname:Database name
       //dbname:Database name
-      "dbname": "test",
+      "dbname": "hello_world",
       //user:'postgres' by default
       //user:'postgres' by default
-      "user": "",
+      "user": "benchmarkdbuser",
       //passwd:'' by default
       //passwd:'' by default
-      "passwd": "",
+      "passwd": "benchmarkdbpass",
       //connection_number:1 by default
       //connection_number:1 by default
       "connection_number": 1
       "connection_number": 1
     }
     }
-  ],*/
+  ],
   "app": {
   "app": {
     //threads_num:the number of IO threads,1 by default, if the value is set to 0, the number of threads
     //threads_num:the number of IO threads,1 by default, if the value is set to 0, the number of threads
-<   //will be the number of processors.
+    //will be the number of processors.
     "threads_num": 0,
     "threads_num": 0,
     //enable_session:false by default
     //enable_session:false by default
     "enable_session": false,
     "enable_session": false,
@@ -89,7 +79,7 @@
     //log:set log output,drogon output logs to stdout by default
     //log:set log output,drogon output logs to stdout by default
     "log": {
     "log": {
       //log_path:log file path,empty by default,in which case,log will output to the stdout
       //log_path:log file path,empty by default,in which case,log will output to the stdout
-      "log_path": "./",
+      //"log_path": "./",
       //logfile_base_name:log file base name,empty by default which means drogon will name logfile as
       //logfile_base_name:log file base name,empty by default which means drogon will name logfile as
       //drogon.log ...
       //drogon.log ...
       "logfile_base_name": "",
       "logfile_base_name": "",
@@ -98,7 +88,7 @@
       "log_size_limit": 100000000,
       "log_size_limit": 100000000,
       //log_level:"DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
       //log_level:"DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
       //The TRACE level is only valid when built in DEBUG mode.
       //The TRACE level is only valid when built in DEBUG mode.
-      "log_level": "DEBUG"
+      "log_level": "WARN"
     },
     },
     //run_as_daemon:false by default
     //run_as_daemon:false by default
     "run_as_daemon": false,
     "run_as_daemon": false,
@@ -108,26 +98,54 @@
     //use sendfile() system-call to send static file to client;
     //use sendfile() system-call to send static file to client;
     "use_sendfile": true,
     "use_sendfile": true,
     //use_gzip:true by default,use gzip to compress the response body's content;
     //use_gzip:true by default,use gzip to compress the response body's content;
-    "use_gzip": true,
+    "use_gzip": false,
     //static_files_cache_time:5 (seconds) by default,the time in which static file response is cached,
     //static_files_cache_time:5 (seconds) by default,the time in which static file response is cached,
     //0 means cache forever,the negative value means no cache
     //0 means cache forever,the negative value means no cache
     "static_files_cache_time": 5,
     "static_files_cache_time": 5,
     //simple_controllers_map:Configuring mapping from path to simple controller
     //simple_controllers_map:Configuring mapping from path to simple controller
     "simple_controllers_map": [
     "simple_controllers_map": [
       {
       {
-        "path": "/path/name",
-        "controller": "controllerClassName",
+        "path": "/plaintext",
+        "controller": "PlaintextCtrl",
         "http_methods": [
         "http_methods": [
-          "get",
-          "post"
+          "get"
+        ]
+      },
+      {
+        "path": "/json",
+        "controller": "JsonCtrl",
+        "http_methods": [
+          "get"
         ],
         ],
-        "filters": [
-          "FilterClassName"
+        "filters": []
+      },
+      {
+        "path": "/db",
+        "controller": "DbCtrl",
+        "http_methods": [
+          "get"
+        ],
+        "filters": []
+      },
+      {
+        "path": "/fortunes",
+        "controller": "FortuneCtrl",
+        "http_methods": [
+          "get"
+        ]
+      },
+      {
+        "path": "/queries",
+        "controller": "QueriesCtrl",
+        "http_methods": [
+          "get"
         ]
         ]
       }
       }
     ],
     ],
     //idle_connection_timeout: defaults to 60 seconds, the lifetime 
     //idle_connection_timeout: defaults to 60 seconds, the lifetime 
     //of the connection without read or write
     //of the connection without read or write
-    "idle_connection_timeout": 60
+    "idle_connection_timeout": 60,
+    //enable_fast_db_client: Defaults to false
+    "enable_fast_db_client": true
   }
   }
 }
 }

+ 33 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrl.cc

@@ -0,0 +1,33 @@
+#include "DbCtrl.h"
+#include "models/World.h"
+#include <drogon/utils/Utilities.h>
+#include <thread>
+#include <stdlib.h>
+#include <time.h>
+using namespace drogon_model::hello_world;
+
+void DbCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
+{
+    //write your application logic here
+    static std::once_flag once;
+    std::call_once(once, []() {
+        srand(time(NULL));
+    });
+    auto client = drogon::app().getFastDbClient();
+
+    auto callbackPtr = std::shared_ptr<std::function<void(const HttpResponsePtr &)>>(new std::function<void(const HttpResponsePtr &)>(callback));
+    drogon::orm::Mapper<World> mapper(client);
+    World::PrimaryKeyType id = rand() % 10000 + 1;
+    mapper.findByPrimaryKey(id,
+                            [callbackPtr](World w) {
+                                auto j = w.toJson();
+                                auto resp = HttpResponse::newHttpJsonResponse(j);
+                                (*callbackPtr)(resp);
+                            },
+                            [callbackPtr](const DrogonDbException &e) {
+                                Json::Value ret;
+                                ret["result"] = "error!";
+                                auto resp = HttpResponse::newHttpJsonResponse(ret);
+                                (*callbackPtr)(resp);
+                            });
+}

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrl.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class DbCtrl:public drogon::HttpSimpleController<DbCtrl>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback) override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    //PATH_ADD("/db", Get);
+    PATH_LIST_END
+};

+ 36 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrlRaw.cc

@@ -0,0 +1,36 @@
+#include "DbCtrlRaw.h"
+#include "models/World.h"
+#include <drogon/utils/Utilities.h>
+#include <stdlib.h>
+#include <thread>
+#include <time.h>
+using namespace drogon_model::hello_world;
+
+void DbCtrlRaw::asyncHandleHttpRequest(
+    const HttpRequestPtr &req,
+    const std::function<void(const HttpResponsePtr &)> &callback)
+{
+    // write your application logic here
+    static std::once_flag once;
+    std::call_once(once, []() { srand(time(NULL)); });
+    auto client = drogon::app().getFastDbClient();
+    int id = rand() % 10000 + 1;
+    auto callbackPtr = std::shared_ptr<std::function<void(const HttpResponsePtr &)>>(new std::function<void(const HttpResponsePtr &)>(callback));
+
+    *client << "select randomnumber from world where id=$1" << id >>
+        [callbackPtr, id](const Result &rows) {
+            auto resp = HttpResponse::newHttpResponse();
+            char json[64];
+            sprintf(json, "{\"id\":%d,\"randomnumber\":%s}", id,
+                    rows[0]["randomnumber"].c_str());
+            resp->setBody(std::string(json));
+            resp->setContentTypeCode(CT_APPLICATION_JSON);
+            (*callbackPtr)(resp);
+        } >>
+        [callbackPtr](const DrogonDbException &err) {
+            Json::Value json{};
+            json["code"] = 0;
+            json["message"] = err.base().what();
+            (*callbackPtr)(HttpResponse::newHttpJsonResponse(json));
+        };
+}

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/DbCtrlRaw.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class DbCtrlRaw:public drogon::HttpSimpleController<DbCtrlRaw>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback) override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    //PATH_ADD("/db", Get);
+    PATH_LIST_END
+};

+ 34 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrl.cc

@@ -0,0 +1,34 @@
+#include "FortuneCtrl.h"
+#include "models/Fortune.h"
+#include <algorithm>
+
+using namespace drogon_model::hello_world;
+void FortuneCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
+{
+    auto client = drogon::app().getFastDbClient();
+    drogon::orm::Mapper<Fortune> mapper(client);
+    mapper.findAll([callback](std::vector<Fortune> rows) {
+                        Fortune newRow;
+                        newRow.setId(0);
+                        newRow.setMessage("Additional fortune added at request time.");
+                        rows.emplace_back(std::move(newRow));
+                        std::sort(rows.begin(),
+                                  rows.end(),
+                                  [](const Fortune &f1, const Fortune &f2) -> bool {
+                                      if (f1.getValueOfMessage() < f2.getValueOfMessage())
+                                          return true;
+                                      else
+                                      {
+                                          return false;
+                                      }
+                                  });
+                        HttpViewData data;
+                        data.insert("rows",std::move(rows));
+                        auto resp=HttpResponse::newHttpViewResponse("fortune.csp",data);
+                        callback(resp); },
+                   [callback](const DrogonDbException &err) {
+                       auto resp = HttpResponse::newHttpResponse();
+                       resp->setBody(std::string("error:") + err.base().what());
+                       callback(resp);
+                   });
+}

+ 11 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrl.h

@@ -0,0 +1,11 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class FortuneCtrl:public drogon::HttpSimpleController<FortuneCtrl>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback) override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    PATH_LIST_END
+};

+ 33 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.cc

@@ -0,0 +1,33 @@
+#include "FortuneCtrlRaw.h"
+#include "models/Fortune.h"
+#include <algorithm>
+
+using namespace drogon_model::hello_world;
+void FortuneCtrlRaw::asyncHandleHttpRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
+{
+    auto client = drogon::app().getFastDbClient();
+    *client << "select * from fortune where 1=$1"
+            << 1 >>
+        [callback](const Result &r) {
+            std::vector<std::pair<int, std::string>> rows;
+            for (auto row : r)
+            {
+                rows.emplace_back(row["id"].as<int>(), row["message"].as<std::string>());
+            }
+            rows.emplace_back(0, "Additional fortune added at request time.");
+            std::sort(rows.begin(), rows.end(), [](const std::pair<int, std::string> &p1, const std::pair<int, std::string> &p2) -> bool {
+                if (p1.second < p2.second)
+                    return true;
+                return false;
+            });
+            HttpViewData data;
+            data.insert("rows", std::move(rows));
+            auto resp = HttpResponse::newHttpViewResponse("fortune_raw.csp", data);
+            callback(resp);
+        } >>
+        [callback](const DrogonDbException &err) {
+            auto resp = HttpResponse::newHttpResponse();
+            resp->setBody(std::string("error:") + err.base().what());
+            callback(resp);
+        };
+}

+ 11 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.h

@@ -0,0 +1,11 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class FortuneCtrlRaw:public drogon::HttpSimpleController<FortuneCtrlRaw>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback) override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    PATH_LIST_END
+};

+ 1 - 1
frameworks/C++/drogon/drogon_benchmark/controllers/JsonCtrl.h

@@ -7,6 +7,6 @@ public:
     virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)override;
     virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)override;
     PATH_LIST_BEGIN
     PATH_LIST_BEGIN
     //list path definitions here;
     //list path definitions here;
-    PATH_ADD("/json",Get);
+    //PATH_ADD("/json",Get);
     PATH_LIST_END
     PATH_LIST_END
 };
 };

+ 1 - 1
frameworks/C++/drogon/drogon_benchmark/controllers/PlaintextCtrl.h

@@ -7,6 +7,6 @@ public:
     virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)override;
     virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)override;
     PATH_LIST_BEGIN
     PATH_LIST_BEGIN
     //list path definitions here;
     //list path definitions here;
-    PATH_ADD("/plaintext",Get);
+    //PATH_ADD("/plaintext",Get);
     PATH_LIST_END
     PATH_LIST_END
 };
 };

+ 50 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrl.cc

@@ -0,0 +1,50 @@
+#include "QueriesCtrl.h"
+#include "models/World.h"
+#include <stdlib.h>
+
+using namespace drogon_model::hello_world;
+
+void QueriesCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
+{
+    //write your application logic here
+    static std::once_flag once;
+    std::call_once(once, []() {
+        srand(time(NULL));
+    });
+    int queries = 1;
+    auto &parameter = req->getParameter("queries");
+    if (!parameter.empty())
+    {
+        queries = atoi(parameter.c_str());
+        if (queries > 500)
+            queries = 500;
+        else if (queries < 1)
+            queries = 1;
+    }
+    auto json = std::make_shared<Json::Value>();
+    json->resize(0);
+    auto callbackPtr = std::shared_ptr<std::function<void(const HttpResponsePtr &)>>(new std::function<void(const HttpResponsePtr &)>(callback));
+    auto counter = std::make_shared<int>(queries);
+    auto client = app().getFastDbClient();
+    drogon::orm::Mapper<World> mapper(client);
+
+    for (int i = 0; i < queries; i++)
+    {
+        World::PrimaryKeyType id = rand() % 10000 + 1;
+        mapper.findByPrimaryKey(id,
+                                [callbackPtr, counter, json](World w) mutable {
+                                    json->append(w.toJson());
+                                    (*counter)--;
+                                    if ((*counter) == 0)
+                                    {
+                                        (*callbackPtr)(HttpResponse::newHttpJsonResponse(*json));
+                                    }
+                                },
+                                [callbackPtr](const DrogonDbException &e) {
+                                    Json::Value ret;
+                                    ret["result"] = "error!";
+                                    auto resp = HttpResponse::newHttpJsonResponse(ret);
+                                    (*callbackPtr)(resp);
+                                });
+    }
+}

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrl.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class QueriesCtrl : public drogon::HttpSimpleController<QueriesCtrl>
+{
+  public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback) override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    //PATH_ADD("/path","filter1","filter2",HttpMethod1,HttpMethod2...);
+    PATH_LIST_END
+};

+ 50 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrlRaw.cc

@@ -0,0 +1,50 @@
+#include "QueriesCtrlRaw.h"
+using namespace drogon::orm;
+void QueriesCtrlRaw::asyncHandleHttpRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
+{
+    //write your application logic here
+    static std::once_flag once;
+    std::call_once(once, []() {
+        srand(time(NULL));
+    });
+    int queries = 1;
+    auto &parameter = req->getParameter("queries");
+    if (!parameter.empty())
+    {
+        queries = atoi(parameter.c_str());
+        if (queries > 500)
+            queries = 500;
+        else if (queries < 1)
+            queries = 1;
+    }
+    auto json = std::make_shared<Json::Value>();
+    json->resize(0);
+    auto callbackPtr = std::shared_ptr<std::function<void(const HttpResponsePtr &)>>(new std::function<void(const HttpResponsePtr &)>(callback));
+    auto counter = std::make_shared<int>(queries);
+    auto client = app().getFastDbClient();
+    for (int i = 0; i < queries; i++)
+    {
+        int id = rand() % 10000 + 1;
+        *client << "select randomnumber from world where id=$1" << id >>
+            [callbackPtr, counter, json, id](const Result &r) mutable {
+                (*counter)--;
+                if (r.size() > 0)
+                {
+                    Json::Value j;
+                    j["id"] = id;
+                    j["randomnumber"] = r[0]["randomnumber"].as<int>();
+                    json->append(std::move(j));
+                }
+                if ((*counter) == 0)
+                {
+                    (*callbackPtr)(HttpResponse::newHttpJsonResponse(*json));
+                }
+            } >>
+            [callbackPtr](const DrogonDbException &e) {
+                Json::Value ret;
+                ret["result"] = "error!";
+                auto resp = HttpResponse::newHttpJsonResponse(ret);
+                (*callbackPtr)(resp);
+            };
+    }
+}

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/QueriesCtrlRaw.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class QueriesCtrlRaw:public drogon::HttpSimpleController<QueriesCtrlRaw>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback) override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    //PATH_ADD("/path","filter1","filter2",HttpMethod1,HttpMethod2...);
+    PATH_LIST_END
+};

+ 10 - 8
frameworks/C++/drogon/drogon_benchmark/main.cc

@@ -1,12 +1,14 @@
 #include <drogon/drogon.h>
 #include <drogon/drogon.h>
-int main() {
-    //Set HTTP listener address and port
-    //app().setLogPath("./");
-    //Print logs to standard output
-    drogon::app().setLogLevel(trantor::Logger::WARN);
-    drogon::app().addListener("0.0.0.0", 8080);
-    drogon::app().setThreadNum(std::thread::hardware_concurrency());
-    //app().enableRunAsDaemon();
+#include <iostream>
+
+int main(int argc, char const *argv[])
+{
+    if(argc<2)
+    {
+        std::cout << "please input the config file name" << std::endl;
+        return -1;
+    }
+    drogon::app().loadConfigFile(argv[1]);
     drogon::app().run();
     drogon::app().run();
     return 0;
     return 0;
 }
 }

+ 175 - 0
frameworks/C++/drogon/drogon_benchmark/models/Fortune.cc

@@ -0,0 +1,175 @@
+/**
+ *
+ *  Fortune.cc
+ *  DO NOT EDIT. This file is generated by drogon_ctl
+ *
+ */
+
+#include "Fortune.h"
+#include <drogon/utils/Utilities.h>
+#include <string>
+
+using namespace drogon_model::hello_world;
+
+const std::string Fortune::Cols::id = "id";
+const std::string Fortune::Cols::message = "message";
+const std::string Fortune::primaryKeyName = "id";
+const bool Fortune::hasPrimaryKey = true;
+const std::string Fortune::tableName = "fortune";
+
+const std::vector<typename Fortune::MetaData> Fortune::_metaData={
+{"id","int32_t","integer",4,0,1,1},
+{"message","std::string","character varying",2048,0,0,1}
+};
+const std::string &Fortune::getColumnName(size_t index) noexcept(false)
+{
+    assert(index < _metaData.size());
+    return _metaData[index]._colName;
+}
+Fortune::Fortune(const Row &r) noexcept
+{
+        if(!r["id"].isNull())
+        {
+            _id=std::make_shared<int32_t>(r["id"].as<int32_t>());
+        }
+        if(!r["message"].isNull())
+        {
+            _message=std::make_shared<std::string>(r["message"].as<std::string>());
+        }
+}
+const int32_t & Fortune::getValueOfId(const int32_t &defaultValue) const noexcept
+{
+    if(_id)
+        return *_id;
+    return defaultValue;
+}
+std::shared_ptr<const int32_t> Fortune::getId() const noexcept
+{
+    return _id;
+}
+void Fortune::setId(const int32_t &id) noexcept
+{
+    _id = std::make_shared<int32_t>(id);
+    _dirtyFlag[0] = true;
+}
+
+const typename Fortune::PrimaryKeyType & Fortune::getPrimaryKey() const
+{
+    assert(_id);
+    return *_id;
+}
+
+const std::string & Fortune::getValueOfMessage(const std::string &defaultValue) const noexcept
+{
+    if(_message)
+        return *_message;
+    return defaultValue;
+}
+std::shared_ptr<const std::string> Fortune::getMessage() const noexcept
+{
+    return _message;
+}
+void Fortune::setMessage(const std::string &message) noexcept
+{
+    _message = std::make_shared<std::string>(message);
+    _dirtyFlag[1] = true;
+}
+void Fortune::setMessage(std::string &&message) noexcept
+{
+    _message = std::make_shared<std::string>(std::move(message));
+    _dirtyFlag[1] = true;
+}
+
+
+void Fortune::updateId(const uint64_t id)
+{
+}
+
+const std::vector<std::string> &Fortune::insertColumns() noexcept
+{
+    static const std::vector<std::string> _inCols={
+        "id",
+        "message"
+    };
+    return _inCols;
+}
+
+void Fortune::outputArgs(drogon::orm::internal::SqlBinder &binder) const
+{
+    if(getId())
+    {
+        binder << getValueOfId();
+    }
+    else
+    {
+        binder << nullptr;
+    }
+    if(getMessage())
+    {
+        binder << getValueOfMessage();
+    }
+    else
+    {
+        binder << nullptr;
+    }
+}
+
+const std::vector<std::string> Fortune::updateColumns() const
+{
+    std::vector<std::string> ret;
+    for(size_t i=0;i<sizeof(_dirtyFlag);i++)
+    {
+        if(_dirtyFlag[i])
+        {
+            ret.push_back(getColumnName(i));
+        }
+    }
+    return ret;
+}
+
+void Fortune::updateArgs(drogon::orm::internal::SqlBinder &binder) const
+{
+    if(_dirtyFlag[0])
+    {
+        if(getId())
+        {
+            binder << getValueOfId();
+        }
+        else
+        {
+            binder << nullptr;
+        }
+    }
+    if(_dirtyFlag[1])
+    {
+        if(getMessage())
+        {
+            binder << getValueOfMessage();
+        }
+        else
+        {
+            binder << nullptr;
+        }
+    }
+}
+Json::Value Fortune::toJson() const
+{
+    Json::Value ret;
+    if(getId())
+    {
+        ret["id"]=getValueOfId();
+    }
+    else
+    {
+        ret["id"]=Json::Value();
+    }
+    if(getMessage())
+    {
+        ret["message"]=getValueOfMessage();
+    }
+    else
+    {
+        ret["message"]=Json::Value();
+    }
+    return ret;
+}

+ 95 - 0
frameworks/C++/drogon/drogon_benchmark/models/Fortune.h

@@ -0,0 +1,95 @@
+/**
+ *
+ *  Fortune.h
+ *  DO NOT EDIT. This file is generated by drogon_ctl
+ *
+ */
+
+#pragma once
+#include <drogon/orm/Result.h>
+#include <drogon/orm/Row.h>
+#include <drogon/orm/Field.h>
+#include <drogon/orm/SqlBinder.h>
+#include <drogon/orm/Mapper.h>
+#include <trantor/utils/Date.h>
+#include <json/json.h>
+#include <string>
+#include <memory>
+#include <vector>
+#include <tuple>
+#include <stdint.h>
+#include <iostream>
+using namespace drogon::orm;
+
+namespace drogon_model
+{
+namespace hello_world 
+{
+
+class Fortune
+{
+  public:
+    struct Cols
+    {
+        static const std::string id;
+        static const std::string message;
+    };
+
+    const static int primaryKeyNumber;
+    const static std::string tableName;
+    const static bool hasPrimaryKey;
+    const static std::string primaryKeyName;
+    typedef int32_t PrimaryKeyType;
+    const PrimaryKeyType & getPrimaryKey() const;
+    Fortune(const Row &r) noexcept;
+    Fortune() = default;
+    
+    /**  For column id  */
+    ///Get the value of the column id, returns the default value if the column is null
+    const int32_t &getValueOfId(const int32_t &defaultValue=int32_t()) const noexcept;
+    ///Returns a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
+    std::shared_ptr<const int32_t> getId() const noexcept;
+    ///Set the value of the column id
+    void setId(const int32_t &id) noexcept;
+
+    /**  For column message  */
+    ///Get the value of the column message, returns the default value if the column is null
+    const std::string &getValueOfMessage(const std::string &defaultValue=std::string()) const noexcept;
+    ///Returns a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
+    std::shared_ptr<const std::string> getMessage() const noexcept;
+    ///Set the value of the column message
+    void setMessage(const std::string &message) noexcept;
+    void setMessage(std::string &&message) noexcept;
+
+
+    static size_t getColumnNumber() noexcept {  return 2;  }
+    static const std::string &getColumnName(size_t index) noexcept(false);
+
+    Json::Value toJson() const;
+
+  private:
+    friend Mapper<Fortune>;
+    static const std::vector<std::string> &insertColumns() noexcept;
+    void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
+    const std::vector<std::string> updateColumns() const;
+    void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
+    ///For mysql only
+    void updateId(const uint64_t id);
+    std::shared_ptr<int32_t> _id;
+    std::shared_ptr<std::string> _message;
+    struct MetaData
+    {
+        const std::string _colName;
+        const std::string _colType;
+        const std::string _colDatabaseType;
+        const ssize_t _colLength;
+        const bool _isAutoVal;
+        const bool _isPrimaryKey;
+        const bool _notNull;
+    };
+    static const std::vector<MetaData> _metaData;
+    bool _dirtyFlag[2]={ false };
+};
+
+} // namespace hello_world
+} // namespace drogon_model

+ 170 - 0
frameworks/C++/drogon/drogon_benchmark/models/World.cc

@@ -0,0 +1,170 @@
+/**
+ *
+ *  World.cc
+ *  DO NOT EDIT. This file is generated by drogon_ctl
+ *
+ */
+
+#include "World.h"
+#include <drogon/utils/Utilities.h>
+#include <string>
+
+using namespace drogon_model::hello_world;
+
+const std::string World::Cols::id = "id";
+const std::string World::Cols::randomnumber = "randomnumber";
+const std::string World::primaryKeyName = "id";
+const bool World::hasPrimaryKey = true;
+const std::string World::tableName = "world";
+
+const std::vector<typename World::MetaData> World::_metaData={
+{"id","int32_t","integer",4,0,1,1},
+{"randomnumber","int32_t","integer",4,0,0,1}
+};
+const std::string &World::getColumnName(size_t index) noexcept(false)
+{
+    assert(index < _metaData.size());
+    return _metaData[index]._colName;
+}
+World::World(const Row &r) noexcept
+{
+        if(!r["id"].isNull())
+        {
+            _id=std::make_shared<int32_t>(r["id"].as<int32_t>());
+        }
+        if(!r["randomnumber"].isNull())
+        {
+            _randomnumber=std::make_shared<int32_t>(r["randomnumber"].as<int32_t>());
+        }
+}
+const int32_t & World::getValueOfId(const int32_t &defaultValue) const noexcept
+{
+    if(_id)
+        return *_id;
+    return defaultValue;
+}
+std::shared_ptr<const int32_t> World::getId() const noexcept
+{
+    return _id;
+}
+void World::setId(const int32_t &id) noexcept
+{
+    _id = std::make_shared<int32_t>(id);
+    _dirtyFlag[0] = true;
+}
+
+const typename World::PrimaryKeyType & World::getPrimaryKey() const
+{
+    assert(_id);
+    return *_id;
+}
+
+const int32_t & World::getValueOfRandomnumber(const int32_t &defaultValue) const noexcept
+{
+    if(_randomnumber)
+        return *_randomnumber;
+    return defaultValue;
+}
+std::shared_ptr<const int32_t> World::getRandomnumber() const noexcept
+{
+    return _randomnumber;
+}
+void World::setRandomnumber(const int32_t &randomnumber) noexcept
+{
+    _randomnumber = std::make_shared<int32_t>(randomnumber);
+    _dirtyFlag[1] = true;
+}
+
+
+void World::updateId(const uint64_t id)
+{
+}
+
+const std::vector<std::string> &World::insertColumns() noexcept
+{
+    static const std::vector<std::string> _inCols={
+        "id",
+        "randomnumber"
+    };
+    return _inCols;
+}
+
+void World::outputArgs(drogon::orm::internal::SqlBinder &binder) const
+{
+    if(getId())
+    {
+        binder << getValueOfId();
+    }
+    else
+    {
+        binder << nullptr;
+    }
+    if(getRandomnumber())
+    {
+        binder << getValueOfRandomnumber();
+    }
+    else
+    {
+        binder << nullptr;
+    }
+}
+
+const std::vector<std::string> World::updateColumns() const
+{
+    std::vector<std::string> ret;
+    for(size_t i=0;i<sizeof(_dirtyFlag);i++)
+    {
+        if(_dirtyFlag[i])
+        {
+            ret.push_back(getColumnName(i));
+        }
+    }
+    return ret;
+}
+
+void World::updateArgs(drogon::orm::internal::SqlBinder &binder) const
+{
+    if(_dirtyFlag[0])
+    {
+        if(getId())
+        {
+            binder << getValueOfId();
+        }
+        else
+        {
+            binder << nullptr;
+        }
+    }
+    if(_dirtyFlag[1])
+    {
+        if(getRandomnumber())
+        {
+            binder << getValueOfRandomnumber();
+        }
+        else
+        {
+            binder << nullptr;
+        }
+    }
+}
+Json::Value World::toJson() const
+{
+    Json::Value ret;
+    if(getId())
+    {
+        ret["id"]=getValueOfId();
+    }
+    else
+    {
+        ret["id"]=Json::Value();
+    }
+    if(getRandomnumber())
+    {
+        ret["randomnumber"]=getValueOfRandomnumber();
+    }
+    else
+    {
+        ret["randomnumber"]=Json::Value();
+    }
+    return ret;
+}

+ 94 - 0
frameworks/C++/drogon/drogon_benchmark/models/World.h

@@ -0,0 +1,94 @@
+/**
+ *
+ *  World.h
+ *  DO NOT EDIT. This file is generated by drogon_ctl
+ *
+ */
+
+#pragma once
+#include <drogon/orm/Result.h>
+#include <drogon/orm/Row.h>
+#include <drogon/orm/Field.h>
+#include <drogon/orm/SqlBinder.h>
+#include <drogon/orm/Mapper.h>
+#include <trantor/utils/Date.h>
+#include <json/json.h>
+#include <string>
+#include <memory>
+#include <vector>
+#include <tuple>
+#include <stdint.h>
+#include <iostream>
+using namespace drogon::orm;
+
+namespace drogon_model
+{
+namespace hello_world 
+{
+
+class World
+{
+  public:
+    struct Cols
+    {
+        static const std::string id;
+        static const std::string randomnumber;
+    };
+
+    const static int primaryKeyNumber;
+    const static std::string tableName;
+    const static bool hasPrimaryKey;
+    const static std::string primaryKeyName;
+    typedef int32_t PrimaryKeyType;
+    const PrimaryKeyType & getPrimaryKey() const;
+    World(const Row &r) noexcept;
+    World() = default;
+    
+    /**  For column id  */
+    ///Get the value of the column id, returns the default value if the column is null
+    const int32_t &getValueOfId(const int32_t &defaultValue=int32_t()) const noexcept;
+    ///Returns a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
+    std::shared_ptr<const int32_t> getId() const noexcept;
+    ///Set the value of the column id
+    void setId(const int32_t &id) noexcept;
+
+    /**  For column randomnumber  */
+    ///Get the value of the column randomnumber, returns the default value if the column is null
+    const int32_t &getValueOfRandomnumber(const int32_t &defaultValue=int32_t()) const noexcept;
+    ///Returns a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
+    std::shared_ptr<const int32_t> getRandomnumber() const noexcept;
+    ///Set the value of the column randomnumber
+    void setRandomnumber(const int32_t &randomnumber) noexcept;
+
+
+    static size_t getColumnNumber() noexcept {  return 2;  }
+    static const std::string &getColumnName(size_t index) noexcept(false);
+
+    Json::Value toJson() const;
+
+  private:
+    friend Mapper<World>;
+    static const std::vector<std::string> &insertColumns() noexcept;
+    void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
+    const std::vector<std::string> updateColumns() const;
+    void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
+    ///For mysql only
+    void updateId(const uint64_t id);
+    std::shared_ptr<int32_t> _id;
+    std::shared_ptr<int32_t> _randomnumber;
+    struct MetaData
+    {
+        const std::string _colName;
+        const std::string _colType;
+        const std::string _colDatabaseType;
+        const ssize_t _colLength;
+        const bool _isAutoVal;
+        const bool _isPrimaryKey;
+        const bool _notNull;
+    };
+    static const std::vector<MetaData> _metaData;
+    bool _dirtyFlag[2]={ false };
+};
+
+} // namespace hello_world
+} // namespace drogon_model

+ 5 - 5
frameworks/C++/drogon/drogon_benchmark/models/model.json

@@ -2,12 +2,12 @@
     //rdbms:server type, postgreSQL 
     //rdbms:server type, postgreSQL 
     "rdbms":"postgreSQL",
     "rdbms":"postgreSQL",
     //host:server address,localhost by default;
     //host:server address,localhost by default;
-    "host":"127.0.0.1",
+    "host":"tfb-database",
     //port:server port, 5432 by default;
     //port:server port, 5432 by default;
     "port":5432,
     "port":5432,
     //dbname:Database name;
     //dbname:Database name;
-    "dbname":"",
-    "user":"",
-    "passwd":"",
-    "tables":[]
+    "dbname":"hello_world",
+    "user":"benchmarkdbuser",
+    "passwd":"benchmarkdbpass",
+    "tables":["world","fortune"]
 }
 }

+ 19 - 0
frameworks/C++/drogon/drogon_benchmark/views/fortune.csp

@@ -0,0 +1,19 @@
+<%inc
+#include "models/Fortune.h"
+using namespace drogon_model::hello_world;
+%>
+<%c++
+auto &rows=@@.get<std::vector<Fortune>>("rows");
+%>
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+<%c++for(auto &row:rows){%>
+<tr><td>{%row.getValueOfId()%}</td><td>{%HttpViewData::htmlTranslate(row.getValueOfMessage())%}</td></tr>
+<%c++}%>
+</table>
+</body>
+</html>

+ 15 - 0
frameworks/C++/drogon/drogon_benchmark/views/fortune_raw.csp

@@ -0,0 +1,15 @@
+<%c++
+auto &rows=@@.get<std::vector<std::pair<int,std::string>>>("rows");
+%>
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+<%c++for(auto &row:rows){%>
+<tr><td>{%row.first%}</td><td>{%HttpViewData::htmlTranslate(row.second)%}</td></tr>
+<%c++}%>
+</table>
+</body>
+</html>