Sfoglia il codice sorgente

FIx benchmark tests for Basolato Nim (#8662)

* wip

* wip

* wip

* wip

* wip

* fix

* fix

* fix

* delete old project

* fix

* fix

* fix

* fix

* fix

* fix

* fix dependency version

* fix

* fix

* fix docs

* remove unnecessary files

* fix readme
itsumura-h 1 anno fa
parent
commit
88cfca68e4

+ 0 - 14
frameworks/Nim/basolato/.gitignore

@@ -1,14 +0,0 @@
-# Binaries
-*
-!*.*
-!*/
-
-# Test coverage
-coverage/*
-lcov.info
-
-logs/*
-# config.nims
-*.sqlite3
-*.db
-*.db.bak

+ 8 - 9
frameworks/Nim/basolato/README.md

@@ -2,17 +2,16 @@
 
 ### Test Type Implementation Source Code
 
-* [JSON](./app/controllers/benchmark_controller.nim)
-* [PLAINTEXT](./app/controllers/benchmark_controller.nim)
-* [DB](./app/controllers/benchmark_controller.nim)
-* [QUERY](./app/controllers/benchmark_controller.nim)
-* [UPDATE](./app/controllers/benchmark_controller.nim)
-* [FORTUNES](./app/controllers/benchmark_controller.nim)
+* [JSON](./app/http/controllers/benchmark_controller.nim)
+* [PLAINTEXT](./app/http/controllers/benchmark_controller.nim)
+* [DB](./app/http/controllers/benchmark_controller.nim)
+* [QUERY](./app/http/controllers/benchmark_controller.nim)
+* [UPDATE](./app/http/controllers/benchmark_controller.nim)
+* [FORTUNES](./app/http/controllers/benchmark_controller.nim)
 
 ## Important Libraries
 The tests were run with:
 * [Software](https://github.com/itsumura-h/nim-basolato)
-* [Example](https://github.com/itsumura-h/nim-basolato/tree/master/examples)
 
 ## Test URLs
 ### JSON
@@ -29,11 +28,11 @@ http://localhost:8080/db
 
 ### QUERY
 
-http://localhost:8080/query?queries=
+http://localhost:8080/queries?queries=1
 
 ### UPDATE
 
-http://localhost:8080/update?queries=
+http://localhost:8080/updates?queries=1
 
 ### FORTUNES
 

+ 0 - 81
frameworks/Nim/basolato/app/controllers/benchmark_controller.nim

@@ -1,81 +0,0 @@
-import json, random, algorithm, cgi, sugar, sequtils
-from strutils import parseInt
-# framework
-import basolato/controller
-import allographer/query_builder
-# view
-import ../../resources/pages/fortune_view
-
-type BenchmarkController* = ref object of Controller
-
-proc newBenchmarkController*(request:Request):BenchmarkController =
-  randomize()
-  return BenchmarkController.newController(request)
-
-
-proc json*(this:BenchmarkController):Response =
-  return render(%*{"message":"Hello, World!"})
-
-proc plainText*(this:BenchmarkController):Response =
-  var headers = newHeaders()
-  headers.set("Content-Type", "text/plain; charset=UTF-8")
-  return render("Hello, World!").setHeader(headers)
-
-proc db*(this:BenchmarkController):Response =
-  let i = rand(1..10000)
-  let response = RDB().table("world").find(i)
-  return render(%*response)
-
-proc query*(this:BenchmarkController):Response =
-  var countNum:int
-  try:
-    countNum = this.request.params["queries"].parseInt()
-  except:
-    countNum = 1
-
-  if countNum < 1:
-    countNum = 1
-  elif countNum > 500:
-    countNum = 500
-
-  var response = newJArray()
-  for _ in 1..countNum:
-    let i = rand(1..10000)
-    let data = RDB().table("world").find(i)
-    response.add(data)
-  return render(%*response)
-
-proc fortune*(this:BenchmarkController):Response =
-  var rows = RDB().table("Fortune").orderBy("message", Asc).get()
-  rows = rows.mapIt(%*{
-    "id": it["id"],
-    "message": xmlEncode(it["message"].getStr)
-  })
-  rows.add(%*{
-    "id": 0,
-    "message": "Additional fortune added at request time."}
-  )
-  rows = rows.sortedByIt(it["message"].getStr)
-  return render(this.view.fortuneView(rows))
-
-proc update*(this:BenchmarkController):Response =
-  var countNum:int
-  try:
-    countNum = this.request.params["queries"].parseInt()
-  except:
-    countNum = 1
-
-  if countNum < 1:
-    countNum = 1
-  elif countNum > 500:
-    countNum = 500
-
-  var response = newJArray()
-  transaction:
-    for _ in 1..countNum:
-        let i = rand(1..10000)
-        let newRandomNumber = rand(1..10000)
-        discard RDB().table("world").find(i)
-        RDB().table("world").where("id", "=", i).update(%*{"randomNumber": newRandomNumber})
-        response.add(%*{"id":i, "randomNumber": newRandomNumber})
-  return render(response)

+ 102 - 0
frameworks/Nim/basolato/app/http/controllers/benchmark_controller.nim

@@ -0,0 +1,102 @@
+import std/algorithm
+import std/json
+import std/random
+import std/strutils
+import std/sequtils
+# framework
+import basolato/controller
+# databse
+import db_connector/db_postgres
+import allographer/query_builder
+import ../../../config/database
+# model
+import ../../models/fortune
+# view
+import ../views/pages/fortune_scf_view
+
+
+const range1_10000 = 1..10000
+let getFirstPrepare = stdRdb.prepare("getFirst", sql""" SELECT * FROM "World" WHERE id = $1 LIMIT 1 """, 1)
+let getFortunePrepare = stdRdb.prepare("getFortunes", sql""" SELECT * FROM "Fortune" ORDER BY message ASC """, 0)
+
+
+proc plaintext*(context:Context, params:Params):Future[Response] {.async.} =
+  let headers = newHttpHeaders()
+  headers.add("Content-Type", "text/plain; charset=UTF-8")
+  return render("Hello, World!", headers)
+
+
+proc json*(context:Context, params:Params):Future[Response] {.async.} =
+  return render(%*{"message":"Hello, World!"})
+
+
+proc db*(context:Context, params:Params):Future[Response] {.async.} =
+  let i = rand(1..10000)
+  let res = stdRdb.getRow(getFirstPrepare, i)
+  return render(%*{"id": res[0].parseInt, "randomNumber": res[1].parseInt})
+
+
+proc query*(context:Context, params:Params):Future[Response] {.async.} =
+  var countNum =
+    try:
+      params.getInt("queries")
+    except:
+      1
+  if countNum < 1:
+    countNum = 1
+  elif countNum > 500:
+    countNum = 500
+
+  var resp:seq[Row]
+  for i in 1..countNum:
+    let n = rand(range1_10000)
+    resp.add(stdRdb.getRow(getFirstPrepare, n))
+
+  let response = resp.map(
+    proc(x:Row):JsonNode =
+      %*{"id": x[0].parseInt, "randomNumber": x[1].parseInt}
+  )
+  return render(%response)
+
+
+proc fortune*(context:Context, params:Params):Future[Response] {.async.} =
+  let results = stdRdb.getAllRows(getFortunePrepare)
+  var rows = results.map(
+    proc(x:seq[string]):Fortune =
+      return Fortune(id: x[0].parseInt, message: x[1])
+  )
+  rows.add(
+    Fortune(
+      id: 0,
+      message: "Additional fortune added at request time."
+    )
+  )
+  rows = rows.sortedByIt(it.message)
+  return render(fortuneScfView(rows).await)
+
+
+proc update*(context:Context, params:Params):Future[Response] {.async.} =
+  var countNum =
+    try:
+      params.getInt("queries")
+    except:
+      1
+  if countNum < 1:
+    countNum = 1
+  elif countNum > 500:
+    countNum = 500
+
+  var response = newSeq[JsonNode](countNum)
+  var futures = newSeq[Future[void]](countNum)
+  for i in 1..countNum:
+    let index = rand(range1_10000)
+    let number = rand(range1_10000)
+    response[i-1] = %*{"id": index, "randomNumber": number}
+    futures[i-1] = (
+      proc():Future[void] {.async.} =
+        discard stdRdb.getRow(getFirstPrepare, i)
+        rdb.raw(""" UPDATE "World" SET "randomnumber" = ? WHERE id = ? """, %*[number, index]).exec()
+    )()
+  all(futures).await
+
+  return render(%response)

+ 29 - 0
frameworks/Nim/basolato/app/http/views/pages/fortune_scf_view.nim

@@ -0,0 +1,29 @@
+#? stdtmpl(toString="toString") | standard
+#import std/asyncdispatch
+#import basolato/view
+#import ../../../models/fortune
+#proc fortuneScfView*(rows:seq[Fortune]):Future[Component] {.async.} =
+# result = Component.new()
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>Fortunes</title>
+</head>
+
+<body>
+  <table>
+    <tr>
+      <th>id</th>
+      <th>message</th>
+    </tr>
+    #for row in rows:
+      <tr>
+        <td>${row.id}</td>
+        <td>${row.message}</td>
+      </tr>
+    #end for
+  </table>
+</body>
+
+</html>

+ 0 - 11
frameworks/Nim/basolato/app/middlewares/framework_middleware.nim

@@ -1,11 +0,0 @@
-import re
-import basolato/middleware
-import basolato/routing
-from custom_headers_middleware import corsHeader
-
-template framework*() =
-  if request.path.match(re"^(?!.*\.).*$"):
-    checkCsrfToken(request).catch()
-    checkAuthToken(request).catch(ErrorAuthRedirect, "/login")
-    if request.reqMethod == HttpOptions:
-      route(render(""), [corsHeader()])

+ 3 - 0
frameworks/Nim/basolato/app/models/fortune.nim

@@ -0,0 +1,3 @@
+type Fortune* = object
+  id*:int
+  message*:string

+ 62 - 16
frameworks/Nim/basolato/basolato.dockerfile

@@ -1,27 +1,73 @@
-FROM nimlang/nim:alpine
+FROM ubuntu:22.04 AS build
 
-ENV PATH $PATH:/root/.nimble/bin
+# prevent timezone dialogue
+ENV DEBIAN_FRONTEND=noninteractive
 
-RUN echo http://dl-cdn.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories
-RUN apk update && \
-    apk upgrade --no-cache && \
-    apk add --no-cache \
-        openssh-client \
+RUN apt update && \
+    apt upgrade -y
+RUN apt install -y --fix-missing \
+        gcc \
+        xz-utils \
         ca-certificates \
-        openssl \
-        pcre \
-        bsd-compat-headers \
-        lcov \
-        sqlite mariadb-dev libpq && \
-    rm /usr/lib/mysqld* -fr && rm /usr/bin/mysql* -fr && \
-    update-ca-certificates
+        curl \
+        git
+
+ARG VERSION="2.0.2"
+WORKDIR /root
+RUN curl https://nim-lang.org/choosenim/init.sh -o init.sh
+RUN sh init.sh -y
+RUN rm -f init.sh
+ENV PATH $PATH:/root/.nimble/bin
+RUN choosenim ${VERSION}
+
+ENV PATH $PATH:/root/.nimble/bin
 
 ADD ./ /basolato
 WORKDIR /basolato
 
 RUN nimble install -y
-RUN ducere build
+RUN ducere build -p:8080 -o:speed
+
+
+FROM ubuntu:22.04 AS runtime
+
+# prevent timezone dialogue
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt update && \
+    apt upgrade -y
+RUN apt install -y --fix-missing \
+        xz-utils \
+        ca-certificates \
+        libpq-dev
+
+WORKDIR /basolato
+COPY --from=build /basolato/main .
+RUN chmod 111 main
+COPY --from=build /basolato/startServer.sh .
+RUN chmod 111 startServer.sh
+
+
+# Secret
+ENV SECRET_KEY="pZWEVzA7h2FcKLgVM3ec5Eiik7eU9Ehpf0uLdYOZDgr0uZKIo5LdQE9sjIub3IDkUTrf3X2Jsh1Uw8b02GtAfWRn4C9NptfdSyoK"
+# DB Connection
+ENV DB_DATABASE="hello_world"
+ENV DB_USER="benchmarkdbuser"
+ENV DB_PASSWORD="benchmarkdbpass"
+ENV DB_HOST="tfb-database"
+ENV DB_PORT=5432
+ENV DB_MAX_CONNECTION=2000
+ENV DB_TIMEOUT=30
+# Logging
+ENV LOG_IS_DISPLAY=false
+ENV LOG_IS_FILE=false
+ENV LOG_IS_ERROR_FILE=false
+# Session db
+# Session type, file or redis, is defined in config.nims
+ENV SESSION_TIME=20160
+ENV LOCALE=en
+
 
 EXPOSE 8080
 
-CMD ./main
+CMD ./startServer.sh

+ 22 - 0
frameworks/Nim/basolato/basolato.nimble

@@ -0,0 +1,22 @@
+# Package
+version       = "0.1.0"
+author        = "Anonymous"
+description   = "A new awesome basolato package"
+license       = "MIT"
+srcDir        = "."
+bin           = @["main"]
+backend       = "c"
+
+# Dependencies
+requires "nim >= 2.0.0"
+requires "https://github.com/itsumura-h/nim-basolato == 0.15.0"
+requires "allographer == 0.29.1"
+requires "interface_implements >= 0.2.2"
+requires "bcrypt >= 0.2.1"
+requires "cligen >= 1.5.9"
+requires "redis >= 0.3.0"
+requires "sass >= 0.1.0"
+
+task test, "run testament":
+  echo staticExec("testament p \"./tests/test_*.nim\"")
+  discard staticExec("find tests/ -type f ! -name \"*.*\" -delete 2> /dev/null")

+ 3 - 4
frameworks/Nim/basolato/benchmark_config.json

@@ -7,8 +7,8 @@
         "plaintext_url": "/plaintext",
         "db_url": "/db",
         "query_url": "/queries?queries=",
-        "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
+        "fortune_url": "/fortunes",
         "port": 8080,
         "approach": "Realistic",
         "classification": "Fullstack",
@@ -17,14 +17,13 @@
         "language": "Nim",
         "flavor": "None",
         "orm": "Full",
-        "platform": "httpbeast",
+        "platform": "asynchttpserver",
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
         "display_name": "Basolato",
         "notes": "",
-        "versus": "jester",
-        "tags": ["broken"]
+        "versus": "httpbeast, prologue"
       }
     }
   ]

+ 9 - 20
frameworks/Nim/basolato/config.nims

@@ -1,20 +1,9 @@
-import os
-
-# DB Connection
-putEnv("DB_DRIVER", "postgres")
-putEnv("DB_CONNECTION", "tfb-database:5432")
-putEnv("DB_USER", "benchmarkdbuser")
-putEnv("DB_PASSWORD", "benchmarkdbpass")
-putEnv("DB_DATABASE", "hello_world")
-
-# Logging
-putEnv("LOG_IS_DISPLAY", "false")
-putEnv("LOG_IS_FILE", "false")
-putEnv("LOG_DIR", "/basolato/logs")
-
-# Security
-putEnv("SECRET_KEY", "1p>G<bEpKnvD^d/nQ,26#!g~") # 24 length
-putEnv("CSRF_TIME", "525600") # minutes of 1 year
-putEnv("SESSION_TIME", "20160") # minutes of 2 weeks
-putEnv("SESSION_DB", "/basolato/session.db")
-putEnv("IS_SESSION_MEMORY", "false")
+import std/os
+putEnv("HOST", "0.0.0.0")
+# putEnv("DB_SQLITE", $true) # "true" or "false"
+putEnv("DB_POSTGRES", $true) # "true" or "false"
+# putEnv("DB_MYSQL", $true) # "true" or "false"
+# putEnv("DB_MARIADB", $true) # "true" or "false"
+putEnv("SESSION_TYPE", "file") # "file" or "redis"
+putEnv("SESSION_DB_PATH", "./session.db") # Session file path or redis host:port. ex:"127.0.0.1:6379"
+putEnv("LIBSASS", $false) # "true" or "false"

+ 0 - 19
frameworks/Nim/basolato/config.toml

@@ -1,19 +0,0 @@
-[framework]
-name = "basolato"
-
-[main]
-urls.plaintext = "/plaintext"
-urls.json = "/json"
-urls.db = "/db"
-urls.query = "/queries?queries="
-urls.update = "/updates?queries="
-urls.fortune = "/fortunes"
-approach = "Realistic"
-classification = "Fullstack"
-database = "postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Full"
-platform = "httpbeast"
-webserver = "None"
-versus = "jester"

+ 30 - 0
frameworks/Nim/basolato/config/database.nim

@@ -0,0 +1,30 @@
+import std/os
+import std/strutils
+import db_connector/db_postgres
+import allographer/connection
+
+when defined(release):
+  import std/cpuinfo
+
+let maxConnections =
+  when defined(release):
+    (getEnv("DB_MAX_CONNECTION").parseInt div countProcessors()) - 2
+  else:
+    95
+echo "maxConnections: ",maxConnections
+
+let rdb* = dbopen(
+  PostgreSQL, # SQLite3 or MySQL or MariaDB or PostgreSQL
+  getEnv("DB_DATABASE"),
+  getEnv("DB_USER"),
+  getEnv("DB_PASSWORD"),
+  getEnv("DB_HOST"),
+  getEnv("DB_PORT").parseInt,
+  maxConnections,
+  getEnv("DB_TIMEOUT").parseInt,
+  getEnv("LOG_IS_DISPLAY").parseBool,
+  getEnv("LOG_IS_FILE").parseBool,
+  getEnv("LOG_DIR"),
+)
+
+let stdRdb* = open(getEnv("DB_HOST"), getEnv("DB_USER"), getEnv("DB_PASSWORD"), getEnv("DB_DATABASE"))

BIN
frameworks/Nim/basolato/main


+ 11 - 14
frameworks/Nim/basolato/main.nim

@@ -1,19 +1,16 @@
 # framework
-import basolato/routing
+import basolato
 # controller
-import app/controllers/benchmark_controller
+import ./app/http/controllers/benchmark_controller
 
-settings:
-  port = Port(8080)
 
-routes:
-  # Framework
-  error Http404: http404Route
-  error Exception: exceptionRoute
+let routes = @[
+  Route.get("/plaintext", benchmark_controller.plainText),
+  Route.get("/json", benchmark_controller.json),
+  Route.get("/db", benchmark_controller.db),
+  Route.get("/queries", benchmark_controller.query),
+  Route.get("/fortunes", benchmark_controller.fortune),
+  Route.get("/updates", benchmark_controller.update),
+]
 
-  get "/json": route(newBenchmarkController(request).json())
-  get "/plaintext": route(newBenchmarkController(request).plainText())
-  get "/db": route(newBenchmarkController(request).db())
-  get "/queries": route(newBenchmarkController(request).query())
-  get "/fortunes": route(newBenchmarkController(request).fortune())
-  get "/updates": route(newBenchmarkController(request).update())
+serve(routes)

+ 0 - 23
frameworks/Nim/basolato/project.nimble

@@ -1,23 +0,0 @@
-# Package
-
-version       = "0.1.0"
-author        = "Anonymous"
-description   = "A new awesome basolato package"
-license       = "MIT"
-srcDir        = "."
-bin           = @["main"]
-
-backend       = "c"
-
-# Dependencies
-
-requires "nim >= 1.2.4"
-requires "https://github.com/itsumura-h/nim-basolato >= 0.5.5"
-requires "httpbeast >= 0.2.2"
-requires "cligen >= 0.9.41"
-requires "templates >= 0.5"
-requires "bcrypt >= 0.2.1"
-requires "nimAES >= 0.1.2"
-requires "flatdb >= 0.2.4"
-requires "allographer >= 0.9.0"
-requires "faker >= 0.12.1"

+ 0 - 32
frameworks/Nim/basolato/resources/pages/fortune_view.nim

@@ -1,32 +0,0 @@
-import json
-import basolato/view
-
-proc impl(title:string, data:seq[JsonNode]):string = tmpli html"""
-<!DOCTYPE html>
-<html>
-
-<head>
-  <title>$title</title>
-</head>
-
-<body>
-  <table>
-    <tr>
-      <th>id</th>
-      <th>message</th>
-    </tr>
-    $for row in data{
-      <tr>
-        <td>$(row["id"].get)</td>
-        <td>$(row["message"].get)</td>
-      </tr>
-    }
-  </table>
-</body>
-
-</html>
-"""
-
-proc fortuneView*(this:View, data=newSeq[JsonNode]()):string =
-  let title = "Fortunes"
-  return impl(title, data)