Ver código fonte

[new c++ framework] Lithium. (#5316)

* [new c++ framework] Lithium.

* Some cleanup.

* [lithium ] Add test to travis.

* Update lithium.

* Update lithium.

* Update lithium.
Matthieu Garrigues 5 anos atrás
pai
commit
f68b317e34

+ 1 - 0
.travis.yml

@@ -19,6 +19,7 @@ env:
     - "TESTDIR=C++/cutelyst"
     - "TESTDIR=C++/libhttpserver"
     - "TESTDIR=C++/silicon"
+    - "TESTDIR=C++/lithium"
     - "TESTDIR=C++/treefrog"
     - "TESTDIR=C++/ulib"
     - "TESTDIR=C++/wt"

+ 45 - 0
frameworks/C++/lithium/README.md

@@ -0,0 +1,45 @@
+# Lithium Benchmarking Test
+
+This test benchmarks the `lithium::http_backend`. It is a modern C++17
+asynchronous web server based on epoll.
+
+Author: Matthieu Garrigues <[email protected]>
+
+### Test Type Implementation Source Code
+
+* [JSON] lithium.cc
+* [PLAINTEXT] lithium.cc
+* [DB] lithium.cc
+* [QUERY] lithium.cc
+* [CACHED QUERY] Not implemented
+* [UPDATE] lithium.cc
+* [FORTUNES] lithium.cc
+
+## Important Libraries
+The tests were run with:
+* [The Lithium libraries](https://github.com/matt-42/lithium)
+
+## Test URLs
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+### DB
+
+http://localhost:8080/db
+
+### QUERY
+
+http://localhost:8080/query?N=
+
+### UPDATE
+
+http://localhost:8080/update?N=
+
+### FORTUNES
+
+http://localhost:8080/fortunes

+ 30 - 0
frameworks/C++/lithium/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+  "framework": "lithium",
+  "tests": [
+    {
+      "default": {
+        "json_url"       : "/json",
+        "db_url"         : "/db",
+        "query_url"      : "/queries?N=",
+        "fortune_url"    : "/fortunes",
+        "update_url"     : "/updates?N=",
+        "plaintext_url"  : "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "mysql",
+        "framework": "Lithium",
+        "language": "C++",
+        "flavor": "None",
+        "orm": "Full",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Lithium",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 120 - 0
frameworks/C++/lithium/lithium.cc

@@ -0,0 +1,120 @@
+#include "lithium_http_backend.hh"
+#include "lithium_mysql.hh"
+
+#include "symbols.hh"
+using namespace li;
+
+
+std::string escape_html_entities(const std::string& data)
+{
+    std::string buffer;
+    buffer.reserve(data.size());
+    for(size_t pos = 0; pos != data.size(); ++pos) {
+        switch(data[pos]) {
+            case '&':  buffer.append("&amp;");       break;
+            case '\"': buffer.append("&quot;");      break;
+            case '\'': buffer.append("&apos;");      break;
+            case '<':  buffer.append("&lt;");        break;
+            case '>':  buffer.append("&gt;");        break;
+            default:   buffer.append(&data[pos], 1); break;
+        }
+    }
+    return std::move(buffer);
+}
+
+int main(int argc, char* argv[]) {
+
+  if (argc != 4)
+  {
+    std::cerr << "Usage: " << argv[0] << " mysql_host port nprocs" << std::endl;
+    return 1;
+  }
+
+  int port = atoi(argv[2]);
+  int nprocs = atoi(argv[3]);
+  
+  auto mysql_db =
+      mysql_database(s::host = argv[1], s::database = "hello_world", s::user = "benchmarkdbuser",
+                     s::password = "benchmarkdbpass", s::port = 3306, s::charset = "utf8");
+
+  auto fortunes = sql_orm_schema(mysql_db, "Fortune").fields(
+    s::id(s::auto_increment, s::primary_key) = int(),
+    s::message = std::string());
+
+  auto random_numbers = sql_orm_schema(mysql_db, "World").fields(
+    s::id(s::auto_increment, s::primary_key) = int(),
+    s::randomNumber = int());
+
+  http_api my_api;
+
+  my_api.get("/plaintext") = [&](http_request& request, http_response& response) {
+    response.set_header("Content-Type", "text/plain");
+    response.write("Hello, World!");
+  };
+
+  my_api.get("/json") = [&](http_request& request, http_response& response) {
+    response.write_json(s::message = "Hello, World!");
+  };
+  my_api.get("/db") = [&](http_request& request, http_response& response) {
+    response.write_json(random_numbers.connect(request.yield).find_one(s::id = 1234).value());
+  };
+
+  my_api.get("/queries") = [&](http_request& request, http_response& response) {
+    std::string N_str = request.get_parameters(s::N = std::optional<std::string>()).N.value_or("1");
+    int N = atoi(N_str.c_str());
+    
+    N = std::max(1, std::min(N, 500));
+    
+    auto c = random_numbers.connect(request.yield);
+    std::vector<decltype(random_numbers.all_fields())> numbers(N);
+    for (int i = 0; i < N; i++)
+      numbers[i] = c.find_one(s::id = 1 + rand() % 9999).value();
+
+    response.write_json(numbers);
+  };
+
+  my_api.get("/updates") = [&](http_request& request, http_response& response) {
+    std::string N_str = request.get_parameters(s::N = std::optional<std::string>()).N.value_or("1");
+    int N = atoi(N_str.c_str());
+    N = std::max(1, std::min(N, 500));
+    
+    auto c = random_numbers.connect(request.yield);
+    std::vector<decltype(random_numbers.all_fields())> numbers(N);
+    for (int i = 0; i < N; i++)
+    {
+      numbers[i] = c.find_one(s::id = 1 + rand() % 9999).value();
+      numbers[i].randomNumber = 1 + rand() % 9999;
+      c.update(numbers[i]);
+    }
+
+    response.write_json(numbers);
+  };
+
+  my_api.get("/fortunes") = [&](http_request& request, http_response& response) {
+
+    typedef decltype(fortunes.all_fields()) fortune;
+    std::vector<fortune> table;
+
+    auto c = fortunes.connect(request.yield);
+    c.forall([&] (auto f) { table.push_back(f); });
+    table.push_back(fortune(0, std::string("Additional fortune added at request time.")));
+
+    std::sort(table.begin(), table.end(),
+              [] (const fortune& a, const fortune& b) { return a.message < b.message; });
+
+    std::stringstream ss;
+
+    ss << "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
+    for(auto& f : table)
+      ss << "<tr><td>" << f.id << "</td><td>" << escape_html_entities(f.message) << "</td></tr>";
+    ss << "</table></body></html>";
+
+    response.set_header("Content-Type", "text/html; charset=utf-8");
+    response.write(ss.str());
+  };
+  
+  http_serve(my_api, port, s::nthreads = nprocs);
+  
+  return 0;
+
+}

+ 16 - 0
frameworks/C++/lithium/lithium.dockerfile

@@ -0,0 +1,16 @@
+FROM buildpack-deps:focal
+
+RUN apt update -yqq
+RUN apt install -yqq g++-9 libboost-dev libmariadb-dev wget
+RUN apt install -yqq libboost-context-dev
+
+COPY ./ ./
+
+ENV COMMIT=032430958169d97798642904072c5e3a8d2c55fe
+
+RUN wget https://raw.githubusercontent.com/matt-42/lithium/$COMMIT/single_headers/lithium_mysql.hh
+RUN wget https://raw.githubusercontent.com/matt-42/lithium/$COMMIT/single_headers/lithium_http_backend.hh
+
+RUN g++ -O3 -DNDEBUG -march=native -std=c++17 ./lithium.cc -I /usr/include/mariadb -lpthread -lmariadbclient -lboost_context -o /lithium_tbf
+
+CMD /lithium_tbf tfb-database 8080 $(nproc)

+ 61 - 0
frameworks/C++/lithium/symbols.hh

@@ -0,0 +1,61 @@
+// Generated by the lithium symbol generator.
+#ifndef LI_SYMBOL_N
+#define LI_SYMBOL_N
+    LI_SYMBOL(N)
+#endif
+
+#ifndef LI_SYMBOL_auto_increment
+#define LI_SYMBOL_auto_increment
+    LI_SYMBOL(auto_increment)
+#endif
+
+#ifndef LI_SYMBOL_charset
+#define LI_SYMBOL_charset
+    LI_SYMBOL(charset)
+#endif
+
+#ifndef LI_SYMBOL_database
+#define LI_SYMBOL_database
+    LI_SYMBOL(database)
+#endif
+
+#ifndef LI_SYMBOL_host
+#define LI_SYMBOL_host
+    LI_SYMBOL(host)
+#endif
+
+#ifndef LI_SYMBOL_id
+#define LI_SYMBOL_id
+    LI_SYMBOL(id)
+#endif
+
+#ifndef LI_SYMBOL_message
+#define LI_SYMBOL_message
+    LI_SYMBOL(message)
+#endif
+
+#ifndef LI_SYMBOL_password
+#define LI_SYMBOL_password
+    LI_SYMBOL(password)
+#endif
+
+#ifndef LI_SYMBOL_port
+#define LI_SYMBOL_port
+    LI_SYMBOL(port)
+#endif
+
+#ifndef LI_SYMBOL_primary_key
+#define LI_SYMBOL_primary_key
+    LI_SYMBOL(primary_key)
+#endif
+
+#ifndef LI_SYMBOL_randomNumber
+#define LI_SYMBOL_randomNumber
+    LI_SYMBOL(randomNumber)
+#endif
+
+#ifndef LI_SYMBOL_user
+#define LI_SYMBOL_user
+    LI_SYMBOL(user)
+#endif
+